debug: implement display variable type setting for vscode (#210258) (#214315)

* Implement display variable type setting for vscode (#210258)

Created two new settings to be added to .vscode/settings.json
('variableDisplayType.watchView' and
'variableDisplayType.variableView') when set
to true it shows the variable type in the
format var_name: type = value in the debug panel and variable panel
respectively and the hover will now display var_name.
When set to false uses the previous
expected behaviour (var_name = value)
and the hover will display the type.

Co-authored-by: Diogo Pinto <diogotfpinto@tecnico.ulisboa.pt>

* Implemented the requested changes.

Registed new setting in debug.contribution.ts
Changed the two settings for a single setting (debug.showVariableTypes)
Made the renderer functions listen to changes so it re-renders elements
Added a different styling for the type in variable panel
Changed function names to use camelCase

Co-authored-by: Diogo Pinto <diogotfpinto@tecnico.ulisboa.pt>

* Implemented Requested small changes.

Removed linkDetector check when rendering the type.
Deleted displayType boolean, now we read from config in render
Added missing line to renderExpressionElement.

Co-authored-by: Diogo Pinto <diogotfpinto@tecnico.ulisboa.pt>

---------

Co-authored-by: Diogo Pinto <diogotfpinto@tecnico.ulisboa.pt>
This commit is contained in:
Connor Peet 2024-06-07 12:13:16 -07:00 committed by GitHub
commit 739a9e8579
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 382 additions and 49 deletions

View file

@ -49,6 +49,7 @@ export interface IRenderValueOptions {
export interface IVariableTemplateData {
expression: HTMLElement;
name: HTMLElement;
type: HTMLElement;
value: HTMLElement;
label: HighlightedLabel;
lazyButton: HTMLElement;
@ -130,13 +131,20 @@ export function renderExpressionValue(expressionOrValue: IExpressionValue | stri
}
}
export function renderVariable(store: DisposableStore, commandService: ICommandService, hoverService: IHoverService, variable: Variable, data: IVariableTemplateData, showChanged: boolean, highlights: IHighlight[], linkDetector?: LinkDetector): void {
export function renderVariable(store: DisposableStore, commandService: ICommandService, hoverService: IHoverService, variable: Variable, data: IVariableTemplateData, showChanged: boolean, highlights: IHighlight[], linkDetector?: LinkDetector, displayType?: boolean): void {
if (variable.available) {
data.type.textContent = '';
let text = variable.name;
if (variable.value && typeof variable.name === 'string') {
text += ':';
if (variable.type && displayType) {
text += ': ';
data.type.textContent = variable.type + ' =';
} else {
text += ' =';
}
}
data.label.set(text, highlights, variable.type ? variable.type : variable.name);
data.label.set(text, highlights, variable.type && !displayType ? variable.type : variable.name);
data.name.classList.toggle('virtual', variable.presentationHint?.kind === 'virtual');
data.name.classList.toggle('internal', variable.presentationHint?.visibility === 'internal');
} else if (variable.value && typeof variable.name === 'string' && variable.name) {
@ -171,6 +179,7 @@ export interface IInputBoxOptions {
export interface IExpressionTemplateData {
expression: HTMLElement;
name: HTMLSpanElement;
type: HTMLSpanElement;
value: HTMLSpanElement;
inputBoxContainer: HTMLElement;
actionBar?: ActionBar;
@ -228,7 +237,10 @@ export abstract class AbstractExpressionsRenderer<T = IExpression> implements IT
const name = dom.append(expression, $('span.name'));
const lazyButton = dom.append(expression, $('span.lazy-button'));
lazyButton.classList.add(...ThemeIcon.asClassNameArray(Codicon.eye));
templateDisposable.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), lazyButton, localize('debug.lazyButton.tooltip', "Click to expand")));
const type = dom.append(expression, $('span.type'));
const value = dom.append(expression, $('span.value'));
const label = templateDisposable.add(new HighlightedLabel(name));
@ -241,7 +253,7 @@ export abstract class AbstractExpressionsRenderer<T = IExpression> implements IT
actionBar = templateDisposable.add(new ActionBar(expression));
}
const template: IExpressionTemplateData = { expression, name, value, label, inputBoxContainer, actionBar, elementDisposable: new DisposableStore(), templateDisposable, lazyButton, currentElement: undefined };
const template: IExpressionTemplateData = { expression, name, type, value, label, inputBoxContainer, actionBar, elementDisposable: new DisposableStore(), templateDisposable, lazyButton, currentElement: undefined };
templateDisposable.add(dom.addDisposableListener(lazyButton, dom.EventType.CLICK, () => {
if (template.currentElement) {
@ -255,7 +267,6 @@ export abstract class AbstractExpressionsRenderer<T = IExpression> implements IT
public abstract renderElement(node: ITreeNode<T, FuzzyScore>, index: number, data: IExpressionTemplateData): void;
protected renderExpressionElement(element: IExpression, node: ITreeNode<T, FuzzyScore>, data: IExpressionTemplateData): void {
data.elementDisposable.clear();
data.currentElement = element;
this.renderExpression(node.element, data, createMatches(node.filterData));
if (data.actionBar) {

View file

@ -440,6 +440,11 @@ configurationRegistry.registerConfiguration({
title: nls.localize('debugConfigurationTitle', "Debug"),
type: 'object',
properties: {
'debug.showVariableTypes': {
type: 'boolean',
description: nls.localize({ comment: ['This is the description for a setting'], key: 'showVariableTypes' }, "Show variable type in variable pane during debug session"),
default: false
},
'debug.allowBreakpointsEverywhere': {
type: 'boolean',
description: nls.localize({ comment: ['This is the description for a setting'], key: 'allowBreakpointsEverywhere' }, "Allow setting breakpoints in any file."),

View file

@ -35,6 +35,7 @@ export const debugIconStartForeground = registerColor('debugIcon.startForeground
export function registerColors() {
const debugTokenExpressionName = registerColor('debugTokenExpression.name', { dark: '#c586c0', light: '#9b46b0', hcDark: foreground, hcLight: foreground }, 'Foreground color for the token names shown in the debug views (ie. the Variables or Watch view).');
const debugTokenExpressionType = registerColor('debugTokenExpression.type', { dark: '#4A90E2', light: '#4A90E2', hcDark: foreground, hcLight: foreground }, 'Foreground color for the token types shown in the debug views (ie. the Variables or Watch view).');
const debugTokenExpressionValue = registerColor('debugTokenExpression.value', { dark: '#cccccc99', light: '#6c6c6ccc', hcDark: foreground, hcLight: foreground }, 'Foreground color for the token values shown in the debug views (ie. the Variables or Watch view).');
const debugTokenExpressionString = registerColor('debugTokenExpression.string', { dark: '#ce9178', light: '#a31515', hcDark: '#f48771', hcLight: '#a31515' }, 'Foreground color for strings in the debug views (ie. the Variables or Watch view).');
const debugTokenExpressionBoolean = registerColor('debugTokenExpression.boolean', { dark: '#4e94ce', light: '#0000ff', hcDark: '#75bdfe', hcLight: '#0000ff' }, 'Foreground color for booleans in the debug views (ie. the Variables or Watch view).');
@ -210,6 +211,7 @@ export function registerColors() {
}
const tokenNameColor = theme.getColor(debugTokenExpressionName)!;
const tokenTypeColor = theme.getColor(debugTokenExpressionType)!;
const tokenValueColor = theme.getColor(debugTokenExpressionValue)!;
const tokenStringColor = theme.getColor(debugTokenExpressionString)!;
const tokenBooleanColor = theme.getColor(debugTokenExpressionBoolean)!;
@ -221,6 +223,10 @@ export function registerColors() {
color: ${tokenNameColor};
}
.monaco-workbench .monaco-list-row .expression .type {
color: ${tokenTypeColor};
}
.monaco-workbench .monaco-list-row .expression .value,
.monaco-workbench .debug-hover-widget .value {
color: ${tokenValueColor};

View file

@ -237,6 +237,7 @@ export class ReplVariablesRenderer extends AbstractExpressionsRenderer<IExpressi
public renderElement(node: ITreeNode<IExpression | ReplVariableElement, FuzzyScore>, _index: number, data: IExpressionTemplateData): void {
const element = node.element;
data.elementDisposable.clear();
super.renderExpressionElement(element instanceof ReplVariableElement ? element.expression : element, node, data);
}

View file

@ -41,7 +41,7 @@ import { IViewDescriptorService } from 'vs/workbench/common/views';
import { AbstractExpressionDataSource, AbstractExpressionsRenderer, IExpressionTemplateData, IInputBoxOptions, renderExpressionValue, renderVariable, renderViewTree } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import { ADD_TO_WATCH_ID, ADD_TO_WATCH_LABEL, COPY_EVALUATE_PATH_ID, COPY_EVALUATE_PATH_LABEL, COPY_VALUE_ID, COPY_VALUE_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { CONTEXT_BREAK_WHEN_VALUE_CHANGES_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_ACCESSED_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_READ_SUPPORTED, CONTEXT_VARIABLES_FOCUSED, DataBreakpointSetType, DebugVisualizationType, IDataBreakpointInfoResponse, IDebugService, IExpression, IScope, IStackFrame, IViewModel, VARIABLES_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug';
import { CONTEXT_BREAK_WHEN_VALUE_CHANGES_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_ACCESSED_SUPPORTED, CONTEXT_BREAK_WHEN_VALUE_IS_READ_SUPPORTED, CONTEXT_VARIABLES_FOCUSED, DataBreakpointSetType, DebugVisualizationType, IDataBreakpointInfoResponse, IDebugConfiguration, IDebugService, IExpression, IScope, IStackFrame, IViewModel, VARIABLES_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug';
import { getContextForVariable } from 'vs/workbench/contrib/debug/common/debugContext';
import { ErrorScope, Expression, Scope, StackFrame, Variable, VisualizedExpression, getUriForDebugMemory } from 'vs/workbench/contrib/debug/common/debugModel';
import { DebugVisualizer, IDebugVisualizerService } from 'vs/workbench/contrib/debug/common/debugVisualizers';
@ -455,6 +455,7 @@ export class VisualizedVariableRenderer extends AbstractExpressionsRenderer {
}
public override renderElement(node: ITreeNode<IExpression, FuzzyScore>, index: number, data: IExpressionTemplateData): void {
data.elementDisposable.clear();
super.renderExpressionElement(node.element, node, data);
}
@ -531,6 +532,7 @@ export class VariablesRenderer extends AbstractExpressionsRenderer {
@IDebugService debugService: IDebugService,
@IContextViewService contextViewService: IContextViewService,
@IHoverService hoverService: IHoverService,
@IConfigurationService private configurationService: IConfigurationService,
) {
super(debugService, contextViewService, hoverService);
}
@ -540,10 +542,17 @@ export class VariablesRenderer extends AbstractExpressionsRenderer {
}
protected renderExpression(expression: IExpression, data: IExpressionTemplateData, highlights: IHighlight[]): void {
renderVariable(data.elementDisposable, this.commandService, this.hoverService, expression as Variable, data, true, highlights, this.linkDetector);
const showType = this.configurationService.getValue<IDebugConfiguration>('debug').showVariableTypes;
renderVariable(data.elementDisposable, this.commandService, this.hoverService, expression as Variable, data, true, highlights, this.linkDetector, showType);
}
public override renderElement(node: ITreeNode<IExpression, FuzzyScore>, index: number, data: IExpressionTemplateData): void {
data.elementDisposable.clear();
data.elementDisposable.add(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('debug.showVariableTypes')) {
super.renderExpressionElement(node.element, node, data);
}
}));
super.renderExpressionElement(node.element, node, data);
}

View file

@ -34,7 +34,7 @@ import { AbstractExpressionDataSource, AbstractExpressionsRenderer, IExpressionT
import { watchExpressionsAdd, watchExpressionsRemoveAll } from 'vs/workbench/contrib/debug/browser/debugIcons';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { VariablesRenderer, VisualizedVariableRenderer } from 'vs/workbench/contrib/debug/browser/variablesView';
import { CONTEXT_CAN_VIEW_MEMORY, CONTEXT_VARIABLE_IS_READONLY, CONTEXT_WATCH_EXPRESSIONS_EXIST, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_WATCH_ITEM_TYPE, IDebugService, IExpression, WATCH_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug';
import { CONTEXT_CAN_VIEW_MEMORY, CONTEXT_VARIABLE_IS_READONLY, CONTEXT_WATCH_EXPRESSIONS_EXIST, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_WATCH_ITEM_TYPE, IDebugConfiguration, IDebugService, IExpression, WATCH_VIEW_ID } from 'vs/workbench/contrib/debug/common/debug';
import { Expression, Variable, VisualizedExpression } from 'vs/workbench/contrib/debug/common/debugModel';
const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024;
@ -274,7 +274,7 @@ class WatchExpressionsDataSource extends AbstractExpressionDataSource<IDebugServ
}
class WatchExpressionsRenderer extends AbstractExpressionsRenderer {
export class WatchExpressionsRenderer extends AbstractExpressionsRenderer {
static readonly ID = 'watchexpression';
@ -284,6 +284,7 @@ class WatchExpressionsRenderer extends AbstractExpressionsRenderer {
@IDebugService debugService: IDebugService,
@IContextViewService contextViewService: IContextViewService,
@IHoverService hoverService: IHoverService,
@IConfigurationService private configurationService: IConfigurationService,
) {
super(debugService, contextViewService, hoverService);
}
@ -293,16 +294,36 @@ class WatchExpressionsRenderer extends AbstractExpressionsRenderer {
}
public override renderElement(node: ITreeNode<IExpression, FuzzyScore>, index: number, data: IExpressionTemplateData): void {
data.elementDisposable.clear();
data.elementDisposable.add(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('debug.showVariableTypes')) {
super.renderExpressionElement(node.element, node, data);
}
}));
super.renderExpressionElement(node.element, node, data);
}
protected renderExpression(expression: IExpression, data: IExpressionTemplateData, highlights: IHighlight[]): void {
const text = typeof expression.value === 'string' ? `${expression.name}:` : expression.name;
let text: string;
data.type.textContent = '';
const showType = this.configurationService.getValue<IDebugConfiguration>('debug').showVariableTypes;
if (showType && expression.type) {
text = typeof expression.value === 'string' ? `${expression.name}: ` : expression.name;
//render type
data.type.textContent = expression.type + ' =';
} else {
text = typeof expression.value === 'string' ? `${expression.name} =` : expression.name;
}
let title: string;
if (expression.type) {
title = expression.type === expression.value ?
expression.type :
`${expression.type}: ${expression.value}`;
if (showType) {
title = `${expression.name}`;
} else {
title = expression.type === expression.value ?
expression.type :
`${expression.type}`;
}
} else {
title = expression.value;
}

View file

@ -788,6 +788,7 @@ export interface IDebugConfiguration {
};
autoExpandLazyVariables: boolean;
enableStatusBarColor: boolean;
showVariableTypes: boolean;
}
export interface IGlobalConfig {

View file

@ -10,6 +10,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
import { isWindows } from 'vs/base/common/platform';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
import { NullCommandService } from 'vs/platform/commands/test/common/nullCommandService';
import { IHoverService } from 'vs/platform/hover/browser/hover';
import { NullHoverService } from 'vs/platform/hover/test/browser/nullHoverService';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { renderExpressionValue, renderVariable, renderViewTree } from 'vs/workbench/contrib/debug/browser/baseDebugView';
@ -23,6 +24,66 @@ import { MockSession } from 'vs/workbench/contrib/debug/test/common/mockDebug';
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
const $ = dom.$;
function assertVariable(session: MockSession, scope: Scope, disposables: Pick<DisposableStore, "add">, linkDetector: LinkDetector, displayType: boolean) {
let variable = new Variable(session, 1, scope, 2, 'foo', 'bar.foo', undefined, 0, 0, undefined, {}, 'string');
let expression = $('.');
let name = $('.');
let type = $('.');
let value = $('.');
const label = new HighlightedLabel(name);
const lazyButton = $('.');
const store = disposables.add(new DisposableStore());
renderVariable(store, NullCommandService, NullHoverService, variable, { expression, name, type, value, label, lazyButton }, false, [], undefined, displayType);
assert.strictEqual(label.element.textContent, 'foo');
assert.strictEqual(value.textContent, '');
variable.value = 'hey';
expression = $('.');
name = $('.');
type = $('.');
value = $('.');
renderVariable(store, NullCommandService, NullHoverService, variable, { expression, name, type, value, label, lazyButton }, false, [], linkDetector, displayType);
assert.strictEqual(value.textContent, 'hey');
assert.strictEqual(label.element.textContent, displayType ? 'foo: ' : 'foo =');
assert.strictEqual(type.textContent, displayType ? 'string =' : '');
variable.value = isWindows ? 'C:\\foo.js:5' : '/foo.js:5';
expression = $('.');
name = $('.');
type = $('.');
value = $('.');
renderVariable(store, NullCommandService, NullHoverService, variable, { expression, name, type, value, label, lazyButton }, false, [], linkDetector, displayType);
assert.ok(value.querySelector('a'));
assert.strictEqual(value.querySelector('a')!.textContent, variable.value);
variable = new Variable(session, 1, scope, 2, 'console', 'console', '5', 0, 0, undefined, { kind: 'virtual' });
expression = $('.');
name = $('.');
type = $('.');
value = $('.');
renderVariable(store, NullCommandService, NullHoverService, variable, { expression, name, type, value, label, lazyButton }, false, [], linkDetector, displayType);
assert.strictEqual(name.className, 'virtual');
assert.strictEqual(label.element.textContent, 'console =');
assert.strictEqual(value.className, 'value number');
variable = new Variable(session, 1, scope, 2, 'xpto', 'xpto.xpto', undefined, 0, 0, undefined, {}, 'custom-type');
renderVariable(store, NullCommandService, NullHoverService, variable, { expression, name, type, value, label, lazyButton }, false, [], linkDetector, displayType);
assert.strictEqual(label.element.textContent, 'xpto');
assert.strictEqual(value.textContent, '');
variable.value = '2';
expression = $('.');
name = $('.');
type = $('.');
value = $('.');
renderVariable(store, NullCommandService, NullHoverService, variable, { expression, name, type, value, label, lazyButton }, false, [], linkDetector, displayType);
assert.strictEqual(value.textContent, '2');
assert.strictEqual(label.element.textContent, displayType ? 'xpto: ' : 'xpto =');
assert.strictEqual(type.textContent, displayType ? 'custom-type =' : '');
label.dispose();
}
suite('Debug - Base Debug View', () => {
const disposables = ensureNoDisposablesAreLeakedInTestSuite();
let linkDetector: LinkDetector;
@ -33,6 +94,7 @@ suite('Debug - Base Debug View', () => {
setup(() => {
const instantiationService: TestInstantiationService = workbenchInstantiationService(undefined, disposables);
linkDetector = instantiationService.createInstance(LinkDetector);
instantiationService.stub(IHoverService, NullHoverService);
});
test('render view tree', () => {
@ -85,47 +147,32 @@ suite('Debug - Base Debug View', () => {
test('render variable', () => {
const session = new MockSession();
const thread = new Thread(session, 'mockthread', 1);
const stackFrame = new StackFrame(thread, 1, null!, 'app.js', 'normal', { startLineNumber: 1, startColumn: 1, endLineNumber: undefined!, endColumn: undefined! }, 0, true);
const range = {
startLineNumber: 1,
startColumn: 1,
endLineNumber: undefined!,
endColumn: undefined!
};
const stackFrame = new StackFrame(thread, 1, null!, 'app.js', 'normal', range, 0, true);
const scope = new Scope(stackFrame, 1, 'local', 1, false, 10, 10);
let variable = new Variable(session, 1, scope, 2, 'foo', 'bar.foo', undefined, 0, 0, undefined, {}, 'string');
let expression = $('.');
let name = $('.');
let value = $('.');
const label = new HighlightedLabel(name);
const lazyButton = $('.');
const store = disposables.add(new DisposableStore());
renderVariable(store, NullCommandService, NullHoverService, variable, { expression, name, value, label, lazyButton }, false, []);
assertVariable(session, scope, disposables, linkDetector, false);
assert.strictEqual(label.element.textContent, 'foo');
assert.strictEqual(value.textContent, '');
});
variable.value = 'hey';
expression = $('.');
name = $('.');
value = $('.');
renderVariable(store, NullCommandService, NullHoverService, variable, { expression, name, value, label, lazyButton }, false, [], linkDetector);
assert.strictEqual(value.textContent, 'hey');
assert.strictEqual(label.element.textContent, 'foo:');
test('render variable with display type setting', () => {
const session = new MockSession();
const thread = new Thread(session, 'mockthread', 1);
const range = {
startLineNumber: 1,
startColumn: 1,
endLineNumber: undefined!,
endColumn: undefined!
};
const stackFrame = new StackFrame(thread, 1, null!, 'app.js', 'normal', range, 0, true);
const scope = new Scope(stackFrame, 1, 'local', 1, false, 10, 10);
variable.value = isWindows ? 'C:\\foo.js:5' : '/foo.js:5';
expression = $('.');
name = $('.');
value = $('.');
renderVariable(store, NullCommandService, NullHoverService, variable, { expression, name, value, label, lazyButton }, false, [], linkDetector);
assert.ok(value.querySelector('a'));
assert.strictEqual(value.querySelector('a')!.textContent, variable.value);
variable = new Variable(session, 1, scope, 2, 'console', 'console', '5', 0, 0, undefined, { kind: 'virtual' });
expression = $('.');
name = $('.');
value = $('.');
renderVariable(store, NullCommandService, NullHoverService, variable, { expression, name, value, label, lazyButton }, false, [], linkDetector);
assert.strictEqual(name.className, 'virtual');
assert.strictEqual(label.element.textContent, 'console:');
assert.strictEqual(value.className, 'value number');
label.dispose();
assertVariable(session, scope, disposables, linkDetector, true);
});
test('statusbar in debug mode', () => {

View file

@ -0,0 +1,118 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import * as dom from 'vs/base/browser/dom';
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { Scope, StackFrame, Thread, Variable } from 'vs/workbench/contrib/debug/common/debugModel';
import { MockDebugService, MockSession } from 'vs/workbench/contrib/debug/test/common/mockDebug';
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
import { IHoverService } from 'vs/platform/hover/browser/hover';
import { NullHoverService } from 'vs/platform/hover/test/browser/nullHoverService';
import { IDebugService, IViewModel } from 'vs/workbench/contrib/debug/common/debug';
import { VariablesRenderer } from 'vs/workbench/contrib/debug/browser/variablesView';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
const $ = dom.$;
function assertVariable(disposables: Pick<DisposableStore, "add">, variablesRenderer: VariablesRenderer, displayType: boolean) {
const session = new MockSession();
const thread = new Thread(session, 'mockthread', 1);
const range = {
startLineNumber: 1,
startColumn: 1,
endLineNumber: undefined!,
endColumn: undefined!
};
const stackFrame = new StackFrame(thread, 1, null!, 'app.js', 'normal', range, 0, true);
const scope = new Scope(stackFrame, 1, 'local', 1, false, 10, 10);
const node = {
element: new Variable(session, 1, scope, 2, 'foo', 'bar.foo', undefined, 0, 0, undefined, {}, 'string'),
depth: 0,
visibleChildrenCount: 1,
visibleChildIndex: -1,
collapsible: false,
collapsed: false,
visible: true,
filterData: undefined,
children: []
};
const expression = $('.');
const name = $('.');
const type = $('.');
const value = $('.');
const label = disposables.add(new HighlightedLabel(name));
const lazyButton = $('.');
const inputBoxContainer = $('.');
const elementDisposable = disposables.add(new DisposableStore());
const templateDisposable = disposables.add(new DisposableStore());
const currentElement = undefined;
const data = {
expression,
name,
type,
value,
label,
lazyButton,
inputBoxContainer,
elementDisposable,
templateDisposable,
currentElement
};
variablesRenderer.renderElement(node, 0, data);
assert.strictEqual(value.textContent, '');
assert.strictEqual(label.element.textContent, 'foo');
node.element.value = 'xpto';
variablesRenderer.renderElement(node, 0, data);
assert.strictEqual(value.textContent, 'xpto');
assert.strictEqual(type.textContent, displayType ? 'string =' : '');
assert.strictEqual(label.element.textContent, displayType ? 'foo: ' : 'foo =');
}
suite('Debug - Variable Debug View', () => {
const disposables = ensureNoDisposablesAreLeakedInTestSuite();
let variablesRenderer: VariablesRenderer;
let instantiationService: TestInstantiationService;
let linkDetector: LinkDetector;
let configurationService: TestConfigurationService;
setup(() => {
instantiationService = workbenchInstantiationService(undefined, disposables);
linkDetector = instantiationService.createInstance(LinkDetector);
const debugService = new MockDebugService();
instantiationService.stub(IHoverService, NullHoverService);
debugService.getViewModel = () => <IViewModel>{ focusedStackFrame: undefined, getSelectedExpression: () => undefined };
debugService.getViewModel().getSelectedExpression = () => undefined;
instantiationService.stub(IDebugService, debugService);
});
test('variable expressions with display type', () => {
configurationService = new TestConfigurationService({
debug: {
showVariableTypes: true
}
});
instantiationService.stub(IConfigurationService, configurationService);
variablesRenderer = instantiationService.createInstance(VariablesRenderer, linkDetector);
assertVariable(disposables, variablesRenderer, true);
});
test('variable expressions', () => {
configurationService = new TestConfigurationService({
debug: {
showVariableTypes: false
}
});
instantiationService.stub(IConfigurationService, configurationService);
variablesRenderer = instantiationService.createInstance(VariablesRenderer, linkDetector);
assertVariable(disposables, variablesRenderer, false);
});
});

View file

@ -0,0 +1,114 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import * as dom from 'vs/base/browser/dom';
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { WatchExpressionsRenderer } from 'vs/workbench/contrib/debug/browser/watchExpressionsView';
import { Scope, StackFrame, Thread, Variable } from 'vs/workbench/contrib/debug/common/debugModel';
import { MockDebugService, MockSession } from 'vs/workbench/contrib/debug/test/common/mockDebug';
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
import { IHoverService } from 'vs/platform/hover/browser/hover';
import { NullHoverService } from 'vs/platform/hover/test/browser/nullHoverService';
import { IDebugService, IViewModel } from 'vs/workbench/contrib/debug/common/debug';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
const $ = dom.$;
function assertWatchVariable(disposables: Pick<DisposableStore, "add">, watchExpressionsRenderer: WatchExpressionsRenderer, displayType: boolean) {
const session = new MockSession();
const thread = new Thread(session, 'mockthread', 1);
const range = {
startLineNumber: 1,
startColumn: 1,
endLineNumber: undefined!,
endColumn: undefined!
};
const stackFrame = new StackFrame(thread, 1, null!, 'app.js', 'normal', range, 0, true);
const scope = new Scope(stackFrame, 1, 'local', 1, false, 10, 10);
const node = {
element: new Variable(session, 1, scope, 2, 'foo', 'bar.foo', undefined, 0, 0, undefined, {}, 'string'),
depth: 0,
visibleChildrenCount: 1,
visibleChildIndex: -1,
collapsible: false,
collapsed: false,
visible: true,
filterData: undefined,
children: []
};
const expression = $('.');
const name = $('.');
const type = $('.');
const value = $('.');
const label = disposables.add(new HighlightedLabel(name));
const lazyButton = $('.');
const inputBoxContainer = $('.');
const elementDisposable = disposables.add(new DisposableStore());
const templateDisposable = disposables.add(new DisposableStore());
const currentElement = undefined;
const data = {
expression,
name,
type,
value,
label,
lazyButton,
inputBoxContainer,
elementDisposable,
templateDisposable,
currentElement
};
watchExpressionsRenderer.renderElement(node, 0, data);
assert.strictEqual(value.textContent, '');
assert.strictEqual(label.element.textContent, displayType ? 'foo: ' : 'foo =');
node.element.value = 'xpto';
watchExpressionsRenderer.renderElement(node, 0, data);
assert.strictEqual(value.textContent, 'xpto');
assert.strictEqual(type.textContent, displayType ? 'string =' : '');
assert.strictEqual(label.element.textContent, displayType ? 'foo: ' : 'foo =');
}
suite('Debug - Watch Debug View', () => {
const disposables = ensureNoDisposablesAreLeakedInTestSuite();
let watchExpressionsRenderer: WatchExpressionsRenderer;
let instantiationService: TestInstantiationService;
let configurationService: TestConfigurationService;
setup(() => {
instantiationService = workbenchInstantiationService(undefined, disposables);
const debugService = new MockDebugService();
instantiationService.stub(IHoverService, NullHoverService);
debugService.getViewModel = () => <IViewModel>{ focusedStackFrame: undefined, getSelectedExpression: () => undefined };
debugService.getViewModel().getSelectedExpression = () => undefined;
instantiationService.stub(IDebugService, debugService);
});
test('watch expressions with display type', () => {
configurationService = new TestConfigurationService({
debug: {
showVariableTypes: true
}
});
instantiationService.stub(IConfigurationService, configurationService);
watchExpressionsRenderer = instantiationService.createInstance(WatchExpressionsRenderer);
assertWatchVariable(disposables, watchExpressionsRenderer, true);
});
test('watch expressions', () => {
configurationService = new TestConfigurationService({
debug: {
showVariableTypes: false
}
});
instantiationService.stub(IConfigurationService, configurationService);
watchExpressionsRenderer = instantiationService.createInstance(WatchExpressionsRenderer);
assertWatchVariable(disposables, watchExpressionsRenderer, false);
});
});