Skip to content
Snippets Groups Projects
Commit 4b0de48a authored by Smit, P.J.M. (Peter, Student M-CS)'s avatar Smit, P.J.M. (Peter, Student M-CS)
Browse files

Dotview now uses parameters from the languageserver

parent 667f349e
No related branches found
No related tags found
No related merge requests found
html, body, #svgImage { html, body, #svgContainer, #svgImage {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
...@@ -15,6 +15,67 @@ polygon { ...@@ -15,6 +15,67 @@ polygon {
fill: none; fill: none;
} }
.vscode-dark { body.vscode-dark #svgContainer {
filter: invert(1); filter: invert(1);
}
#svgContainer {
position: fixed;
}
#buttonContainer {
background: var(--vscode-editorWidget-border);
display: flex;
padding: 10px;
}
#buttonContainer h3 {
align-self: center;
flex-grow: 1;
padding: 0;
}
#buttonContainer button {
height: fit-content;
width: fit-content;
display: flex;
margin-left: 5px;
padding: 2px;
}
#paramContainer {
background: var(--vscode-editorWidget-background);
z-index: 10;
position: fixed;
top: 10px;
right: 10px;
}
#paramList {
max-width: 250px;
max-height: 400px;
overflow-y: scroll;
list-style: none;
padding: 10px;
}
#paramList li {
display: flex;
justify-content: space-between;
padding: 0.15em 0;
height: 2.5em;
}
#paramList li label {
text-overflow: ellipsis;
overflow: hidden;
vertical-align: middle;
}
#paramList li input[type=text] {
max-width: 100px;
}
#paramList li input[type=checkbox] {
outline: none;
} }
\ No newline at end of file
// FULL CREDIT TO https://stackoverflow.com/questions/52576376/how-to-zoom-in-on-a-complex-svg-structure const vscode = acquireVsCodeApi();
// also https://stackoverflow.com/questions/1685326/responding-to-the-onmousemove-event-outside-of-the-browser-window-in-ie
const svgContainer = document.getElementById("svgContainer"); const svgContainer = document.getElementById("svgContainer");
const paramList = document.getElementById("paramList");
var svgImage; var svgImage;
...@@ -28,6 +27,36 @@ window.addEventListener('message', event => { ...@@ -28,6 +27,36 @@ window.addEventListener('message', event => {
case 'zoomOut': case 'zoomOut':
zoom(false); zoom(false);
break; break;
case 'params':
event.data.params.parameterDefinitions.forEach(addParameterItem);
break;
case 'allData':
if (svgImage === undefined && event.data.svg) {
// Set svg again
svgContainer.innerHTML = event.data.svg.replace('<svg', '<svg id="svgImage"');
svgImage = document.getElementById("svgImage");
scale = 1;
viewBox = { x: 0, y: 0, w: svgImage.clientWidth, h: svgImage.clientHeight };
svgImage.setAttribute('viewBox', `0 0 ${svgImage.clientWidth} ${svgImage.clientHeight}`);
}
if (paramList.innerHTML === '') {
// Set parameters again
event.data.params.parameterDefinitions.forEach(addParameterItem);
// Set all the updated values
const values = event.data.values;
for (const entry of values) {
const id = entry[0];
const value = entry[1];
const valueElem = document.getElementById('value-' + id);
if (valueElem.type === 'checkbox') {
valueElem.checked = value;
} else {
valueElem.value = value;
}
}
}
case 'svg': case 'svg':
const newSvg = event.data.svg; const newSvg = event.data.svg;
if (svgImage === undefined) { if (svgImage === undefined) {
...@@ -44,8 +73,130 @@ window.addEventListener('message', event => { ...@@ -44,8 +73,130 @@ window.addEventListener('message', event => {
} }
}); });
function addParameterItem(param) {
const li = document.createElement("li");
const nameBox = document.createElement("label");
nameBox.id = "name-" + param.id;
nameBox.appendChild(document.createTextNode(param.name));
nameBox.classList.add("name");
nameBox.title = param.description;
li.appendChild(nameBox);
const valueBox = document.createElement("input");
valueBox.id = "value-" + param.id;
switch (param.type.valueType) {
case 'String':
valueBox.value = param.defaultValue;
valueBox.type = 'text';
valueBox.addEventListener("input", e => {
vscode.postMessage({
type: 'paramUpdate',
id: param.id,
value: valueBox.value
});
});
break;
case 'Boolean':
valueBox.value = param.defaultValue;
valueBox.type = 'checkbox';
valueBox.addEventListener("input", e => {
vscode.postMessage({
type: 'paramUpdate',
id: param.id,
value: valueBox.checked
});
});
break;
default:
console.log("OKAY WHAT THE FUCK IS THIS TYPE??? " + param.type.valueType);
break;
};
// if (type === "Enum") {
// /**
// * @type {HTMLSelectElement}
// */
// const valueBox = document.createElement("select");
// valueBox.id = "value-" + name;
// valueBox.classList.add("value");
// for (const value of possibleValues) {
// const option = document.createElement("option");
// option.value = value;
// option.text = value;
// valueBox.appendChild(option);
// }
// valueBox.value = value;
// valueBox.addEventListener("input", _ => {
// let oldState = vscode.getState();
// for (const tool of oldState.parameters) {
// if (tool.toolName === oldState.currentTool) {
// for (const parameter of tool.parameters) {
// if (parameter.id === name) {
// parameter.value = valueBox.options[valueBox.selectedIndex].value;
// break;
// }
// }
// break;
// }
// }
// vscode.setState({ tools: oldState.tools, documentVars: oldState.documentVars, parameters: oldState.parameters, currentUri: oldState.currentUri, currentTool: oldState.currentTool });
// });
// li.appendChild(valueBox);
// } else {
li.appendChild(valueBox);
// }
paramList.appendChild(li);
}
// FULL CREDIT TO https://stackoverflow.com/questions/52576376/how-to-zoom-in-on-a-complex-svg-structure
// also https://stackoverflow.com/questions/1685326/responding-to-the-onmousemove-event-outside-of-the-browser-window-in-ie
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
if (svgImage !== null) { if (svgImage !== undefined) {
viewBox.w = svgImage.clientWidth / scale; viewBox.w = svgImage.clientWidth / scale;
viewBox.h = svgImage.clientHeight / scale; viewBox.h = svgImage.clientHeight / scale;
svgImage.setAttribute('viewBox', `${viewBox.x} ${viewBox.y} ${viewBox.w} ${viewBox.h}`); svgImage.setAttribute('viewBox', `${viewBox.x} ${viewBox.y} ${viewBox.w} ${viewBox.h}`);
...@@ -53,7 +204,7 @@ window.addEventListener('resize', () => { ...@@ -53,7 +204,7 @@ window.addEventListener('resize', () => {
}); });
function zoom(zoomIn) { function zoom(zoomIn) {
if (svgImage !== null) { if (svgImage !== undefined) {
var w = viewBox.w; var w = viewBox.w;
var h = viewBox.h; var h = viewBox.h;
var mx = svgImage.clientWidth / 2;//middle of screen var mx = svgImage.clientWidth / 2;//middle of screen
...@@ -70,7 +221,7 @@ function zoom(zoomIn) { ...@@ -70,7 +221,7 @@ function zoom(zoomIn) {
} }
svgContainer.onmousewheel = (e) => { svgContainer.onmousewheel = (e) => {
if (svgImage !== null) { if (svgImage !== undefined) {
var w = viewBox.w; var w = viewBox.w;
var h = viewBox.h; var h = viewBox.h;
var mx = e.offsetX; //mouse x var mx = e.offsetX; //mouse x
...@@ -87,7 +238,7 @@ svgContainer.onmousewheel = (e) => { ...@@ -87,7 +238,7 @@ svgContainer.onmousewheel = (e) => {
}; };
svgContainer.onmousedown = (e) => { svgContainer.onmousedown = (e) => {
if (svgImage !== null && e.button !== 1) { if (svgImage !== undefined && e.button !== 1) {
lastPoint = { x: e.x, y: e.y }; lastPoint = { x: e.x, y: e.y };
document.onmousemove = (e) => { document.onmousemove = (e) => {
......
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { CancellationToken, NotificationType, TextDocumentIdentifier } from 'vscode-languageclient/node'; import { CancellationToken, NotificationType, TextDocumentIdentifier } from 'vscode-languageclient/node';
import { client, extensionUri } from './extension'; import { client, clientReady, extensionUri, resultHandlers } from './extension';
import * as fs from "fs"; import * as fs from "fs";
import { ParameterDefinitions, getNonce, ResultNotification } from './utils'; import { ParameterDefinitions, getNonce, ResultNotification } from './utils';
import { CancellationTokenSource } from 'vscode';
export namespace ModestCommands { export namespace ModestCommands {
...@@ -61,13 +62,15 @@ export namespace ModestCommands { ...@@ -61,13 +62,15 @@ export namespace ModestCommands {
public static currentDotView: LiveDotView | undefined; public static currentDotView: LiveDotView | undefined;
public static liveDotViews = new Map<vscode.Uri, LiveDotView>(); public static liveDotViews = new Map<vscode.Uri, LiveDotView>();
private static availableParameters: ParameterDefinitions | undefined;
private fileUri: vscode.Uri; private fileUri: vscode.Uri;
private panel: vscode.WebviewPanel; private panel: vscode.WebviewPanel;
private webview: vscode.Webview; private webview: vscode.Webview;
private lastDotString: string | undefined; private lastDotString: string | undefined;
private lastSvgString: string | undefined; private lastSvgString: string | undefined;
private dotParameters: Array<{ id: string, value: string }> = []; private dotParameters: Map<string, string> = new Map();
private lastRunToken: string | undefined;
public constructor(fileUri: vscode.Uri, sameColumn = false) { public constructor(fileUri: vscode.Uri, sameColumn = false) {
this.fileUri = fileUri; this.fileUri = fileUri;
...@@ -83,7 +86,7 @@ export namespace ModestCommands { ...@@ -83,7 +86,7 @@ export namespace ModestCommands {
// Enable scripts in the webview // Enable scripts in the webview
enableScripts: true, enableScripts: true,
// And restrict the webview to only loading content from our extension's `assets` directory. // And restrict the webview to only loading content from our extension's `assets` directory.
localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'media'), vscode.Uri.joinPath(extensionUri, 'assets')] localResourceRoots: [extensionUri]
} }
); );
...@@ -102,17 +105,27 @@ export namespace ModestCommands { ...@@ -102,17 +105,27 @@ export namespace ModestCommands {
if (e.webviewPanel.active) { if (e.webviewPanel.active) {
LiveDotView.currentDotView = this; LiveDotView.currentDotView = this;
} }
if (this.lastSvgString) { this.postMessage({
this.postMessage({ type: 'allData',
type: 'svg', svg: this.lastSvgString,
svg: this.lastSvgString params: LiveDotView.availableParameters,
}); values: Array.from(this.dotParameters.entries()),
} });
}, },
null, undefined,
undefined undefined
); );
this.webview.onDidReceiveMessage(
message => {
this.dotParameters.set(message.id, message.value);
this.updateDot();
},
undefined,
undefined
);
vscode.workspace.onDidSaveTextDocument(td => { vscode.workspace.onDidSaveTextDocument(td => {
if (td.uri === this.fileUri) { if (td.uri === this.fileUri) {
this.updateDot(); this.updateDot();
...@@ -122,16 +135,29 @@ export namespace ModestCommands { ...@@ -122,16 +135,29 @@ export namespace ModestCommands {
vscode.commands.executeCommand('setContext', 'modest:dotViewFocused', this.panel.active); vscode.commands.executeCommand('setContext', 'modest:dotViewFocused', this.panel.active);
LiveDotView.currentDotView = this; LiveDotView.currentDotView = this;
LiveDotView.liveDotViews.set(fileUri, this); LiveDotView.liveDotViews.set(fileUri, this);
}
if (!LiveDotView.availableParameters) {
public static init() { client?.sendRequest<ParameterDefinitions>("modest/getParameters", { "toolName": "mosta (export-to-dot)" }).then(data => {
client?.sendRequest<ParameterDefinitions>("modest/getParameters", { "toolName": "mosta (export-to-dot)" }).then(data => { LiveDotView.availableParameters = data;
console.log(data); this.postMessage({
}); type: 'params',
params: LiveDotView.availableParameters,
});
});
} else {
this.postMessage({
type: 'params',
params: LiveDotView.availableParameters,
});
}
} }
public static addOrOpen(uri: vscode.Uri, sameColumn = false) { public static addOrOpen(uri: vscode.Uri, sameColumn = false) {
if (!clientReady) {
vscode.window.showErrorMessage("Server not ready yet, try again later");
return;
}
var dotView = LiveDotView.liveDotViews.get(uri); var dotView = LiveDotView.liveDotViews.get(uri);
if (dotView !== undefined) { if (dotView !== undefined) {
dotView.panel.reveal(); dotView.panel.reveal();
...@@ -192,38 +218,87 @@ export namespace ModestCommands { ...@@ -192,38 +218,87 @@ export namespace ModestCommands {
private updateDot() { private updateDot() {
let uri = this.fileUri.toString(); let uri = this.fileUri.toString();
let parameters = [];
for (const entry of this.dotParameters.entries()) {
parameters.push({
id: entry[0],
value: entry[1]
});
}
let runToken = uri + this.dotParameters + Date.now();
let jsonObject = { let jsonObject = {
textDocument: TextDocumentIdentifier.create(uri), textDocument: TextDocumentIdentifier.create(uri),
toolName: "mosta (export-to-dot)", toolName: "mosta (export-to-dot)",
constants: [], constants: [],
parameters: this.dotParameters, parameters: parameters,
progressToken: uri + this.dotParameters + Date.now() progressToken: runToken
};
vscode.window.withProgress({ location: vscode.ProgressLocation.Window, title: `Loading new dot for ${this.fileUri.path.split("/").pop()}` }, async (progress, token) => {
await new Promise<null>(async (resolveProgress, _) => {
try {
let resultHandler = (data: ResultNotification) => {
if (data.progressToken === jsonObject.progressToken) {
if (data.data && data.data !== "") {
try {
this.lastDotString = data.data;
this.dotToSvg(runToken, resolveProgress);
} catch (error) {
console.error(error);
resultHandlers.splice(resultHandlers.indexOf(resultHandler), 1);
resolveProgress(null);
}
} else {
resultHandlers.splice(resultHandlers.indexOf(resultHandler), 1);
resolveProgress(null);
}
}
};
resultHandlers.push(resultHandler);
await client?.sendRequest<string>("modest/runTool", jsonObject, token);
} catch (e) {
vscode.window.showErrorMessage("Internal error: " + e);
resolveProgress(null);
return;
}
});
});
}
private dotToSvg(runToken: string, resolveProgress: (value: any | PromiseLike<any>) => void) {
let jsonObject = {
dot: this.lastDotString,
runToken: runToken
}; };
let resultHandler = client?.onNotification(new NotificationType<ResultNotification>("modest/toolResult"), data => { client?.sendRequest("modest/cancelRunTool", { progressToken: this.lastRunToken });
if (data.progressToken === jsonObject.progressToken) { this.lastRunToken = runToken;
let resultHandler = (data: ResultNotification) => {
if (data.progressToken === runToken) {
if (data.data && data.data !== "") { if (data.data && data.data !== "") {
try { try {
this.lastDotString = data.data; this.lastSvgString = data.data;
this.postMessage({
client?.sendRequest<string>("modest/dot", { dot: this.lastDotString }).then(data => { type: 'svg',
if(data !== null){ svg: this.lastSvgString
this.lastSvgString = data;
this.postMessage({
type: 'svg',
svg: this.lastSvgString
});
}
}); });
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
} }
resultHandler?.dispose(); resultHandlers.splice(resultHandlers.indexOf(resultHandler), 1);
resolveProgress(null);
} }
}); };
client?.sendRequest<string>("modest/runTool", jsonObject, CancellationToken.None);
resultHandlers.push(resultHandler);
client?.sendRequest<string>("modest/dot", jsonObject);
} }
...@@ -232,7 +307,11 @@ export namespace ModestCommands { ...@@ -232,7 +307,11 @@ export namespace ModestCommands {
let webview = this.webview; let webview = this.webview;
const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, "media", "dotview.js")); const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, "media", "dotview.js"));
const styleResetUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, 'media', 'reset.css'));
const styleVSCodeUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, 'media', 'vscode.css'));
const styleMainUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, 'media', 'dotview.css')); const styleMainUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, 'media', 'dotview.css'));
const styleCodicons = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, 'node_modules', 'vscode-codicons', 'dist', 'codicon.css'));
const fontCodicons = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, 'node_modules', 'vscode-codicons', 'dist', 'codicon.ttf'));
// Use a nonce to only allow a specific script to be run. // Use a nonce to only allow a specific script to be run.
const nonce = getNonce(); const nonce = getNonce();
...@@ -242,18 +321,34 @@ export namespace ModestCommands { ...@@ -242,18 +321,34 @@ export namespace ModestCommands {
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';"> <meta http-equiv="Content-Security-Policy" content="default-src 'none'; font-src ${fontCodicons}; style-src ${webview.cspSource}; script-src 'nonce-${nonce}';">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="${styleResetUri}" rel="stylesheet">
<link href="${styleVSCodeUri}" rel="stylesheet">
<link href="${styleMainUri}" rel="stylesheet"> <link href="${styleMainUri}" rel="stylesheet">
<link href="${styleCodicons}" rel="stylesheet">
<title>[Preview] ${this.fileUri.path.split("/").pop()}</title> <title>[Preview] ${this.fileUri.path.split("/").pop()}</title>
</head> </head>
<body id="svgContainer"> <body>
<div id="svgContainer"></div>
<div id="paramContainer">
<div id="buttonContainer">
<h3>
DOT OPTIONS
</h3>
<button id="revert" title="Reset selected options">
<i class="codicon codicon-discard"></i>
</button>
<button id="minimize" title="Minimize window">
<i class="codicon codicon-chrome-minimize"></i>
</button>
</div>
<ul id="paramList"></ul>
</div>
</body> </body>
<script nonce="${nonce}" src="${scriptUri}"></script> <script nonce="${nonce}" src="${scriptUri}"></script>
</html> </html>
`; `;
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment