In workspaces with Archify files, Archify Sync sits in the status bar and opens a menu: sign in, share, join, server address, settings. The new archify.sync.server setting (empty by default) is used without asking, and in workspace settings gives a project one server. archify.sync.statusBar hides the entry.
75 lines
3.2 KiB
TypeScript
75 lines
3.2 KiB
TypeScript
import * as path from 'node:path';
|
||
import * as vscode from 'vscode';
|
||
import type { ModelService } from '../model/service';
|
||
import { log } from '../util/log';
|
||
import type { SyncFeature } from './index';
|
||
import { liveBridge } from './liveBridge';
|
||
|
||
// Kept in step with SYNC_COMMANDS in ./index (which lives in the other bundle).
|
||
const COMMANDS = [
|
||
'archify.sync.signIn',
|
||
'archify.sync.signOut',
|
||
'archify.sync.share',
|
||
'archify.sync.invite',
|
||
'archify.sync.join',
|
||
'archify.sync.publish',
|
||
'archify.sync.versions',
|
||
'archify.sync.stop',
|
||
'archify.sync.menu',
|
||
'archify.sync.setServer',
|
||
] as const;
|
||
|
||
/**
|
||
* Archify Sync is optional. This registers its commands and the URI handler,
|
||
* and loads dist/sync.js (Yjs, the WebSocket) only when it is needed: a model
|
||
* in the workspace is shared, someone signed in on this machine, or a sync
|
||
* command or link runs. Without that, nothing else happens.
|
||
*/
|
||
export function registerSync(context: vscode.ExtensionContext, models: ModelService): vscode.Disposable[] {
|
||
let feature: Promise<SyncFeature> | undefined;
|
||
// Until the sync bundle loads, this entry is the way in; then the bundle's own one takes over.
|
||
const entry = vscode.window.createStatusBarItem('archify.sync', vscode.StatusBarAlignment.Left, 50);
|
||
entry.name = 'Archify Sync';
|
||
entry.text = '$(cloud) Archify Sync';
|
||
entry.tooltip = 'Archify Sync (optional): sign in, share a model with others or join one. Set the server under Settings › Archify › Sync.';
|
||
entry.command = 'archify.sync.menu';
|
||
// Only where there are Archify files: the extension also starts for JSON and HTML.
|
||
let archifyHere = false;
|
||
const showEntry = () => {
|
||
const wanted = archifyHere && !feature && vscode.workspace.getConfiguration('archify.sync').get<boolean>('statusBar', true);
|
||
if (wanted) entry.show();
|
||
else entry.hide();
|
||
};
|
||
void Promise.resolve(vscode.workspace.findFiles('**/*.{archify,archify-registry,archify-decision}', '{**/node_modules/**,**/.git/**}', 1)).then((found) => {
|
||
archifyHere = found.length > 0;
|
||
showEntry();
|
||
});
|
||
const load = (): Promise<SyncFeature> =>
|
||
(feature ??= (async () => {
|
||
showEntry();
|
||
// A runtime path, so esbuild leaves the sync bundle out of this one.
|
||
const bundle = path.join(__dirname, 'sync.js');
|
||
const mod = require(bundle) as typeof import('./index');
|
||
const sync = new mod.SyncFeature(context, models, log(), liveBridge);
|
||
context.subscriptions.push(sync);
|
||
await sync.start();
|
||
return sync;
|
||
})());
|
||
|
||
void (async () => {
|
||
const used = context.globalState.get<boolean>('archifySync.used') === true;
|
||
const shared = used || (await vscode.workspace.findFiles('**/.archify-sync', '{**/node_modules/**,**/.git/**}', 1)).length > 0;
|
||
if (shared) load().catch((error) => log().error(`sync: did not start: ${String(error)}`));
|
||
})();
|
||
|
||
return [
|
||
entry,
|
||
vscode.workspace.onDidChangeConfiguration((e) => e.affectsConfiguration('archify.sync.statusBar') && showEntry()),
|
||
liveBridge,
|
||
...COMMANDS.map((id) =>
|
||
vscode.commands.registerCommand(id, async (...args: unknown[]) => (await load()).run(id, ...args)),
|
||
),
|
||
vscode.window.registerUriHandler({ handleUri: async (uri) => (await load()).handleUri(uri) }),
|
||
];
|
||
}
|