From 05a7638761733a0326134e7d542c67690e1b02df Mon Sep 17 00:00:00 2001 From: frelodev Date: Tue, 1 Oct 2024 19:44:55 +0200 Subject: [PATCH] feat: leave and detach --- package.json | 11 +++++++++-- src/commands/buffers.ts | 36 ++++++++++++++++++++++++++++++------ src/commands/client.ts | 19 +++++++++++++++---- src/commands/workspaces.ts | 2 +- src/extension.ts | 6 ++++-- src/mapping.ts | 14 +++++++++++++- 6 files changed, 72 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index eb280c2..6086bd7 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "homepage": "https://code.mp", "repository": "https://github.com/hexedtech/codemp-vscode", "publisher": "hexedtech", - "version": "0.1.2", + "version": "0.1.3", "engines": { "vscode": "^1.81.0" }, @@ -173,7 +173,14 @@ "title": "Jump", "category": "codemp", "icon": "$(debug-console-evaluation-input)" + }, + { + "command": "codemp.forceDesync", + "title": "Desync", + "category": "codemp" } + + ], "configuration": { "title": "codemp", @@ -236,6 +243,6 @@ "typescript": "^5.1.6" }, "dependencies": { - "codemp": "^0.7.2" + "codemp": "^0.7.3" } } diff --git a/src/commands/buffers.ts b/src/commands/buffers.ts index 594d4c4..08f086f 100644 --- a/src/commands/buffers.ts +++ b/src/commands/buffers.ts @@ -8,10 +8,13 @@ import { LOGGER, provider } from '../extension'; let locks: Map = new Map(); let autoResync = vscode.workspace.getConfiguration('codemp').get("autoResync"); -export async function apply_changes_to_buffer(path: string, controller: codemp.BufferController | undefined | null, force?: boolean) { - if (workspace === null) throw "can't apply changes while not in a workspace"; - if (!controller) controller = workspace.buffer_by_name(path); - if (!controller) return; +export async function apply_changes_to_buffer(path: string, controller: codemp.BufferController, force?: boolean) { + if (workspace === null) { + LOGGER.info(`left workspace, unregistering buffer controller '${path}' callback`); + controller.clear_callback(); + return; + } + let editor = mapping.bufferMapper.visible_by_buffer(path); if (editor === undefined) return; @@ -88,7 +91,6 @@ export async function attach_to_remote_buffer(buffer_name: string, set_content?: LOGGER.info(`attached to buffer ${buffer_name}`); let file_uri: vscode.Uri = editor.document.uri; - mapping.bufferMapper.register(buffer.get_path(), file_uri); let remoteContent = await buffer.content(); let localContent = editor.document.getText(); @@ -110,7 +112,7 @@ export async function attach_to_remote_buffer(buffer_name: string, set_content?: }); } - vscode.workspace.onDidChangeTextDocument(async (event: vscode.TextDocumentChangeEvent) => { + let disposable = vscode.workspace.onDidChangeTextDocument(async (event: vscode.TextDocumentChangeEvent) => { if (locks.get(buffer_name)) { return } if (event.document.uri !== file_uri) return; // ? for (let change of event.contentChanges) { @@ -127,6 +129,8 @@ export async function attach_to_remote_buffer(buffer_name: string, set_content?: await apply_changes_to_buffer(controller.get_path(), controller) ); + mapping.bufferMapper.register(buffer.get_path(), file_uri, disposable); + provider.refresh(); } @@ -146,6 +150,26 @@ export async function attach(selected: vscode.TreeItem | undefined) { await attach_to_remote_buffer(buffer_name); } +export async function detach(selected: vscode.TreeItem | undefined) { + if (workspace === null) return vscode.window.showWarningMessage("Not in a workspace"); + let buffer_name: string | undefined; + if (selected !== undefined && selected.label !== undefined) { + if (typeof (selected.label) === 'string') { + buffer_name = selected.label; + } else { + buffer_name = selected.label.label; // TODO ughh what is this api? + } + } else { + buffer_name = await vscode.window.showInputBox({ prompt: "path of buffer to attach to" }); + } + if (!buffer_name) return; + let controller = workspace.buffer_by_name(buffer_name); + if (controller) controller.clear_callback(); + workspace.detach(buffer_name); + mapping.bufferMapper.remove(buffer_name); + vscode.window.showInformationMessage(`Detached from buffer ${buffer_name}`) +} + export async function share(selected: vscode.TreeItem | undefined) { if (workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); diff --git a/src/commands/client.ts b/src/commands/client.ts index 2315e3a..9950f92 100644 --- a/src/commands/client.ts +++ b/src/commands/client.ts @@ -8,6 +8,7 @@ import { LOGGER, provider } from '../extension'; // TODO this "global state" should probably live elsewher but we need lo update it from these commands export let client: codemp.Client | null = null; export let workspace_list: string[] = []; +export let cursor_disposable : vscode.Disposable | null; export async function connect() { let config = vscode.workspace.getConfiguration('codemp'); @@ -61,6 +62,11 @@ export async function join(selected: vscode.TreeItem | undefined) { controller.callback(async function(controller: codemp.CursorController) { while (true) { let event = await controller.try_recv(); + if (workspace === null) { + controller.clear_callback(); + LOGGER.info("left workspace, stopping cursor controller"); + return; + } if (event === null) break; if (event.user === undefined) { LOGGER.warn(`Skipping cursor event without user: ${event}`) @@ -80,7 +86,7 @@ export async function join(selected: vscode.TreeItem | undefined) { }); let once = true; - vscode.window.onDidChangeTextEditorSelection(async (event: vscode.TextEditorSelectionChangeEvent) => { + cursor_disposable = vscode.window.onDidChangeTextEditorSelection(async (event: vscode.TextEditorSelectionChangeEvent) => { if (event.kind == vscode.TextEditorSelectionChangeKind.Command) return; // TODO commands might move cursor too let buf = event.textEditor.document.uri; let selection: vscode.Selection = event.selections[0] @@ -138,9 +144,14 @@ export async function join(selected: vscode.TreeItem | undefined) { provider.refresh(); } - - - +export async function leave() { + if (!client) throw "can't leave while disconnected"; + if (!workspace) return vscode.window.showWarningMessage("Not in a workspace"); + client.leave_workspace(workspace.id()); + if (cursor_disposable !== null) cursor_disposable.dispose(); + cursor_disposable = null; + setWorkspace(null); +} export async function listWorkspaces() { diff --git a/src/commands/workspaces.ts b/src/commands/workspaces.ts index 06955f1..f04351e 100644 --- a/src/commands/workspaces.ts +++ b/src/commands/workspaces.ts @@ -8,7 +8,7 @@ import { LOGGER, provider } from '../extension'; export let workspace: codemp.Workspace | null = null; -export function setWorkspace(ws: codemp.Workspace) { +export function setWorkspace(ws: codemp.Workspace | null) { workspace = ws; } diff --git a/src/extension.ts b/src/extension.ts index 7812f3c..f1a6d1c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -22,8 +22,10 @@ export function activate(context: vscode.ExtensionContext) { if (workspace === null) return; for (let editor of editors) { let path = mapping.bufferMapper.by_editor(editor.document.uri); - if (path === undefined) continue; - await apply_changes_to_buffer(path, undefined, true); + if (!path) continue; + let controller = workspace.buffer_by_name(path); + if (!controller) continue; + await apply_changes_to_buffer(path, controller, true); } }); diff --git a/src/mapping.ts b/src/mapping.ts index cc3f99d..93a04e1 100644 --- a/src/mapping.ts +++ b/src/mapping.ts @@ -3,11 +3,13 @@ import * as codemp from 'codemp'; class BufferMapper { bufferToEditorMapping: Map = new Map(); + bufferToDisposableMapping: Map = new Map(); editorToBufferMapping: Map = new Map(); - public register(buffer: string, uri: vscode.Uri) { + public register(buffer: string, uri: vscode.Uri, disposable: vscode.Disposable) { this.bufferToEditorMapping.set(buffer, uri); this.editorToBufferMapping.set(uri, buffer); + this.bufferToDisposableMapping.set(buffer, disposable); } public uri_by_buffer(name: string): vscode.Uri | undefined { @@ -24,6 +26,16 @@ class BufferMapper { return this.editorToBufferMapping.get(name); } + public remove(name: string) { + let uri = this.bufferToEditorMapping.get(name); + let disposable = this.bufferToDisposableMapping.get(name); + if (disposable) disposable.dispose(); + if (!uri) return; + this.bufferToEditorMapping.delete(name); + this.editorToBufferMapping.delete(uri); + this.bufferToDisposableMapping.delete(name); + } + private constructor() { } public static instance = new BufferMapper();