0.3.0: .archify files are YAML and open straight into the diagram
- .archify content is YAML (JSON still accepted); converted to JSON for the renderer - Archify Diagram custom editor is the default for *.archify; Show Source opens the YAML beside it - YAML syntax errors and validation problems mapped to YAML lines - yamlValidation for schema completion with redhat.vscode-yaml - scripts/to-yaml.mjs converts existing .archify files
This commit is contained in:
+43
-10
@@ -7,6 +7,8 @@ import { handleWebviewMessage, WebviewMessage } from './webviewMessages';
|
||||
import { makeNonce, messagePage, prepareDiagramHtml } from './webviewHtml';
|
||||
|
||||
export const PREVIEW_VIEW_TYPE = 'archify.preview';
|
||||
/** Default editor for .archify files: the rendered diagram. */
|
||||
export const DIAGRAM_EDITOR_VIEW_TYPE = 'archify.diagram';
|
||||
|
||||
interface PreviewState {
|
||||
uri: string;
|
||||
@@ -28,11 +30,15 @@ class DiagramPreview implements vscode.Disposable {
|
||||
readonly panel: vscode.WebviewPanel,
|
||||
readonly uri: vscode.Uri,
|
||||
state?: PreviewState,
|
||||
/** True when this is the custom editor of the file, not a side preview. */
|
||||
readonly isEditor = false,
|
||||
) {
|
||||
this.hash = state?.hash;
|
||||
panel.webview.options = { enableScripts: true, localResourceRoots: [] };
|
||||
panel.iconPath = vscode.Uri.joinPath(context.extensionUri, 'media', 'preview.svg');
|
||||
panel.title = `Preview ${path.basename(uri.path)}`;
|
||||
if (!isEditor) {
|
||||
panel.iconPath = vscode.Uri.joinPath(context.extensionUri, 'media', 'preview.svg');
|
||||
panel.title = `Preview ${path.basename(uri.path)}`;
|
||||
}
|
||||
|
||||
this.disposables.push(
|
||||
panel.onDidDispose(() => this.dispose()),
|
||||
@@ -102,7 +108,7 @@ class DiagramPreview implements vscode.Disposable {
|
||||
let result;
|
||||
try {
|
||||
const runtime = await runtimeFor(this.context, this.uri);
|
||||
result = await renderDiagram(runtime, { ...source, text }, evidenceMode(this.uri));
|
||||
result = await renderDiagram(runtime, source, evidenceMode(this.uri));
|
||||
} catch (error) {
|
||||
result = { ok: false, error: error instanceof Error ? error.message : String(error) };
|
||||
}
|
||||
@@ -152,19 +158,30 @@ function firstLines(text: string | undefined, count = 6): string {
|
||||
return (text ?? '').split('\n').slice(0, count).join('\n');
|
||||
}
|
||||
|
||||
export class PreviewManager implements vscode.Disposable, vscode.WebviewPanelSerializer<PreviewState> {
|
||||
export class PreviewManager
|
||||
implements vscode.Disposable, vscode.WebviewPanelSerializer<PreviewState>, vscode.CustomTextEditorProvider
|
||||
{
|
||||
/** Side previews, one per source file. */
|
||||
private readonly previews = new Map<string, DiagramPreview>();
|
||||
/** Custom-editor tabs of .archify files (several per file are allowed). */
|
||||
private readonly editors = new Set<DiagramPreview>();
|
||||
private active: DiagramPreview | undefined;
|
||||
private readonly disposables: vscode.Disposable[] = [];
|
||||
|
||||
constructor(private readonly context: vscode.ExtensionContext) {
|
||||
this.disposables.push(
|
||||
vscode.window.registerWebviewPanelSerializer(PREVIEW_VIEW_TYPE, this),
|
||||
vscode.window.registerCustomEditorProvider(DIAGRAM_EDITOR_VIEW_TYPE, this, {
|
||||
webviewOptions: { retainContextWhenHidden: true, enableFindWidget: true },
|
||||
supportsMultipleEditorsPerDocument: true,
|
||||
}),
|
||||
vscode.workspace.onDidChangeTextDocument((event) => {
|
||||
const preview = this.previews.get(event.document.uri.toString());
|
||||
if (preview && event.contentChanges.length && this.liveUpdate(preview.uri)) preview.scheduleUpdate();
|
||||
if (!event.contentChanges.length || !this.liveUpdate(event.document.uri)) return;
|
||||
for (const preview of this.forUri(event.document.uri)) preview.scheduleUpdate();
|
||||
}),
|
||||
vscode.workspace.onDidSaveTextDocument((doc) => {
|
||||
for (const preview of this.forUri(doc.uri)) void preview.update();
|
||||
}),
|
||||
vscode.workspace.onDidSaveTextDocument((doc) => void this.previews.get(doc.uri.toString())?.update()),
|
||||
vscode.workspace.onDidChangeConfiguration((event) => {
|
||||
if (event.affectsConfiguration('archify')) this.refreshAll();
|
||||
}),
|
||||
@@ -180,6 +197,17 @@ export class PreviewManager implements vscode.Disposable, vscode.WebviewPanelSer
|
||||
return this.active;
|
||||
}
|
||||
|
||||
private forUri(uri: vscode.Uri): DiagramPreview[] {
|
||||
const key = uri.toString();
|
||||
return [...this.previews.values(), ...this.editors].filter((preview) => preview.uri.toString() === key);
|
||||
}
|
||||
|
||||
/** Opening a .archify file lands here: the diagram is the editor. */
|
||||
async resolveCustomTextEditor(document: vscode.TextDocument, panel: vscode.WebviewPanel): Promise<void> {
|
||||
panel.webview.options = { enableScripts: true, localResourceRoots: [] };
|
||||
this.track(new DiagramPreview(this.context, panel, document.uri, undefined, true));
|
||||
}
|
||||
|
||||
show(uri: vscode.Uri, viewColumn: vscode.ViewColumn, preserveFocus = false): void {
|
||||
const existing = this.previews.get(uri.toString());
|
||||
if (existing) {
|
||||
@@ -205,8 +233,11 @@ export class PreviewManager implements vscode.Disposable, vscode.WebviewPanelSer
|
||||
|
||||
private track(preview: DiagramPreview): void {
|
||||
const key = preview.uri.toString();
|
||||
this.previews.get(key)?.panel.dispose();
|
||||
this.previews.set(key, preview);
|
||||
if (preview.isEditor) this.editors.add(preview);
|
||||
else {
|
||||
this.previews.get(key)?.panel.dispose();
|
||||
this.previews.set(key, preview);
|
||||
}
|
||||
const onViewState = () => {
|
||||
if (preview.panel.active) this.active = preview;
|
||||
else if (this.active === preview) this.active = undefined;
|
||||
@@ -215,6 +246,7 @@ export class PreviewManager implements vscode.Disposable, vscode.WebviewPanelSer
|
||||
preview.panel.onDidChangeViewState(onViewState);
|
||||
onViewState();
|
||||
preview.onDidDispose(() => {
|
||||
this.editors.delete(preview);
|
||||
if (this.previews.get(key) === preview) this.previews.delete(key);
|
||||
if (this.active === preview) {
|
||||
this.active = undefined;
|
||||
@@ -224,12 +256,13 @@ export class PreviewManager implements vscode.Disposable, vscode.WebviewPanelSer
|
||||
}
|
||||
|
||||
refreshAll(force = false): void {
|
||||
for (const preview of this.previews.values()) void preview.update(force);
|
||||
for (const preview of [...this.previews.values(), ...this.editors]) void preview.update(force);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
for (const preview of this.previews.values()) preview.panel.dispose();
|
||||
this.previews.clear();
|
||||
this.editors.clear();
|
||||
for (const disposable of this.disposables.splice(0)) disposable.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user