diff --git a/Bitmagic.VscExtension/esbuild.js b/Bitmagic.VscExtension/esbuild.js index 01b9804..f7926a5 100644 --- a/Bitmagic.VscExtension/esbuild.js +++ b/Bitmagic.VscExtension/esbuild.js @@ -25,18 +25,44 @@ const extensionConfig = { // Config for webview source code (to be run in a web-based context) /** @type BuildOptions */ -const webviewConfig = { +const layerViewWebviewConfig = { ...baseConfig, target: "es2020", format: "esm", - entryPoints: ["./src/layerView/layerView.webview.ts"], + entryPoints: [ + "./src/layerView/layerView.webview.ts" + ], + outdir: "./out/", + plugins: [ + // Copy webview css files to `out` directory unaltered + copy({ + resolveFrom: "cwd", + assets: { + from: [ + "./src/layerView/layerView.css", + ], + to: ["./out"], + }, + }), + ], +}; + +const memoryViewWebviewConfig = { + ...baseConfig, + target: "es2020", + format: "esm", + entryPoints: [ + "./src/memoryView/memoryView.webview.ts" + ], outdir: "./out/", plugins: [ // Copy webview css files to `out` directory unaltered copy({ resolveFrom: "cwd", assets: { - from: ["./src/layerView/layerView.css"], + from: [ + "./src/memoryView/memoryView.css", + ], to: ["./out"], }, }), @@ -75,14 +101,19 @@ const watchConfig = { ...watchConfig, }); await build({ - ...webviewConfig, + ...layerViewWebviewConfig, + ...watchConfig, + }); + await build({ + ...memoryViewWebviewConfig, ...watchConfig, }); console.log("[watch] build finished"); } else { // Build extension and webview code await build(extensionConfig); - await build(webviewConfig); + await build(layerViewWebviewConfig); + await build(memoryViewWebviewConfig); console.log("build complete"); } } catch (err) { diff --git a/Bitmagic.VscExtension/package.json b/Bitmagic.VscExtension/package.json index 62196b9..508cfdd 100644 --- a/Bitmagic.VscExtension/package.json +++ b/Bitmagic.VscExtension/package.json @@ -2,7 +2,7 @@ "name": "bitmagic", "displayName": "BitMagic X16 Debugger", "description": "BitMagic X16 Debugger and Development Solution", - "version": "0.1.21", + "version": "0.1.22", "preview": false, "publisher": "yazwh0", "icon": "package/butterfly.png", @@ -181,6 +181,11 @@ "command": "layerView.start", "title": "Open The Layer View", "category": "BitMagic" + }, + { + "command": "memoryView.start", + "title": "Open The Memory View", + "category": "BitMagic" } ], "debuggers": [ diff --git a/Bitmagic.VscExtension/src/extension.ts b/Bitmagic.VscExtension/src/extension.ts index 6a09431..2f97f2e 100644 --- a/Bitmagic.VscExtension/src/extension.ts +++ b/Bitmagic.VscExtension/src/extension.ts @@ -11,6 +11,7 @@ import path = require('path'); import Constants from './constants'; import { LayerView } from './layerView/layerView'; import { provideVSCodeDesignSystem, vsCodeButton } from "@vscode/webview-ui-toolkit"; +import { MemoryView } from './memoryView/memoryView'; const bmOutput = vscode.window.createOutputChannel("BitMagic"); @@ -124,6 +125,7 @@ export function activate(context: vscode.ExtensionContext) { // Action Replay LayerView.activate(context); + MemoryView.activate(context); // Visualiser diff --git a/Bitmagic.VscExtension/src/memoryView/memoryView.css b/Bitmagic.VscExtension/src/memoryView/memoryView.css new file mode 100644 index 0000000..fac650c --- /dev/null +++ b/Bitmagic.VscExtension/src/memoryView/memoryView.css @@ -0,0 +1,35 @@ +img.memory_display +{ + height : 512px; + width : 512px; + border : 1px white solid; + image-rendering: pixelated; +} + +div.memory_container +{ + display: flex; + flex-wrap: wrap; + flex-direction: row; + justify-content: flex-start; +} + +div.memory +{ + margin: 0 5px; +} + +div.display_control +{ + margin-top: 10px; + display: flex; + flex-wrap: wrap; + flex-direction: row; + justify-content: flex-start; + align-items: center; +} + +div.control_holder +{ + margin: 0 5px; +} diff --git a/Bitmagic.VscExtension/src/memoryView/memoryView.ts b/Bitmagic.VscExtension/src/memoryView/memoryView.ts new file mode 100644 index 0000000..1f34c40 --- /dev/null +++ b/Bitmagic.VscExtension/src/memoryView/memoryView.ts @@ -0,0 +1,121 @@ +import { Disposable, Webview, WebviewPanel, window, Uri, ViewColumn, ExtensionContext, commands, debug } from "vscode"; +import { getUri } from "../utilities/getUri"; +import { getNonce } from "../utilities/getNonce"; + +export class MemoryView { + + public static currentPanel: MemoryView | undefined; + + public static activate(context: ExtensionContext) { + + const uri = context.extensionUri; + + context.subscriptions.push( + commands.registerCommand('memoryView.start', () => { + const columnToShowIn = window.activeTextEditor + ? window.activeTextEditor.viewColumn + : undefined; + + if (MemoryView.currentPanel) { + MemoryView.currentPanel._panel.reveal(columnToShowIn); + } + else { + const panel = window.createWebviewPanel( + 'memoryView', + 'Memory View', + columnToShowIn || ViewColumn.One, + { + enableScripts: true + } + ); + + MemoryView.currentPanel = new MemoryView(panel, uri); + } + }) + ); + } + + private readonly _panel: WebviewPanel; + private _disposables: Disposable[] = []; + + private constructor(panel: WebviewPanel, extensionUri: Uri) { + this._panel = panel; + + this._panel.onDidDispose(() => { this.dispose(), null, this, this._disposables }); + + this._panel.webview.html = this._getWebviewContent(this._panel.webview, extensionUri); + + this._setWebviewMessageListener(this._panel.webview); + } + + private dispose() { + MemoryView.currentPanel = undefined; + + this._panel.dispose(); + + while (this._disposables.length) { + const disposable = this._disposables.pop(); + if (disposable) { + disposable.dispose(); + } + } + } + + private _setWebviewMessageListener(webview: Webview) { + webview.onDidReceiveMessage( + (message: any) => { + const command = message.command; + + switch (command) { + case "getMemoryUse": + this._updateMemoryUse(webview); + return; + } + }, + undefined, + this._disposables + ); + } + + private _updateMemoryUse(webview: Webview) { + debug.activeDebugSession?.customRequest("getMemoryUse").then(i => { + webview.postMessage({ command: "memoryUpdate", payload: JSON.stringify(i) }); + }); + } + + private _getWebviewContent(webview: Webview, extensionUri: Uri) { + const webviewUri = getUri(webview, extensionUri, ["out", "memoryView.webview.js"]); + const nonce = getNonce(); + const styleUri = getUri(webview, extensionUri, ["out", "memoryView.css"]); + + return /*html*/ ` + + + + + + Layer View + + + +
+
+ Update +
+
+ Automatically Update +
+
+
+
+
+

Main Ram

+ +
+
+
+ + + `; + } +} diff --git a/Bitmagic.VscExtension/src/memoryView/memoryView.webview.ts b/Bitmagic.VscExtension/src/memoryView/memoryView.webview.ts new file mode 100644 index 0000000..8d7d468 --- /dev/null +++ b/Bitmagic.VscExtension/src/memoryView/memoryView.webview.ts @@ -0,0 +1,48 @@ +import { provideVSCodeDesignSystem, vsCodeButton, Button, vsCodeCheckbox, Checkbox } from "@vscode/webview-ui-toolkit"; + +provideVSCodeDesignSystem().register( + vsCodeButton(), + vsCodeCheckbox() +); + +const vscode = acquireVsCodeApi(); + +window.addEventListener("load", main); + +function main() { + setVSCodeMessageListener(); + // To get improved type annotations/IntelliSense the associated class for + // a given toolkit component can be imported and used to type cast a reference + // to the element (i.e. the `as Button` syntax) + const updateButton = document.getElementById("update") as Button; + updateButton.addEventListener("click", () => updateMemory()); +} + +function setVSCodeMessageListener() { + window.addEventListener("message", (event) => { + const command = event.data.command; + const messageData = JSON.parse(event.data.payload); + + switch (command) { + case "memoryUpdate": + updateDisplay(messageData); + break; + } + }); +} + +function updateMemory() { + vscode.postMessage({ command: "getMemoryUse" }); +} + +function updateDisplay(messageData: any) { + const d = messageData.Display; + const layer = document.getElementById("main_ram") as HTMLImageElement; + + layer.src = `data:image/bmp;base64,${d}`; + const checkBox = document.getElementById("automatically_update") as Checkbox; + + if (checkBox.checked) { + setTimeout(updateMemory, 10); + } +}