Skip to content

Commit

Permalink
debug: respect variable.evaluateName
Browse files Browse the repository at this point in the history
fixes #10210
  • Loading branch information
isidorn committed Oct 24, 2016
1 parent be90e83 commit 6ce07ca
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 55 deletions.
5 changes: 2 additions & 3 deletions src/vs/workbench/parts/debug/browser/debugActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -768,9 +768,8 @@ export class AddToWatchExpressionsAction extends AbstractDebugAction {
}

public run(): TPromise<any> {
const process = this.debugService.getViewModel().focusedProcess;
const type = process ? process.session.configuration.type : null;
return this.debugService.addWatchExpression(model.getFullExpressionName(this.expression, type));
const name = this.expression instanceof model.Variable ? this.expression.evaluateName : this.expression.name;
return this.debugService.addWatchExpression(name);
}
}

Expand Down
66 changes: 34 additions & 32 deletions src/vs/workbench/parts/debug/common/debugModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,35 +57,6 @@ export function evaluateExpression(stackFrame: debug.IStackFrame, expression: Ex
});
}

const notPropertySyntax = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
const arrayElementSyntax = /\[.*\]$/;

export function getFullExpressionName(expression: debug.IExpression, sessionType: string): string {
let names = [expression.name];
if (expression instanceof Variable) {
let v = (<Variable>expression).parent;
while (v instanceof Variable || v instanceof Expression) {
names.push((<Variable>v).name);
v = (<Variable>v).parent;
}
}
names = names.reverse();

let result = null;
names.forEach(name => {
if (!result) {
result = name;
} else if (arrayElementSyntax.test(name) || (sessionType === 'node' && !notPropertySyntax.test(name))) {
// use safe way to access node properties a['property_name']. Also handles array elements.
result = name && name.indexOf('[') === 0 ? `${result}${name}` : `${result}['${name}']`;
} else {
result = `${result}.${name}`;
}
});

return result;
}

export class OutputElement implements debug.ITreeElement {
private static ID_COUNTER = 0;

Expand Down Expand Up @@ -203,7 +174,7 @@ export abstract class ExpressionContainer implements debug.IExpressionContainer
for (let i = 0; i < numberOfChunks; i++) {
const start = this.startOfVariables + i * chunkSize;
const count = Math.min(chunkSize, this.indexedVariables - i * chunkSize);
childrenArray.push(new Variable(this.stackFrame, this, this.reference, `[${start}..${start + count - 1}]`, '', null, count, null, true, start));
childrenArray.push(new Variable(this.stackFrame, this, this.reference, `[${start}..${start + count - 1}]`, '', '', null, count, null, true, start));
}

return childrenArray;
Expand Down Expand Up @@ -236,9 +207,9 @@ export abstract class ExpressionContainer implements debug.IExpressionContainer
filter
}).then(response => {
return response && response.body && response.body.variables ? arrays.distinct(response.body.variables.filter(v => !!v), v => v.name).map(
v => new Variable(this.stackFrame, this, v.variablesReference, v.name, v.value, v.namedVariables, v.indexedVariables, v.type)
v => new Variable(this.stackFrame, this, v.variablesReference, v.name, v.evaluateName, v.value, v.namedVariables, v.indexedVariables, v.type)
) : [];
}, (e: Error) => [new Variable(this.stackFrame, this, 0, null, e.message, 0, 0, null, false)]);
}, (e: Error) => [new Variable(this.stackFrame, this, 0, null, e.message, '', 0, 0, null, false)]);
}

// The adapter explicitly sents the children count of an expression only if there are lots of children which should be chunked.
Expand Down Expand Up @@ -271,12 +242,15 @@ export class Variable extends ExpressionContainer implements debug.IExpression {

// Used to show the error message coming from the adapter when setting the value #7807
public errorMessage: string;
private static NOT_PROPERTY_SYNTAX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
private static ARRAY_ELEMENT_SYNTAX = /\[.*\]$/;

constructor(
stackFrame: debug.IStackFrame,
public parent: debug.IExpressionContainer,
reference: number,
public name: string,
private _evaluateName: string,
value: string,
namedVariables: number,
indexedVariables: number,
Expand All @@ -288,6 +262,34 @@ export class Variable extends ExpressionContainer implements debug.IExpression {
this.value = massageValue(value);
}

public get evaluateName(): string {
if (this._evaluateName) {
return this._evaluateName;
}

let names = [this.name];
let v = this.parent;
while (v instanceof Variable || v instanceof Expression) {
names.push((<Variable>v).name);
v = (<Variable>v).parent;
}
names = names.reverse();

let result = null;
names.forEach(name => {
if (!result) {
result = name;
} else if (Variable.ARRAY_ELEMENT_SYNTAX.test(name) || (this.stackFrame.thread.process.session.configuration.type === 'node' && !Variable.NOT_PROPERTY_SYNTAX.test(name))) {
// use safe way to access node properties a['property_name']. Also handles array elements.
result = name && name.indexOf('[') === 0 ? `${result}${name}` : `${result}['${name}']`;
} else {
result = `${result}.${name}`;
}
});

return result;
}

public setVariable(value: string): TPromise<any> {
return this.stackFrame.thread.process.session.setVariable({
name: this.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import nls = require('vs/nls');
import actions = require('vs/base/common/actions');
import { TPromise } from 'vs/base/common/winjs.base';
import { clipboard } from 'electron';
import { Variable, getFullExpressionName } from 'vs/workbench/parts/debug/common/debugModel';
import { Variable } from 'vs/workbench/parts/debug/common/debugModel';
import { IDebugService } from 'vs/workbench/parts/debug/common/debug';

export class CopyValueAction extends actions.Action {
Expand All @@ -22,7 +22,7 @@ export class CopyValueAction extends actions.Action {
if (this.value instanceof Variable) {
const frameId = this.debugService.getViewModel().focusedStackFrame.frameId;
const process = this.debugService.getViewModel().focusedProcess;
return process.session.evaluate({ expression: getFullExpressionName(this.value, process.session.configuration.type), frameId }).then(result => {
return process.session.evaluate({ expression: this.value.evaluateName, frameId }).then(result => {
clipboard.writeText(result.body.result);
}, err => clipboard.writeText(this.value.value));
}
Expand Down
18 changes: 0 additions & 18 deletions src/vs/workbench/parts/debug/test/node/debugModel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,22 +364,4 @@ suite('Debug - Model', () => {
model.removeReplExpressions();
assert.equal(model.getReplElements().length, 0);
});

// Utils

test('full expression name', () => {
const type = 'node';
assert.equal(debugmodel.getFullExpressionName(new debugmodel.Expression(null, false), type), null);
assert.equal(debugmodel.getFullExpressionName(new debugmodel.Expression('son', false), type), 'son');

const process = new debugmodel.Process('mockProcess', rawSession);
const thread = new debugmodel.Thread(process, 'mockthread', 1);
const stackFrame = new debugmodel.StackFrame(thread, 1, null, 'app.js', 1, 1);
const scope = new debugmodel.Scope(stackFrame, 'myscope', 1, false, 1, 0);
const son = new debugmodel.Variable(stackFrame, new debugmodel.Variable(stackFrame, new debugmodel.Variable(stackFrame, scope, 0, 'grandfather', '75', 1, 0), 0, 'father', '45', 1, 0), 0, 'son', '20', 1, 0);
assert.equal(debugmodel.getFullExpressionName(son, type), 'grandfather.father.son');

const grandson = new debugmodel.Variable(stackFrame, son, 0, '/weird_name', '1', 0, 0);
assert.equal(debugmodel.getFullExpressionName(grandson, type), 'grandfather.father.son[\'/weird_name\']');
});
});

0 comments on commit 6ce07ca

Please sign in to comment.