Skip to content

Commit

Permalink
debug: debug console group support
Browse files Browse the repository at this point in the history
fixes #34981
  • Loading branch information
isidorn committed Feb 20, 2020
1 parent cb9ba64 commit 454fad2
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 7 deletions.
11 changes: 11 additions & 0 deletions src/vs/workbench/contrib/debug/browser/debugSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,17 @@ export class DebugSession implements IDebugSession {
column: event.body.column ? event.body.column : 1,
source: this.getSource(event.body.source)
} : undefined;

if (event.body.group === 'start' || event.body.group === 'startCollapsed') {
const expanded = event.body.group === 'start';
this.repl.startGroup(event.body.output || '', expanded, source);
return;
}
if (event.body.group === 'end') {
this.repl.endGroup();
// Do not return, the end event can have additional output in it
}

if (event.body.variablesReference) {
const container = new ExpressionContainer(this, undefined, event.body.variablesReference, generateUuid());
outpuPromises.push(container.getChildren().then(async children => {
Expand Down
14 changes: 13 additions & 1 deletion src/vs/workbench/contrib/debug/browser/repl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,13 @@ import { RunOnceScheduler } from 'vs/base/common/async';
import { FuzzyScore } from 'vs/base/common/filters';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { PANEL_BACKGROUND } from 'vs/workbench/common/theme';
import { ReplDelegate, ReplVariablesRenderer, ReplSimpleElementsRenderer, ReplEvaluationInputsRenderer, ReplEvaluationResultsRenderer, ReplRawObjectsRenderer, ReplDataSource, ReplAccessibilityProvider } from 'vs/workbench/contrib/debug/browser/replViewer';
import { ReplDelegate, ReplVariablesRenderer, ReplSimpleElementsRenderer, ReplEvaluationInputsRenderer, ReplEvaluationResultsRenderer, ReplRawObjectsRenderer, ReplDataSource, ReplAccessibilityProvider, ReplGroupRenderer } from 'vs/workbench/contrib/debug/browser/replViewer';
import { localize } from 'vs/nls';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IViewsService, IViewDescriptorService } from 'vs/workbench/common/views';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { ReplGroup } from 'vs/workbench/contrib/debug/common/replModel';

const $ = dom.$;

Expand Down Expand Up @@ -425,6 +426,16 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {

const lastElementVisible = this.tree.scrollTop + this.tree.renderHeight >= this.tree.scrollHeight;
await this.tree.updateChildren();

const session = this.tree.getInput();
if (session) {
const replElements = session.getReplElements();
const lastElement = replElements.length ? replElements[replElements.length - 1] : undefined;
if (lastElement instanceof ReplGroup && lastElement.autoExpand) {
await this.tree.expand(lastElement);
}
}

if (lastElementVisible) {
// Only scroll if we were scrolled all the way down before tree refreshed #10486
revealLastElement(this.tree);
Expand Down Expand Up @@ -454,6 +465,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget {
this.instantiationService.createInstance(ReplVariablesRenderer, linkDetector),
this.instantiationService.createInstance(ReplSimpleElementsRenderer, linkDetector),
new ReplEvaluationInputsRenderer(),
new ReplGroupRenderer(),
new ReplEvaluationResultsRenderer(linkDetector),
new ReplRawObjectsRenderer(linkDetector),
],
Expand Down
40 changes: 38 additions & 2 deletions src/vs/workbench/contrib/debug/browser/replViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import severity from 'vs/base/common/severity';
import * as dom from 'vs/base/browser/dom';
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { Variable } from 'vs/workbench/contrib/debug/common/debugModel';
import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel';
import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplEvaluationResult, ReplGroup } from 'vs/workbench/contrib/debug/common/replModel';
import { CachedListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { ITreeRenderer, ITreeNode, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
Expand All @@ -30,6 +30,10 @@ interface IReplEvaluationInputTemplateData {
label: HighlightedLabel;
}

interface IReplGroupTemplateData {
label: HighlightedLabel;
}

interface IReplEvaluationResultTemplateData {
value: HTMLElement;
annotation: HTMLElement;
Expand Down Expand Up @@ -76,6 +80,29 @@ export class ReplEvaluationInputsRenderer implements ITreeRenderer<ReplEvaluatio
}
}

export class ReplGroupRenderer implements ITreeRenderer<ReplGroup, FuzzyScore, IReplGroupTemplateData> {
static readonly ID = 'replGroup';

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

renderTemplate(container: HTMLElement): IReplEvaluationInputTemplateData {
const input = dom.append(container, $('.expression'));
const label = new HighlightedLabel(input, false);
return { label };
}

renderElement(element: ITreeNode<ReplGroup, FuzzyScore>, _index: number, templateData: IReplGroupTemplateData): void {
const replGroup = element.element;
templateData.label.set(replGroup.name, createMatches(element.filterData));
}

disposeTemplate(_templateData: IReplEvaluationInputTemplateData): void {
// noop
}
}

export class ReplEvaluationResultsRenderer implements ITreeRenderer<ReplEvaluationResult, FuzzyScore, IReplEvaluationResultTemplateData> {
static readonly ID = 'replEvaluationResult';

Expand Down Expand Up @@ -296,6 +323,9 @@ export class ReplDelegate extends CachedListVirtualDelegate<IReplElement> {
// Variable with no name is a top level variable which should be rendered like a repl element #17404
return ReplSimpleElementsRenderer.ID;
}
if (element instanceof ReplGroup) {
return ReplGroupRenderer.ID;
}

return ReplRawObjectsRenderer.ID;
}
Expand All @@ -317,7 +347,7 @@ export class ReplDataSource implements IAsyncDataSource<IDebugSession, IReplElem
return true;
}

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

getChildren(element: IReplElement | IDebugSession): Promise<IReplElement[]> {
Expand All @@ -327,6 +357,9 @@ export class ReplDataSource implements IAsyncDataSource<IDebugSession, IReplElem
if (element instanceof RawObjectReplElement) {
return element.getChildren();
}
if (element instanceof ReplGroup) {
return Promise.resolve(element.getChildren());
}

return (<IExpression>element).getChildren();
}
Expand All @@ -343,6 +376,9 @@ export class ReplAccessibilityProvider implements IAccessibilityProvider<IReplEl
if (element instanceof RawObjectReplElement) {
return localize('replRawObjectAriaLabel', "Repl variable {0} has value {1}, read eval print loop, debug", element.name, element.value);
}
if (element instanceof ReplGroup) {
return localize('replGroup', "Repl group {0}, read eval print loop, debug", element.name);
}

return '';
}
Expand Down
78 changes: 75 additions & 3 deletions src/vs/workbench/contrib/debug/common/replModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,60 @@ export class ReplEvaluationResult extends ExpressionContainer implements IReplEl
}
}

export class ReplGroup implements IReplElement {

private children: IReplElement[] = [];
private id: string;
private ended = false;
static COUNTER = 0;

constructor(
public name: string,
public autoExpand: boolean,
public sourceData?: IReplElementSource
) {
this.id = `replGroup:${ReplGroup.COUNTER++}`;
}

get hasChildren() {
return true;
}

getId(): string {
return this.id;
}

toString(): string {
return this.name;
}

addChild(child: IReplElement): void {
const lastElement = this.children.length ? this.children[this.children.length - 1] : undefined;
if (lastElement instanceof ReplGroup && !lastElement.hasEnded) {
lastElement.addChild(child);
} else {
this.children.push(child);
}
}

getChildren(): IReplElement[] {
return this.children;
}

end(): void {
const lastElement = this.children.length ? this.children[this.children.length - 1] : undefined;
if (lastElement instanceof ReplGroup && !lastElement.hasEnded) {
lastElement.end();
} else {
this.ended = true;
}
}

get hasEnded(): boolean {
return this.ended;
}
}

export class ReplModel {
private replElements: IReplElement[] = [];
private readonly _onDidChangeElements = new Emitter<void>();
Expand Down Expand Up @@ -162,11 +216,29 @@ export class ReplModel {
}
}

startGroup(name: string, autoExpand: boolean, sourceData?: IReplElementSource): void {
const group = new ReplGroup(name, autoExpand, sourceData);
this.addReplElement(group);
}

endGroup(): void {
const lastElement = this.replElements[this.replElements.length - 1];
if (lastElement instanceof ReplGroup) {
lastElement.end();
}
}

private addReplElement(newElement: IReplElement): void {
this.replElements.push(newElement);
if (this.replElements.length > MAX_REPL_LENGTH) {
this.replElements.splice(0, this.replElements.length - MAX_REPL_LENGTH);
const lastElement = this.replElements.length ? this.replElements[this.replElements.length - 1] : undefined;
if (lastElement instanceof ReplGroup && !lastElement.hasEnded) {
lastElement.addChild(newElement);
} else {
this.replElements.push(newElement);
if (this.replElements.length > MAX_REPL_LENGTH) {
this.replElements.splice(0, this.replElements.length - MAX_REPL_LENGTH);
}
}

this._onDidChangeElements.fire();
}

Expand Down
40 changes: 39 additions & 1 deletion src/vs/workbench/contrib/debug/test/browser/repl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as assert from 'assert';
import severity from 'vs/base/common/severity';
import { DebugModel, StackFrame, Thread } from 'vs/workbench/contrib/debug/common/debugModel';
import { MockRawSession, MockDebugAdapter } from 'vs/workbench/contrib/debug/test/common/mockDebug';
import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplModel, ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel';
import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplModel, ReplEvaluationResult, ReplGroup } from 'vs/workbench/contrib/debug/common/replModel';
import { RawDebugSession } from 'vs/workbench/contrib/debug/browser/rawDebugSession';
import { timeout } from 'vs/base/common/async';
import { createMockSession } from 'vs/workbench/contrib/debug/test/browser/callStack.test';
Expand Down Expand Up @@ -151,4 +151,42 @@ suite('Debug - REPL', () => {
assert.equal((<ReplEvaluationResult>session.getReplElements()[4]).value, '=after.2');
assert.equal((<SimpleReplElement>session.getReplElements()[5]).value, 'after.2');
});

test('repl groups', async () => {
const session = createMockSession(model);
const repl = new ReplModel();

repl.appendToRepl(session, 'first global line', severity.Info);
repl.startGroup('group_1', true);
repl.appendToRepl(session, 'first line in group', severity.Info);
repl.appendToRepl(session, 'second line in group', severity.Info);
const elements = repl.getReplElements();
assert.equal(elements.length, 2);
const group = elements[1] as ReplGroup;
assert.equal(group.name, 'group_1');
assert.equal(group.autoExpand, true);
assert.equal(group.hasChildren, true);
assert.equal(group.hasEnded, false);

repl.startGroup('group_2', false);
repl.appendToRepl(session, 'first line in subgroup', severity.Info);
repl.appendToRepl(session, 'second line in subgroup', severity.Info);
const children = group.getChildren();
assert.equal(children.length, 3);
assert.equal((<SimpleReplElement>children[0]).value, 'first line in group');
assert.equal((<SimpleReplElement>children[1]).value, 'second line in group');
assert.equal((<ReplGroup>children[2]).name, 'group_2');
assert.equal((<ReplGroup>children[2]).hasEnded, false);
assert.equal((<ReplGroup>children[2]).getChildren().length, 2);
repl.endGroup();
assert.equal((<ReplGroup>children[2]).hasEnded, true);
repl.appendToRepl(session, 'third line in group', severity.Info);
assert.equal(group.getChildren().length, 4);
assert.equal(group.hasEnded, false);
repl.endGroup();
assert.equal(group.hasEnded, true);
repl.appendToRepl(session, 'second global line', severity.Info);
assert.equal(repl.getReplElements().length, 3);
assert.equal((<SimpleReplElement>repl.getReplElements()[2]).value, 'second global line');
});
});

0 comments on commit 454fad2

Please sign in to comment.