diff --git a/src/commands/buffers.ts b/src/commands/buffers.ts index 53cf1bb..219d4c5 100644 --- a/src/commands/buffers.ts +++ b/src/commands/buffers.ts @@ -1,7 +1,7 @@ import * as vscode from 'vscode'; import * as codemp from 'codemp'; import * as mapping from "../mapping"; -import { workspace } from "./workspaces"; +import { workspaceState } from "./workspaces"; import { LOGGER, provider } from '../extension'; let singles: Map = new Map(); @@ -16,7 +16,7 @@ export async function apply_changes_to_buffer(path: string, controller: codemp.B singles.set(path, true); while (true) { - if (workspace === null) { + if (workspaceState.workspace === null) { LOGGER.info(`left workspace, unregistering buffer controller '${path}' callback`); controller.clear_callback(); return; @@ -36,7 +36,7 @@ export async function apply_changes_to_buffer(path: string, controller: codemp.B .replace(range, event.content) })) { vscode.window.showWarningMessage("Couldn't apply changes"); - await resync(path, workspace, editor, 100); + await resync(path, workspaceState.workspace, editor, 100); } locks.delete(path); @@ -44,12 +44,12 @@ export async function apply_changes_to_buffer(path: string, controller: codemp.B if (codemp.hash(editor.document.getText()) !== event.hash) { if (autoResync) { vscode.window.showWarningMessage("Out of Sync, resynching..."); - await resync(path, workspace, editor, 20); + await resync(path, workspaceState.workspace, editor, 20); } else { controller.clear_callback(); const selection = await vscode.window.showWarningMessage('Out of Sync', 'Resync'); - if (selection !== undefined && workspace) { - await resync(path, workspace, editor, 20); + if (selection !== undefined && workspaceState.workspace) { + await resync(path, workspaceState.workspace, editor, 20); controller.callback(async (controller: codemp.BufferController) => await apply_changes_to_buffer(controller.get_path(), controller) ); @@ -62,7 +62,7 @@ export async function apply_changes_to_buffer(path: string, controller: codemp.B } export async function attach_to_remote_buffer(buffer_name: string, set_content?: boolean): Promise { - if (workspace === null) { + if (workspaceState.workspace === null) { vscode.window.showErrorMessage("join a Workspace first"); return; } @@ -86,7 +86,7 @@ export async function attach_to_remote_buffer(buffer_name: string, set_content?: let doc = await vscode.workspace.openTextDocument(path); let editor = await vscode.window.showTextDocument(doc, { preserveFocus: false }) await editor.edit((editor) => editor.setEndOfLine(vscode.EndOfLine.LF)); // set LF for EOL sequence - let buffer: codemp.BufferController = await workspace.attach(buffer_name); + let buffer: codemp.BufferController = await workspaceState.workspace.attach(buffer_name); // wait for server changes // TODO poll never unblocks, so this dirty fix is necessary @@ -148,7 +148,7 @@ export async function attach_to_remote_buffer(buffer_name: string, set_content?: } export async function attach(selected: vscode.TreeItem | undefined) { - if (workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); + if (workspaceState.workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); let buffer_name: string | undefined; if (selected !== undefined && selected.label !== undefined) { if (typeof (selected.label) === 'string') { @@ -157,14 +157,14 @@ export async function attach(selected: vscode.TreeItem | undefined) { buffer_name = selected.label.label; // TODO ughh what is this api? } } else { - buffer_name = await vscode.window.showQuickPick(workspace.filetree(null, false), { placeHolder: "buffer to attach to:" }, undefined); + buffer_name = await vscode.window.showQuickPick(workspaceState.workspace.filetree(null, false), { placeHolder: "buffer to attach to:" }, undefined); } if (!buffer_name) return; 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"); + if (workspaceState.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') { @@ -173,12 +173,12 @@ export async function detach(selected: vscode.TreeItem | undefined) { buffer_name = selected.label.label; // TODO ughh what is this api? } } else { - buffer_name = await vscode.window.showQuickPick(workspace.buffer_list(), { placeHolder: "buffer to detach from:" }, undefined); + buffer_name = await vscode.window.showQuickPick(workspaceState.workspace.buffer_list(), { placeHolder: "buffer to detach from:" }, undefined); } if (!buffer_name) return; - let controller = workspace.buffer_by_name(buffer_name); + let controller = workspaceState.workspace.buffer_by_name(buffer_name); if (controller) controller.clear_callback(); - workspace.detach(buffer_name); + workspaceState.workspace.detach(buffer_name); mapping.bufferMapper.remove(buffer_name); vscode.window.showInformationMessage(`Detached from buffer ${buffer_name}`) provider.refresh(); @@ -186,7 +186,7 @@ export async function detach(selected: vscode.TreeItem | undefined) { export async function share() { - if (workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); + if (workspaceState.workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); let buffer_name: string | undefined; if (vscode.window.activeTextEditor !== null) { buffer_name = vscode.window.activeTextEditor?.document.uri.toString(); @@ -198,12 +198,12 @@ export async function share() { let workspacePath: string = vscode.workspace.workspaceFolders[0].uri.toString(); buffer_name = buffer_name.replace(workspacePath, "").substring(1); //vscode.workspace.asRelativePath doesn't work properly with other extensions like ssh, substring(1) to remove "/" console.log("After: " + buffer_name); - await workspace.create(buffer_name); + await workspaceState.workspace.create(buffer_name); await attach_to_remote_buffer(buffer_name, true); } export async function sync(selected: vscode.TreeItem | undefined) { - if (workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); + if (workspaceState.workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); let editor; let buffer_name; if (selected !== undefined && selected.label !== undefined) { @@ -221,7 +221,7 @@ export async function sync(selected: vscode.TreeItem | undefined) { if (buffer_name === undefined) return vscode.window.showWarningMessage("Buffer not synched with codemp"); } - resync(buffer_name, workspace, editor); + resync(buffer_name, workspaceState.workspace, editor); } export async function resync(buffer_name: string, workspace: codemp.Workspace, editor: vscode.TextEditor, tries?: number) { diff --git a/src/commands/client.ts b/src/commands/client.ts index d7b2b96..251fd2e 100644 --- a/src/commands/client.ts +++ b/src/commands/client.ts @@ -1,7 +1,7 @@ import * as vscode from 'vscode'; import * as codemp from 'codemp'; import * as mapping from "../mapping"; -import { workspace, setWorkspace, follow, setFollow, executeJump } from "./workspaces"; +import { executeJump, workspaceState } from "./workspaces"; import { LOGGER, provider } from '../extension'; @@ -9,7 +9,6 @@ import { LOGGER, provider } from '../extension'; export let client: codemp.Client | null = null; export let workspace_list: string[] = []; export let cursor_disposable: vscode.Disposable | null; -let movedByFollow = false; export async function connect() { let config = vscode.workspace.getConfiguration('codemp'); @@ -57,13 +56,12 @@ export async function join(selected: vscode.TreeItem | undefined) { let ws = await vscode.window.showWorkspaceFolderPick({ placeHolder: "directory to open workspace into:" }); if (ws === undefined) return vscode.window.showErrorMessage("Open a Workspace folder first"); } - setWorkspace(await client.join_workspace(workspace_id)); - if (!workspace) return; - let controller = workspace.cursor(); + workspaceState.workspace = await client.join_workspace(workspace_id); + let controller = workspaceState.workspace.cursor(); controller.callback(async function (controller: codemp.CursorController) { while (true) { let event = await controller.try_recv(); - if (workspace === null) { + if (workspaceState.workspace === null) { controller.clear_callback(); LOGGER.info("left workspace, stopping cursor controller"); return; @@ -79,14 +77,11 @@ export async function join(selected: vscode.TreeItem | undefined) { mapping.colors_cache.set(event.user, mapp); provider.refresh(); } - if (follow === event.user) { - movedByFollow = true; - executeJump(event.user); - } let editor = mapping.bufferMapper.visible_by_buffer(event.buffer); let refresh = event.buffer != mapp.buffer; mapp.update(event, editor); + if (workspaceState.follow === event.user) executeJump(event.user); if (refresh) provider.refresh(); } }); @@ -94,8 +89,8 @@ export async function join(selected: vscode.TreeItem | undefined) { let once = true; cursor_disposable = vscode.window.onDidChangeTextEditorSelection(async (event: vscode.TextEditorSelectionChangeEvent) => { if (event.kind == vscode.TextEditorSelectionChangeKind.Command) return; // TODO commands might move cursor too - if (!movedByFollow) setFollow(null); - else movedByFollow = false; + if (!workspaceState.justJumped) workspaceState.follow = null; + workspaceState.justJumped = false; let buf = event.textEditor.document.uri; let selection: vscode.Selection = event.selections[0]; let buffer = mapping.bufferMapper.by_editor(buf); @@ -128,8 +123,8 @@ export async function join(selected: vscode.TreeItem | undefined) { let event_handler = async () => { try { while (true) { - if (workspace === null) break; - let event = await workspace.event(); + if (workspaceState.workspace === null) break; + let event = await workspaceState.workspace.event(); if (event.type == "leave") { mapping.colors_cache.get(event.value)?.clear() mapping.colors_cache.delete(event.value); @@ -145,7 +140,7 @@ export async function join(selected: vscode.TreeItem | undefined) { }; event_handler(); - for (let user of workspace.user_list()) { + for (let user of workspaceState.workspace.user_list()) { mapping.colors_cache.set(user, new mapping.UserDecoration(user)); } @@ -183,12 +178,12 @@ export async function inviteToWorkspace() { export async function leave() { if (!client) throw "can't leave while disconnected"; - if (!workspace) throw "can't leave while not in a workspace"; - workspace.cursor().clear_callback() - client.leave_workspace(workspace.id()); + if (!workspaceState.workspace) throw "can't leave while not in a workspace"; + workspaceState.workspace.cursor().clear_callback() + client.leave_workspace(workspaceState.workspace.id()); if (cursor_disposable !== null) cursor_disposable.dispose(); - let workspace_id = workspace.id(); - setWorkspace(null); + let workspace_id = workspaceState.workspace.id(); + workspaceState.workspace = null; provider.refresh(); vscode.window.showInformationMessage("Left workspace " + workspace_id); } diff --git a/src/commands/workspaces.ts b/src/commands/workspaces.ts index 85a98bf..5adad92 100644 --- a/src/commands/workspaces.ts +++ b/src/commands/workspaces.ts @@ -5,17 +5,15 @@ import { client } from "./client" import { LOGGER, provider } from '../extension'; -export let workspace: codemp.Workspace | null = null; -export let follow: string | null = null; - - -export function setWorkspace(ws: codemp.Workspace | null) { - workspace = ws; -} - -export function setFollow(doFollow: string | null) { - follow = doFollow; -} +export let workspaceState: { + workspace: codemp.Workspace | null, + follow: string | null, + justJumped: boolean, +} = { + workspace: null, + follow: null, + justJumped: false, +}; export async function jump(selected: vscode.TreeItem | undefined) { @@ -30,7 +28,7 @@ export async function jump(selected: vscode.TreeItem | undefined) { } if (!user) user = await vscode.window.showInputBox({ prompt: "username" }); if (!user) return; // user cancelled with ESC - setFollow(user); + workspaceState.follow=user; executeJump(user); } @@ -41,35 +39,36 @@ export async function executeJump(user: string) { if (uri === undefined) { return vscode.window.showWarningMessage("user is on an untracked buffer: " + user_hl.buffer); } - let editor = await vscode.window.showTextDocument(uri, { preserveFocus: false }); + let editor = vscode.window.activeTextEditor; + if (editor === undefined || editor.document.uri != uri) { + workspaceState.justJumped = true; + editor = await vscode.window.showTextDocument(uri, { preserveFocus: false }); + } let range_start: vscode.Position = new vscode.Position(user_hl.startRow, user_hl.startCol); let range_end: vscode.Position = new vscode.Position(user_hl.endRow, user_hl.endCol); let cursor_range = new vscode.Range(range_start, range_end); editor.revealRange(cursor_range, vscode.TextEditorRevealType.InCenter); } - export async function createBuffer() { let bufferName: any = (await vscode.window.showInputBox({ prompt: "path of the buffer to create" })); - if (workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); - await workspace.create(bufferName); + if (workspaceState.workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); + await workspaceState.workspace.create(bufferName); vscode.window.showInformationMessage(`new buffer created :${bufferName}`); - listBuffers(); - //provider.refresh(); + provider.refresh(); } export async function listBuffers() { - if (workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); - let buffers = workspace.filetree(undefined, false); + if (workspaceState.workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); + let buffers = workspaceState.workspace.filetree(undefined, false); vscode.window.showInformationMessage(buffers.join("\n")); provider.refresh(); } export async function deleteBuffer() { let bufferName: any = (await vscode.window.showInputBox({ prompt: "path of the buffer to delete" })); - if (workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); - await workspace.delete(bufferName); + if (workspaceState.workspace === null) return vscode.window.showWarningMessage("Join a workspace first"); + await workspaceState.workspace.delete(bufferName); vscode.window.showInformationMessage(`Deleted buffer :${bufferName}`); - listBuffers(); - + provider.refresh(); } diff --git a/src/extension.ts b/src/extension.ts index c34c608..b012969 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -3,7 +3,7 @@ import * as codemp from 'codemp'; import { client, connect, join, refresh, createWorkspace, inviteToWorkspace, listWorkspaces, leave } from './commands/client'; import { CodempTreeProvider } from './tree'; import * as mapping from './mapping'; -import { workspace, jump, listBuffers, createBuffer, deleteBuffer } from './commands/workspaces' +import { workspaceState, jump, listBuffers, createBuffer, deleteBuffer } from './commands/workspaces' import { attach, share, sync, apply_changes_to_buffer, detach } from './commands/buffers' export let provider = new CodempTreeProvider(); @@ -19,11 +19,11 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(sub); vscode.window.onDidChangeVisibleTextEditors(async (editors: readonly vscode.TextEditor[]) => { - if (workspace === null) return; + if (workspaceState.workspace === null) return; for (let editor of editors) { let path = mapping.bufferMapper.by_editor(editor.document.uri); if (!path) continue; - let controller = workspace.buffer_by_name(path); + let controller = workspaceState.workspace.buffer_by_name(path); if (!controller) continue; await apply_changes_to_buffer(path, controller, true); } @@ -52,8 +52,8 @@ export function activate(context: vscode.ExtensionContext) { } export async function deactivate() { - if (client && workspace) { - await client.leave_workspace(workspace.id()); + if (client && workspaceState.workspace) { + await client.leave_workspace(workspaceState.workspace.id()); } } diff --git a/src/tree.ts b/src/tree.ts index 766d17a..eabdc64 100644 --- a/src/tree.ts +++ b/src/tree.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode'; import { client, workspace_list } from './commands/client'; -import { workspace } from './commands/workspaces'; +import { workspaceState } from './commands/workspaces'; import { bufferMapper, colors_cache } from './mapping'; export class CodempTreeProvider implements vscode.TreeDataProvider { @@ -22,9 +22,9 @@ export class CodempTreeProvider implements vscode.TreeDataProvider + if (workspaceState.workspace === null) return []; + else if (element.label == workspaceState.workspace.id()) { + return workspaceState.workspace.filetree(undefined, false).map((x) => new CodempTreeItem(x, Type.Buffer, { active: bufferMapper.bufferToEditorMapping.has(x) }) ); } else return []; @@ -48,9 +48,9 @@ export class CodempTreeProvider implements vscode.TreeDataProvider - new CodempTreeItem(x, Type.Workspace, { expandable: true, active: workspace === null }) + new CodempTreeItem(x, Type.Workspace, { expandable: true, active: workspaceState.workspace === null }) ); - if (workspace !== null) { + if (workspaceState.workspace !== null) { items.push(new CodempTreeItem("", Type.Placeholder, {})); items.push(new CodempTreeItem("Users", Type.UserList, { expandable: true })); }