Skip to content
Snippets Groups Projects
sidebar.ts 14.2 KiB
Newer Older
import * as vscode from "vscode";
import {
    TextDocument
} from "vscode";
import {
    NotificationType,
    ProgressType,
    TextDocumentIdentifier
} from "vscode-languageclient/node";
import { analysisResultsProvider, client, clientReady, disposalQueue, provider, resultHandlers, treeView } from './extension';
import { ParameterDefinitions, ProgressIndication, ResultNotification, getNonce } from "./utils";
let localToolNames: Array<string> | undefined;
let localDocumentVars: Array<{ uri: string, constants: Array<{ name: string, value: string }>, distributions: Array<{ name: string, value: string }> }> = [];
let localParameters: Array<{ toolName: string, parameters: Array<{ id: string, name: string, value: string, type: string, category: string }> }> = [];

export function initializeTools() {
    client?.sendRequest<any>("modest/getTools").then(data => {
        localToolNames = data.availableTools;
            tools: localToolNames
export function getDocumentVars(document: TextDocument) {
    if (document.languageId === "modest") {
        if (document.uri) {
            let uri = document.uri.toString();
            let jsonObject = { "textDocument": TextDocumentIdentifier.create(uri) };
            client?.sendRequest<{ constants: Array<string>, distributions: Array<string> }>("modest/getDocumentVars", jsonObject).then(data => {
                const index = localDocumentVars.findIndex(x => x.uri === uri);
                const newConstants = data.constants.map(constant => {
                const newDistributions = data.distributions.map(distribution => {
                    return { name: distribution, value: "" };
                });
                    localDocumentVars.push({ "uri": uri, constants: newConstants, distributions: newDistributions });
                    localDocumentVars[index].constants = newConstants;
                    localDocumentVars[index].distributions = newDistributions;
                    type: "updateDocumentVars",
                    documentVars: localDocumentVars,
                    "uri": uri
                });
            });
        }
    }
}

function getParameters(toolName: string) {
    let jsonObject = { "toolName": toolName };
    client?.sendRequest<ParameterDefinitions>("modest/getParameters", jsonObject).then(data => {
        const index = localParameters.findIndex(x => x.toolName === toolName);
        const newParameters = data.parameterDefinitions.map(parameter => {
                return { id: parameter.id, name: parameter.name, value: parameter.defaultValue, type: "Enum", category: parameter.category, description: parameter.description, possibleValues: parameter.type.possibleValues };
            return { id: parameter.id, name: parameter.name, value: parameter.defaultValue, type: parameter.type.valueType, category: parameter.category, description: parameter.description };
            localParameters.push({ toolName: toolName, parameters: newParameters });
            localParameters[index].parameters = newParameters;
            parameters: localParameters,
function runTool(uri: string, toolName: string, constants: { name: string; value: string; }[], suppliedDistributions: { name: string, value: string }[], suppliedParameters: { id: string; value: string; }[]) {
    const toolIndex = localParameters.findIndex(x => x.toolName === toolName);
    let serverParameters: Array<{ id: string, value: string }> = [];
    if (toolIndex !== -1) {
        for (const parameter of suppliedParameters) {
            const parameterIndex = localParameters[toolIndex].parameters.findIndex(x => x.id === parameter.id);
                if (String(localParameters[toolIndex].parameters[parameterIndex].value) !== String(parameter.value)) {
s1995588's avatar
s1995588 committed
    }

    const fileIndex = localDocumentVars.findIndex(x => x.uri === uri);
    if (fileIndex !== -1) {
        for (const distribution of suppliedDistributions) {
s1995588's avatar
s1995588 committed
            const distributionIndex = localDocumentVars[fileIndex].distributions.findIndex(x => x.name === distribution.name);
            if (distributionIndex !== -1) {
s1995588's avatar
s1995588 committed
                if (String(localDocumentVars[fileIndex].distributions[distributionIndex].value) !== String(distribution.value)) {
    }

    let jsonObject = {
        textDocument: TextDocumentIdentifier.create(uri),
        toolName: toolName,
        runToken: uri + toolName + JSON.stringify(constants) + JSON.stringify(serverParameters) + Date.now()
    vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, cancellable: true, title: "Running " + toolName }, async (progress, token) => {
                vscode.window.showErrorMessage("Server not ready yet, try again later");
                resolve(null);
                let progressHandler = client?.onProgress(new ProgressType<ProgressIndication>(), jsonObject.runToken, indication => {
                    progress.report({ message: indication.message, increment: indication.progress * 100 });
                });
                if (progressHandler) { disposalQueue.push(progressHandler); }
                let resultHandler = (data: ResultNotification) => {
                    if (data.runToken === jsonObject.runToken) {
                                analysisResultsProvider.setJsonObject(JSON.parse(data.data.trim()));
                                treeView.reveal(treeRoot, { focus: false, select: false, expand: true });
                                let language = "plaintext";
                                }
                                // TODO: Look at parameters for mosta to automatically determine extension?
                                vscode.workspace.openTextDocument({ language: language, content: data.data }).then(document => {
                                    vscode.window.showTextDocument(document);
                        resultHandlers.splice(resultHandlers.indexOf(resultHandler), 1);
                };
                resultHandlers.push(resultHandler);
                disposalQueue.push({
                    dispose: function () {
                        vscode.window.showErrorMessage("Language server restarting, operation cancelled");
                        resultHandlers.splice(resultHandlers.indexOf(resultHandler), 1);
                        resolve(null);
                        token.isCancellationRequested = true;
                    }
                });
                token.onCancellationRequested(_ => {
                    client?.sendRequest("modest/cancelRun", { runToken: jsonObject.runToken });
                }, null, disposalQueue);
                await client?.sendRequest<string>("modest/runTool", jsonObject);
                vscode.window.showErrorMessage("Internal error: " + e);
        });
    });
}
export class ModestSidebarProvider implements vscode.WebviewViewProvider {
    public static readonly viewType = "modest.modestSidebar";

    private _view?: vscode.WebviewView;

    constructor(private readonly _extensionUri: vscode.Uri) { }

    resolveWebviewView(
        webviewView: vscode.WebviewView,
        context: vscode.WebviewViewResolveContext<unknown>,
        token: vscode.CancellationToken
    ): void | Thenable<void> {
        this._view = webviewView;

        webviewView.webview.options = {
            // Allow scripts in the webview
            enableScripts: true,

            localResourceRoots: [this._extensionUri],
        };

        webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);
        webviewView.webview.onDidReceiveMessage(data => {
            console.log(data);
            switch (data.type) {
                case 'init': {
                    if (localToolNames) {
                            tools: localToolNames
                    if (localDocumentVars) {
                            type: "updateDocumentVars",
                            documentVars: localDocumentVars
                    if (data.toolName !== "") {
                        getParameters(data.toolName);
                    }
                    if (vscode.window.activeTextEditor) {
                        getDocumentVars(vscode.window.activeTextEditor.document);
                    }
                    runTool(data.uri, data.toolName, data.constants, data.distributions, data.parameters);
                    break;
                }
            }
        });
    }

    /**
     * sendMessage
     * @param {any} message
     */
    public sendMessage(message: any) {
        this._view?.show(true);
        this._view?.webview?.postMessage(message);
    }

    private _getHtmlForWebview(webview: vscode.Webview) {
        // Get the local path to main script run in the webview, then convert it to a uri we can use in the webview.
        const scriptUri = webview.asWebviewUri(
            vscode.Uri.joinPath(this._extensionUri, "media", "main.js")
        );

        // Do the same for the stylesheet.
        const styleResetUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'reset.css'));
        const styleVSCodeUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'vscode.css'));
        const styleMainUri = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'media', 'main.css'));
        const styleCodicons = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'node_modules', 'vscode-codicons', 'dist', 'codicon.css'));
        const fontCodicons = webview.asWebviewUri(vscode.Uri.joinPath(this._extensionUri, 'node_modules', 'vscode-codicons', 'dist', 'codicon.ttf'));

        // Use a nonce to only allow a specific script to be run.
        const nonce = getNonce();

        return `<!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <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>Modest run dialog</title>
        </head>
        <body>
            <h3 title="Select tool">Select tool</h3>
            <div id="run-box">
                <select class="tools-dropdown" id="tools"> </select>
                <button id="run-button"><i class="codicon codicon-play"></i></button>
            </div>

            <div class="pane-view">
                <div class="split-view-view">
                    <div class="pane vertical">
                        <div class="pane-header">
                            <h3 class="title" title="Open constants">Open constants</h3>
                        </div>
                        <div class="pane-body">
                            <ul class="option-list" id="constants">There are no undefined constants.</ul>
                        </div>
                    </div>
                    <div class="pane vertical">
                        <div class="pane-header">
                            <div class="codicon codicon-chevron-right"></div>
                            <h3 class="title" title="Distributions">Distributions</h3>
                        </div>
                        <div class="pane-body">
                            <ul class="option-list" id="distributions">There are no distributions.</ul>
                        </div>
                    </div>
                    <div class="pane vertical">
                        <div class="pane-header">
                            <div class="codicon codicon-chevron-right"></div>
                            <h3 class="title" title="Parameters">Parameters</h3>
                        <div id="parameters"class="pane-body">
            </div>

            <script nonce="${nonce}" src="${scriptUri}"></script>
        </body>
        </html>
        `;