0.10.0: Archify Sync, optional live collaboration on a model
Several people edit one model at once through a server you run yourself (archify-vscode-ext-sync); the files stay ordinary files on each disk. Sign-in through the browser, offline-first with later merge, teammates' cursors in the Source view and text editors, and a Shared section on the model page with people, versions, Compare and Restore. Without a server nothing changes: the sync code is a separate bundle that loads only when a model is shared, after a sign-in, or when a sync command or invite link is used.
This commit is contained in:
1 parent
a9021312b0
commit
c99f3e5fe8
27 files changed
+2899
-14
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { EditorSchemas } from '../language/editorSchemas';
|
||||
import { readSchemas } from '../language/schemaCheck';
|
||||
import { liveBridge } from '../sync/liveBridge';
|
||||
import { log } from '../util/log';
|
||||
import { TextChange, normalizeEol, offsetOf, positionOf } from '../util/textDiff';
|
||||
|
||||
@@ -9,7 +10,8 @@ export type SourceMessage =
|
||||
| { type: 'sourceReady' }
|
||||
| { type: 'sourceOpen' }
|
||||
| { type: 'sourceClose' }
|
||||
| { type: 'sourceEdit'; base: string; text: string; changes: TextChange[] };
|
||||
| { type: 'sourceEdit'; base: string; text: string; changes: TextChange[] }
|
||||
| { type: 'sourceSelection'; anchor: number; head: number };
|
||||
|
||||
export type SourceKind = 'diagram' | 'registry' | 'decision';
|
||||
|
||||
@@ -27,7 +29,13 @@ function schemasFor(context: vscode.ExtensionContext): EditorSchemas {
|
||||
}
|
||||
|
||||
export function isSourceMessage(message: { type?: string }): message is SourceMessage {
|
||||
return message.type === 'sourceReady' || message.type === 'sourceOpen' || message.type === 'sourceClose' || message.type === 'sourceEdit';
|
||||
return (
|
||||
message.type === 'sourceReady' ||
|
||||
message.type === 'sourceOpen' ||
|
||||
message.type === 'sourceClose' ||
|
||||
message.type === 'sourceEdit' ||
|
||||
message.type === 'sourceSelection'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,6 +76,8 @@ export class SourceSession implements vscode.Disposable {
|
||||
vscode.workspace.onDidSaveTextDocument((doc) => {
|
||||
if (same(doc.uri)) this.post({ type: 'sourceDirty', dirty: false });
|
||||
}),
|
||||
// Teammates' cursors, when the model is shared (Archify Sync); nothing otherwise.
|
||||
liveBridge.onDidChangeCursors(() => this.postCursors()),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -94,10 +104,14 @@ export class SourceSession implements vscode.Disposable {
|
||||
break;
|
||||
case 'sourceClose':
|
||||
this.setShown(false);
|
||||
liveBridge.setCursor(this.uri, undefined);
|
||||
break;
|
||||
case 'sourceEdit':
|
||||
this.edit(message);
|
||||
break;
|
||||
case 'sourceSelection':
|
||||
liveBridge.setCursor(this.uri, { anchor: message.anchor, head: message.head });
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -108,6 +122,17 @@ export class SourceSession implements vscode.Disposable {
|
||||
this.onShown(shown);
|
||||
}
|
||||
|
||||
private lastCursors = '[]';
|
||||
|
||||
private postCursors(): void {
|
||||
if (!this.shown) return;
|
||||
const cursors = liveBridge.cursors(this.uri);
|
||||
const key = JSON.stringify(cursors);
|
||||
if (key === this.lastCursors) return;
|
||||
this.lastCursors = key;
|
||||
this.post({ type: 'sourceCursors', cursors });
|
||||
}
|
||||
|
||||
private post(message: unknown): void {
|
||||
Promise.resolve(this.panel.webview.postMessage(message)).catch(() => undefined);
|
||||
}
|
||||
@@ -123,6 +148,8 @@ export class SourceSession implements vscode.Disposable {
|
||||
this.schemaKey = undefined;
|
||||
this.post({ type: 'sourceText', text, schema: this.schemaChange(text), checks: CHECKS[this.kind] });
|
||||
this.post({ type: 'sourceDirty', dirty: doc.isDirty });
|
||||
this.lastCursors = '';
|
||||
this.postCursors();
|
||||
if (withDiagnostics) await this.postDiagnostics();
|
||||
}
|
||||
|
||||
@@ -196,6 +223,7 @@ export class SourceSession implements vscode.Disposable {
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
if (this.shown) liveBridge.setCursor(this.uri, undefined);
|
||||
for (const d of this.disposables.splice(0)) d.dispose();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user