Skip to content

Commit

Permalink
debug: collapse identical lines in the debug console
Browse files Browse the repository at this point in the history
fixes #104162
  • Loading branch information
isidorn authored and meganrogge committed Nov 18, 2020
1 parent 4a37670 commit ef1d69b
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 7 deletions.
9 changes: 9 additions & 0 deletions src/vs/workbench/contrib/debug/browser/media/repl.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@
margin-right: 4px;
}

.monaco-workbench .repl .repl-tree .output.expression.value-and-source .count-badge-wrapper {
margin-right: 2px;
}

/* Allow the badge to be a bit shorter so it does not look cut off */
.monaco-workbench .repl .repl-tree .output.expression.value-and-source .count-badge-wrapper .monaco-count-badge {
min-height: 16px;
}

.monaco-workbench .repl .repl-tree .monaco-tl-contents .arrow {
position:absolute;
left: 2px;
Expand Down
23 changes: 23 additions & 0 deletions src/vs/workbench/contrib/debug/browser/replViewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { IReplElementSource, IDebugService, IExpression, IReplElement, IDebugCon
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { localize } from 'vs/nls';
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
import { attachBadgeStyler } from 'vs/platform/theme/common/styler';

const $ = dom.$;

Expand All @@ -40,10 +42,13 @@ interface IReplEvaluationResultTemplateData {

interface ISimpleReplElementTemplateData {
container: HTMLElement;
count: CountBadge;
countContainer: HTMLElement;
value: HTMLElement;
source: HTMLElement;
getReplElementSource(): IReplElementSource | undefined;
toDispose: IDisposable[];
elementListener: IDisposable;
}

interface IRawObjectReplTemplateData {
Expand Down Expand Up @@ -151,9 +156,12 @@ export class ReplSimpleElementsRenderer implements ITreeRenderer<SimpleReplEleme
const expression = dom.append(container, $('.output.expression.value-and-source'));

data.container = container;
data.countContainer = dom.append(expression, $('.count-badge-wrapper'));
data.count = new CountBadge(data.countContainer);
data.value = dom.append(expression, $('span.value'));
data.source = dom.append(expression, $('.source'));
data.toDispose = [];
data.toDispose.push(attachBadgeStyler(data.count, this.themeService));
data.toDispose.push(dom.addDisposableListener(data.source, 'click', e => {
e.preventDefault();
e.stopPropagation();
Expand All @@ -172,6 +180,8 @@ export class ReplSimpleElementsRenderer implements ITreeRenderer<SimpleReplEleme
}

renderElement({ element }: ITreeNode<SimpleReplElement, FuzzyScore>, index: number, templateData: ISimpleReplElementTemplateData): 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
Expand All @@ -185,9 +195,22 @@ export class ReplSimpleElementsRenderer implements ITreeRenderer<SimpleReplEleme
templateData.getReplElementSource = () => element.sourceData;
}

private setElementCount(element: SimpleReplElement, templateData: ISimpleReplElementTemplateData): void {
if (element.count >= 2) {
templateData.count.setCount(element.count);
templateData.countContainer.hidden = false;
} else {
templateData.countContainer.hidden = true;
}
}

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

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

export class ReplVariablesRenderer extends AbstractExpressionsRenderer {
Expand Down
39 changes: 32 additions & 7 deletions src/vs/workbench/contrib/debug/common/replModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ import { isString, isUndefinedOrNull, isObject } from 'vs/base/common/types';
import { basenameOrAuthority } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { Emitter } from 'vs/base/common/event';
import { Emitter, Event } from 'vs/base/common/event';

const MAX_REPL_LENGTH = 10000;
let topReplElementCounter = 0;

export class SimpleReplElement implements IReplElement {

private _count = 1;
private _onDidChangeCount = new Emitter<void>();

constructor(
public session: IDebugSession,
private id: string,
Expand All @@ -33,6 +37,19 @@ export class SimpleReplElement implements IReplElement {
getId(): string {
return this.id;
}

set count(value: number) {
this._count = value;
this._onDidChangeCount.fire();
}

get count(): number {
return this._count;
}

get onDidChangeCount(): Event<void> {
return this._onDidChangeCount.event;
}
}

export class RawObjectReplElement implements IExpression {
Expand Down Expand Up @@ -202,13 +219,21 @@ export class ReplModel {

if (typeof data === 'string') {
const previousElement = this.replElements.length ? this.replElements[this.replElements.length - 1] : undefined;
if (previousElement instanceof SimpleReplElement && previousElement.severity === sev && !previousElement.value.endsWith('\n') && !previousElement.value.endsWith('\r\n')) {
previousElement.value += data;
this._onDidChangeElements.fire();
} else {
const element = new SimpleReplElement(session, `topReplElement:${topReplElementCounter++}`, data, sev, source);
this.addReplElement(element);
if (previousElement instanceof SimpleReplElement && previousElement.severity === sev) {
if (previousElement.value === data) {
previousElement.count++;
// No need to fire an event, just the count updates and badge will adjust automatically
return;
}
if (!previousElement.value.endsWith('\n') && !previousElement.value.endsWith('\r\n')) {
previousElement.value += data;
this._onDidChangeElements.fire();
return;
}
}

const element = new SimpleReplElement(session, `topReplElement:${topReplElementCounter++}`, data, sev, source);
this.addReplElement(element);
} else {
// TODO@Isidor hack, we should introduce a new type which is an output that can fetch children like an expression
(<any>data).severity = sev;
Expand Down

0 comments on commit ef1d69b

Please sign in to comment.