diff --git a/README.md b/README.md index 7bf3b6a..2c8ca3e 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ -uiae +# VS Code Debug Visualizer + +See [extension](extension) for the extension readme. diff --git a/example-project/.vscode/launch.json b/example-project/.vscode/launch.json index 7ff5c94..75473e8 100644 --- a/example-project/.vscode/launch.json +++ b/example-project/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "type": "node", + "type": "node2-with-pause-event", "request": "launch", "name": "Launch Program", "program": "${workspaceFolder}\\dist\\index.js", diff --git a/example-project/src/index.ts b/example-project/src/index.ts index 100dc27..5d05930 100644 --- a/example-project/src/index.ts +++ b/example-project/src/index.ts @@ -10,47 +10,36 @@ import { } from "@hediet/debug-visualizer-data-extraction"; enableHotReload(); import * as ts from "typescript"; -//import { liveLogId, liveLog } from "@hediet/live-debug"; registerUpdateReconciler(module); registerAll(); -/* -let i = 0; -setInterval(() => { - i++; - liveLog("bla" + i * 2); - liveLog("test" + i); -}, 1000); -*/ - @hotClass(module) class Main { run() { const sf = ts.createSourceFile( "test", ` -class uiae { - +class Test1 { +} +class Test2 { } - `, ts.ScriptTarget.Latest, true ); - - console.log(sf); - debugger; - } - - test() { - // iue - return { - kind: { graph: true }, - edges: [{ from: "1", to: "2", label: "aa" }], - nodes: [{ id: "1", label: "uiae" }, { id: "2", label: "bar" }], - } as CommonDataTypes.GraphData; + let myValue: any = sf.statements[0]; + myValue = sf.statements[1]; + myValue = sf.getText(); + myValue = { + kind: { text: true, svg: true }, + text: ` + + Sorry, your browser does not support inline SVG. + + `, + }; } } diff --git a/extension/README.md b/extension/README.md new file mode 100644 index 0000000..92f4ac8 --- /dev/null +++ b/extension/README.md @@ -0,0 +1,81 @@ +# Debug Visualizer (Preview) + +[![](https://img.shields.io/twitter/follow/hediet_dev.svg?style=social)](https://twitter.com/intent/follow?screen_name=hediet_dev) + +Provides infrastructure to visualize values while debugging. + +This extension is still in development. Some VS Code APIs are still missing for the best experience. + +![](docs/demo.gif) + +## Usage + +Install this extension and the extension `Node Debug With Pause Events` +which is required for technical reasons for now. +Then use a debug configuration like this: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node2-with-pause-event", + "request": "launch", + "name": "Launch Program", + "program": "${workspaceFolder}\\dist\\index.js", + "outFiles": ["${workspaceFolder}/dist/**/*.js"], + "preLaunchTask": "npm: dev" + } + ] +} +``` + +Use the command `Open a new Debug Visualizer View` to open a new visualizer view. +There you can enter an expression that is visualized when debugging your application. + +## Integrated Visualizers + +Visualizers present preprocessed data. +They are mostly React-Components and live in the webview. + +These visualizers are integrated: + +- Tree Viewer + +![](./docs/tree-viewer.png) + +- Svg Viewer +- Dot Graph Viewer +- Graph Viewer + +![](./docs/graph-viewer.png) + +- Text Viewer + - Plain Text + - Monaco + +## Integrated Data Extractors + +Data extractors convert arbitrary values into visualizable data. +They live in the debugee. + +These visualizers are integrated: + +- ToString Text Extractor +- TypeScript Ast to Tree Data + - Direct Visualization of `ts.Node`s + - Visualization of `Record` and `[ts.Node]`. If the record contains a key `fn`, its value is displayed for each node. + +![](./docs/ast-viewer.png) + +- As Is Data Extractor. Allows to return data directly. + +## Limitations + +Currently, only JavaScript (and thus TypeScript) values can be visualized and only a few visualizations are supported. + +# See Also + +This extension works very well together with my library [`@hediet/node-reload`](https://github.com/hediet/node-reload): + +![](./docs/demo-hot.gif) diff --git a/extension/docs/ast-viewer.png b/extension/docs/ast-viewer.png new file mode 100644 index 0000000..5807be8 Binary files /dev/null and b/extension/docs/ast-viewer.png differ diff --git a/extension/docs/demo-hot.gif b/extension/docs/demo-hot.gif new file mode 100644 index 0000000..633a4a9 Binary files /dev/null and b/extension/docs/demo-hot.gif differ diff --git a/extension/docs/demo.gif b/extension/docs/demo.gif new file mode 100644 index 0000000..1b74c14 Binary files /dev/null and b/extension/docs/demo.gif differ diff --git a/extension/docs/graph-viewer.png b/extension/docs/graph-viewer.png new file mode 100644 index 0000000..b811e3a Binary files /dev/null and b/extension/docs/graph-viewer.png differ diff --git a/extension/docs/tree-viewer.png b/extension/docs/tree-viewer.png new file mode 100644 index 0000000..2c738bc Binary files /dev/null and b/extension/docs/tree-viewer.png differ diff --git a/extension/package.json b/extension/package.json index 1d6541c..d1207bb 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1,7 +1,7 @@ { - "name": "vscode-debug-visualizer", - "displayName": "VS Code Debug Visualizer", - "description": "", + "name": "debug-visualizer", + "displayName": "Debug Visualizer", + "description": "An extension that visualizes values while debugging.", "icon": "docs/logo.png", "version": "0.1.0", "license": "MIT", @@ -21,13 +21,28 @@ "categories": [ "Other" ], + "preview": true, "activationEvents": [ "*" ], "main": "./out/extension.js", "contributes": { - "commands": [], - "configuration": {} + "commands": [ + { + "command": "vscode-debug-visualizer.new-visualizer", + "title": "Open a new Debug Visualizer View" + } + ], + "configuration": { + "title": "Debug Visualizer", + "properties": { + "debugVisualizer.useChromeKioskMode": { + "type": "boolean", + "default": true, + "description": "Pop out Debug Visualization Views with Chrome in Kiosk Mode." + } + } + } }, "scripts": { "vscode:prepublish": "yarn run build", diff --git a/extension/src/Config.ts b/extension/src/Config.ts new file mode 100644 index 0000000..8f54c04 --- /dev/null +++ b/extension/src/Config.ts @@ -0,0 +1,28 @@ +import { workspace } from "vscode"; +import { Disposable } from "@hediet/std/disposable"; +import { EventEmitter, EventSource } from "@hediet/std/events"; + +export const useChromeKioskModeKey = "debugVisualizer.useChromeKioskMode"; + +export class Config { + private changeEventEmitter = new EventEmitter(); + public readonly onChange: EventSource = this.changeEventEmitter; + public dispose = Disposable.fn(); + + constructor() { + this.dispose.track( + workspace.onDidChangeConfiguration(() => { + this.changeEventEmitter.emit(); + }) + ); + } + + public useChromeKioskModeKey(): boolean { + const c = workspace.getConfiguration(); + const b = c.get(useChromeKioskModeKey); + if (b === undefined) { + return true; + } + return b; + } +} diff --git a/extension/src/ConnectionHandler.ts b/extension/src/ConnectionHandler.ts index 143fd24..03c8852 100644 --- a/extension/src/ConnectionHandler.ts +++ b/extension/src/ConnectionHandler.ts @@ -13,7 +13,12 @@ export class ConnectionHandler { @observable private watcher: EvaluationWatcher | undefined = undefined; - constructor(sources: Sources, stream: WebSocketStream, server: Server) { + constructor( + sources: Sources, + stream: WebSocketStream, + server: Server, + config: Config + ) { const { client, channel, @@ -43,10 +48,13 @@ export class ConnectionHandler { ); }, openInBrowser: async ({}) => { - try { - //await launchChrome(server.indexUrl); + let opened = false; + if (config.useChromeKioskModeKey()) { + opened = await launchChrome(server.indexUrl); + } + if (!opened) { open(server.indexUrl); - } catch (e) {} + } }, setPreferredDataExtractor: async ({ dataExtractorId }) => { if (this.watcher) { @@ -84,11 +92,17 @@ export class ConnectionHandler { } import chromeLauncher = require("chrome-launcher"); +import { Config } from "./Config"; -async function launchChrome(url: string): Promise { - const chrome = await chromeLauncher.launch({ - startingUrl: url, - // `--window-size=${width},${height}` - chromeFlags: ["--app=" + url], - }); +async function launchChrome(url: string): Promise { + try { + const chrome = await chromeLauncher.launch({ + startingUrl: url, + // `--window-size=${width},${height}` + chromeFlags: ["--app=" + url], + }); + return true; + } catch (e) { + return false; + } } diff --git a/extension/src/Server.ts b/extension/src/Server.ts index f877b39..1e3ffcc 100644 --- a/extension/src/Server.ts +++ b/extension/src/Server.ts @@ -7,11 +7,12 @@ import { Sources } from "./extension"; import * as express from "express"; import * as http from "http"; import * as serveStatic from "serve-static"; +import { Config } from "./Config"; export class Server { private server: http.Server; - constructor(sources: Sources) { + constructor(sources: Sources, config: Config) { const app = express(); app.use(serveStatic(join(__dirname, "../ui/dist"))); @@ -20,7 +21,7 @@ export class Server { const wss = new WebSocket.Server({ server: this.server }); wss.on("connection", ws => { const stream = new WebSocketStream(ws); - new ConnectionHandler(sources, stream, this); + new ConnectionHandler(sources, stream, this, config); }); console.log(this.port); } diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 87a9ac3..18777c5 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -1,4 +1,4 @@ -import { window, ExtensionContext, WebviewPanel } from "vscode"; +import { window, ExtensionContext, WebviewPanel, commands } from "vscode"; import { enableHotReload, hotRequireExportedFn, @@ -16,6 +16,7 @@ import { createJsDebuggerSource } from "./DataSource/JsDebuggerSource"; import { WebViews } from "./WebViews"; import { Server } from "./Server"; +import { Config } from "./Config"; registerUpdateReconciler(module); @@ -26,8 +27,9 @@ export class Sources { export class Extension { public dispose = Disposable.fn(); + private readonly config = new Config(); private readonly sources = new Sources(); - private readonly server = new Server(this.sources); + private readonly server = new Server(this.sources, this.config); private readonly views = this.dispose.track(new WebViews(this.server)); constructor() { @@ -36,7 +38,13 @@ export class Extension { i.text = "reload" + getReloadCount(module); i.show(); } - this.views.createNew(); + + commands.registerCommand( + "vscode-debug-visualizer.new-visualizer", + () => { + this.views.createNew(); + } + ); } } diff --git a/node-debug2-1.33.0.vsix b/node-debug2-1.33.0.vsix deleted file mode 100644 index 62ed112..0000000 Binary files a/node-debug2-1.33.0.vsix and /dev/null differ