Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

debug: show output test when present with variablesReference #172880

Merged
merged 1 commit into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/vs/workbench/api/browser/mainThreadDebugService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
public $appendDebugConsole(value: string): void {
// Use warning as severity to get the orange color for messages coming from the debug extension
const session = this.debugService.getViewModel().focusedSession;
session?.appendToRepl(value, severity.Warning);
session?.appendToRepl({ output: value, sev: severity.Warning });
}

public $acceptDAMessage(handle: number, message: DebugProtocol.ProtocolMessage) {
Expand Down
13 changes: 7 additions & 6 deletions src/vs/workbench/contrib/debug/browser/baseDebugView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export interface IExpressionTemplateData {
currentElement: IExpression | undefined;
}

export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpression, FuzzyScore, IExpressionTemplateData> {
export abstract class AbstractExpressionsRenderer<T = IExpression> implements ITreeRenderer<T, FuzzyScore, IExpressionTemplateData> {

constructor(
@IDebugService protected debugService: IDebugService,
Expand Down Expand Up @@ -185,10 +185,11 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
return template;
}

renderElement(node: ITreeNode<IExpression, FuzzyScore>, index: number, data: IExpressionTemplateData): void {
const { element } = node;
public abstract renderElement(node: ITreeNode<T, FuzzyScore>, index: number, data: IExpressionTemplateData): void;

protected renderExpressionElement(element: IExpression, node: ITreeNode<T, FuzzyScore>, data: IExpressionTemplateData): void {
data.currentElement = element;
this.renderExpression(element, data, createMatches(node.filterData));
this.renderExpression(node.element, data, createMatches(node.filterData));
if (data.actionBar) {
this.renderActionBar!(data.actionBar, element, data);
}
Expand Down Expand Up @@ -252,12 +253,12 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
});
}

protected abstract renderExpression(expression: IExpression, data: IExpressionTemplateData, highlights: IHighlight[]): void;
protected abstract renderExpression(expression: T, data: IExpressionTemplateData, highlights: IHighlight[]): void;
protected abstract getInputBoxOptions(expression: IExpression, settingValue: boolean): IInputBoxOptions | undefined;

protected renderActionBar?(actionBar: ActionBar, expression: IExpression, data: IExpressionTemplateData): void;

disposeElement(node: ITreeNode<IExpression, FuzzyScore>, index: number, templateData: IExpressionTemplateData): void {
disposeElement(node: ITreeNode<T, FuzzyScore>, index: number, templateData: IExpressionTemplateData): void {
dispose(templateData.elementDisposable);
templateData.elementDisposable = [];
}
Expand Down
21 changes: 14 additions & 7 deletions src/vs/workbench/contrib/debug/browser/debugSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'
import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { ViewContainerLocation } from 'vs/workbench/common/views';
import { RawDebugSession } from 'vs/workbench/contrib/debug/browser/rawDebugSession';
import { AdapterEndEvent, IBreakpoint, IConfig, IDataBreakpoint, IDebugConfiguration, IDebugger, IDebugService, IDebugSession, IDebugSessionOptions, IExceptionBreakpoint, IExceptionInfo, IExpression, IFunctionBreakpoint, IInstructionBreakpoint, IMemoryRegion, IRawModelUpdate, IRawStoppedDetails, IReplElement, IReplElementSource, IStackFrame, IThread, LoadedSourceEvent, State, VIEWLET_ID } from 'vs/workbench/contrib/debug/common/debug';
import { AdapterEndEvent, IBreakpoint, IConfig, IDataBreakpoint, IDebugConfiguration, IDebugger, IDebugService, IDebugSession, IDebugSessionOptions, IExceptionBreakpoint, IExceptionInfo, IFunctionBreakpoint, IInstructionBreakpoint, IMemoryRegion, IRawModelUpdate, IRawStoppedDetails, IReplElement, IStackFrame, IThread, LoadedSourceEvent, State, VIEWLET_ID } from 'vs/workbench/contrib/debug/common/debug';
import { DebugCompoundRoot } from 'vs/workbench/contrib/debug/common/debugCompoundRoot';
import { DebugModel, ExpressionContainer, MemoryRegion, Thread } from 'vs/workbench/contrib/debug/common/debugModel';
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
import { filterExceptionsFromTelemetry } from 'vs/workbench/contrib/debug/common/debugUtils';
import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
import { INewReplElementData, ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
Expand Down Expand Up @@ -1085,10 +1085,17 @@ export class DebugSession implements IDebugSession {
// see https://github.com/microsoft/vscode/issues/126967#issuecomment-874954269
outputQueue.queue(async () => {
const resolved = await children;
// For single logged variables, try to use the output if we can so
// present a better (i.e. ANSI-aware) representation of the output
if (resolved.length === 1) {
this.appendToRepl({ output: event.body.output, expression: resolved[0], sev: Severity.Info, source }, event.body.category === 'important');
return;
}

resolved.forEach((child) => {
// Since we can not display multiple trees in a row, we are displaying these variables one after the other (ignoring their names)
(<any>child).name = null;
this.appendToRepl(child, Severity.Info, event.body.category === 'important', source);
this.appendToRepl({ output: '', expression: child, sev: Severity.Info, source }, event.body.category === 'important');
});
});
return;
Expand Down Expand Up @@ -1137,7 +1144,7 @@ export class DebugSession implements IDebugSession {
}

if (typeof event.body.output === 'string') {
this.appendToRepl(event.body.output, outputSeverity, event.body.category === 'important', source);
this.appendToRepl({ output: event.body.output, sev: outputSeverity, source }, event.body.category === 'important');
}
});
}));
Expand Down Expand Up @@ -1330,10 +1337,10 @@ export class DebugSession implements IDebugSession {
this.debugService.getViewModel().updateViews();
}

appendToRepl(data: string | IExpression, severity: Severity, isImportant?: boolean, source?: IReplElementSource): void {
this.repl.appendToRepl(this, data, severity, source);
appendToRepl(data: INewReplElementData, isImportant?: boolean): void {
this.repl.appendToRepl(this, data);
if (isImportant) {
this.notificationService.notify({ message: data.toString(), severity: severity, source: this.name });
this.notificationService.notify({ message: data.toString(), severity: data.sev, source: this.name });
}
}
}
4 changes: 2 additions & 2 deletions src/vs/workbench/contrib/debug/browser/repl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ import { FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/d
import { debugConsoleClearAll, debugConsoleEvaluationPrompt } from 'vs/workbench/contrib/debug/browser/debugIcons';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { ReplFilter } from 'vs/workbench/contrib/debug/browser/replFilter';
import { ReplAccessibilityProvider, ReplDataSource, ReplDelegate, ReplEvaluationInputsRenderer, ReplEvaluationResultsRenderer, ReplGroupRenderer, ReplRawObjectsRenderer, ReplSimpleElementsRenderer, ReplVariablesRenderer } from 'vs/workbench/contrib/debug/browser/replViewer';
import { ReplAccessibilityProvider, ReplDataSource, ReplDelegate, ReplEvaluationInputsRenderer, ReplEvaluationResultsRenderer, ReplGroupRenderer, ReplRawObjectsRenderer, ReplOutputElementRenderer, ReplVariablesRenderer } from 'vs/workbench/contrib/debug/browser/replViewer';
import { CONTEXT_DEBUG_STATE, CONTEXT_IN_DEBUG_REPL, CONTEXT_MULTI_SESSION_REPL, DEBUG_SCHEME, getStateLabel, IDebugConfiguration, IDebugService, IDebugSession, IReplConfiguration, IReplElement, IReplOptions, REPL_VIEW_ID, State } from 'vs/workbench/contrib/debug/common/debug';
import { Variable } from 'vs/workbench/contrib/debug/common/debugModel';
import { ReplGroup } from 'vs/workbench/contrib/debug/common/replModel';
Expand Down Expand Up @@ -576,7 +576,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
this.replDelegate,
[
this.instantiationService.createInstance(ReplVariablesRenderer, linkDetector),
this.instantiationService.createInstance(ReplSimpleElementsRenderer, linkDetector),
this.instantiationService.createInstance(ReplOutputElementRenderer, linkDetector),
new ReplEvaluationInputsRenderer(),
this.instantiationService.createInstance(ReplGroupRenderer, linkDetector),
new ReplEvaluationResultsRenderer(linkDetector),
Expand Down
72 changes: 38 additions & 34 deletions src/vs/workbench/contrib/debug/browser/replViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ import { AbstractExpressionsRenderer, IExpressionTemplateData, IInputBoxOptions,
import { handleANSIOutput } from 'vs/workbench/contrib/debug/browser/debugANSIHandling';
import { debugConsoleEvaluationInput } from 'vs/workbench/contrib/debug/browser/debugIcons';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { IDebugConfiguration, IDebugService, IDebugSession, IExpression, IExpressionContainer, IReplElement, IReplElementSource, IReplOptions } from 'vs/workbench/contrib/debug/common/debug';
import { IDebugConfiguration, IDebugService, IDebugSession, IExpression, IExpressionContainer, INestingReplElement, IReplElement, IReplElementSource, IReplOptions } from 'vs/workbench/contrib/debug/common/debug';
import { Variable } from 'vs/workbench/contrib/debug/common/debugModel';
import { RawObjectReplElement, ReplEvaluationInput, ReplEvaluationResult, ReplGroup, SimpleReplElement } from 'vs/workbench/contrib/debug/common/replModel';
import { RawObjectReplElement, ReplEvaluationInput, ReplEvaluationResult, ReplGroup, ReplOutputElement, ReplVariableElement } from 'vs/workbench/contrib/debug/common/replModel';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';

const $ = dom.$;
Expand All @@ -43,7 +43,7 @@ interface IReplEvaluationResultTemplateData {
value: HTMLElement;
}

interface ISimpleReplElementTemplateData {
interface IOutputReplElementTemplateData {
container: HTMLElement;
count: CountBadge;
countContainer: HTMLElement;
Expand Down Expand Up @@ -145,8 +145,8 @@ export class ReplEvaluationResultsRenderer implements ITreeRenderer<ReplEvaluati
}
}

export class ReplSimpleElementsRenderer implements ITreeRenderer<SimpleReplElement, FuzzyScore, ISimpleReplElementTemplateData> {
static readonly ID = 'simpleReplElement';
export class ReplOutputElementRenderer implements ITreeRenderer<ReplOutputElement, FuzzyScore, IOutputReplElementTemplateData> {
static readonly ID = 'outputReplElement';

constructor(
private readonly linkDetector: LinkDetector,
Expand All @@ -156,11 +156,11 @@ export class ReplSimpleElementsRenderer implements ITreeRenderer<SimpleReplEleme
) { }

get templateId(): string {
return ReplSimpleElementsRenderer.ID;
return ReplOutputElementRenderer.ID;
}

renderTemplate(container: HTMLElement): ISimpleReplElementTemplateData {
const data: ISimpleReplElementTemplateData = Object.create(null);
renderTemplate(container: HTMLElement): IOutputReplElementTemplateData {
const data: IOutputReplElementTemplateData = Object.create(null);
container.classList.add('output');
const expression = dom.append(container, $('.output.expression.value-and-source'));

Expand All @@ -187,23 +187,23 @@ export class ReplSimpleElementsRenderer implements ITreeRenderer<SimpleReplEleme
return data;
}

renderElement({ element }: ITreeNode<SimpleReplElement, FuzzyScore>, index: number, templateData: ISimpleReplElementTemplateData): void {
renderElement({ element }: ITreeNode<ReplOutputElement, FuzzyScore>, index: number, templateData: IOutputReplElementTemplateData): void {
this.setElementCount(element, templateData);
templateData.elementListener = element.onDidChangeCount(() => this.setElementCount(element, templateData));
// value
dom.clearNode(templateData.value);
// Reset classes to clear ansi decorations since templates are reused
templateData.value.className = 'value';
const result = handleANSIOutput(element.value, this.linkDetector, this.themeService, element.session.root);
templateData.value.appendChild(result);

templateData.value.appendChild(handleANSIOutput(element.value, this.linkDetector, this.themeService, element.session.root));

templateData.value.classList.add((element.severity === severity.Warning) ? 'warn' : (element.severity === severity.Error) ? 'error' : (element.severity === severity.Ignore) ? 'ignore' : 'info');
templateData.source.textContent = element.sourceData ? `${basename(element.sourceData.source.name)}:${element.sourceData.lineNumber}` : '';
templateData.source.title = element.sourceData ? `${this.labelService.getUriLabel(element.sourceData.source.uri)}:${element.sourceData.lineNumber}` : '';
templateData.getReplElementSource = () => element.sourceData;
}

private setElementCount(element: SimpleReplElement, templateData: ISimpleReplElementTemplateData): void {
private setElementCount(element: ReplOutputElement, templateData: IOutputReplElementTemplateData): void {
if (element.count >= 2) {
templateData.count.setCount(element.count);
templateData.countContainer.hidden = false;
Expand All @@ -212,16 +212,16 @@ export class ReplSimpleElementsRenderer implements ITreeRenderer<SimpleReplEleme
}
}

disposeTemplate(templateData: ISimpleReplElementTemplateData): void {
disposeTemplate(templateData: IOutputReplElementTemplateData): void {
dispose(templateData.toDispose);
}

disposeElement(_element: ITreeNode<SimpleReplElement, FuzzyScore>, _index: number, templateData: ISimpleReplElementTemplateData): void {
disposeElement(_element: ITreeNode<ReplOutputElement, FuzzyScore>, _index: number, templateData: IOutputReplElementTemplateData): void {
templateData.elementListener.dispose();
}
}

export class ReplVariablesRenderer extends AbstractExpressionsRenderer {
export class ReplVariablesRenderer extends AbstractExpressionsRenderer<IExpression | ReplVariableElement> {

static readonly ID = 'replVariable';

Expand All @@ -237,9 +237,20 @@ export class ReplVariablesRenderer extends AbstractExpressionsRenderer {
super(debugService, contextViewService);
}

protected renderExpression(expression: IExpression, data: IExpressionTemplateData, highlights: IHighlight[]): void {
renderVariable(expression as Variable, data, true, highlights, this.linkDetector);
data.expression.classList.toggle('nested-variable', isNestedVariable(expression));
public renderElement(node: ITreeNode<IExpression | ReplVariableElement, FuzzyScore>, _index: number, data: IExpressionTemplateData): void {
const element = node.element;
super.renderExpressionElement(element instanceof ReplVariableElement ? element.expr : element, node, data);
}

protected renderExpression(expression: IExpression | ReplVariableElement, data: IExpressionTemplateData, highlights: IHighlight[]): void {
const isReplVariable = expression instanceof ReplVariableElement;
if (isReplVariable || !expression.name) {
renderExpressionValue(isReplVariable ? expression.expr : expression, data.value, { showHover: false, colorize: true, linkDetector: this.linkDetector });
data.expression.classList.remove('nested-variable');
} else {
renderVariable(expression as Variable, data, true, highlights, this.linkDetector);
data.expression.classList.toggle('nested-variable', isNestedVariable(expression));
}
}

protected getInputBoxOptions(expression: IExpression): IInputBoxOptions | undefined {
Expand Down Expand Up @@ -324,7 +335,7 @@ export class ReplDelegate extends CachedListVirtualDelegate<IReplElement> {
const value = element.value;
const valueRows = countNumberOfLines(value)
+ (ignoreValueLength ? 0 : Math.floor(value.length / 70)) // Make an estimate for wrapping
+ (element instanceof SimpleReplElement ? 0 : 1); // A SimpleReplElement ends in \n if it's a complete line
+ (element instanceof ReplOutputElement ? 0 : 1); // A SimpleReplElement ends in \n if it's a complete line

return Math.max(valueRows, 1) * lineHeight;
}
Expand All @@ -333,18 +344,17 @@ export class ReplDelegate extends CachedListVirtualDelegate<IReplElement> {
}

getTemplateId(element: IReplElement): string {
if (element instanceof Variable && element.name) {
if (element instanceof Variable || element instanceof ReplVariableElement) {
return ReplVariablesRenderer.ID;
}
if (element instanceof ReplEvaluationResult || (element instanceof Variable && !element.name)) {
// Variable with no name is a top level variable which should be rendered like a repl element #17404
if (element instanceof ReplEvaluationResult) {
return ReplEvaluationResultsRenderer.ID;
}
if (element instanceof ReplEvaluationInput) {
return ReplEvaluationInputsRenderer.ID;
}
if (element instanceof SimpleReplElement) {
return ReplSimpleElementsRenderer.ID;
if (element instanceof ReplOutputElement) {
return ReplOutputElementRenderer.ID;
}
if (element instanceof ReplGroup) {
return ReplGroupRenderer.ID;
Expand Down Expand Up @@ -374,21 +384,15 @@ export class ReplDataSource implements IAsyncDataSource<IDebugSession, IReplElem
return true;
}

return !!(<IExpressionContainer | ReplGroup>element).hasChildren;
return !!(<IExpressionContainer | INestingReplElement>element).hasChildren;
}

getChildren(element: IReplElement | IDebugSession): Promise<IReplElement[]> {
if (isDebugSession(element)) {
return Promise.resolve(element.getReplElements());
}
if (element instanceof RawObjectReplElement) {
return element.getChildren();
}
if (element instanceof ReplGroup) {
return Promise.resolve(element.getChildren());
}

return (<IExpression>element).getChildren();
return Promise.resolve((<IExpression | INestingReplElement>element).getChildren());
}
}

Expand All @@ -402,8 +406,8 @@ export class ReplAccessibilityProvider implements IListAccessibilityProvider<IRe
if (element instanceof Variable) {
return localize('replVariableAriaLabel', "Variable {0}, value {1}", element.name, element.value);
}
if (element instanceof SimpleReplElement || element instanceof ReplEvaluationInput || element instanceof ReplEvaluationResult) {
return element.value + (element instanceof SimpleReplElement && element.count > 1 ? localize({ key: 'occurred', comment: ['Front will the value of the debug console element. Placeholder will be replaced by a number which represents occurrance count.'] },
if (element instanceof ReplOutputElement || element instanceof ReplEvaluationInput || element instanceof ReplEvaluationResult) {
return element.value + (element instanceof ReplOutputElement && element.count > 1 ? localize({ key: 'occurred', comment: ['Front will the value of the debug console element. Placeholder will be replaced by a number which represents occurrance count.'] },
", occurred {0} times", element.count) : '');
}
if (element instanceof RawObjectReplElement) {
Expand Down
4 changes: 4 additions & 0 deletions src/vs/workbench/contrib/debug/browser/variablesView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,10 @@ export class VariablesRenderer extends AbstractExpressionsRenderer {
renderVariable(expression as Variable, data, true, highlights, this.linkDetector);
}

public override renderElement(node: ITreeNode<IExpression, FuzzyScore>, index: number, data: IExpressionTemplateData): void {
super.renderExpressionElement(node.element, node, data);
}

protected getInputBoxOptions(expression: IExpression): IInputBoxOptions {
const variable = <Variable>expression;
return {
Expand Down
Loading