diff --git a/package.json b/package.json index c74ff8b1..fde1185e 100644 --- a/package.json +++ b/package.json @@ -101,6 +101,16 @@ "description": "Additional arguments to pass to GDB", "default": [] }, + "valuesFormatting": { + "type": "string", + "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any", + "default": "parseText", + "enum": [ + "disabled", + "parseText", + "prettyPrinters" + ] + }, "printCalls": { "type": "boolean", "description": "Prints all GDB calls to the console", @@ -192,6 +202,16 @@ "description": "If true this will connect to a gdbserver instead of attaching to a PID", "default": false }, + "valuesFormatting": { + "type": "string", + "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any", + "default": "parseText", + "enum": [ + "disabled", + "parseText", + "prettyPrinters" + ] + }, "printCalls": { "type": "boolean", "description": "Prints all GDB calls to the console", @@ -466,6 +486,16 @@ "description": "Additional arguments to pass to LLDB", "default": [] }, + "valuesFormatting": { + "type": "string", + "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any", + "default": "parseText", + "enum": [ + "disabled", + "parseText", + "prettyPrinters" + ] + }, "printCalls": { "type": "boolean", "description": "Prints all lldb calls to the console", @@ -552,6 +582,16 @@ "type": "string", "description": "PID of running program or program name" }, + "valuesFormatting": { + "type": "string", + "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any", + "default": "parseText", + "enum": [ + "disabled", + "parseText", + "prettyPrinters" + ] + }, "printCalls": { "type": "boolean", "description": "Prints all LLDB calls to the console", @@ -713,6 +753,16 @@ "description": "Additional arguments to pass to mago", "default": [] }, + "valuesFormatting": { + "type": "string", + "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any", + "default": "parseText", + "enum": [ + "disabled", + "parseText", + "prettyPrinters" + ] + }, "printCalls": { "type": "boolean", "description": "Prints all mago calls to the console", @@ -739,6 +789,16 @@ "type": "string", "description": "PID of running program or program name" }, + "valuesFormatting": { + "type": "string", + "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any", + "default": "parseText", + "enum": [ + "disabled", + "parseText", + "prettyPrinters" + ] + }, "printCalls": { "type": "boolean", "description": "Prints all mago calls to the console", @@ -834,4 +894,4 @@ "@types/node": "^7.0.5", "@types/mocha": "^2.2.39" } -} \ No newline at end of file +} diff --git a/src/backend/backend.ts b/src/backend/backend.ts index d2738a70..d85cd267 100644 --- a/src/backend/backend.ts +++ b/src/backend/backend.ts @@ -1,3 +1,8 @@ +import { MINode } from "./mi_parse"; +import { DebugProtocol } from "vscode-debugprotocol/lib/debugProtocol"; + +export type ValuesFormattingMode = "disabled" | "parseText" | "prettyPrinters"; + export interface Breakpoint { file?: string; line?: number; @@ -59,4 +64,62 @@ export interface IBackend { isReady(): boolean; changeVariable(name: string, rawValue: string): Thenable; examineMemory(from: number, to: number): Thenable; -} \ No newline at end of file +} + +export class VariableObject { + name: string; + exp: string; + numchild: number; + type: string; + value: string; + threadId: string; + frozen: boolean; + dynamic: boolean; + displayhint: string; + has_more: boolean; + id: number; + constructor(node: any) { + this.name = MINode.valueOf(node, "name"); + this.exp = MINode.valueOf(node, "exp"); + this.numchild = parseInt(MINode.valueOf(node, "numchild")); + this.type = MINode.valueOf(node, "type"); + this.value = MINode.valueOf(node, "value"); + this.threadId = MINode.valueOf(node, "thread-id"); + this.frozen = !!MINode.valueOf(node, "frozen"); + this.dynamic = !!MINode.valueOf(node, "dynamic"); + this.displayhint = MINode.valueOf(node, "displayhint"); + // TODO: use has_more when it's > 0 + this.has_more = !!MINode.valueOf(node, "has_more"); + } + + public applyChanges(node: MINode) { + this.value = MINode.valueOf(node, "value"); + if (!!MINode.valueOf(node, "type_changed")) { + this.type = MINode.valueOf(node, "new_type"); + } + this.dynamic = !!MINode.valueOf(node, "dynamic"); + this.displayhint = MINode.valueOf(node, "displayhint"); + this.has_more = !!MINode.valueOf(node, "has_more"); + } + + public isCompound(): boolean { + return this.numchild > 0 || + this.value === "{...}" || + (this.dynamic && (this.displayhint === "array" || this.displayhint === "map")); + } + + public toProtocolVariable(): DebugProtocol.Variable { + let res: DebugProtocol.Variable = { + name: this.exp, + evaluateName: this.name, + value: (this.value === void 0) ? "" : this.value, + type: this.type, + // kind: this.displayhint, + variablesReference: this.id + }; + if (this.displayhint) { + res.kind = this.displayhint; + } + return res; + } +} diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts index 84e562af..9a895940 100644 --- a/src/backend/mi2/mi2.ts +++ b/src/backend/mi2/mi2.ts @@ -1,4 +1,4 @@ -import { Breakpoint, IBackend, Stack, SSHArguments, Variable } from "../backend" +import { Breakpoint, IBackend, Stack, SSHArguments, Variable, VariableObject } from "../backend" import * as ChildProcess from "child_process" import { EventEmitter } from "events" import { parseMI, MINode } from '../mi_parse'; @@ -196,6 +196,9 @@ export class MI2 extends EventEmitter implements IBackend { ]; if (!attach) cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\"")); + if (this.prettyPrint) + cmds.push(this.sendCommand("enable-pretty-printing")); + return cmds; } @@ -617,27 +620,25 @@ export class MI2 extends EventEmitter implements IBackend { }); } - getStackVariables(thread: number, frame: number): Thenable { + async getStackVariables(thread: number, frame: number): Promise { if (trace) this.log("stderr", "getStackVariables"); - return new Promise((resolve, reject) => { - this.sendCommand("stack-list-variables --thread " + thread + " --frame " + frame + " --simple-values").then((result) => { - let variables = result.result("variables"); - let ret: Variable[] = []; - variables.forEach(element => { - const key = MINode.valueOf(element, "name"); - const value = MINode.valueOf(element, "value"); - const type = MINode.valueOf(element, "type"); - ret.push({ - name: key, - valueStr: value, - type: type, - raw: element - }); - }); - resolve(ret); - }, reject); - }); + + const result = await this.sendCommand(`stack-list-variables --thread ${thread} --frame ${frame} --simple-values`); + const variables = result.result("variables"); + let ret: Variable[] = []; + for (const element of variables) { + const key = MINode.valueOf(element, "name"); + const value = MINode.valueOf(element, "value"); + const type = MINode.valueOf(element, "type"); + ret.push({ + name: key, + valueStr: value, + type: type, + raw: element + }); + } + return ret; } examineMemory(from: number, length: number): Thenable { @@ -660,6 +661,41 @@ export class MI2 extends EventEmitter implements IBackend { }); } + async varCreate(expression: string, name: string = "-"): Promise { + if (trace) + this.log("stderr", "varCreate"); + const res = await this.sendCommand(`var-create ${name} @ "${expression}"`); + return new VariableObject(res.result("")); + } + + async varEvalExpression(name: string): Promise { + if (trace) + this.log("stderr", "varEvalExpression"); + return this.sendCommand(`var-evaluate-expression ${name}`); + } + + async varListChildren(name: string): Promise { + if (trace) + this.log("stderr", "varListChildren"); + //TODO: add `from` and `to` arguments + const res = await this.sendCommand(`var-list-children --all-values ${name}`); + const children = res.result("children"); + let omg: VariableObject[] = children.map(child => new VariableObject(child[1])); + return omg; + } + + async varUpdate(name: string = "*"): Promise { + if (trace) + this.log("stderr", "varUpdate"); + return this.sendCommand(`var-update --all-values ${name}`) + } + + async varAssign(name: string, rawValue: string): Promise { + if (trace) + this.log("stderr", "varAssign"); + return this.sendCommand(`var-assign ${name} ${rawValue}`); + } + logNoNewLine(type: string, msg: string) { this.emit("msg", type, msg); } @@ -710,6 +746,7 @@ export class MI2 extends EventEmitter implements IBackend { return this.isSSH ? this.sshReady : !!this.process; } + prettyPrint: boolean = true; printCalls: boolean; debugOutput: boolean; public procEnv: any; diff --git a/src/gdb.ts b/src/gdb.ts index 2bc2812f..d4d06822 100644 --- a/src/gdb.ts +++ b/src/gdb.ts @@ -2,7 +2,7 @@ import { MI2DebugSession } from './mibase'; import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter'; import { DebugProtocol } from 'vscode-debugprotocol'; import { MI2 } from "./backend/mi2/mi2"; -import { SSHArguments } from './backend/backend'; +import { SSHArguments, ValuesFormattingMode } from './backend/backend'; export interface LaunchRequestArguments { cwd: string; @@ -14,6 +14,7 @@ export interface LaunchRequestArguments { terminal: string; autorun: string[]; ssh: SSHArguments; + valuesFormatting: ValuesFormattingMode; printCalls: boolean; showDevDebugOutput: boolean; } @@ -28,6 +29,7 @@ export interface AttachRequestArguments { remote: boolean; autorun: string[]; ssh: SSHArguments; + valuesFormatting: ValuesFormattingMode; printCalls: boolean; showDevDebugOutput: boolean; } @@ -54,6 +56,7 @@ class GDBDebugSession extends MI2DebugSession { this.started = false; this.crashed = false; this.debugReady = false; + this.setValuesFormattingMode(args.valuesFormatting); this.miDebugger.printCalls = !!args.printCalls; this.miDebugger.debugOutput = !!args.showDevDebugOutput; if (args.ssh !== undefined) { @@ -121,6 +124,7 @@ class GDBDebugSession extends MI2DebugSession { this.needContinue = true; this.isSSH = false; this.debugReady = false; + this.setValuesFormattingMode(args.valuesFormatting); this.miDebugger.printCalls = !!args.printCalls; this.miDebugger.debugOutput = !!args.showDevDebugOutput; if (args.ssh !== undefined) { @@ -177,4 +181,4 @@ class GDBDebugSession extends MI2DebugSession { } } -DebugSession.run(GDBDebugSession); \ No newline at end of file +DebugSession.run(GDBDebugSession); diff --git a/src/lldb.ts b/src/lldb.ts index f634c0fd..28a92e80 100644 --- a/src/lldb.ts +++ b/src/lldb.ts @@ -2,7 +2,7 @@ import { MI2DebugSession } from './mibase'; import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter'; import { DebugProtocol } from 'vscode-debugprotocol'; import { MI2_LLDB } from "./backend/mi2/mi2lldb"; -import { SSHArguments } from './backend/backend'; +import { SSHArguments, ValuesFormattingMode } from './backend/backend'; export interface LaunchRequestArguments { cwd: string; @@ -13,6 +13,7 @@ export interface LaunchRequestArguments { arguments: string; autorun: string[]; ssh: SSHArguments; + valuesFormatting: ValuesFormattingMode; printCalls: boolean; showDevDebugOutput: boolean; } @@ -25,6 +26,7 @@ export interface AttachRequestArguments { debugger_args: string[]; executable: string; autorun: string[]; + valuesFormatting: ValuesFormattingMode; printCalls: boolean; showDevDebugOutput: boolean; } @@ -49,6 +51,7 @@ class LLDBDebugSession extends MI2DebugSession { this.started = false; this.crashed = false; this.debugReady = false; + this.setValuesFormattingMode(args.valuesFormatting); this.miDebugger.printCalls = !!args.printCalls; this.miDebugger.debugOutput = !!args.showDevDebugOutput; if (args.ssh !== undefined) { @@ -108,6 +111,7 @@ class LLDBDebugSession extends MI2DebugSession { this.needContinue = true; this.isSSH = false; this.debugReady = false; + this.setValuesFormattingMode(args.valuesFormatting); this.miDebugger.printCalls = !!args.printCalls; this.miDebugger.debugOutput = !!args.showDevDebugOutput; this.miDebugger.attach(args.cwd, args.executable, args.target).then(() => { @@ -120,4 +124,4 @@ class LLDBDebugSession extends MI2DebugSession { } } -DebugSession.run(LLDBDebugSession); \ No newline at end of file +DebugSession.run(LLDBDebugSession); diff --git a/src/mago.ts b/src/mago.ts index bd6d1660..e06c3e1c 100644 --- a/src/mago.ts +++ b/src/mago.ts @@ -2,7 +2,7 @@ import { MI2DebugSession } from './mibase'; import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter'; import { DebugProtocol } from 'vscode-debugprotocol'; import { MI2_Mago } from "./backend/mi2/mi2mago"; -import { SSHArguments } from './backend/backend'; +import { SSHArguments, ValuesFormattingMode } from './backend/backend'; export interface LaunchRequestArguments { cwd: string; @@ -12,6 +12,7 @@ export interface LaunchRequestArguments { debugger_args: string[]; arguments: string; autorun: string[]; + valuesFormatting: ValuesFormattingMode; printCalls: boolean; showDevDebugOutput: boolean; } @@ -24,6 +25,7 @@ export interface AttachRequestArguments { debugger_args: string[]; executable: string; autorun: string[]; + valuesFormatting: ValuesFormattingMode; printCalls: boolean; showDevDebugOutput: boolean; } @@ -56,6 +58,7 @@ class MagoDebugSession extends MI2DebugSession { this.started = false; this.crashed = false; this.debugReady = false; + this.setValuesFormattingMode(args.valuesFormatting); this.miDebugger.printCalls = !!args.printCalls; this.miDebugger.debugOutput = !!args.showDevDebugOutput; this.miDebugger.load(args.cwd, args.target, args.arguments, undefined).then(() => { @@ -83,6 +86,7 @@ class MagoDebugSession extends MI2DebugSession { this.needContinue = true; this.isSSH = false; this.debugReady = false; + this.setValuesFormattingMode(args.valuesFormatting); this.miDebugger.printCalls = !!args.printCalls; this.miDebugger.debugOutput = !!args.showDevDebugOutput; this.miDebugger.attach(args.cwd, args.executable, args.target).then(() => { @@ -95,4 +99,4 @@ class MagoDebugSession extends MI2DebugSession { } } -DebugSession.run(MagoDebugSession); \ No newline at end of file +DebugSession.run(MagoDebugSession); diff --git a/src/mibase.ts b/src/mibase.ts index 03819ea4..aaeef587 100644 --- a/src/mibase.ts +++ b/src/mibase.ts @@ -1,6 +1,6 @@ import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter'; import { DebugProtocol } from 'vscode-debugprotocol'; -import { Breakpoint, IBackend } from './backend/backend'; +import { Breakpoint, IBackend, Variable, VariableObject, ValuesFormattingMode } from './backend/backend'; import { MINode } from './backend/mi_parse'; import { expandValue, isExpandable } from './backend/gdb_expansion'; import { MI2 } from './backend/mi2/mi2'; @@ -18,8 +18,13 @@ class ExtendedVariable { } } +const STACK_HANDLES_START = 1000; +const VAR_HANDLES_START = 2000; + export class MI2DebugSession extends DebugSession { - protected variableHandles = new Handles(); + protected variableHandles = new Handles(VAR_HANDLES_START); + protected variableHandlesReverse: { [id: string]: number } = {}; + protected useVarObjects: boolean; protected quit: boolean; protected attached: boolean; protected needContinue: boolean; @@ -78,6 +83,23 @@ export class MI2DebugSession extends DebugSession { } } + protected setValuesFormattingMode(mode: ValuesFormattingMode) { + switch (mode) { + case "disabled": + this.useVarObjects = true; + this.miDebugger.prettyPrint = false; + break; + case "prettyPrinters": + this.useVarObjects = true; + this.miDebugger.prettyPrint = true; + break; + case "parseText": + default: + this.useVarObjects = false; + this.miDebugger.prettyPrint = false; + } + } + protected handleMsg(type: string, msg: string) { if (type == "target") type = "stdout"; @@ -126,15 +148,31 @@ export class MI2DebugSession extends DebugSession { this.sendResponse(response); } - protected setVariableRequest(response: DebugProtocol.SetVariableResponse, args: DebugProtocol.SetVariableArguments): void { - this.miDebugger.changeVariable(args.name, args.value).then(() => { - response.body = { - value: args.value - }; + protected async setVariableRequest(response: DebugProtocol.SetVariableResponse, args: DebugProtocol.SetVariableArguments): Promise { + try { + if (this.useVarObjects) { + let name = args.name; + if (args.variablesReference >= VAR_HANDLES_START) { + const parent = this.variableHandles.get(args.variablesReference) as VariableObject; + name = `${parent.name}.${name}`; + } + + let res = await this.miDebugger.varAssign(name, args.value); + response.body = { + value: res.result("value") + }; + } + else { + await this.miDebugger.changeVariable(args.name, args.value); + response.body = { + value: args.value + }; + } this.sendResponse(response); - }, err => { + } + catch (err) { this.sendErrorResponse(response, 11, `Could not continue: ${err}`); - }); + }; } protected setFunctionBreakPointsRequest(response: DebugProtocol.SetFunctionBreakpointsResponse, args: DebugProtocol.SetFunctionBreakpointsArguments): void { @@ -253,7 +291,7 @@ export class MI2DebugSession extends DebugSession { protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void { const scopes = new Array(); - scopes.push(new Scope("Local", this.variableHandles.create("@frame:" + (args.frameId || 0)), false)); + scopes.push(new Scope("Local", STACK_HANDLES_START + (parseInt(args.frameId as any) || 0), false)); response.body = { scopes: scopes @@ -261,9 +299,15 @@ export class MI2DebugSession extends DebugSession { this.sendResponse(response); } - protected variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): void { + protected async variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): Promise { const variables: DebugProtocol.Variable[] = []; - const id = this.variableHandles.get(args.variablesReference); + let id: number | string | VariableObject | ExtendedVariable; + if (args.variablesReference < VAR_HANDLES_START) { + id = args.variablesReference - STACK_HANDLES_START; + } + else { + id = this.variableHandles.get(args.variablesReference); + } let createVariable = (arg, options?) => { if (options) @@ -272,12 +316,57 @@ export class MI2DebugSession extends DebugSession { return this.variableHandles.create(arg); }; - if (typeof id == "string") { - if (id.startsWith("@frame:")) { - this.miDebugger.getStackVariables(this.threadID, parseInt(id.substr("@frame:".length))).then(stack => { - stack.forEach(variable => { + let findOrCreateVariable = (varObj: VariableObject): number => { + let id: number; + if (this.variableHandlesReverse.hasOwnProperty(varObj.name)) { + id = this.variableHandlesReverse[varObj.name]; + } + else { + id = createVariable(varObj); + this.variableHandlesReverse[varObj.name] = id; + } + return varObj.isCompound() ? id : 0; + }; + + if (typeof id == "number") { + let stack: Variable[]; + try { + stack = await this.miDebugger.getStackVariables(this.threadID, id); + for (const variable of stack) { + if (this.useVarObjects) { + try { + let varObj: VariableObject; + try { + const changes = await this.miDebugger.varUpdate(variable.name); + const changelist = changes.result("changelist"); + changelist.forEach((change) => { + const name = MINode.valueOf(change, "name"); + const vId = this.variableHandlesReverse[variable.name]; + const v = this.variableHandles.get(vId) as any; + v.applyChanges(change); + }); + const varId = this.variableHandlesReverse[variable.name]; + varObj = this.variableHandles.get(varId) as any; + } + catch (err) { + varObj = await this.miDebugger.varCreate(variable.name, variable.name); + const varId = findOrCreateVariable(varObj); + varObj.exp = variable.name; + varObj.id = varId; + } + variables.push(varObj.toProtocolVariable()); + } + catch (err) { + variables.push({ + name: variable.name, + value: `<${err}>`, + variablesReference: 0 + }); + } + } + else { if (variable.valueStr !== undefined) { - let expanded = expandValue(createVariable, "{" + variable.name + "=" + variable.valueStr + ")", "", variable.raw); + let expanded = expandValue(createVariable, `{${variable.name}=${variable.valueStr})`, "", variable.raw); if (expanded) { if (typeof expanded[0] == "string") expanded = [ @@ -296,49 +385,73 @@ export class MI2DebugSession extends DebugSession { value: "", variablesReference: createVariable(variable.name) }); - }); - response.body = { - variables: variables - }; - this.sendResponse(response); - }, err => { - this.sendErrorResponse(response, 1, "Could not expand variable: " + err); - }); + } + } + response.body = { + variables: variables + }; + this.sendResponse(response); } - else { - // Variable members - this.miDebugger.evalExpression(JSON.stringify(id)).then(variable => { - try { - let expanded = expandValue(createVariable, variable.result("value"), id, variable); - if (!expanded) { - this.sendErrorResponse(response, 2, `Could not expand variable`); - } - else { - if (typeof expanded[0] == "string") - expanded = [ - { - name: "", - value: prettyStringArray(expanded), - variablesReference: 0 - } - ]; - response.body = { - variables: expanded - }; - this.sendResponse(response); - } + catch (err) { + this.sendErrorResponse(response, 1, `Could not expand variable: ${err}`); + } + } + else if (typeof id == "string") { + // Variable members + let variable; + try { + variable = await this.miDebugger.evalExpression(JSON.stringify(id)); + try { + let expanded = expandValue(createVariable, variable.result("value"), id, variable); + if (!expanded) { + this.sendErrorResponse(response, 2, `Could not expand variable`); } - catch (e) { - this.sendErrorResponse(response, 2, `Could not expand variable: ` + e); + else { + if (typeof expanded[0] == "string") + expanded = [ + { + name: "", + value: prettyStringArray(expanded), + variablesReference: 0 + } + ]; + response.body = { + variables: expanded + }; + this.sendResponse(response); } - }, err => { - this.sendErrorResponse(response, 1, `Could not expand variable`); - }); + } + catch (e) { + this.sendErrorResponse(response, 2, `Could not expand variable: ${e}`); + } + } + catch (err) { + this.sendErrorResponse(response, 1, `Could not expand variable: ${err}`); } } else if (typeof id == "object") { - if (id instanceof ExtendedVariable) { - let varReq = id; + if (id instanceof VariableObject) { + // Variable members + let children: VariableObject[]; + try { + children = await this.miDebugger.varListChildren(id.name); + const vars = children.map(child => { + const varId = findOrCreateVariable(child); + child.id = varId; + return child.toProtocolVariable(); + }); + + response.body = { + variables: vars + } + this.sendResponse(response); + } + catch (err) { + this.sendErrorResponse(response, 1, `Could not expand variable: ${err}`); + } + } + else if (id instanceof ExtendedVariable) { + let varReq = id; if (varReq.options.arg) { let strArr = []; let argsPart = true; @@ -349,55 +462,54 @@ export class MI2DebugSession extends DebugSession { }; this.sendResponse(response); }; - let addOne = () => { - this.miDebugger.evalExpression(JSON.stringify(varReq.name + "+" + arrIndex + ")")).then(variable => { - try { - let expanded = expandValue(createVariable, variable.result("value"), varReq.name, variable); - if (!expanded) { - this.sendErrorResponse(response, 15, `Could not expand variable`); - } - else { - if (typeof expanded == "string") { - if (expanded == "") { - if (argsPart) - argsPart = false; - else - return submit(); - } - else if (expanded[0] != '"') { - strArr.push({ - name: "[err]", - value: expanded, - variablesReference: 0 - }); + let addOne = async () => { + const variable = await this.miDebugger.evalExpression(JSON.stringify(`${varReq.name}+${arrIndex})`)); + try { + let expanded = expandValue(createVariable, variable.result("value"), varReq.name, variable); + if (!expanded) { + this.sendErrorResponse(response, 15, `Could not expand variable`); + } + else { + if (typeof expanded == "string") { + if (expanded == "") { + if (argsPart) + argsPart = false; + else return submit(); - } - strArr.push({ - name: "[" + (arrIndex++) + "]", - value: expanded, - variablesReference: 0 - }); - addOne(); } - else { + else if (expanded[0] != '"') { strArr.push({ name: "[err]", value: expanded, variablesReference: 0 }); - submit(); + return submit(); } + strArr.push({ + name: `[${(arrIndex++)}]`, + value: expanded, + variablesReference: 0 + }); + addOne(); + } + else { + strArr.push({ + name: "[err]", + value: expanded, + variablesReference: 0 + }); + submit(); } } - catch (e) { - this.sendErrorResponse(response, 14, `Could not expand variable: ` + e); - } - }); + } + catch (e) { + this.sendErrorResponse(response, 14, `Could not expand variable: ${e}`); + } }; addOne(); } else - this.sendErrorResponse(response, 13, `Unimplemented variable request options: ` + JSON.stringify(varReq.options)); + this.sendErrorResponse(response, 13, `Unimplemented variable request options: ${JSON.stringify(varReq.options)}`); } else { response.body = { @@ -509,4 +621,4 @@ function prettyStringArray(strings) { return JSON.stringify(strings); } else return strings; -} \ No newline at end of file +}