Skip to content

Commit f178d6c

Browse files
committed
debug: support evalaution when no stack frame exist
fixes microsoft#14571
1 parent f492317 commit f178d6c

4 files changed

Lines changed: 63 additions & 60 deletions

File tree

src/vs/workbench/parts/debug/common/debugModel.ts

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -24,39 +24,6 @@ function massageValue(value: string): string {
2424
return value ? value.replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t') : value;
2525
}
2626

27-
export function evaluateExpression(stackFrame: debug.IStackFrame, expression: Expression, context: string): TPromise<Expression> {
28-
if (!stackFrame || !stackFrame.thread.process) {
29-
expression.value = context === 'repl' ? nls.localize('startDebugFirst', "Please start a debug session to evaluate") : Expression.DEFAULT_VALUE;
30-
expression.available = false;
31-
expression.reference = 0;
32-
return TPromise.as(expression);
33-
}
34-
expression.stackFrame = stackFrame;
35-
36-
return stackFrame.thread.process.session.evaluate({
37-
expression: expression.name,
38-
frameId: stackFrame ? stackFrame.frameId : undefined,
39-
context
40-
}).then(response => {
41-
expression.available = !!(response && response.body);
42-
if (response && response.body) {
43-
expression.value = response.body.result;
44-
expression.reference = response.body.variablesReference;
45-
expression.namedVariables = response.body.namedVariables;
46-
expression.indexedVariables = response.body.indexedVariables;
47-
expression.type = response.body.type;
48-
}
49-
50-
return expression;
51-
}, err => {
52-
expression.value = err.message;
53-
expression.available = false;
54-
expression.reference = 0;
55-
56-
return expression;
57-
});
58-
}
59-
6027
export class OutputElement implements debug.ITreeElement {
6128
private static ID_COUNTER = 0;
6229

@@ -238,6 +205,39 @@ export class Expression extends ExpressionContainer implements debug.IExpression
238205
this.value = Expression.DEFAULT_VALUE;
239206
this.available = false;
240207
}
208+
209+
public evaluate(process: debug.IProcess, stackFrame: debug.IStackFrame, context: string): TPromise<void> {
210+
if (!process) {
211+
this.value = context === 'repl' ? nls.localize('startDebugFirst', "Please start a debug session to evaluate") : Expression.DEFAULT_VALUE;
212+
this.available = false;
213+
this.reference = 0;
214+
215+
return TPromise.as(null);
216+
}
217+
218+
// Create a fake stack frame which is just used as a container for the process.
219+
// TODO@Isidor revisit if variables should have a reference to the StackFrame or a process after all
220+
this.stackFrame = stackFrame || new StackFrame(new Thread(process, undefined, undefined), undefined, undefined, undefined, undefined, undefined);
221+
222+
return process.session.evaluate({
223+
expression: this.name,
224+
frameId: stackFrame ? stackFrame.frameId : undefined,
225+
context
226+
}).then(response => {
227+
this.available = !!(response && response.body);
228+
if (response && response.body) {
229+
this.value = response.body.result;
230+
this.reference = response.body.variablesReference;
231+
this.namedVariables = response.body.namedVariables;
232+
this.indexedVariables = response.body.indexedVariables;
233+
this.type = response.body.type;
234+
}
235+
}, err => {
236+
this.value = err.message;
237+
this.available = false;
238+
this.reference = 0;
239+
});
240+
}
241241
}
242242

243243
export class Variable extends ExpressionContainer implements debug.IExpression {
@@ -800,10 +800,10 @@ export class Model implements debug.IModel {
800800
return this.replElements;
801801
}
802802

803-
public addReplExpression(stackFrame: debug.IStackFrame, name: string): TPromise<void> {
803+
public addReplExpression(process: debug.IProcess, stackFrame: debug.IStackFrame, name: string): TPromise<void> {
804804
const expression = new Expression(name, true);
805805
this.addReplElements([expression]);
806-
return evaluateExpression(stackFrame, expression, 'repl')
806+
return expression.evaluate(process, stackFrame, 'repl')
807807
.then(() => this._onDidChangeREPLElements.fire());
808808
}
809809

@@ -875,42 +875,42 @@ export class Model implements debug.IModel {
875875
return this.watchExpressions;
876876
}
877877

878-
public addWatchExpression(stackFrame: debug.IStackFrame, name: string): TPromise<void> {
878+
public addWatchExpression(process: debug.IProcess, stackFrame: debug.IStackFrame, name: string): TPromise<void> {
879879
const we = new Expression(name, false);
880880
this.watchExpressions.push(we);
881881
if (!name) {
882882
this._onDidChangeWatchExpressions.fire(we);
883883
return TPromise.as(null);
884884
}
885885

886-
return this.evaluateWatchExpressions(stackFrame, we.getId());
886+
return this.evaluateWatchExpressions(process, stackFrame, we.getId());
887887
}
888888

889-
public renameWatchExpression(stackFrame: debug.IStackFrame, id: string, newName: string): TPromise<void> {
889+
public renameWatchExpression(process: debug.IProcess, stackFrame: debug.IStackFrame, id: string, newName: string): TPromise<void> {
890890
const filtered = this.watchExpressions.filter(we => we.getId() === id);
891891
if (filtered.length === 1) {
892892
filtered[0].name = newName;
893-
return evaluateExpression(stackFrame, filtered[0], 'watch').then(() => {
893+
return filtered[0].evaluate(process, stackFrame, 'watch').then(() => {
894894
this._onDidChangeWatchExpressions.fire(filtered[0]);
895895
});
896896
}
897897

898898
return TPromise.as(null);
899899
}
900900

901-
public evaluateWatchExpressions(stackFrame: debug.IStackFrame, id: string = null): TPromise<void> {
901+
public evaluateWatchExpressions(process: debug.IProcess, stackFrame: debug.IStackFrame, id: string = null): TPromise<void> {
902902
if (id) {
903903
const filtered = this.watchExpressions.filter(we => we.getId() === id);
904904
if (filtered.length !== 1) {
905905
return TPromise.as(null);
906906
}
907907

908-
return evaluateExpression(stackFrame, filtered[0], 'watch').then(() => {
908+
return filtered[0].evaluate(process, stackFrame, 'watch').then(() => {
909909
this._onDidChangeWatchExpressions.fire(filtered[0]);
910910
});
911911
}
912912

913-
return TPromise.join(this.watchExpressions.map(we => evaluateExpression(stackFrame, we, 'watch'))).then(() => {
913+
return TPromise.join(this.watchExpressions.map(we => we.evaluate(process, stackFrame, 'watch'))).then(() => {
914914
this._onDidChangeWatchExpressions.fire();
915915
});
916916
}

src/vs/workbench/parts/debug/electron-browser/debugHover.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { IConfigurationChangedEvent } from 'vs/editor/common/editorCommon';
1515
import editorbrowser = require('vs/editor/browser/editorBrowser');
1616
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
1717
import debug = require('vs/workbench/parts/debug/common/debug');
18-
import { evaluateExpression, Expression } from 'vs/workbench/parts/debug/common/debugModel';
18+
import { Expression } from 'vs/workbench/parts/debug/common/debugModel';
1919
import viewer = require('vs/workbench/parts/debug/electron-browser/debugViewer');
2020
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
2121
import { Position } from 'vs/editor/common/core/position';
@@ -158,13 +158,16 @@ export class DebugHoverWidget implements editorbrowser.IContentWidget {
158158
const expressionRange = this.getExactExpressionRange(lineContent, range);
159159
// use regex to extract the sub-expression #9821
160160
const matchingExpression = lineContent.substring(expressionRange.startColumn - 1, expressionRange.endColumn);
161+
let promise: TPromise<debug.IExpression>;
162+
if (process.session.configuration.capabilities.supportsEvaluateForHovers) {
163+
const result = new Expression(matchingExpression, true);
164+
promise = result.evaluate(process, focusedStackFrame, 'hover').then(() => result);
165+
} else {
166+
promise = this.findExpressionInStackFrame(matchingExpression.split('.').map(word => word.trim()).filter(word => !!word));
167+
}
161168

162-
const evaluatedExpression = process.session.configuration.capabilities.supportsEvaluateForHovers ?
163-
evaluateExpression(focusedStackFrame, new Expression(matchingExpression, true), 'hover') :
164-
this.findExpressionInStackFrame(matchingExpression.split('.').map(word => word.trim()).filter(word => !!word));
165-
166-
return evaluatedExpression.then(expression => {
167-
if (!expression || !expression.available) {
169+
return promise.then(expression => {
170+
if (!expression || (expression instanceof Expression && !expression.available)) {
168171
this.hide();
169172
return;
170173
}

src/vs/workbench/parts/debug/electron-browser/debugService.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ export class DebugService implements debug.IDebugService {
451451
this.viewModel.setFocusedStackFrame(focusedStackFrame, process);
452452
this._onDidChangeState.fire();
453453
if (focusedStackFrame) {
454-
return this.model.evaluateWatchExpressions(focusedStackFrame);
454+
return this.model.evaluateWatchExpressions(process, focusedStackFrame);
455455
} else {
456456
this.model.clearWatchExpressionValues();
457457
return TPromise.as(null);
@@ -512,7 +512,7 @@ export class DebugService implements debug.IDebugService {
512512

513513
public addReplExpression(name: string): TPromise<void> {
514514
this.telemetryService.publicLog('debugService/addReplExpression');
515-
return this.model.addReplExpression(this.viewModel.focusedStackFrame, name)
515+
return this.model.addReplExpression(this.viewModel.focusedProcess, this.viewModel.focusedStackFrame, name)
516516
// Evaluate all watch expressions again since repl evaluation might have changed some.
517517
.then(() => this.setFocusedStackFrameAndEvaluate(this.viewModel.focusedStackFrame));
518518
}
@@ -530,11 +530,11 @@ export class DebugService implements debug.IDebugService {
530530
}
531531

532532
public addWatchExpression(name: string): TPromise<void> {
533-
return this.model.addWatchExpression(this.viewModel.focusedStackFrame, name);
533+
return this.model.addWatchExpression(this.viewModel.focusedProcess, this.viewModel.focusedStackFrame, name);
534534
}
535535

536536
public renameWatchExpression(id: string, newName: string): TPromise<void> {
537-
return this.model.renameWatchExpression(this.viewModel.focusedStackFrame, id, newName);
537+
return this.model.renameWatchExpression(this.viewModel.focusedProcess, this.viewModel.focusedStackFrame, id, newName);
538538
}
539539

540540
public removeWatchExpressions(id?: string): void {

src/vs/workbench/parts/debug/test/node/debugModel.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -294,13 +294,13 @@ suite('Debug - Model', () => {
294294
const process = new debugmodel.Process('mockProcess', rawSession);
295295
const thread = new debugmodel.Thread(process, 'mockthread', 1);
296296
const stackFrame = new debugmodel.StackFrame(thread, 1, null, 'app.js', 1, 1);
297-
model.addWatchExpression(stackFrame, 'console').done();
298-
model.addWatchExpression(stackFrame, 'console').done();
297+
model.addWatchExpression(process, stackFrame, 'console').done();
298+
model.addWatchExpression(process, stackFrame, 'console').done();
299299
const watchExpressions = model.getWatchExpressions();
300300
assertWatchExpressions(watchExpressions, 'console');
301301

302-
model.renameWatchExpression(stackFrame, watchExpressions[0].getId(), 'new_name').done();
303-
model.renameWatchExpression(stackFrame, watchExpressions[1].getId(), 'new_name').done();
302+
model.renameWatchExpression(process, stackFrame, watchExpressions[0].getId(), 'new_name').done();
303+
model.renameWatchExpression(process, stackFrame, watchExpressions[1].getId(), 'new_name').done();
304304
assertWatchExpressions(model.getWatchExpressions(), 'new_name');
305305

306306
model.clearWatchExpressionValues();
@@ -315,9 +315,9 @@ suite('Debug - Model', () => {
315315
const process = new debugmodel.Process('mockProcess', rawSession);
316316
const thread = new debugmodel.Thread(process, 'mockthread', 1);
317317
const stackFrame = new debugmodel.StackFrame(thread, 1, null, 'app.js', 1, 1);
318-
model.addReplExpression(stackFrame, 'myVariable').done();
319-
model.addReplExpression(stackFrame, 'myVariable').done();
320-
model.addReplExpression(stackFrame, 'myVariable').done();
318+
model.addReplExpression(process, stackFrame, 'myVariable').done();
319+
model.addReplExpression(process, stackFrame, 'myVariable').done();
320+
model.addReplExpression(process, stackFrame, 'myVariable').done();
321321

322322
assert.equal(model.getReplElements().length, 3);
323323
model.getReplElements().forEach(re => {

0 commit comments

Comments
 (0)