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%;
height: 100%;
}
......@@ -15,6 +15,67 @@ polygon {
fill: none;
}
.vscode-dark {
body.vscode-dark #svgContainer {
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
// also https://stackoverflow.com/questions/1685326/responding-to-the-onmousemove-event-outside-of-the-browser-window-in-ie
const vscode = acquireVsCodeApi();
const svgContainer = document.getElementById("svgContainer");
const paramList = document.getElementById("paramList");
var svgImage;
......@@ -28,6 +27,36 @@ window.addEventListener('message', event => {
case 'zoomOut':
zoom(false);
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':
const newSvg = event.data.svg;
if (svgImage === undefined) {
......@@ -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', () => {
if (svgImage !== null) {
if (svgImage !== undefined) {
viewBox.w = svgImage.clientWidth / scale;
viewBox.h = svgImage.clientHeight / scale;
svgImage.setAttribute('viewBox', `${viewBox.x} ${viewBox.y} ${viewBox.w} ${viewBox.h}`);
......@@ -53,7 +204,7 @@ window.addEventListener('resize', () => {
});
function zoom(zoomIn) {
if (svgImage !== null) {
if (svgImage !== undefined) {
var w = viewBox.w;
var h = viewBox.h;
var mx = svgImage.clientWidth / 2;//middle of screen
......@@ -70,7 +221,7 @@ function zoom(zoomIn) {
}
svgContainer.onmousewheel = (e) => {
if (svgImage !== null) {
if (svgImage !== undefined) {
var w = viewBox.w;
var h = viewBox.h;
var mx = e.offsetX; //mouse x
......@@ -87,7 +238,7 @@ svgContainer.onmousewheel = (e) => {
};
svgContainer.onmousedown = (e) => {
if (svgImage !== null && e.button !== 1) {
if (svgImage !== undefined && e.button !== 1) {
lastPoint = { x: e.x, y: e.y };
document.onmousemove = (e) => {
......
import * as vscode from 'vscode';
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 { ParameterDefinitions, getNonce, ResultNotification } from './utils';
import { CancellationTokenSource } from 'vscode';
export namespace ModestCommands {
......@@ -61,13 +62,15 @@ export namespace ModestCommands {
public static currentDotView: LiveDotView | undefined;
public static liveDotViews = new Map<vscode.Uri, LiveDotView>();
private static availableParameters: ParameterDefinitions | undefined;
private fileUri: vscode.Uri;
private panel: vscode.WebviewPanel;
private webview: vscode.Webview;
private lastDotString: 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) {
this.fileUri = fileUri;
......@@ -83,7 +86,7 @@ export namespace ModestCommands {
// Enable scripts in the webview
enableScripts: true,
// 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 {
if (e.webviewPanel.active) {
LiveDotView.currentDotView = this;
}
if (this.lastSvgString) {
this.postMessage({
type: 'svg',
svg: this.lastSvgString
});
}
this.postMessage({
type: 'allData',
svg: this.lastSvgString,
params: LiveDotView.availableParameters,
values: Array.from(this.dotParameters.entries()),
});
},
null,
undefined,
undefined
);
this.webview.onDidReceiveMessage(
message => {
this.dotParameters.set(message.id, message.value);
this.updateDot();
},
undefined,
undefined
);
vscode.workspace.onDidSaveTextDocument(td => {
if (td.uri === this.fileUri) {
this.updateDot();
......@@ -122,16 +135,29 @@ export namespace ModestCommands {
vscode.commands.executeCommand('setContext', 'modest:dotViewFocused', this.panel.active);
LiveDotView.currentDotView = this;
LiveDotView.liveDotViews.set(fileUri, this);
}
public static init() {
client?.sendRequest<ParameterDefinitions>("modest/getParameters", { "toolName": "mosta (export-to-dot)" }).then(data => {
console.log(data);
});
if (!LiveDotView.availableParameters) {
client?.sendRequest<ParameterDefinitions>("modest/getParameters", { "toolName": "mosta (export-to-dot)" }).then(data => {
LiveDotView.availableParameters = data;
this.postMessage({
type: 'params',
params: LiveDotView.availableParameters,
});
});
} else {
this.postMessage({
type: 'params',
params: LiveDotView.availableParameters,
});
}
}
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);
if (dotView !== undefined) {
dotView.panel.reveal();
......@@ -192,38 +218,87 @@ export namespace ModestCommands {
private updateDot() {
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 = {
textDocument: TextDocumentIdentifier.create(uri),
toolName: "mosta (export-to-dot)",
constants: [],
parameters: this.dotParameters,
progressToken: uri + this.dotParameters + Date.now()
parameters: parameters,
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 => {
if (data.progressToken === jsonObject.progressToken) {
client?.sendRequest("modest/cancelRunTool", { progressToken: this.lastRunToken });
this.lastRunToken = runToken;
let resultHandler = (data: ResultNotification) => {
if (data.progressToken === runToken) {
if (data.data && data.data !== "") {
try {
this.lastDotString = data.data;
client?.sendRequest<string>("modest/dot", { dot: this.lastDotString }).then(data => {
if(data !== null){
this.lastSvgString = data;
this.postMessage({
type: 'svg',
svg: this.lastSvgString
});
}
this.lastSvgString = data.data;
this.postMessage({
type: 'svg',
svg: this.lastSvgString
});
} catch (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 {
let webview = this.webview;
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 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.
const nonce = getNonce();
......@@ -242,18 +321,34 @@ export namespace ModestCommands {
<html lang="en">
<head>
<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">
<link href="${styleResetUri}" rel="stylesheet">
<link href="${styleVSCodeUri}" rel="stylesheet">
<link href="${styleMainUri}" rel="stylesheet">
<link href="${styleCodicons}" rel="stylesheet">
<title>[Preview] ${this.fileUri.path.split("/").pop()}</title>
</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>
<script nonce="${nonce}" src="${scriptUri}"></script>
</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