2024-09-25 19:51:03 +02:00
|
|
|
import * as vscode from 'vscode';
|
|
|
|
import * as codemp from 'codemp';
|
|
|
|
import * as mapping from "../mapping";
|
2024-10-13 00:36:09 +02:00
|
|
|
import { executeJump, workspaceState } from "./workspaces";
|
2024-09-25 19:51:03 +02:00
|
|
|
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[] = [];
|
2024-10-05 18:21:20 +02:00
|
|
|
export let cursor_disposable: vscode.Disposable | null;
|
2024-09-25 19:51:03 +02:00
|
|
|
|
|
|
|
export async function connect() {
|
|
|
|
let config = vscode.workspace.getConfiguration('codemp');
|
|
|
|
|
|
|
|
let username = config.get<string>("username");
|
|
|
|
if (!username) {
|
|
|
|
return vscode.window.showErrorMessage("missing username in settings: configure it first!");
|
|
|
|
}
|
|
|
|
|
|
|
|
let password = config.get<string>("password");
|
|
|
|
if (!password) {
|
|
|
|
return vscode.window.showErrorMessage("missing password in settings: configure it first!");
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
client = await codemp.connect({
|
|
|
|
username: username,
|
|
|
|
password: password,
|
|
|
|
host: config.get<string>("server"),
|
|
|
|
port: config.get<number>("port"),
|
|
|
|
tls: config.get<boolean>("tls"),
|
|
|
|
});
|
|
|
|
vscode.window.showInformationMessage("Connected to codemp");
|
|
|
|
provider.refresh();
|
|
|
|
listWorkspaces(); // dont await, run in background
|
|
|
|
} catch (e) {
|
|
|
|
vscode.window.showErrorMessage("could not connect: " + e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function join(selected: vscode.TreeItem | undefined) {
|
|
|
|
if (client === null) return vscode.window.showWarningMessage("Connect first");
|
|
|
|
let workspace_id: string | undefined;
|
|
|
|
if (selected !== undefined && selected.label !== undefined) {
|
2024-10-01 16:11:36 +02:00
|
|
|
if (typeof (selected.label) === 'string') {
|
2024-09-25 19:51:03 +02:00
|
|
|
workspace_id = selected.label;
|
|
|
|
} else {
|
|
|
|
workspace_id = selected.label.label; // TODO ughh what is this api?
|
|
|
|
}
|
|
|
|
} else {
|
2024-10-12 23:56:45 +02:00
|
|
|
workspace_id = await vscode.window.showQuickPick(workspace_list, { placeHolder: "workspace to join:" }, undefined);
|
2024-09-25 19:51:03 +02:00
|
|
|
}
|
|
|
|
if (!workspace_id) return; // user cancelled with ESC
|
2024-10-01 16:11:36 +02:00
|
|
|
if (vscode.workspace.workspaceFolders === undefined) {
|
2024-10-12 23:56:45 +02:00
|
|
|
let ws = await vscode.window.showWorkspaceFolderPick({ placeHolder: "directory to open workspace into:" });
|
|
|
|
if (ws === undefined) return vscode.window.showErrorMessage("Open a Workspace folder first");
|
2024-09-25 19:51:03 +02:00
|
|
|
}
|
2024-10-20 17:25:27 +02:00
|
|
|
workspaceState.workspace = await client.attachWorkspace(workspace_id);
|
2024-10-13 00:36:09 +02:00
|
|
|
let controller = workspaceState.workspace.cursor();
|
2024-10-05 18:21:20 +02:00
|
|
|
controller.callback(async function (controller: codemp.CursorController) {
|
2024-09-25 19:51:03 +02:00
|
|
|
while (true) {
|
2024-10-20 17:25:27 +02:00
|
|
|
let event = await controller.tryRecv();
|
2024-10-13 00:36:09 +02:00
|
|
|
if (workspaceState.workspace === null) {
|
2024-10-20 17:25:27 +02:00
|
|
|
controller.clearCallback();
|
2024-10-01 19:44:55 +02:00
|
|
|
LOGGER.info("left workspace, stopping cursor controller");
|
|
|
|
return;
|
|
|
|
}
|
2024-09-25 19:51:03 +02:00
|
|
|
if (event === null) break;
|
|
|
|
if (event.user === undefined) {
|
|
|
|
LOGGER.warn(`Skipping cursor event without user: ${event}`)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let mapp = mapping.colors_cache.get(event.user);
|
|
|
|
if (mapp === undefined) { // first time we see this user
|
|
|
|
mapp = new mapping.UserDecoration(event.user);
|
|
|
|
mapping.colors_cache.set(event.user, mapp);
|
|
|
|
provider.refresh();
|
|
|
|
}
|
2024-10-12 23:07:16 +02:00
|
|
|
|
2024-10-20 17:25:27 +02:00
|
|
|
let editor = mapping.bufferMapper.visible_by_buffer(event.sel.buffer);
|
|
|
|
let refresh = event.sel.buffer != mapp.buffer;
|
2024-09-25 19:51:03 +02:00
|
|
|
mapp.update(event, editor);
|
2024-10-13 00:36:09 +02:00
|
|
|
if (workspaceState.follow === event.user) executeJump(event.user);
|
2024-09-25 19:51:03 +02:00
|
|
|
if (refresh) provider.refresh();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-10-01 18:54:30 +02:00
|
|
|
let once = true;
|
2024-10-01 19:44:55 +02:00
|
|
|
cursor_disposable = vscode.window.onDidChangeTextEditorSelection(async (event: vscode.TextEditorSelectionChangeEvent) => {
|
2024-09-25 19:51:03 +02:00
|
|
|
if (event.kind == vscode.TextEditorSelectionChangeKind.Command) return; // TODO commands might move cursor too
|
2024-10-13 00:36:09 +02:00
|
|
|
if (!workspaceState.justJumped) workspaceState.follow = null;
|
|
|
|
workspaceState.justJumped = false;
|
2024-09-25 19:51:03 +02:00
|
|
|
let buf = event.textEditor.document.uri;
|
2024-10-12 23:07:16 +02:00
|
|
|
let selection: vscode.Selection = event.selections[0];
|
|
|
|
let buffer = mapping.bufferMapper.by_editor(buf);
|
2024-10-01 18:54:30 +02:00
|
|
|
if (buffer === undefined) {
|
|
|
|
if (once) {
|
2024-10-26 18:40:52 +02:00
|
|
|
controller.send({
|
2024-10-01 18:54:30 +02:00
|
|
|
startRow: 0,
|
|
|
|
startCol: 0,
|
|
|
|
endRow: 0,
|
|
|
|
endCol: 0,
|
|
|
|
buffer: "",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
once = false;
|
|
|
|
} else {
|
2024-10-12 23:07:16 +02:00
|
|
|
|
2024-10-26 18:40:52 +02:00
|
|
|
controller.send({
|
2024-10-05 18:21:20 +02:00
|
|
|
startRow: selection.anchor.line,
|
|
|
|
startCol: selection.anchor.character,
|
|
|
|
endRow: selection.active.line,
|
2024-10-01 18:53:53 +02:00
|
|
|
endCol: selection.active.character,
|
2024-10-05 18:21:20 +02:00
|
|
|
buffer: buffer,
|
2024-10-01 18:54:30 +02:00
|
|
|
});
|
|
|
|
once = true;
|
2024-09-25 19:51:03 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-10-26 21:56:41 +02:00
|
|
|
|
2024-10-20 17:25:27 +02:00
|
|
|
workspaceState.workspace.callback(async function (controller: codemp.Workspace) {
|
2024-10-26 21:56:41 +02:00
|
|
|
while (true) {
|
|
|
|
if (workspaceState.workspace === null) {
|
|
|
|
controller.clearCallback();
|
|
|
|
LOGGER.info("left workspace, stopping receiving events");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let event = await workspaceState.workspace.tryRecv();
|
|
|
|
if (event === null) break;
|
|
|
|
if (event.type == "leave") {
|
|
|
|
mapping.colors_cache.get(event.value)?.clear()
|
|
|
|
mapping.colors_cache.delete(event.value);
|
|
|
|
}
|
|
|
|
if (event.type == "join") {
|
|
|
|
mapping.colors_cache.set(event.value, new mapping.UserDecoration(event.value));
|
|
|
|
}
|
|
|
|
provider.refresh();
|
2024-10-20 17:25:27 +02:00
|
|
|
}
|
|
|
|
});
|
2024-10-01 18:55:01 +02:00
|
|
|
|
2024-10-20 17:25:27 +02:00
|
|
|
for (let user of workspaceState.workspace.userList()) {
|
|
|
|
mapping.colors_cache.set(user.name, new mapping.UserDecoration(user.name));
|
2024-10-01 18:55:01 +02:00
|
|
|
}
|
2024-09-25 19:51:03 +02:00
|
|
|
|
|
|
|
vscode.window.showInformationMessage("Connected to workspace");
|
|
|
|
provider.refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export async function listWorkspaces() {
|
|
|
|
if (client === null) return vscode.window.showWarningMessage("Connect first");
|
2024-10-20 17:25:27 +02:00
|
|
|
workspace_list = await client.fetchJoinedWorkspaces();
|
2024-09-25 19:51:03 +02:00
|
|
|
provider.refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function createWorkspace() {
|
|
|
|
if (client === null) return vscode.window.showWarningMessage("Connect first");
|
|
|
|
let workspace_id = await vscode.window.showInputBox({ prompt: "Enter name for workspace" });
|
|
|
|
if (workspace_id === undefined) return;
|
2024-10-20 17:25:27 +02:00
|
|
|
await client.createWorkspace(workspace_id);
|
2024-09-25 19:51:03 +02:00
|
|
|
vscode.window.showInformationMessage("Created new workspace " + workspace_id);
|
2024-09-28 12:37:44 +02:00
|
|
|
listWorkspaces();
|
2024-09-25 19:51:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export async function inviteToWorkspace() {
|
|
|
|
if (client === null) return vscode.window.showWarningMessage("Connect first");
|
2024-10-12 23:56:45 +02:00
|
|
|
let workspace_id = await vscode.window.showQuickPick(workspace_list, { placeHolder: "workspace to invite to:" });
|
2024-09-25 19:51:03 +02:00
|
|
|
if (workspace_id === undefined) return;
|
2024-10-12 23:56:45 +02:00
|
|
|
let user_id = await vscode.window.showInputBox({ prompt: "Name of user to invite" });
|
2024-09-25 19:51:03 +02:00
|
|
|
if (user_id === undefined) return;
|
2024-10-20 17:25:27 +02:00
|
|
|
await client.inviteToWorkspace(workspace_id, user_id);
|
2024-09-28 12:32:28 +02:00
|
|
|
vscode.window.showInformationMessage("Invited " + user_id + " into workspace " + workspace_id);
|
2024-09-25 19:51:03 +02:00
|
|
|
}
|
|
|
|
|
2024-10-04 23:20:42 +02:00
|
|
|
export async function leave() {
|
|
|
|
if (!client) throw "can't leave while disconnected";
|
2024-10-13 00:36:09 +02:00
|
|
|
if (!workspaceState.workspace) throw "can't leave while not in a workspace";
|
2024-10-20 17:25:27 +02:00
|
|
|
workspaceState.workspace.cursor().clearCallback()
|
|
|
|
client.leaveWorkspace(workspaceState.workspace.id());
|
2024-10-04 23:20:42 +02:00
|
|
|
if (cursor_disposable !== null) cursor_disposable.dispose();
|
2024-10-13 00:36:09 +02:00
|
|
|
let workspace_id = workspaceState.workspace.id();
|
|
|
|
workspaceState.workspace = null;
|
2024-09-25 19:51:03 +02:00
|
|
|
provider.refresh();
|
2024-10-04 23:20:42 +02:00
|
|
|
vscode.window.showInformationMessage("Left workspace " + workspace_id);
|
2024-09-25 19:51:03 +02:00
|
|
|
}
|
|
|
|
|
2024-10-27 22:48:07 +01:00
|
|
|
export async function deleteWorkspace() {
|
|
|
|
if (client === null) return vscode.window.showWarningMessage("Connect first");
|
|
|
|
let workspace_id = await vscode.window.showInputBox({ prompt: "Enter workspace's name to delete" });
|
|
|
|
if (workspace_id === undefined) return;
|
|
|
|
await client.deleteWorkspace(workspace_id);
|
|
|
|
vscode.window.showInformationMessage("Deleted workspace " + workspace_id);
|
|
|
|
listWorkspaces();
|
|
|
|
}
|
|
|
|
|
2024-10-04 23:20:42 +02:00
|
|
|
|
2024-09-25 19:51:03 +02:00
|
|
|
export async function refresh() {
|
|
|
|
if (client === null) return vscode.window.showWarningMessage("Connect first");
|
|
|
|
await client.refresh();
|
|
|
|
vscode.window.showInformationMessage("Refreshed Session token");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|