diff --git a/src/vs/workbench/parts/debug/browser/debugHover.ts b/src/vs/workbench/parts/debug/browser/debugHover.ts index cef12be1382c1c9cfc1feb080853743a62ce88e0..dda8083354880c9158be566571d1dc72caef5fd1 100644 --- a/src/vs/workbench/parts/debug/browser/debugHover.ts +++ b/src/vs/workbench/parts/debug/browser/debugHover.ts @@ -150,7 +150,7 @@ export class DebugHoverWidget implements editorbrowser.IContentWidget { } else { this.treeContainer.hidden = true; this.valueContainer.hidden = false; - viewer.renderExpressionValue(expression, false, this.valueContainer); + viewer.renderExpressionValue(expression, false, this.valueContainer, false); } this.showAtPosition = position; diff --git a/src/vs/workbench/parts/debug/browser/debugViewer.ts b/src/vs/workbench/parts/debug/browser/debugViewer.ts index caa942cc8ee359dd9e0b889fef094da8b3cb0e8c..5577288a3a209aff7fb0f7190a34d09b8aee2c72 100644 --- a/src/vs/workbench/parts/debug/browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/browser/debugViewer.ts @@ -35,13 +35,13 @@ const $ = dom.emmet; const booleanRegex = /^true|false$/i; const stringRegex = /^(['"]).*\1$/; -export function renderExpressionValue(arg2: debug.IExpression|string, debugInactive: boolean, container: HTMLElement): void { - let value = typeof arg2 === 'string' ? arg2 : arg2.value; +export function renderExpressionValue(expressionOrValue: debug.IExpression|string, debugInactive: boolean, container: HTMLElement, showChanged: boolean): void { + let value = typeof expressionOrValue === 'string' ? expressionOrValue : expressionOrValue.value; // remove stale classes container.className = 'value'; // when resolving expressions we represent errors from the server as a variable with name === null. - if (value === null || ((arg2 instanceof model.Expression || arg2 instanceof model.Variable) && !arg2.available)) { + if (value === null || ((expressionOrValue instanceof model.Expression || expressionOrValue instanceof model.Variable) && !expressionOrValue.available)) { dom.addClass(container, 'unavailable'); debugInactive ? dom.removeClass(container, 'error') : dom.addClass(container, 'error'); } else if (!isNaN(+value)) { @@ -52,6 +52,10 @@ export function renderExpressionValue(arg2: debug.IExpression|string, debugInact dom.addClass(container, 'string'); } + if (showChanged && (expressionOrValue).valueChanged) { + // value changed color has priority over other colors. + container.className = 'value changed'; + } container.textContent = value; container.title = value; } @@ -62,11 +66,7 @@ export function renderVariable(tree: tree.ITree, variable: model.Variable, data: } if (variable.value) { - renderExpressionValue(variable, debugInactive, data.value); - if (variable.valueChanged && showChanged) { - // value changed color has priority over other colors. - data.value.className = 'value changed'; - } + renderExpressionValue(variable, debugInactive, data.value, showChanged); } else { data.value.textContent = ''; data.value.title = ''; @@ -570,7 +570,7 @@ export class WatchExpressionsRenderer implements tree.IRenderer { if (templateId === WatchExpressionsRenderer.WATCH_EXPRESSION_TEMPLATE_ID) { this.renderWatchExpression(tree, element, templateData); } else { - this.renderExpression(tree, element, templateData); + renderVariable(tree, element, templateData, this.debugService.getState() === debug.State.Inactive, true); } } @@ -581,13 +581,9 @@ export class WatchExpressionsRenderer implements tree.IRenderer { } data.actionBar.context = watchExpression; - this.renderExpression(tree, watchExpression, data); - } - - private renderExpression(tree: tree.ITree, expression: debug.IExpression, data: IVariableTemplateData): void { - data.name.textContent = `${expression.name}:`; - if (expression.value) { - renderExpressionValue(expression, this.debugService.getState() === debug.State.Inactive, data.value); + data.name.textContent = `${watchExpression.name}:`; + if (watchExpression.value) { + renderExpressionValue(watchExpression, this.debugService.getState() === debug.State.Inactive, data.value, true); } } diff --git a/src/vs/workbench/parts/debug/browser/replViewer.ts b/src/vs/workbench/parts/debug/browser/replViewer.ts index 95924f6fea3951fae82e24f2f38a7c9c8550260e..0362a8e053fbe8862e1456fad2f1ed8495895ab2 100644 --- a/src/vs/workbench/parts/debug/browser/replViewer.ts +++ b/src/vs/workbench/parts/debug/browser/replViewer.ts @@ -213,7 +213,7 @@ export class ReplExpressionsRenderer implements tree.IRenderer { private renderInputOutputPair(tree: tree.ITree, expression: debug.IExpression, templateData: IInputOutputPairTemplateData): void { templateData.input.textContent = expression.name; - debugviewer.renderExpressionValue(expression, this.debugService.getState() === debug.State.Inactive, templateData.value); + debugviewer.renderExpressionValue(expression, this.debugService.getState() === debug.State.Inactive, templateData.value, false); if (expression.reference > 0) { templateData.annotation.className = 'annotation octicon octicon-info'; templateData.annotation.title = nls.localize('stateCapture', "Object state is captured from first evaluation"); @@ -406,7 +406,7 @@ export class ReplExpressionsRenderer implements tree.IRenderer { } // value - debugviewer.renderExpressionValue(output.value, false, templateData.value); + debugviewer.renderExpressionValue(output.value, false, templateData.value, false); // annotation if any if (output.annotation) { diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 483151ee8a96368f0711b2ac8e995504b23a24bb..6748fdfb32f758db991437e116a1362f3c01de1e 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -40,6 +40,7 @@ export interface IExpressionContainer extends ITreeElement { export interface IExpression extends ITreeElement, IExpressionContainer { name: string; value: string; + valueChanged: boolean; } export interface IThread extends ITreeElement { diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index 824c5f3d3db67197c98696bf679e2782a6caeb90..072d2097d0129ec085c514e5188d34ae1350b22a 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -145,11 +145,14 @@ export class KeyValueOutputElement extends OutputElement { } } +// TODO@Isidor move common code for expression and variable into a super class export class Expression implements debug.IExpression { static DEFAULT_VALUE = 'not available'; + public static allValues: { [id: string]: string } = {}; public reference: number; public available: boolean; + public valueChanged: boolean; private _value: string; private children: TPromise; @@ -166,6 +169,8 @@ export class Expression implements debug.IExpression { public set value(value: string) { this._value = massageValue(value); + this.valueChanged = Expression.allValues[this.getId()] && Expression.allValues[this.getId()] !== value; + Expression.allValues[this.getId()] = value; } public getId(): string { @@ -341,6 +346,7 @@ export class Model extends ee.EventEmitter implements debug.IModel { if (removeThreads) { this.threads = {}; Variable.allValues = {}; + Expression.allValues = {}; } else { for (let ref in this.threads) { if (this.threads.hasOwnProperty(ref)) { @@ -612,7 +618,7 @@ export class Model extends ee.EventEmitter implements debug.IModel { if (!rsf) { return new StackFrame(data.threadId, 0, new Source({ name: 'unknown' }), nls.localize('unknownStack', "Unknown stack location"), undefined, undefined); } - + return new StackFrame(data.threadId, rsf.id, rsf.source ? new Source(rsf.source) : new Source({ name: 'unknown' }), rsf.name, rsf.line, rsf.column); });