Skip to content

Commit 3bcaff8

Browse files
committed
Separate REPL evaluation from it's result; fixes microsoft#79196
REPL now has two elements: one for the evaluation text added immediately (ReplEvaluationInput), and another for the evaluation result once available (ReplEvaluationResult).
1 parent 332c4d9 commit 3bcaff8

9 files changed

Lines changed: 205 additions & 146 deletions

File tree

src/vs/workbench/contrib/debug/browser/baseDebugView.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as dom from 'vs/base/browser/dom';
7-
import { IExpression, IDebugService } from 'vs/workbench/contrib/debug/common/debug';
7+
import { IExpression, IDebugService, IExpressionContainer } from 'vs/workbench/contrib/debug/common/debug';
88
import { Expression, Variable, ExpressionContainer } from 'vs/workbench/contrib/debug/common/debugModel';
99
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
1010
import { IInputValidationOptions, InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
@@ -50,7 +50,7 @@ export function replaceWhitespace(value: string): string {
5050
return value.replace(/[\n\r\t]/g, char => map[char]);
5151
}
5252

53-
export function renderExpressionValue(expressionOrValue: IExpression | string, container: HTMLElement, options: IRenderValueOptions): void {
53+
export function renderExpressionValue(expressionOrValue: IExpressionContainer | string, container: HTMLElement, options: IRenderValueOptions): void {
5454
let value = typeof expressionOrValue === 'string' ? expressionOrValue : expressionOrValue.value;
5555

5656
// remove stale classes
@@ -221,4 +221,4 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer<IExpr
221221
disposeTemplate(templateData: IExpressionTemplateData): void {
222222
dispose(templateData.toDispose);
223223
}
224-
}
224+
}

src/vs/workbench/contrib/debug/browser/debugSession.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,9 @@ export class DebugSession implements IDebugSession {
921921
}
922922

923923
async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void> {
924-
await this.repl.addReplExpression(stackFrame, name);
924+
const expressionEvaluated = this.repl.addReplExpression(stackFrame, name);
925+
this._onDidChangeREPLElements.fire();
926+
await expressionEvaluated;
925927
this._onDidChangeREPLElements.fire();
926928
// Evaluate all watch expressions and fetch variables again since repl evaluation might have changed some.
927929
variableSetEmitter.fire();

src/vs/workbench/contrib/debug/browser/media/repl.css

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@
4848
cursor: text;
4949
}
5050

51-
.repl .repl-tree .output.expression > .value {
51+
.repl .repl-tree .output.expression > .value,
52+
.repl .repl-tree .evaluation-result.expression > .value {
5253
margin-left: 0px;
5354
}
5455

55-
.repl .repl-tree .output.expression > .annotation {
56+
.repl .repl-tree .output.expression > .annotation,
57+
.repl .repl-tree .evaluation-result.expression > .annotation {
5658
font-size: inherit;
5759
padding-left: 6px;
5860
}
@@ -67,7 +69,7 @@
6769
}
6870

6971
/* Only show 'stale expansion' info when the element gets expanded. */
70-
.repl .repl-tree .input-output-pair > .output > .annotation::before {
72+
.repl .repl-tree .evaluation-result > .annotation::before {
7173
content: '';
7274
}
7375

@@ -134,7 +136,8 @@
134136
.monaco-workbench .repl .repl-tree .output.expression .code-underline { text-decoration: underline; }
135137

136138
/* Links */
137-
.monaco-workbench .repl .repl-tree .output.expression a {
139+
.monaco-workbench .repl .repl-tree .output.expression a,
140+
.monaco-workbench .repl .repl-tree .evaluation-result.expression a {
138141
text-decoration: underline;
139142
cursor: pointer;
140143
}

src/vs/workbench/contrib/debug/browser/repl.ts

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ import { CompletionContext, CompletionList, CompletionProviderRegistry } from 'v
4444
import { first } from 'vs/base/common/arrays';
4545
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
4646
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
47-
import { Variable, Expression, SimpleReplElement, RawObjectReplElement } from 'vs/workbench/contrib/debug/common/debugModel';
47+
import { Variable } from 'vs/workbench/contrib/debug/common/debugModel';
48+
import { SimpleReplElement, RawObjectReplElement, ReplEvaluationInput, ReplEvaluationResult } from 'vs/workbench/contrib/debug/common/replModel';
4849
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
4950
import { ITreeRenderer, ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
5051
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
@@ -412,7 +413,8 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
412413
[
413414
this.instantiationService.createInstance(VariablesRenderer),
414415
this.instantiationService.createInstance(ReplSimpleElementsRenderer),
415-
new ReplExpressionsRenderer(),
416+
new ReplEvaluationInputsRenderer(),
417+
new ReplEvaluationResultsRenderer(),
416418
new ReplRawObjectsRenderer()
417419
],
418420
// https://github.com/microsoft/TypeScript/issues/32526
@@ -568,12 +570,13 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati
568570

569571
// Repl tree
570572

571-
interface IExpressionTemplateData {
572-
input: HTMLElement;
573-
output: HTMLElement;
573+
interface IReplEvaluationInputTemplateData {
574+
label: HighlightedLabel;
575+
}
576+
577+
interface IReplEvaluationResultTemplateData {
574578
value: HTMLElement;
575579
annotation: HTMLElement;
576-
label: HighlightedLabel;
577580
}
578581

579582
interface ISimpleReplElementTemplateData {
@@ -593,27 +596,46 @@ interface IRawObjectReplTemplateData {
593596
label: HighlightedLabel;
594597
}
595598

596-
class ReplExpressionsRenderer implements ITreeRenderer<Expression, FuzzyScore, IExpressionTemplateData> {
597-
static readonly ID = 'expressionRepl';
599+
class ReplEvaluationInputsRenderer implements ITreeRenderer<ReplEvaluationInput, FuzzyScore, IReplEvaluationInputTemplateData> {
600+
static readonly ID = 'replEvaluationInput';
598601

599602
get templateId(): string {
600-
return ReplExpressionsRenderer.ID;
603+
return ReplEvaluationInputsRenderer.ID;
601604
}
602605

603-
renderTemplate(container: HTMLElement): IExpressionTemplateData {
604-
dom.addClass(container, 'input-output-pair');
605-
const input = dom.append(container, $('.input.expression'));
606+
renderTemplate(container: HTMLElement): IReplEvaluationInputTemplateData {
607+
const input = dom.append(container, $('.expression'));
606608
const label = new HighlightedLabel(input, false);
607-
const output = dom.append(container, $('.output.expression'));
609+
return { label };
610+
}
611+
612+
renderElement(element: ITreeNode<ReplEvaluationInput, FuzzyScore>, index: number, templateData: IReplEvaluationInputTemplateData): void {
613+
const evaluation = element.element;
614+
templateData.label.set(evaluation.value, createMatches(element.filterData));
615+
}
616+
617+
disposeTemplate(templateData: IReplEvaluationInputTemplateData): void {
618+
// noop
619+
}
620+
}
621+
622+
class ReplEvaluationResultsRenderer implements ITreeRenderer<ReplEvaluationResult, FuzzyScore, IReplEvaluationResultTemplateData> {
623+
static readonly ID = 'replEvaluationResult';
624+
625+
get templateId(): string {
626+
return ReplEvaluationResultsRenderer.ID;
627+
}
628+
629+
renderTemplate(container: HTMLElement): IReplEvaluationResultTemplateData {
630+
const output = dom.append(container, $('.evaluation-result.expression'));
608631
const value = dom.append(output, $('span.value'));
609632
const annotation = dom.append(output, $('span'));
610633

611-
return { input, label, output, value, annotation };
634+
return { value, annotation };
612635
}
613636

614-
renderElement(element: ITreeNode<Expression, FuzzyScore>, index: number, templateData: IExpressionTemplateData): void {
637+
renderElement(element: ITreeNode<ReplEvaluationResult, FuzzyScore>, index: number, templateData: IReplEvaluationResultTemplateData): void {
615638
const expression = element.element;
616-
templateData.label.set(expression.name, createMatches(element.filterData));
617639
renderExpressionValue(expression, templateData.value, {
618640
preserveWhitespace: !expression.hasChildren,
619641
showHover: false,
@@ -625,7 +647,7 @@ class ReplExpressionsRenderer implements ITreeRenderer<Expression, FuzzyScore, I
625647
}
626648
}
627649

628-
disposeTemplate(templateData: IExpressionTemplateData): void {
650+
disposeTemplate(templateData: IReplEvaluationResultTemplateData): void {
629651
// noop
630652
}
631653
}
@@ -757,24 +779,23 @@ class ReplDelegate implements IListVirtualDelegate<IReplElement> {
757779
const rowHeight = Math.ceil(1.4 * fontSize);
758780
const wordWrap = config.console.wordWrap;
759781
if (!wordWrap) {
760-
return element instanceof Expression ? 2 * rowHeight : rowHeight;
782+
return rowHeight;
761783
}
762784

763785
// In order to keep scroll position we need to give a good approximation to the tree
764786
// For every 150 characters increase the number of lines needed
765-
if (element instanceof Expression) {
766-
let { name, value } = element;
767-
let nameRows = countNumberOfLines(name) + Math.floor(name.length / 150);
787+
if (element instanceof ReplEvaluationResult) {
788+
let value = element.value;
768789

769790
if (element.hasChildren) {
770-
return (nameRows + 1) * rowHeight;
791+
return rowHeight;
771792
}
772793

773794
let valueRows = value ? (countNumberOfLines(value) + Math.floor(value.length / 150)) : 0;
774-
return rowHeight * (nameRows + valueRows);
795+
return rowHeight * valueRows;
775796
}
776797

777-
if (element instanceof SimpleReplElement) {
798+
if (element instanceof SimpleReplElement || element instanceof ReplEvaluationInput) {
778799
let value = element.value;
779800
let valueRows = countNumberOfLines(value) + Math.floor(value.length / 150);
780801

@@ -788,8 +809,11 @@ class ReplDelegate implements IListVirtualDelegate<IReplElement> {
788809
if (element instanceof Variable && element.name) {
789810
return VariablesRenderer.ID;
790811
}
791-
if (element instanceof Expression) {
792-
return ReplExpressionsRenderer.ID;
812+
if (element instanceof ReplEvaluationResult) {
813+
return ReplEvaluationResultsRenderer.ID;
814+
}
815+
if (element instanceof ReplEvaluationInput) {
816+
return ReplEvaluationInputsRenderer.ID;
793817
}
794818
if (element instanceof SimpleReplElement || (element instanceof Variable && !element.name)) {
795819
// Variable with no name is a top level variable which should be rendered like a repl element #17404
@@ -836,10 +860,7 @@ class ReplAccessibilityProvider implements IAccessibilityProvider<IReplElement>
836860
if (element instanceof Variable) {
837861
return nls.localize('replVariableAriaLabel', "Variable {0} has value {1}, read eval print loop, debug", element.name, element.value);
838862
}
839-
if (element instanceof Expression) {
840-
return nls.localize('replExpressionAriaLabel', "Expression {0} has value {1}, read eval print loop, debug", element.name, element.value);
841-
}
842-
if (element instanceof SimpleReplElement) {
863+
if (element instanceof SimpleReplElement || element instanceof ReplEvaluationInput || element instanceof ReplEvaluationResult) {
843864
return nls.localize('replValueOutputAriaLabel', "{0}, read eval print loop, debug", element.value);
844865
}
845866
if (element instanceof RawObjectReplElement) {

src/vs/workbench/contrib/debug/common/debug.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,13 @@ export interface IExpressionContainer extends ITreeElement {
104104
readonly hasChildren: boolean;
105105
getChildren(): Promise<IExpression[]>;
106106
readonly reference?: number;
107+
readonly value: string;
108+
readonly type?: string;
109+
valueChanged?: boolean;
107110
}
108111

109-
export interface IExpression extends IReplElement, IExpressionContainer {
112+
export interface IExpression extends IExpressionContainer {
110113
name: string;
111-
readonly value: string;
112-
valueChanged?: boolean;
113-
readonly type?: string;
114114
}
115115

116116
export interface IDebugger {

0 commit comments

Comments
 (0)