import * as vscode from 'vscode'; // What the model page shows of a shared model. Lives in the main bundle; the // sync bundle plugs in as the provider once it loads. Without it, the model // page has no Live section and nothing else changes. export interface LivePerson { name: string; /** Model-relative path of the file the person has open. */ file?: string; me?: boolean; } export interface LiveVersion { id: number; label: string; kind: 'snapshot' | 'publish' | 'restore'; name?: string; /** ISO time. */ at: string; restoredFrom?: string; } export interface LivePanel { name: string; host: string; state: 'connecting' | 'online' | 'offline' | 'signed-out' | 'forbidden' | 'outdated'; people: LivePerson[]; versions?: LiveVersion[]; versionsProblem?: string; } /** Someone else's cursor in a file, as offsets into its "\n" text. */ export interface LiveCursor { name: string; color: string; anchor: number; head: number; } /** A selection as offsets into a file's "\n" text. */ export interface LiveSelection { anchor: number; head: number; } export type LiveAction = | { kind: 'publish' } | { kind: 'invite' } | { kind: 'signIn' } | { kind: 'versions' } | { kind: 'compare'; version: number } | { kind: 'restore'; version: number }; export interface LiveProvider { panel(root: vscode.Uri): Promise; act(root: vscode.Uri, action: LiveAction): Promise; /** Others' cursors in a shared file; empty when the file is not shared. */ cursors(file: vscode.Uri): LiveCursor[]; /** This person's cursor in a page's Source view; undefined when it closes. */ setCursor(file: vscode.Uri, selection: LiveSelection | undefined): void; } class LiveBridge implements vscode.Disposable { private provider: LiveProvider | undefined; private readonly emitter = new vscode.EventEmitter(); /** A model root whose Live section changed; undefined for all of them. */ readonly onDidChange = this.emitter.event; private readonly cursorEmitter = new vscode.EventEmitter(); /** Someone's cursor moved somewhere; ask `cursors` for the file you show. */ readonly onDidChangeCursors = this.cursorEmitter.event; setProvider(provider: LiveProvider | undefined): void { this.provider = provider; this.emitter.fire(undefined); this.cursorEmitter.fire(); } changed(root?: vscode.Uri): void { this.emitter.fire(root); } async panel(root: vscode.Uri): Promise { return this.provider?.panel(root); } async act(root: vscode.Uri, action: LiveAction): Promise { await this.provider?.act(root, action); } cursorsChanged(): void { this.cursorEmitter.fire(); } cursors(file: vscode.Uri): LiveCursor[] { return this.provider?.cursors(file) ?? []; } setCursor(file: vscode.Uri, selection: LiveSelection | undefined): void { this.provider?.setCursor(file, selection); } dispose(): void { this.emitter.dispose(); this.cursorEmitter.dispose(); } } export const liveBridge = new LiveBridge(); export type { LiveBridge };