import * as vscode from "vscode";
import type { RoomClient } from "./room-client";
type Selection = { anchor: number; head: number };
type PeerState = {
user?: { name?: string; color?: string; kind?: string };
path?: string | null;
selections?: Selection[];
};
const PALETTE = ["#f778ba", "#3fb950", "#d29922", "#58a6ff", "#a371f7", "#ff7b72", "#39c5cf", "#e3b341"];
function colorFor(clientId: number, preferred?: string): string {
if (preferred && /^#[0-9a-f]{6}$/i.test(preferred)) return preferred;
return PALETTE[clientId % PALETTE.length];
}
/** Publishes the local cursor and paints every peer's cursor, selection and name in visible editors. */
export class Cursors implements vscode.Disposable {
private readonly decorations = new Map<
number,
{ caret: vscode.TextEditorDecorationType; range: vscode.TextEditorDecorationType }
>();
private readonly disposables: vscode.Disposable[] = [];
constructor(
private readonly room: RoomClient,
private readonly pathOf: (uri: vscode.Uri) => string | null,
name: string,
) {
room.awareness.setLocalStateField("user", { name, color: colorFor(room.doc.clientID) });
room.awareness.on("change", () => this.render());
this.disposables.push(
vscode.window.onDidChangeTextEditorSelection((event) => this.publish(event.textEditor)),
vscode.window.onDidChangeActiveTextEditor((editor) => (editor ? this.publish(editor) : this.clearLocal())),
vscode.window.onDidChangeVisibleTextEditors(() => this.render()),
vscode.workspace.onDidChangeTextDocument(() => this.render()),
);
if (vscode.window.activeTextEditor) this.publish(vscode.window.activeTextEditor);
}