Skip to content

Commit 9fd803c

Browse files
adrianlehBhakti Shah
andauthored
Version 0.2.0 (#21)
* Version 0.2.0 comes with the following features: - Automatic rendering more robust: + Checking for lsp installation + Waiting for lsp to start - Don't automatically render non-vyzx terms (or set printing all terms) - Parse/Render errors allow user to one-click file GitHub issue - Allow project/global setting to have user choose if they want auto rendering - Add support for \propto= and \propto[c] * Apply suggestions from AI code review * Fix AI suggestion edits. Turns out this thing can't refactor * fixed spacing and sizing for propto specializations * Add (very basic) qualifiers to webview * Make rendering a little less eager --------- Co-authored-by: Bhakti Shah <bhaktishah21@gmail.com>
1 parent 1c26936 commit 9fd803c

File tree

15 files changed

+1074
-648
lines changed

15 files changed

+1074
-648
lines changed

.vscode/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
"**/CVS": true,
1313
"**/.DS_Store": true,
1414
"**/Thumbs.db": true,
15+
"**/.*.aux": true,
16+
"**/.lia.cache": true,
17+
"**/.nia.cache": true,
18+
"**/.nra.cache": true,
1519
"**/.classpath": true,
1620
"**/.project": true,
1721
"**/.settings": true,

package-lock.json

Lines changed: 335 additions & 519 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"name": "vizx",
3-
"displayName": "ViZX",
3+
"displayName": "ZXViz",
44
"description": "Visualizer for the ZX calculus",
5-
"version": "0.1.4",
5+
"version": "0.2.0",
66
"repository": "https://github.com/inQWIRE/ViZX/",
77
"publisher": "inQWIRE",
88
"engines": {
@@ -12,11 +12,13 @@
1212
"Other"
1313
],
1414
"activationEvents": [
15-
"onCommand:vizx.render",
16-
"onCommand:vizx.lspRender",
17-
"onCommand:vizx.activateRendering"
15+
"onLanguage:coq",
16+
"onLanguage:rocq"
1817
],
1918
"main": "./out/extension.js",
19+
"extensionDependencies": [
20+
"ejgallego.coq-lsp"
21+
],
2022
"contributes": {
2123
"commands": [
2224
{
@@ -35,21 +37,39 @@
3537
"command": "vizx.deactivateRendering",
3638
"title": "ZXViz: Deactivate ZXViz automatic rendering"
3739
}
38-
]
40+
],
41+
"configuration": {
42+
"type": "object",
43+
"title": "ViZX Extension Configuration",
44+
"properties": {
45+
"vizx.ignoreActiveVsCoq": {
46+
"type": "boolean",
47+
"default": false,
48+
"description": "Allow ViZX to run with VSCoq active despite possible issues. Setting to true will disable bug reporting features, as this is not officially supported."
49+
},
50+
"vizx.enableAutomaticRendering": {
51+
"type": "boolean",
52+
"default": true,
53+
"description": "Enable automatic rendering of ZX diagrams when the file is saved or the editor is focused. Disable this to manually trigger rendering."
54+
}
55+
}
56+
}
3957
},
4058
"scripts": {
4159
"vscode:prepublish": "npm run package",
4260
"compile": "node ./esbuild.js",
4361
"package": "NODE_ENV=production node ./esbuild.js",
44-
"watch": "node ./esbuild.js --watch",
62+
"watch": "node ./esbuild.js & node ./esbuild.js --watch",
4563
"lint": "eslint src --ext ts & npx prettier --write .",
46-
"deploy": "vsce publish"
64+
"deploy": "vsce publish",
65+
"check-types": "tsc --noEmit"
4766
},
4867
"devDependencies": {
4968
"@babel/core": "^7.21.4",
5069
"@babel/preset-env": "^7.21.4",
5170
"@babel/preset-typescript": "^7.21.4",
5271
"@types/glob": "^7.2.0",
72+
"@types/minimatch": "^6.0.0",
5373
"@types/node": "14.x",
5474
"@types/vscode": "^1.74.0",
5575
"@typescript-eslint/eslint-plugin": "^5.16.0",
@@ -61,7 +81,8 @@
6181
"glob": "^7.2.0",
6282
"lodash": "^4.17.21",
6383
"prettier": "2.8.4",
64-
"typescript": "^4.5.5"
84+
"typescript": "^4.5.5",
85+
"vscode-languageserver-types": "^3.17.5"
6586
},
6687
"dependencies": {
6788
"deep-object-diff": "^1.1.9",

src/constants/consts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const STACK_OP = "↕"; // \updownarrow
1111
export const N_STACK_1_OP = "↑";
1212

1313
export const PROP_TO = "∝";
14+
export const EQ = "=";
1415
export const CAP = "⊂";
1516
export const CUP = "⊃";
1617
export const WIRE = "—";

src/extension.ts

Lines changed: 154 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
// The module 'vscode' contains the VS Code extensibility API
22
// Import the module and reference it with the alias vscode in your code below
33
import * as vscode from "vscode";
4-
import * as parser from "./parsing/parser";
5-
import * as sizer from "./parsing/sizes";
6-
import * as coord from "./parsing/coords";
7-
import { boundary, setCanvasWidthHeight } from "./constants/variableconsts";
8-
import * as vconsts from "./constants/variableconsts";
9-
import * as ast from "./parsing/ast";
10-
import { getCanvasHtml } from "./webview/webview";
4+
import { coqLspApi, only_with_lsp } from "./lspguards";
5+
import { render, renderCallback } from "./rendering/callback";
116

12-
let openWebview: vscode.WebviewPanel | undefined = undefined;
137
let history: string[] = [];
148
const HISTORY_LENGTH = vscode.workspace
159
.getConfiguration("vizx")
1610
.get<number>("historyLength", 25);
1711
const HISTORY_KEY = "vizxInputHistory";
1812

13+
let hook: vscode.Disposable | undefined = undefined;
1914
// this method is called when your extension is activated
2015
// your extension is activated the very first time the command is executed
2116
export function activate(context: vscode.ExtensionContext) {
@@ -26,121 +21,168 @@ export function activate(context: vscode.ExtensionContext) {
2621
// The command has been defined in the package.json file
2722
// Now provide the implementation of the command with registerCommand
2823
// The commandId parameter must match the command field in package.json
29-
let disposable = vscode.commands.registerCommand("vizx.render", () => {
30-
const newDiag = "New...";
31-
const inputBox = vscode.window
32-
.showQuickPick([...history, newDiag], {
33-
placeHolder: "Diagram syntax with notations",
34-
title: "Enter or choose diagram",
35-
})
36-
.then((selected) => {
37-
if (selected === undefined) {
38-
return;
39-
} else if (selected === newDiag) {
40-
vscode.window
41-
.showInputBox({ prompt: "Enter diagram syntax with notations" })
42-
.then((value) => {
43-
if (value) {
44-
history.unshift(value); // Add to history
45-
if (history.length > HISTORY_LENGTH) {
46-
history.pop(); // Limit history size
47-
}
48-
context.workspaceState.update(HISTORY_KEY, history); // Save to workspaceState
49-
renderCallback(context, value);
50-
}
51-
});
52-
} else {
53-
history = history.filter((item) => item !== selected);
54-
history.unshift(selected); // Add to the front of history
55-
context.workspaceState.update(HISTORY_KEY, history);
56-
renderCallback(context, selected);
57-
}
58-
});
59-
});
24+
let disposables = [
25+
vscode.commands.registerCommand("vizx.render", () =>
26+
renderCommand(context)
27+
),
28+
];
29+
30+
disposables.push(
31+
vscode.commands.registerCommand("vizx.lspRender", (expr) =>
32+
renderCallback(context, expr)
33+
)
34+
);
6035

61-
context.subscriptions.push(disposable);
62-
disposable = vscode.commands.registerCommand("vizx.lspRender", (expr) =>
63-
renderCallback(context, expr)
36+
disposables.push(
37+
vscode.commands.registerCommand("vizx.activateRendering", () =>
38+
activateRenderingCommand(context)
39+
)
6440
);
65-
context.subscriptions.push(disposable);
66-
let coqLspApi = vscode.extensions.getExtension("ejgallego.coq-lsp")!.exports;
67-
let hook = coqLspApi.onUserGoals((goals: any) =>
68-
vscode.commands.executeCommand("vizx.lspRender", goals)
41+
disposables.push(
42+
vscode.commands.registerCommand("vizx.deactivateRendering", () =>
43+
deactivateRenderingCommand()
44+
)
6945
);
46+
context.subscriptions.push(...disposables);
7047

71-
disposable = vscode.commands.registerCommand("vizx.activateRendering", () => {
72-
vscode.window.showInformationMessage(
73-
"Automatic rendering is now turned on."
74-
);
75-
});
76-
context.subscriptions.push(disposable);
77-
disposable = vscode.commands.registerCommand(
78-
"vizx.deactivateRendering",
79-
() => {
80-
deactivate();
81-
vscode.window.showInformationMessage(
82-
"Automatic rendering is now turned off."
48+
const config = vscode.workspace.getConfiguration("vizx");
49+
const autoRenderingEnabled = config.get<boolean>(
50+
"enableAutomaticRendering",
51+
false
52+
);
53+
if (autoRenderingEnabled) {
54+
// Wait until a tab named "goals" exists before activating rendering
55+
activateRendering(context);
56+
if (hook === undefined) {
57+
vscode.window.showWarningMessage(
58+
"Automatic rendering is enabled, but the LSP hook could not be set up. Please ensure that the Coq LSP is running."
8359
);
84-
hook.dispose();
8560
}
86-
);
61+
vscode.window.showInformationMessage(
62+
"ViZX automatic rendering is now turned on."
63+
);
64+
} else {
65+
vscode.window
66+
.showInformationMessage(
67+
"ViZX automatic rendering is currently disabled.",
68+
"Enable",
69+
"OK"
70+
)
71+
.then((selection) => {
72+
if (selection === "Enable") {
73+
vscode.commands.executeCommand("vizx.activateRendering");
74+
}
75+
});
76+
}
77+
}
8778

88-
context.subscriptions.push(disposable);
79+
function renderCommand(context: vscode.ExtensionContext): void {
80+
const newDiag = "New...";
81+
vscode.window
82+
.showQuickPick([...history, newDiag], {
83+
placeHolder: "Diagram syntax with notations",
84+
title: "Enter or choose diagram",
85+
})
86+
.then((selected) => {
87+
if (selected === undefined) {
88+
return;
89+
} else if (selected === newDiag) {
90+
vscode.window
91+
.showInputBox({ prompt: "Enter diagram syntax with notations" })
92+
.then((value) => {
93+
if (value) {
94+
history.unshift(value); // Add to history
95+
if (history.length > HISTORY_LENGTH) {
96+
history.pop(); // Limit history size
97+
}
98+
context.workspaceState.update(HISTORY_KEY, history); // Save to workspaceState
99+
render(context, value);
100+
}
101+
});
102+
} else {
103+
history = history.filter((item) => item !== selected);
104+
history.unshift(selected); // Add to the front of history
105+
context.workspaceState.update(HISTORY_KEY, history);
106+
render(context, selected);
107+
}
108+
});
89109
}
90110

91-
function renderCallback(context: vscode.ExtensionContext, expr: any) {
92-
{
93-
if (expr === undefined) {
94-
console.log("no expression to be rendered");
95-
return;
96-
}
97-
if (expr.goals !== undefined) {
98-
// extract correct field from lsp information
99-
expr = expr.goals.goals[0].ty.toString();
100-
}
101-
console.log("expr: ", expr);
102-
let node: ast.ASTNode;
103-
try {
104-
node = parser.parseAST(expr);
105-
node = sizer.addSizes(node);
106-
console.log("sized node: ", node);
107-
const size = sizer.determineCanvasWidthHeight(node);
108-
setCanvasWidthHeight(size);
109-
node = coord.addCoords(node, boundary);
110-
} catch (e) {
111-
vscode.window.showErrorMessage(
112-
`Error rendering your expression (${expr}): ${e}`
113-
);
114-
return;
115-
}
116-
if (openWebview !== undefined) {
117-
openWebview.dispose();
118-
}
119-
const panel = vscode.window.createWebviewPanel(
120-
"ViZX",
121-
`ViZX: ${expr}`,
122-
{
123-
viewColumn: vscode.ViewColumn.Three,
124-
preserveFocus: true,
125-
},
126-
{
127-
enableScripts: true,
128-
retainContextWhenHidden: true,
111+
function activateRenderingCommand(context: vscode.ExtensionContext): void {
112+
const config = vscode.workspace.getConfiguration("vizx");
113+
const enabled = config.get<boolean>("enableAutomaticRendering", false);
114+
if (!enabled) {
115+
// if disabled, then ask user if they want to enable it
116+
vscode.window
117+
.showInformationMessage(
118+
"Automatic rendering is currently disabled. Do you want to enable it?",
119+
"Enable for this project",
120+
"Enable globally"
121+
)
122+
.then((selection) => {
123+
if (selection === "Enable for this project") {
124+
config.update(
125+
"enableAutomaticRendering",
126+
true,
127+
vscode.ConfigurationTarget.Workspace
128+
);
129+
} else if (selection === "Enable globally") {
130+
config.update(
131+
"enableAutomaticRendering",
132+
true,
133+
vscode.ConfigurationTarget.Global
134+
);
135+
}
136+
activateRendering(context);
137+
});
138+
return;
139+
}
140+
vscode.window.showInformationMessage("Automatic rendering is now turned on.");
141+
}
142+
143+
function deactivateRenderingCommand(): void {
144+
vscode.window
145+
.showInformationMessage(
146+
"Automatic rendering is now turned off.",
147+
"Deactivate for this project",
148+
"Deactivate globally"
149+
)
150+
.then((selection) => {
151+
if (selection === "Deactivate for this project") {
152+
vscode.workspace
153+
.getConfiguration("vizx")
154+
.update(
155+
"enableAutomaticRendering",
156+
false,
157+
vscode.ConfigurationTarget.Workspace
158+
);
159+
} else if (selection === "Deactivate globally") {
160+
vscode.workspace
161+
.getConfiguration("vizx")
162+
.update(
163+
"enableAutomaticRendering",
164+
false,
165+
vscode.ConfigurationTarget.Global
166+
);
129167
}
130-
);
131-
panel.onDidDispose(
132-
async () => {
133-
console.log("openWebview before: ", openWebview);
134-
openWebview = undefined;
135-
},
136-
null,
137-
context.subscriptions
138-
);
139-
openWebview = panel;
140-
panel.webview.html = getCanvasHtml(panel, context);
141-
panel.webview.onDidReceiveMessage((msg) => console.log(msg));
142-
panel.webview.postMessage({ command: JSON.stringify(node) });
168+
});
169+
deactivateRendering();
170+
}
171+
172+
function activateRendering(context: vscode.ExtensionContext): void {
173+
if (hook !== undefined) {
174+
return; // no need to recreate as it would be the exact same
143175
}
176+
only_with_lsp(() => {
177+
hook = coqLspApi!.onUserGoals((goals: any) =>
178+
renderCallback(context, goals)
179+
);
180+
});
181+
}
182+
183+
function deactivateRendering() {
184+
hook?.dispose();
185+
hook = undefined;
144186
}
145187

146188
// this method is called when your extension is deactivated

0 commit comments

Comments
 (0)