-
Notifications
You must be signed in to change notification settings - Fork 1
/
extension.ts
159 lines (133 loc) · 5.35 KB
/
extension.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/* eslint-disable @typescript-eslint/naming-convention */
'use strict';
import * as vscode from 'vscode';
import { EditorGlue } from './editorglue';
export interface SelectionTypes {
anySelected: Boolean,
stateSelected: Boolean,
transitionSelected: Boolean,
parentStateSelected: Boolean,
parallelSelected: Boolean
}
const BlankSCXML = `<?xml version="1.0" encoding="UTF-8"?>
<scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml" xmlns:viz="http://phrogz.net/visual-scxml">
<state id="MyFirstState"/>
</scxml>`;
let manager: SCXMLEditorManager;
export function activate(context: vscode.ExtensionContext) {
manager = new SCXMLEditorManager(context);
}
export function deactivate() {}
const PassAlongCommands = ['createState','createChildState','fitChildren','layoutDiagram','zoomToExtents','zoomTo100','zoomToSelected',
'toggleEventDisplay','deleteSelectionOnly','deleteSelectionAndMore','removeVisualization','addVerticalWayline','addHorizontalWayline'];
export class SCXMLEditorManager {
public glueByURI: Map<vscode.Uri, EditorGlue> = new Map();
private _glueWithActiveWebView: EditorGlue | null = null;
public context: vscode.ExtensionContext;
public diagnostics: vscode.DiagnosticCollection;
constructor(context: vscode.ExtensionContext) {
this.context = context;
vscode.workspace.onDidChangeTextDocument((evt: vscode.TextDocumentChangeEvent) => {
const glue = this.glueByURI.get(evt.document.uri);
glue?.maybeUpdateVisualsFromText();
});
context.subscriptions.push(vscode.commands.registerCommand('visual-scxml-editor.createBlank', () => {
vscode.commands.executeCommand('workbench.action.files.newUntitledFile').then(() => {
const textEditor = vscode.window.activeTextEditor;
if (textEditor) {
vscode.languages.setTextDocumentLanguage(textEditor.document, 'xml').then(() => {
this.showEditor()?.replaceDocument(BlankSCXML, true);
});
}
});
}));
context.subscriptions.push(vscode.commands.registerCommand('visual-scxml-editor.showEditor', () => {
console.info(`SCXML Editor showing editor for ${vscode.window.activeTextEditor?.document.uri.fsPath}`);
this.showEditor();
}));
context.subscriptions.push(vscode.commands.registerCommand('visual-scxml-editor.undo', () => {
this.activeGlue?.undo();
}));
context.subscriptions.push(vscode.commands.registerCommand('visual-scxml-editor.save', () => {
this.activeGlue?.save();
}));
context.subscriptions.push(vscode.commands.registerCommand('visual-scxml-editor.createTransition', () => {
this.activeGlue?.createTransition();
}));
for (const cmd of PassAlongCommands) {
context.subscriptions.push(vscode.commands.registerCommand(`visual-scxml-editor.${cmd}`, () => {
console.info(`SCXML Editor handling command ${cmd}`);
this.sendToActiveEditor(cmd);
}));
}
this.diagnostics = vscode.languages.createDiagnosticCollection("emoji");
context.subscriptions.push(this.diagnostics);
}
// If any webview was last active, use that
// Otherwise, see if the active text editor is associated with existing glue
public get activeGlue() {
if (this._glueWithActiveWebView) {
return this._glueWithActiveWebView;
} else if (vscode.window.activeTextEditor) {
return this.glueByURI.get(vscode.window.activeTextEditor.document.uri) || null;
} else {
return null;
}
}
public set activeGlue(newValue: EditorGlue | null) {
this._glueWithActiveWebView = newValue;
vscode.commands.executeCommand('setContext', 'visual-scxml-editor.visualEditorActive', !!newValue);
// FIXME: if a webview is focused, then an editor is focused, then the editor loses focus, this will be incorrectly left as true
// Need to track when editor views gain and lose focus
vscode.commands.executeCommand('setContext', 'visual-scxml-editor.editorActive', !!this.activeGlue);
this.updateSelectionScopes(newValue);
}
public showErrors(doc: vscode.TextDocument, errors: any[]) {
const diags: vscode.Diagnostic[] = errors.map(error => {
return new vscode.Diagnostic(
new vscode.Range(error.line-1, error.col-1, error.line-1, error.col),
`Error parsing SCXML: ${error.msg}`,
vscode.DiagnosticSeverity.Error
);
});
this.diagnostics.set(doc.uri, diags);
}
public showEditor() {
const editor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
if (editor) {
const doc = editor.document;
if (doc?.languageId === "xml") {
const scxmlURI = doc.uri;
let glueForDoc = this.glueByURI.get(scxmlURI);
if (glueForDoc) {
glueForDoc.panel.reveal();
} else {
glueForDoc = new EditorGlue(this, editor);
this.glueByURI.set(scxmlURI, glueForDoc);
}
return glueForDoc;
}
}
}
public sendToActiveEditor(command: String) {
if (this.activeGlue) {
this.activeGlue.panel.webview.postMessage({command});
} else {
console.info(`Visual SCXML Editor not sending command '${command}' to anyone because there is no active EditorGlue.`);
}
}
public updateSelectionScopes(glue: EditorGlue | null) {
const selectedTypes: SelectionTypes = glue ? glue.selectedTypes : {
anySelected: false,
stateSelected: false,
transitionSelected: false,
parentStateSelected: false,
parallelSelected: false
};
for (const [scope, active] of Object.entries(selectedTypes)) {
vscode.commands.executeCommand('setContext', `visual-scxml-editor.${scope}`, active);
}
}
public dispose() {
}
}