Skip to content

Commit

Permalink
Add webview panel for mumax webui
Browse files Browse the repository at this point in the history
  • Loading branch information
MathieuMoalic committed Nov 22, 2023
1 parent b23d081 commit 8d03858
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 24 deletions.
56 changes: 47 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,23 @@
"properties": {
"mx3.path": {
"type": "string",
"default": "mumax3",
"default": "amumax",
"description": "Path to mumax3/amumax executable"
},
"mx3.webInterfaceUrl": {
"type": "string",
"default": "http://localhost:35367",
"description": "The URL of the MX3 web interface"
},
"mx3.openWebUI": {
"type": "boolean",
"default": true,
"description": "Control whether to open the MX3 web interface automatically"
},
"mx3.clearOutput": {
"type": "boolean",
"default": true,
"description": "Control whether to clear the output of previous simulations when running a new simulation"
}
}
},
Expand Down Expand Up @@ -53,41 +68,64 @@
"keybindings": [
{
"key": "ctrl+alt+r",
"command": "extension.runmumax3",
"command": "extension.runSimulation",
"when": "resourceExtname == .mx3 && editorTextFocus"
}
],
"menus": {
"editor/title": [
{
"when": "resourceExtname == .mx3",
"command": "extension.runmumax3",
"group": "navigation"
"command": "extension.runSimulation",
"group": "navigation",
"when": "!isRunning && resourceExtname == .mx3"
},
{
"command": "extension.stopSimulation",
"group": "navigation",
"when": "isRunning"
}
],
"editor/context": [
{
"when": "resourceExtname == .mx3",
"command": "extension.runmumax3",
"command": "extension.runSimulation",
"group": "1_modification"
}
],
"explorer/context": [
{
"when": "resourceExtname == .mx3",
"command": "extension.runmumax3",
"command": "extension.runSimulation",
"group": "1_modification"
}
]
},
"commands": [
{
"command": "extension.runmumax3",
"title": "Run Amumax",
"command": "extension.runSimulation",
"title": "Run Simulation",
"icon": {
"light": "resources/run-file.svg",
"dark": "resources/run-file.svg"
}
},
{
"command": "extension.stopSimulation",
"title": "Stop Simulation",
"icon": {
"light": "resources/stop.svg",
"dark": "resources/stop.svg"
}
},
{
"command": "extension.showWebInterface",
"title": "Show Web Interface"
}
],
"snippets": [
{
"language": "mx3",
"path": "snippets/snippets.json"
}
]
},
Expand Down
155 changes: 140 additions & 15 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,163 @@
import * as vscode from 'vscode';
import { ChildProcessWithoutNullStreams, spawn } from 'child_process';
let childProcess: ChildProcessWithoutNullStreams;

let isRunning = false;
let webviewPanel: vscode.WebviewPanel | undefined = undefined;

export function activate(context: vscode.ExtensionContext) {
const outputChannel = vscode.window.createOutputChannel("Simulation Output");
context.subscriptions.push(outputChannel);

let disposable = vscode.commands.registerCommand('extension.runmumax3', () => {
let runDisposable = vscode.commands.registerCommand('extension.runSimulation', () => {
if (isRunning) {
vscode.window.showInformationMessage('The command is already running.');
return;
}

// Check for active text editor
const editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showErrorMessage('No active text editor found.');
return;
}

// Extract the file name
const fileName = editor.document.fileName;

// Get configuration
const config = vscode.workspace.getConfiguration('mx3');
const mumax3Path: string | undefined = config.get('path');
if (!mumax3Path) {
const binaryPath: string | undefined = config.get('path');
const shouldOpenWebUI = config.get<boolean>('openWebUI', true);
const shouldCLearOutput = config.get<boolean>('clearOutput', true);


if (!binaryPath) {
vscode.window.showErrorMessage('Path to mumax3 or amumax is not set. Please configure it in settings.');
return;
}

// Validate mumax3Path here if necessary
if (shouldCLearOutput) {
outputChannel.clear();
}
outputChannel.show(true);

childProcess = spawn(binaryPath, [fileName], {
shell: true
});
childProcess.stdout.on('data', (data: Buffer) => {
outputChannel.append(data.toString());
});

childProcess.stderr.on('data', (data: Buffer) => {
outputChannel.append(data.toString());
});
childProcess.on('close', (code) => {
isRunning = false;
updateButtonCommand();
if (code !== 0) {
outputChannel.appendLine(`Process exited with code ${code}`);
}
});

isRunning = true;
updateButtonCommand();
if (shouldOpenWebUI) {
if (webviewPanel) {
webviewPanel.reveal(vscode.ViewColumn.One);
} else {
webviewPanel = createWebviewPanel(context);
}
}

});

let stopDisposable = vscode.commands.registerCommand('extension.stopSimulation', () => {
stopSimulation(outputChannel);
});

// Create a new terminal
const terminal = vscode.window.createTerminal('Mumax3 Terminal');
let GUIdisposable = vscode.commands.registerCommand('extension.showWebInterface', () => {
// Create and show a new webview
const panel = vscode.window.createWebviewPanel(
'webInterface', // Identifies the type of the webview. Used internally
'Mumax Interface', // Title of the panel displayed to the user
vscode.ViewColumn.One, // Editor column to show the new webview panel in.
{
// Enable scripts in the webview
enableScripts: true
}
);

// Show the terminal
terminal.show();
// And set its HTML content
const config = vscode.workspace.getConfiguration();
const webInterfaceUrl = config.get('mx3.webInterfaceUrl') as string;

// Send the fully-resolved command
terminal.sendText(`${mumax3Path} ${fileName}`);
panel.webview.html = getWebviewContent(webInterfaceUrl);
});

context.subscriptions.push(disposable);
context.subscriptions.push(runDisposable, stopDisposable, GUIdisposable);
}

function createWebviewPanel(context: vscode.ExtensionContext): vscode.WebviewPanel {
const panel = vscode.window.createWebviewPanel(
'webInterface',
'Mumax WebUI',
vscode.ViewColumn.One,
{ enableScripts: true }
);

const config = vscode.workspace.getConfiguration();
const webInterfaceUrl = config.get('mx3.webInterfaceUrl') as string;

panel.webview.html = getWebviewContent(webInterfaceUrl);

// Handle when the panel is disposed (when the user closes the panel)
panel.onDidDispose(() => {
webviewPanel = undefined;
}, null, context.subscriptions);

return panel;
}

function getWebviewContent(webInterfaceUrl: string) {
return `
<!DOCTYPE html>
<html style="height: 100%;">
<head>
<meta charset="UTF-8">
<style>
body, html {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
iframe {
width: 100%;
height: 100%;
border: none;
}
</style>
</head>
<body>
<iframe src="${webInterfaceUrl}"></iframe>
</body>
</html>
`;
}

function updateButtonCommand() {
vscode.commands.executeCommand('setContext', 'isRunning', isRunning);
}
function stopSimulation(outputChannel: vscode.OutputChannel) {
if (childProcess && typeof childProcess.pid === 'number') {
try {
process.kill(childProcess.pid); // Kill the process group
outputChannel.appendLine('Process was stopped.');
} catch (error) {
outputChannel.appendLine(`Failed to stop the process: ${error}`);
}
} else {
outputChannel.appendLine('No running process to stop.');
}

isRunning = false;
updateButtonCommand();
}

0 comments on commit 8d03858

Please sign in to comment.