Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80c5d34c81 | ||
|
|
787fc73b33 | ||
|
|
33b076cbd3 | ||
|
|
d73b3797cb | ||
|
|
04ea412322 | ||
|
|
b65ba5fdbe | ||
|
|
410e5d3048 | ||
|
|
e9803a0e98 | ||
|
|
0a65f6425e | ||
|
|
c9625d4939 | ||
|
|
59f94eda45 | ||
|
|
507e4fc695 | ||
|
|
52599482f3 | ||
|
|
415f061697 |
18
demos/nim/.vscode/launch.json
vendored
Normal file
18
demos/nim/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Run your Executable",
|
||||
"program": "${workspaceFolder}/main",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"initCommands": [
|
||||
// To let LLDB know that NCSTRING is just like a C string
|
||||
"type format add --format c-string NCSTRING"
|
||||
],
|
||||
"preLaunchTask": "build"
|
||||
}
|
||||
]
|
||||
}
|
||||
10
demos/nim/.vscode/tasks.json
vendored
Normal file
10
demos/nim/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"type": "shell",
|
||||
"command": "nim c main.nim"
|
||||
}
|
||||
]
|
||||
}
|
||||
21
demos/nim/LICENSE
Executable file
21
demos/nim/LICENSE
Executable file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Danil Yarantsev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
82
demos/nim/main.nim
Normal file
82
demos/nim/main.nim
Normal file
@@ -0,0 +1,82 @@
|
||||
import random, json, options, sugar
|
||||
|
||||
type
|
||||
Kind = object
|
||||
array: bool
|
||||
|
||||
Label = object
|
||||
label: Option[string]
|
||||
|
||||
Column = object
|
||||
content: Option[string]
|
||||
tag: Option[string]
|
||||
color: Option[string]
|
||||
|
||||
Row = object
|
||||
label: Option[string]
|
||||
columns: seq[Column]
|
||||
|
||||
Marker = object
|
||||
id: string
|
||||
row: int
|
||||
column: int
|
||||
rows: Option[int]
|
||||
columns: Option[int]
|
||||
label: Option[string]
|
||||
color: Option[string]
|
||||
|
||||
Grid = object
|
||||
kind: Kind
|
||||
columnLabels: Option[seq[Label]]
|
||||
rows: seq[Row]
|
||||
markers: Option[seq[Marker]]
|
||||
|
||||
proc showSeq[T](data: seq[T], markers: seq[(string, int)] = @[]): cstring =
|
||||
# Need to use cstring string type for C-compatible strings
|
||||
let labels = collect(newSeq):
|
||||
# Labels are indexes of the seq
|
||||
for x in 0 ..< data.len():
|
||||
Label(label: some($x))
|
||||
|
||||
let columns = collect(newSeq):
|
||||
# Columns contain values of the seq
|
||||
for x in data:
|
||||
Column(content: some($x), tag: some($x))
|
||||
|
||||
let marks = collect(newSeq):
|
||||
# If there are any markers (id - string, index - int)
|
||||
for marker in markers:
|
||||
Marker(id: marker[0], row: 0, column: marker[1])
|
||||
|
||||
let grid = Grid(
|
||||
kind: Kind(array: true),
|
||||
rows: @[Row(columns: columns)],
|
||||
columnLabels: some(labels),
|
||||
markers: some(marks)
|
||||
)
|
||||
# Serialize to JSON
|
||||
result = $ %grid
|
||||
|
||||
proc main =
|
||||
# Random seed
|
||||
randomize()
|
||||
|
||||
# Fill seq with 10 random values from 1 to 999
|
||||
var a = newSeq[int]()
|
||||
for x in 0..10:
|
||||
a.add rand(1..999)
|
||||
|
||||
# Simple bubble sort with some markers
|
||||
# Open the visualizer and type in "ress"
|
||||
let n = a.len() - 1
|
||||
var ress = showSeq(a, @[("i", 0), ("j", 0)])
|
||||
for i in 0 .. n:
|
||||
for j in 0 .. n - i - 1:
|
||||
if a[j] > a[j+1]:
|
||||
ress = showSeq(a, @[("i", i), ("j", j)]) # breakpoint
|
||||
let temp = a[j]
|
||||
a[j] = a[j + 1]
|
||||
a[j + 1] = temp
|
||||
ress = showSeq(a, @[("i", i), ("j", j)]) # breakpoint
|
||||
|
||||
main()
|
||||
2
demos/nim/nim.cfg
Normal file
2
demos/nim/nim.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
# For Nim source code lines
|
||||
debugger:native
|
||||
@@ -1,5 +1,15 @@
|
||||
# Change Log
|
||||
|
||||
## 1.1.0
|
||||
|
||||
- Fixes a bug that occurs when the debug visualizer is opened after the debug session has started.
|
||||
- Fixes a bug that is caused by VS Code invoking the debug tracker multiple times for the same session.
|
||||
- Adds support for the new `pwa-chrome` debug adapter.
|
||||
- Uses `repl` mode as default evaluation context so that responses don't get truncated.
|
||||
- Improves error messages when evaluating an expression or parsing the result goes wrong.
|
||||
- Sets `webview.retainContextWhenHidden` to true, so that visualizer views load faster when they were already opened.
|
||||
- Configures `webview.portMapping` so that this extension should work with remote development.
|
||||
|
||||
## 1.0.0
|
||||
|
||||
- "Debug Visualizer: Use Selection as Expression" will open a new view if no Debug Visualizer view was opened.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
[](https://twitter.com/intent/follow?screen_name=hediet_dev)
|
||||
|
||||
A VS Code extension for visualizing data structures while debugging.
|
||||
Like the VS Code's watch view, but with custom visualizations.
|
||||
|
||||

|
||||
|
||||
@@ -28,8 +29,9 @@ Fully supported languages offer _Data Extractors_ which convert some well known
|
||||
|
||||
After installing this extension, use the command `Debug Visualizer: New View` to open a new visualizer view.
|
||||
In this view you can enter an expression that is evaluated and visualized while stepping through your application.
|
||||
This view works the same as the watch view of VS Code, except that the resulting value is presented visually rather than textually.
|
||||
|
||||
You can refresh the evaluation and pop out the current visualizer view into a new browser window by using the top right buttons.
|
||||
You can refresh the evaluation and open the current visualizer view into a new browser window by using the top right buttons.
|
||||
You can also unfold the details pane to select a _Data Extractor_ and a _Visualizer_.
|
||||
|
||||
Use the command `Debug Visualizer: Use Selection as Expression` (Shift + F1) to use the currently selected text as expression
|
||||
@@ -39,7 +41,7 @@ in the most recently opened debug visualizer.
|
||||
|
||||
Visualizers consume specific JSON data. See [Integrated Visualizers](#Integrated%20Visualizers) for the schema of supported JSON data.
|
||||
|
||||
The currently visualized expression should evaluate to a JSON Object string,
|
||||
The currently watched expression should evaluate to a JSON Object string,
|
||||
matching the schema of one of the supported visualizers. This JSON string may be surrounded by single or double quotation marks (or none at all) and must not be escaped.
|
||||
A valid example is `"{ "kind": { "text": true }, "text": "some text\nmore text" }"`.
|
||||
|
||||
@@ -217,7 +219,7 @@ interface DotGraph extends Text {
|
||||
## JavaScript/TypeScript Integrated Data Extractors
|
||||
|
||||
Data extractors convert arbitrary values into data consumable by visualizers.
|
||||
They live in the debugee. The following data extractors are injected automatically into the debugee by this extension when using the `node`, `node2`, `extensionHost` or `chrome` debug adapter.
|
||||
They live in the debugee. The following data extractors are injected automatically into the debugee by this extension when using the `node`, `node2`, `extensionHost`, `chrome` or `pwa-chrome` debug adapter.
|
||||
Custom data extractors can be registered too.
|
||||
See the package `@hediet/debug-visualizer-data-extraction` and its [README](../data-extraction/README.md) for the implementation and its API.
|
||||
Also, a global object of name `hedietDbgVis` with helper functions is injected.
|
||||
|
||||
@@ -4,12 +4,24 @@
|
||||
"displayName": "Debug Visualizer",
|
||||
"description": "An extension that visualizes values while debugging.",
|
||||
"icon": "docs/logo.png",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"license": "GPL-3.0",
|
||||
"engines": {
|
||||
"vscode": "^1.35.0"
|
||||
},
|
||||
"publisher": "hediet",
|
||||
"keywords": [
|
||||
"debugger",
|
||||
"debugging",
|
||||
"debug",
|
||||
"visual",
|
||||
"javascript",
|
||||
"graph",
|
||||
"ast"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/hediet/vscode-debug-visualizer/issues"
|
||||
},
|
||||
"author": {
|
||||
"email": "henning.dieterichs@live.de",
|
||||
"name": "Henning Dieterichs"
|
||||
|
||||
@@ -51,6 +51,7 @@ export class GenericEvaluator implements Evaluator {
|
||||
message: {
|
||||
kind: "list",
|
||||
items: [
|
||||
"An error occurred while evaluating the expression:",
|
||||
error.message,
|
||||
`Used debug adapter: ${this.session.session.configuration.type}`,
|
||||
{
|
||||
@@ -65,7 +66,9 @@ export class GenericEvaluator implements Evaluator {
|
||||
};
|
||||
}
|
||||
|
||||
return parseEvaluationResultFromGenericDebugAdapter(reply.result);
|
||||
return parseEvaluationResultFromGenericDebugAdapter(reply.result, {
|
||||
debugAdapterType: this.session.session.configuration.type,
|
||||
});
|
||||
}
|
||||
|
||||
protected getFinalExpression(args: {
|
||||
@@ -76,6 +79,7 @@ export class GenericEvaluator implements Evaluator {
|
||||
}
|
||||
|
||||
protected getContext(): "watch" | "repl" {
|
||||
return "watch";
|
||||
// we will use "repl" as default so that results are not truncated.
|
||||
return "repl";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ export class JsEvaluationEngine implements EvaluationEngine {
|
||||
"node2",
|
||||
"extensionHost",
|
||||
"chrome",
|
||||
"pwa-chrome",
|
||||
];
|
||||
if (supportedDebugAdapters.indexOf(session.session.type) !== -1) {
|
||||
return new JsEvaluator(session);
|
||||
@@ -74,6 +75,7 @@ class JsEvaluator implements Evaluator {
|
||||
const reply = await this.session.evaluate({
|
||||
expression: wrappedExpr,
|
||||
frameId,
|
||||
context: "repl",
|
||||
});
|
||||
const resultStr = reply.result;
|
||||
const jsonData = resultStr.substr(1, resultStr.length - 2);
|
||||
@@ -115,6 +117,7 @@ class JsEvaluator implements Evaluator {
|
||||
await this.session.evaluate({
|
||||
expression,
|
||||
frameId,
|
||||
context: "repl",
|
||||
});
|
||||
|
||||
return true;
|
||||
|
||||
@@ -4,8 +4,13 @@ import {
|
||||
} from "@hediet/debug-visualizer-data-extraction";
|
||||
import { FormattedMessage } from "../../contract";
|
||||
|
||||
export interface ParseEvaluationResultContext {
|
||||
debugAdapterType: string;
|
||||
}
|
||||
|
||||
export function parseEvaluationResultFromGenericDebugAdapter(
|
||||
resultText: string
|
||||
resultText: string,
|
||||
context: ParseEvaluationResultContext
|
||||
):
|
||||
| { kind: "data"; result: DataExtractionResult }
|
||||
| { kind: "error"; message: FormattedMessage } {
|
||||
@@ -26,12 +31,12 @@ export function parseEvaluationResultFromGenericDebugAdapter(
|
||||
// Just in case no quoting is done.
|
||||
jsonData2 = jsonData;
|
||||
}
|
||||
resultObj = parseJson(jsonData2);
|
||||
resultObj = parseJson(jsonData2, context);
|
||||
} catch (e) {
|
||||
// in case of C++: `"{ \"kind\": { ... }, \"text\": \"some\\ntext\" }"`
|
||||
const str = parseJson(jsonData);
|
||||
const str = parseJson(jsonData, context);
|
||||
// str is now `{ "kind": { ... }, "text": "some\ntext" }"`
|
||||
resultObj = parseJson(str);
|
||||
resultObj = parseJson(str, context);
|
||||
// result is now { kind: { ... }, text: "some\ntext" }
|
||||
}
|
||||
|
||||
@@ -85,7 +90,7 @@ function isEnclosedWith(str: string, char: string): boolean {
|
||||
return str.startsWith(char) && str.endsWith(char);
|
||||
}
|
||||
|
||||
function parseJson(str: string) {
|
||||
function parseJson(str: string, context: ParseEvaluationResultContext) {
|
||||
try {
|
||||
return JSON.parse(str);
|
||||
} catch (error) {
|
||||
@@ -104,6 +109,7 @@ function parseJson(str: string) {
|
||||
},
|
||||
],
|
||||
},
|
||||
`Used debug adapter: ${context.debugAdapterType}`,
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { distPath } from "debug-visualizer-webview";
|
||||
import { EvaluationWatchService } from "./EvaluationWatchService/EvaluationWatchService";
|
||||
|
||||
export class Server {
|
||||
private server: http.Server;
|
||||
private readonly server: http.Server;
|
||||
public readonly secret = cryptoRandomString({ length: 20 });
|
||||
|
||||
public readonly connections = new Set<ClientConnection>();
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Disposable } from "@hediet/std/disposable";
|
||||
import { debug, DebugSession } from "vscode";
|
||||
import { EventEmitter } from "@hediet/std/events";
|
||||
import { CompletionItem } from "./contract";
|
||||
import { observable, runInAction } from "mobx";
|
||||
import { observable, runInAction, action } from "mobx";
|
||||
|
||||
export class VsCodeDebugger {
|
||||
public readonly dispose = Disposable.fn();
|
||||
@@ -14,7 +14,12 @@ export class VsCodeDebugger {
|
||||
public readonly onDidStartDebugSession = this._onDidStartDebugSession.asEvent();
|
||||
|
||||
public getDebugSession(session: DebugSession): VsCodeDebugSession {
|
||||
return this.sessions.get(session)!;
|
||||
let result = this.sessions.get(session);
|
||||
if (!result) {
|
||||
result = new VsCodeDebugSession(session);
|
||||
this.sessions.set(session, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
@@ -24,15 +29,11 @@ export class VsCodeDebugger {
|
||||
this._onDidStartDebugSession.emit({ session: e });
|
||||
}),
|
||||
debug.onDidTerminateDebugSession(session => {
|
||||
const e = this.sessions.get(session)!;
|
||||
// TODO add proper event
|
||||
this.sessions.delete(session);
|
||||
}),
|
||||
debug.registerDebugAdapterTrackerFactory("*", {
|
||||
createDebugAdapterTracker: session => {
|
||||
const extendedSession = new VsCodeDebugSession(session);
|
||||
this.sessions.set(session, extendedSession);
|
||||
|
||||
const extendedSession = this.getDebugSession(session);
|
||||
return {
|
||||
onWillReceiveMessage: msg => {
|
||||
console.log(msg.type, msg.event, msg);
|
||||
@@ -159,15 +160,20 @@ export class VsCodeDebugSession {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the given expression.
|
||||
* If context is "watch", long results are usually shortened.
|
||||
*/
|
||||
public async evaluate(args: {
|
||||
expression: string;
|
||||
frameId: number | undefined;
|
||||
context?: "watch" | "repl";
|
||||
context: "watch" | "repl";
|
||||
}): Promise<{ result: string }> {
|
||||
const reply = await this.session.customRequest("evaluate", {
|
||||
expression: args.expression,
|
||||
frameId: args.frameId,
|
||||
context: args.context || "watch",
|
||||
|
||||
context: args.context,
|
||||
});
|
||||
return { result: reply.result };
|
||||
}
|
||||
@@ -193,17 +199,19 @@ export class VsCodeDebuggerView {
|
||||
constructor(private vsCodeDebugger: VsCodeDebugger) {
|
||||
this.dispose.track(
|
||||
debug.onDidChangeActiveDebugSession(activeSession => {
|
||||
runInAction("Update active debug session", () => {
|
||||
if (!activeSession) {
|
||||
this._activeDebugSession = undefined;
|
||||
} else {
|
||||
const s = this.vsCodeDebugger.getDebugSession(
|
||||
activeSession
|
||||
);
|
||||
this._activeDebugSession = s;
|
||||
}
|
||||
});
|
||||
this.updateActiveDebugSession(activeSession);
|
||||
})
|
||||
);
|
||||
this.updateActiveDebugSession(debug.activeDebugSession);
|
||||
}
|
||||
|
||||
@action
|
||||
private updateActiveDebugSession(activeSession: DebugSession | undefined) {
|
||||
if (!activeSession) {
|
||||
this._activeDebugSession = undefined;
|
||||
} else {
|
||||
const s = this.vsCodeDebugger.getDebugSession(activeSession);
|
||||
this._activeDebugSession = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,16 @@ export class WebViews {
|
||||
debugVisualizer,
|
||||
"Debug Visualizer",
|
||||
ViewColumn.Two,
|
||||
{ enableScripts: true }
|
||||
{
|
||||
enableScripts: true,
|
||||
retainContextWhenHidden: true,
|
||||
portMapping: [
|
||||
{
|
||||
webviewPort: this.server.port,
|
||||
extensionHostPort: this.server.port,
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
this.setupView(panel, expression);
|
||||
|
||||
@@ -13,5 +13,8 @@
|
||||
"build-extension": "yarn workspace debug-visualizer build",
|
||||
"build-visualization": "yarn workspace @hediet/visualization build",
|
||||
"build-ui": "yarn workspace debug-visualizer-webview build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^1.19.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7690,6 +7690,11 @@ prepend-http@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
||||
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
|
||||
|
||||
prettier@^1.19.1:
|
||||
version "1.19.1"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
|
||||
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
|
||||
|
||||
pretty-error@^2.0.2:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3"
|
||||
|
||||
Reference in New Issue
Block a user