@theia/debug 1.67.0-next.59 → 1.67.0-next.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/console/debug-console-items.d.ts +13 -3
- package/lib/browser/console/debug-console-items.d.ts.map +1 -1
- package/lib/browser/console/debug-console-items.js +81 -20
- package/lib/browser/console/debug-console-items.js.map +1 -1
- package/lib/browser/console/debug-console-session.d.ts.map +1 -1
- package/lib/browser/console/debug-console-session.js +1 -0
- package/lib/browser/console/debug-console-session.js.map +1 -1
- package/lib/browser/debug-session-contribution.d.ts.map +1 -1
- package/lib/browser/debug-session-contribution.js +1 -1
- package/lib/browser/debug-session-contribution.js.map +1 -1
- package/lib/browser/debug-session-manager.d.ts +7 -0
- package/lib/browser/debug-session-manager.d.ts.map +1 -1
- package/lib/browser/debug-session-manager.js +3 -0
- package/lib/browser/debug-session-manager.js.map +1 -1
- package/lib/browser/debug-session.d.ts +7 -2
- package/lib/browser/debug-session.d.ts.map +1 -1
- package/lib/browser/debug-session.js +10 -1
- package/lib/browser/debug-session.js.map +1 -1
- package/lib/browser/editor/debug-hover-source.d.ts +1 -0
- package/lib/browser/editor/debug-hover-source.d.ts.map +1 -1
- package/lib/browser/editor/debug-hover-source.js +9 -0
- package/lib/browser/editor/debug-hover-source.js.map +1 -1
- package/lib/browser/editor/debug-inline-value-decorator.js +1 -1
- package/lib/browser/editor/debug-inline-value-decorator.js.map +1 -1
- package/lib/browser/model/debug-stack-frame.d.ts +2 -2
- package/lib/browser/model/debug-stack-frame.d.ts.map +1 -1
- package/lib/browser/model/debug-stack-frame.js +13 -5
- package/lib/browser/model/debug-stack-frame.js.map +1 -1
- package/lib/browser/model/debug-thread.d.ts +2 -2
- package/lib/browser/model/debug-thread.d.ts.map +1 -1
- package/lib/browser/model/debug-thread.js +13 -9
- package/lib/browser/model/debug-thread.js.map +1 -1
- package/lib/browser/view/debug-variables-source.d.ts.map +1 -1
- package/lib/browser/view/debug-variables-source.js +1 -0
- package/lib/browser/view/debug-variables-source.js.map +1 -1
- package/lib/browser/view/debug-variables-widget.d.ts +15 -0
- package/lib/browser/view/debug-variables-widget.d.ts.map +1 -1
- package/lib/browser/view/debug-variables-widget.js +56 -1
- package/lib/browser/view/debug-variables-widget.js.map +1 -1
- package/lib/browser/view/debug-view-model.d.ts +4 -0
- package/lib/browser/view/debug-view-model.d.ts.map +1 -1
- package/lib/browser/view/debug-view-model.js +11 -1
- package/lib/browser/view/debug-view-model.js.map +1 -1
- package/lib/browser/view/debug-watch-expression.d.ts.map +1 -1
- package/lib/browser/view/debug-watch-expression.js +4 -5
- package/lib/browser/view/debug-watch-expression.js.map +1 -1
- package/lib/browser/view/debug-watch-source.d.ts.map +1 -1
- package/lib/browser/view/debug-watch-source.js +1 -0
- package/lib/browser/view/debug-watch-source.js.map +1 -1
- package/lib/common/debug-preferences.d.ts +1 -0
- package/lib/common/debug-preferences.d.ts.map +1 -1
- package/lib/common/debug-preferences.js +11 -1
- package/lib/common/debug-preferences.js.map +1 -1
- package/package.json +15 -15
- package/src/browser/console/debug-console-items.tsx +90 -21
- package/src/browser/console/debug-console-session.ts +1 -0
- package/src/browser/debug-session-contribution.ts +3 -1
- package/src/browser/debug-session-manager.ts +10 -0
- package/src/browser/debug-session.tsx +13 -1
- package/src/browser/editor/debug-hover-source.tsx +6 -2
- package/src/browser/editor/debug-inline-value-decorator.ts +1 -1
- package/src/browser/model/debug-stack-frame.tsx +13 -6
- package/src/browser/model/debug-thread.tsx +14 -10
- package/src/browser/style/index.css +17 -0
- package/src/browser/view/debug-variables-source.ts +1 -0
- package/src/browser/view/debug-variables-widget.ts +59 -0
- package/src/browser/view/debug-view-model.ts +13 -0
- package/src/browser/view/debug-watch-expression.tsx +5 -6
- package/src/browser/view/debug-watch-source.ts +1 -0
- package/src/common/debug-preferences.ts +12 -1
package/package.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theia/debug",
|
|
3
|
-
"version": "1.67.0-next.
|
|
3
|
+
"version": "1.67.0-next.86+03f92ff1d",
|
|
4
4
|
"description": "Theia - Debug Extension",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@theia/console": "1.67.0-next.
|
|
7
|
-
"@theia/core": "1.67.0-next.
|
|
8
|
-
"@theia/editor": "1.67.0-next.
|
|
9
|
-
"@theia/filesystem": "1.67.0-next.
|
|
10
|
-
"@theia/markers": "1.67.0-next.
|
|
11
|
-
"@theia/monaco": "1.67.0-next.
|
|
6
|
+
"@theia/console": "1.67.0-next.86+03f92ff1d",
|
|
7
|
+
"@theia/core": "1.67.0-next.86+03f92ff1d",
|
|
8
|
+
"@theia/editor": "1.67.0-next.86+03f92ff1d",
|
|
9
|
+
"@theia/filesystem": "1.67.0-next.86+03f92ff1d",
|
|
10
|
+
"@theia/markers": "1.67.0-next.86+03f92ff1d",
|
|
11
|
+
"@theia/monaco": "1.67.0-next.86+03f92ff1d",
|
|
12
12
|
"@theia/monaco-editor-core": "1.96.302",
|
|
13
|
-
"@theia/output": "1.67.0-next.
|
|
14
|
-
"@theia/process": "1.67.0-next.
|
|
15
|
-
"@theia/task": "1.67.0-next.
|
|
16
|
-
"@theia/terminal": "1.67.0-next.
|
|
17
|
-
"@theia/test": "1.67.0-next.
|
|
18
|
-
"@theia/variable-resolver": "1.67.0-next.
|
|
19
|
-
"@theia/workspace": "1.67.0-next.
|
|
13
|
+
"@theia/output": "1.67.0-next.86+03f92ff1d",
|
|
14
|
+
"@theia/process": "1.67.0-next.86+03f92ff1d",
|
|
15
|
+
"@theia/task": "1.67.0-next.86+03f92ff1d",
|
|
16
|
+
"@theia/terminal": "1.67.0-next.86+03f92ff1d",
|
|
17
|
+
"@theia/test": "1.67.0-next.86+03f92ff1d",
|
|
18
|
+
"@theia/variable-resolver": "1.67.0-next.86+03f92ff1d",
|
|
19
|
+
"@theia/workspace": "1.67.0-next.86+03f92ff1d",
|
|
20
20
|
"@vscode/debugprotocol": "^1.51.0",
|
|
21
21
|
"fast-deep-equal": "^3.1.3",
|
|
22
22
|
"jsonc-parser": "^2.2.0",
|
|
@@ -64,5 +64,5 @@
|
|
|
64
64
|
"nyc": {
|
|
65
65
|
"extends": "../../configs/nyc.json"
|
|
66
66
|
},
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "03f92ff1d97dcb199de39b48e60a53535de22808"
|
|
68
68
|
}
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
|
|
17
17
|
import * as React from '@theia/core/shared/react';
|
|
18
18
|
import { DebugProtocol } from '@vscode/debugprotocol/lib/debugProtocol';
|
|
19
|
-
import { SingleTextInputDialog } from '@theia/core/lib/browser';
|
|
19
|
+
import { codicon, SingleTextInputDialog } from '@theia/core/lib/browser';
|
|
20
20
|
import { ConsoleItem, CompositeConsoleItem } from '@theia/console/lib/browser/console-session';
|
|
21
21
|
import { DebugSession, formatMessage } from '../debug-session';
|
|
22
22
|
import { Severity } from '@theia/core/lib/common/severity';
|
|
23
23
|
import * as monaco from '@theia/monaco-editor-core';
|
|
24
|
-
import { nls } from '@theia/core';
|
|
24
|
+
import { generateUuid, nls } from '@theia/core';
|
|
25
25
|
|
|
26
26
|
export type DebugSessionProvider = () => DebugSession | undefined;
|
|
27
27
|
|
|
@@ -34,17 +34,24 @@ export class ExpressionContainer implements CompositeConsoleItem {
|
|
|
34
34
|
return this.sessionProvider();
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
readonly id: string | number;
|
|
37
38
|
protected variablesReference: number;
|
|
38
39
|
protected namedVariables: number | undefined;
|
|
39
40
|
protected indexedVariables: number | undefined;
|
|
41
|
+
protected presentationHint: DebugProtocol.VariablePresentationHint | undefined;
|
|
40
42
|
protected readonly startOfVariables: number;
|
|
41
43
|
|
|
42
44
|
constructor(options: ExpressionContainer.Options) {
|
|
43
45
|
this.sessionProvider = options.session;
|
|
46
|
+
this.id = options.id ?? generateUuid();
|
|
44
47
|
this.variablesReference = options.variablesReference || 0;
|
|
45
48
|
this.namedVariables = options.namedVariables;
|
|
46
49
|
this.indexedVariables = options.indexedVariables;
|
|
47
50
|
this.startOfVariables = options.startOfVariables || 0;
|
|
51
|
+
this.presentationHint = options.presentationHint;
|
|
52
|
+
if (this.lazy) {
|
|
53
|
+
(this as CompositeConsoleItem).expandByDefault = () => !this.lazy && !this.session?.autoExpandLazyVariables;
|
|
54
|
+
}
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
render(): React.ReactNode {
|
|
@@ -56,7 +63,31 @@ export class ExpressionContainer implements CompositeConsoleItem {
|
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
get hasElements(): boolean {
|
|
59
|
-
return this.variablesReference
|
|
66
|
+
return !!this.variablesReference && !this.lazy;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get lazy(): boolean {
|
|
70
|
+
return !!this.presentationHint?.lazy;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async resolveLazy(): Promise<void> {
|
|
74
|
+
const { session, variablesReference, lazy } = this;
|
|
75
|
+
if (!session || !variablesReference || !lazy) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const response = await session.sendRequest('variables', { variablesReference });
|
|
79
|
+
const { variables } = response.body;
|
|
80
|
+
if (variables.length !== 1) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
this.handleResolvedLazy(variables[0]);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
protected handleResolvedLazy(resolved: DebugProtocol.Variable): void {
|
|
87
|
+
this.variablesReference = resolved.variablesReference;
|
|
88
|
+
this.namedVariables = resolved.namedVariables;
|
|
89
|
+
this.indexedVariables = resolved.indexedVariables;
|
|
90
|
+
this.presentationHint = resolved.presentationHint;
|
|
60
91
|
}
|
|
61
92
|
|
|
62
93
|
protected elements: Promise<ExpressionContainer[]> | undefined;
|
|
@@ -85,13 +116,15 @@ export class ExpressionContainer implements CompositeConsoleItem {
|
|
|
85
116
|
const start = this.startOfVariables + i * chunkSize;
|
|
86
117
|
const count = Math.min(chunkSize, this.indexedVariables - i * chunkSize);
|
|
87
118
|
const { variablesReference } = this;
|
|
119
|
+
const name = `[${start}..${start + count - 1}]`;
|
|
88
120
|
result.push(new DebugVirtualVariable({
|
|
89
121
|
session: this.sessionProvider,
|
|
122
|
+
id: `${this.id}:${name}`,
|
|
90
123
|
variablesReference,
|
|
91
124
|
namedVariables: 0,
|
|
92
125
|
indexedVariables: count,
|
|
93
126
|
startOfVariables: start,
|
|
94
|
-
name
|
|
127
|
+
name
|
|
95
128
|
}));
|
|
96
129
|
}
|
|
97
130
|
return result;
|
|
@@ -105,14 +138,23 @@ export class ExpressionContainer implements CompositeConsoleItem {
|
|
|
105
138
|
protected fetch(result: ConsoleItem[], filter: 'indexed', start: number, count?: number): Promise<void>;
|
|
106
139
|
protected async fetch(result: ConsoleItem[], filter: 'indexed' | 'named', start?: number, count?: number): Promise<void> {
|
|
107
140
|
try {
|
|
108
|
-
const {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
141
|
+
const { session } = this;
|
|
142
|
+
if (session) {
|
|
143
|
+
const { variablesReference } = this;
|
|
144
|
+
const response = await session.sendRequest('variables', { variablesReference, filter, start, count });
|
|
145
|
+
const { variables } = response.body;
|
|
146
|
+
const names = new Set<string>();
|
|
147
|
+
const debugVariables: DebugVariable[] = [];
|
|
148
|
+
for (const variable of variables) {
|
|
149
|
+
if (!names.has(variable.name)) {
|
|
150
|
+
const v = new DebugVariable(this.sessionProvider, variable, this);
|
|
151
|
+
debugVariables.push(v);
|
|
152
|
+
result.push(v);
|
|
153
|
+
names.add(variable.name);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (session.autoExpandLazyVariables) {
|
|
157
|
+
await Promise.all(debugVariables.map(v => v.lazy && v.resolveLazy()));
|
|
116
158
|
}
|
|
117
159
|
}
|
|
118
160
|
} catch (e) {
|
|
@@ -128,10 +170,12 @@ export class ExpressionContainer implements CompositeConsoleItem {
|
|
|
128
170
|
export namespace ExpressionContainer {
|
|
129
171
|
export interface Options {
|
|
130
172
|
session: DebugSessionProvider,
|
|
173
|
+
id?: string | number,
|
|
131
174
|
variablesReference?: number
|
|
132
175
|
namedVariables?: number
|
|
133
176
|
indexedVariables?: number
|
|
134
177
|
startOfVariables?: number
|
|
178
|
+
presentationHint?: DebugProtocol.VariablePresentationHint
|
|
135
179
|
}
|
|
136
180
|
}
|
|
137
181
|
|
|
@@ -147,9 +191,11 @@ export class DebugVariable extends ExpressionContainer {
|
|
|
147
191
|
) {
|
|
148
192
|
super({
|
|
149
193
|
session,
|
|
194
|
+
id: `${parent.id}:${variable.name}`,
|
|
150
195
|
variablesReference: variable.variablesReference,
|
|
151
196
|
namedVariables: variable.namedVariables,
|
|
152
|
-
indexedVariables: variable.indexedVariables
|
|
197
|
+
indexedVariables: variable.indexedVariables,
|
|
198
|
+
presentationHint: variable.presentationHint
|
|
153
199
|
});
|
|
154
200
|
}
|
|
155
201
|
|
|
@@ -169,17 +215,20 @@ export class DebugVariable extends ExpressionContainer {
|
|
|
169
215
|
}
|
|
170
216
|
|
|
171
217
|
get readOnly(): boolean {
|
|
172
|
-
return this.
|
|
218
|
+
return this.presentationHint?.attributes?.includes('readOnly') || this.lazy;
|
|
173
219
|
}
|
|
174
220
|
|
|
175
221
|
override render(): React.ReactNode {
|
|
176
|
-
const { type, value, name } = this;
|
|
222
|
+
const { type, value, name, lazy } = this;
|
|
177
223
|
return <div className={this.variableClassName}>
|
|
178
|
-
<span title={type || name} className='name' ref={this.setNameRef}>{name}{
|
|
179
|
-
<span title={
|
|
224
|
+
<span title={type || name} className='name' ref={this.setNameRef}>{name}{(value || lazy) && ': '}</span>
|
|
225
|
+
{lazy && <span title={nls.localizeByDefault('Click to expand')} className={codicon('eye') + ' lazy-button'} onClick={this.handleLazyButtonClick} />}
|
|
226
|
+
<span title={value} className='value' ref={this.setValueRef}>{value}</span>
|
|
180
227
|
</div>;
|
|
181
228
|
}
|
|
182
229
|
|
|
230
|
+
private readonly handleLazyButtonClick = () => this.resolveLazy();
|
|
231
|
+
|
|
183
232
|
protected get variableClassName(): string {
|
|
184
233
|
const { type, value } = this;
|
|
185
234
|
const classNames = ['theia-debug-console-variable'];
|
|
@@ -195,6 +244,13 @@ export class DebugVariable extends ExpressionContainer {
|
|
|
195
244
|
return classNames.join(' ');
|
|
196
245
|
}
|
|
197
246
|
|
|
247
|
+
protected override handleResolvedLazy(resolved: DebugProtocol.Variable): void {
|
|
248
|
+
this._value = resolved.value;
|
|
249
|
+
this._type = resolved.type || this._type;
|
|
250
|
+
super.handleResolvedLazy(resolved);
|
|
251
|
+
this.session?.['onDidResolveLazyVariableEmitter'].fire(this);
|
|
252
|
+
}
|
|
253
|
+
|
|
198
254
|
get supportSetVariable(): boolean {
|
|
199
255
|
return !!this.session && !!this.session.capabilities.supportsSetVariable;
|
|
200
256
|
}
|
|
@@ -312,9 +368,10 @@ export class ExpressionItem extends ExpressionContainer {
|
|
|
312
368
|
|
|
313
369
|
constructor(
|
|
314
370
|
protected _expression: string,
|
|
315
|
-
session: DebugSessionProvider
|
|
371
|
+
session: DebugSessionProvider,
|
|
372
|
+
id?: string | number
|
|
316
373
|
) {
|
|
317
|
-
super({ session });
|
|
374
|
+
super({ session, id });
|
|
318
375
|
}
|
|
319
376
|
|
|
320
377
|
get expression(): string {
|
|
@@ -333,7 +390,7 @@ export class ExpressionItem extends ExpressionContainer {
|
|
|
333
390
|
</div>;
|
|
334
391
|
}
|
|
335
392
|
|
|
336
|
-
async evaluate(context: string = 'repl'): Promise<void> {
|
|
393
|
+
async evaluate(context: string = 'repl', resolveLazy = true): Promise<void> {
|
|
337
394
|
const session = this.session;
|
|
338
395
|
if (!session?.currentFrame) {
|
|
339
396
|
this.setResult(undefined, ExpressionItem.notAvailable);
|
|
@@ -343,6 +400,9 @@ export class ExpressionItem extends ExpressionContainer {
|
|
|
343
400
|
try {
|
|
344
401
|
const body = await session.evaluate(this._expression, context);
|
|
345
402
|
this.setResult(body);
|
|
403
|
+
if (this.lazy && resolveLazy) {
|
|
404
|
+
await this.resolveLazy();
|
|
405
|
+
}
|
|
346
406
|
} catch (err) {
|
|
347
407
|
this.setResult(undefined, err.message);
|
|
348
408
|
}
|
|
@@ -356,6 +416,7 @@ export class ExpressionItem extends ExpressionContainer {
|
|
|
356
416
|
this.variablesReference = body.variablesReference;
|
|
357
417
|
this.namedVariables = body.namedVariables;
|
|
358
418
|
this.indexedVariables = body.indexedVariables;
|
|
419
|
+
this.presentationHint = body.presentationHint;
|
|
359
420
|
this.severity = Severity.Log;
|
|
360
421
|
} else {
|
|
361
422
|
this._value = error;
|
|
@@ -364,21 +425,29 @@ export class ExpressionItem extends ExpressionContainer {
|
|
|
364
425
|
this.variablesReference = 0;
|
|
365
426
|
this.namedVariables = undefined;
|
|
366
427
|
this.indexedVariables = undefined;
|
|
428
|
+
this.presentationHint = undefined;
|
|
367
429
|
this.severity = Severity.Error;
|
|
368
430
|
}
|
|
369
431
|
this.elements = undefined;
|
|
370
432
|
}
|
|
371
433
|
|
|
434
|
+
protected override handleResolvedLazy(resolved: DebugProtocol.Variable): void {
|
|
435
|
+
this._value = resolved.value;
|
|
436
|
+
this._type = resolved.type || this._type;
|
|
437
|
+
super.handleResolvedLazy(resolved);
|
|
438
|
+
}
|
|
372
439
|
}
|
|
373
440
|
|
|
374
441
|
export class DebugScope extends ExpressionContainer {
|
|
375
442
|
|
|
376
443
|
constructor(
|
|
377
444
|
protected readonly raw: DebugProtocol.Scope,
|
|
378
|
-
session: DebugSessionProvider
|
|
445
|
+
session: DebugSessionProvider,
|
|
446
|
+
id: number
|
|
379
447
|
) {
|
|
380
448
|
super({
|
|
381
449
|
session,
|
|
450
|
+
id: `${raw.name}:${id}`,
|
|
382
451
|
variablesReference: raw.variablesReference,
|
|
383
452
|
namedVariables: raw.namedVariables,
|
|
384
453
|
indexedVariables: raw.indexedVariables
|
|
@@ -85,6 +85,7 @@ export class DebugConsoleSession extends ConsoleSession {
|
|
|
85
85
|
triggerCharacters: ['.'],
|
|
86
86
|
provideCompletionItems: (model, position) => this.completions(model, position),
|
|
87
87
|
}));
|
|
88
|
+
this.toDispose.push(this.sessionManager.onDidResolveLazyVariable(() => this.fireDidChange()));
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
getElements(): IterableIterator<ConsoleItem> {
|
|
@@ -146,7 +146,9 @@ export class DefaultDebugSessionFactory implements DebugSessionFactory {
|
|
|
146
146
|
this.messages,
|
|
147
147
|
this.fileService,
|
|
148
148
|
this.debugContributionProvider,
|
|
149
|
-
this.workspaceService
|
|
149
|
+
this.workspaceService,
|
|
150
|
+
this.debugPreferences
|
|
151
|
+
);
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
protected getTraceOutputChannel(): OutputChannel | undefined {
|
|
@@ -39,6 +39,7 @@ import * as monaco from '@theia/monaco-editor-core';
|
|
|
39
39
|
import { DebugInstructionBreakpoint } from './model/debug-instruction-breakpoint';
|
|
40
40
|
import { DebugSessionConfigurationLabelProvider } from './debug-session-configuration-label-provider';
|
|
41
41
|
import { DebugDataBreakpoint } from './model/debug-data-breakpoint';
|
|
42
|
+
import { DebugVariable } from './console/debug-console-items';
|
|
42
43
|
|
|
43
44
|
export interface WillStartDebugSession extends WaitUntilEvent {
|
|
44
45
|
}
|
|
@@ -57,6 +58,11 @@ export interface DidChangeBreakpointsEvent {
|
|
|
57
58
|
uri: URI
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
export interface DidResolveLazyVariableEvent {
|
|
62
|
+
readonly session: DebugSession
|
|
63
|
+
readonly variable: DebugVariable
|
|
64
|
+
}
|
|
65
|
+
|
|
60
66
|
export interface DebugSessionCustomEvent {
|
|
61
67
|
readonly body?: any // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
62
68
|
readonly event: string
|
|
@@ -112,6 +118,9 @@ export class DebugSessionManager {
|
|
|
112
118
|
this.onDidChangeEmitter.fire(current);
|
|
113
119
|
}
|
|
114
120
|
|
|
121
|
+
protected readonly onDidResolveLazyVariableEmitter = new Emitter<DidResolveLazyVariableEvent>();
|
|
122
|
+
readonly onDidResolveLazyVariable: Event<DidResolveLazyVariableEvent> = this.onDidResolveLazyVariableEmitter.event;
|
|
123
|
+
|
|
115
124
|
@inject(DebugSessionFactory)
|
|
116
125
|
protected readonly debugSessionFactory: DebugSessionFactory;
|
|
117
126
|
|
|
@@ -544,6 +553,7 @@ export class DebugSessionManager {
|
|
|
544
553
|
}
|
|
545
554
|
this.fireDidChange(current);
|
|
546
555
|
}));
|
|
556
|
+
this.disposeOnCurrentSessionChanged.push(current.onDidResolveLazyVariable(variable => this.onDidResolveLazyVariableEmitter.fire({ session: current, variable })));
|
|
547
557
|
this.disposeOnCurrentSessionChanged.push(current.onDidFocusStackFrame(frame => this.onDidFocusStackFrameEmitter.fire(frame)));
|
|
548
558
|
this.disposeOnCurrentSessionChanged.push(current.onDidFocusThread(thread => this.onDidFocusThreadEmitter.fire(thread)));
|
|
549
559
|
const { currentThread } = current;
|
|
@@ -25,7 +25,7 @@ import { EditorManager } from '@theia/editor/lib/browser';
|
|
|
25
25
|
import { CompositeTreeElement } from '@theia/core/lib/browser/source-tree';
|
|
26
26
|
import { DebugSessionConnection, DebugRequestTypes, DebugEventTypes } from './debug-session-connection';
|
|
27
27
|
import { DebugThread, StoppedDetails, DebugThreadData } from './model/debug-thread';
|
|
28
|
-
import { DebugScope } from './console/debug-console-items';
|
|
28
|
+
import { DebugScope, DebugVariable } from './console/debug-console-items';
|
|
29
29
|
import { DebugStackFrame } from './model/debug-stack-frame';
|
|
30
30
|
import { DebugSource } from './model/debug-source';
|
|
31
31
|
import { DebugBreakpoint, DebugBreakpointOptions } from './model/debug-breakpoint';
|
|
@@ -47,6 +47,7 @@ import { nls } from '@theia/core';
|
|
|
47
47
|
import { TestService, TestServices } from '@theia/test/lib/browser/test-service';
|
|
48
48
|
import { DebugSessionManager } from './debug-session-manager';
|
|
49
49
|
import { DebugDataBreakpoint } from './model/debug-data-breakpoint';
|
|
50
|
+
import { DebugPreferences } from '../common/debug-preferences';
|
|
50
51
|
|
|
51
52
|
export enum DebugState {
|
|
52
53
|
Inactive,
|
|
@@ -103,6 +104,9 @@ export class DebugSession implements CompositeTreeElement {
|
|
|
103
104
|
this.onDidChangeBreakpointsEmitter.fire(uri);
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
protected readonly onDidResolveLazyVariableEmitter = new Emitter<DebugVariable>();
|
|
108
|
+
readonly onDidResolveLazyVariable: Event<DebugVariable> = this.onDidResolveLazyVariableEmitter.event;
|
|
109
|
+
|
|
106
110
|
protected readonly childSessions = new Map<string, DebugSession>();
|
|
107
111
|
protected readonly toDispose = new DisposableCollection();
|
|
108
112
|
|
|
@@ -124,6 +128,7 @@ export class DebugSession implements CompositeTreeElement {
|
|
|
124
128
|
protected readonly fileService: FileService,
|
|
125
129
|
protected readonly debugContributionProvider: ContributionProvider<DebugContribution>,
|
|
126
130
|
protected readonly workspaceService: WorkspaceService,
|
|
131
|
+
protected readonly debugPreferences: DebugPreferences,
|
|
127
132
|
/**
|
|
128
133
|
* Number of millis after a `stop` request times out. It's 5 seconds by default.
|
|
129
134
|
*/
|
|
@@ -157,7 +162,10 @@ export class DebugSession implements CompositeTreeElement {
|
|
|
157
162
|
this.connection.onDidClose(() => this.toDispose.dispose());
|
|
158
163
|
this.toDispose.pushAll([
|
|
159
164
|
this.onDidChangeEmitter,
|
|
165
|
+
this.onDidFocusStackFrameEmitter,
|
|
166
|
+
this.onDidFocusThreadEmitter,
|
|
160
167
|
this.onDidChangeBreakpointsEmitter,
|
|
168
|
+
this.onDidResolveLazyVariableEmitter,
|
|
161
169
|
Disposable.create(() => {
|
|
162
170
|
this.clearBreakpoints();
|
|
163
171
|
this.doUpdateThreads([]);
|
|
@@ -186,6 +194,10 @@ export class DebugSession implements CompositeTreeElement {
|
|
|
186
194
|
return this._capabilities;
|
|
187
195
|
}
|
|
188
196
|
|
|
197
|
+
get autoExpandLazyVariables(): boolean {
|
|
198
|
+
return this.debugPreferences['debug.autoExpandLazyVariables'] === 'on';
|
|
199
|
+
}
|
|
200
|
+
|
|
189
201
|
protected readonly sources = new Map<string, DebugSource>();
|
|
190
202
|
getSource(raw: DebugProtocol.Source): DebugSource {
|
|
191
203
|
const uri = DebugSource.toUri(raw).toString();
|
|
@@ -18,7 +18,7 @@ import * as React from '@theia/core/shared/react';
|
|
|
18
18
|
import { TreeSource, TreeElement } from '@theia/core/lib/browser/source-tree';
|
|
19
19
|
import { ExpressionContainer, ExpressionItem, DebugVariable } from '../console/debug-console-items';
|
|
20
20
|
import { DebugSessionManager } from '../debug-session-manager';
|
|
21
|
-
import { injectable, inject } from '@theia/core/shared/inversify';
|
|
21
|
+
import { injectable, inject, postConstruct } from '@theia/core/shared/inversify';
|
|
22
22
|
|
|
23
23
|
@injectable()
|
|
24
24
|
export class DebugHoverSource extends TreeSource {
|
|
@@ -36,6 +36,11 @@ export class DebugHoverSource extends TreeSource {
|
|
|
36
36
|
return this.elements[Symbol.iterator]();
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
@postConstruct()
|
|
40
|
+
init(): void {
|
|
41
|
+
this.toDispose.push(this.sessions.onDidResolveLazyVariable(() => this.fireDidChange()));
|
|
42
|
+
}
|
|
43
|
+
|
|
39
44
|
protected renderTitle(element: ExpressionItem | DebugVariable): React.ReactNode {
|
|
40
45
|
return <div className='theia-debug-hover-title' title={element.value}>{element.value}</div>;
|
|
41
46
|
}
|
|
@@ -101,5 +106,4 @@ export class DebugHoverSource extends TreeSource {
|
|
|
101
106
|
return this.doFindVariable(variables[0], namesToFind.slice(1));
|
|
102
107
|
}
|
|
103
108
|
}
|
|
104
|
-
|
|
105
109
|
}
|
|
@@ -194,7 +194,7 @@ export class DebugInlineValueDecorator implements FrontendApplicationContributio
|
|
|
194
194
|
}
|
|
195
195
|
if (expr) {
|
|
196
196
|
const expression = new ExpressionItem(expr, () => stackFrame.thread.session);
|
|
197
|
-
await expression.evaluate('watch');
|
|
197
|
+
await expression.evaluate('watch', false);
|
|
198
198
|
if (expression.available) {
|
|
199
199
|
text = this.formatInlineValue(expr, expression.value);
|
|
200
200
|
}
|
|
@@ -31,6 +31,7 @@ import { RecursivePartial } from '@theia/core';
|
|
|
31
31
|
import { DebugSession } from '../debug-session';
|
|
32
32
|
import { DebugThread } from './debug-thread';
|
|
33
33
|
import * as monaco from '@theia/monaco-editor-core';
|
|
34
|
+
import { stringHash } from '@theia/core/lib/common/hash';
|
|
34
35
|
|
|
35
36
|
export class DebugStackFrameData {
|
|
36
37
|
readonly raw: DebugProtocol.StackFrame;
|
|
@@ -40,15 +41,12 @@ export class DebugStackFrame extends DebugStackFrameData implements TreeElement
|
|
|
40
41
|
|
|
41
42
|
constructor(
|
|
42
43
|
readonly thread: DebugThread,
|
|
43
|
-
readonly session: DebugSession
|
|
44
|
+
readonly session: DebugSession,
|
|
45
|
+
readonly id: string
|
|
44
46
|
) {
|
|
45
47
|
super();
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
get id(): string {
|
|
49
|
-
return this.session.id + ':' + this.thread.id + ':' + this.raw.id;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
50
|
/**
|
|
53
51
|
* Returns the frame identifier from the debug protocol.
|
|
54
52
|
*/
|
|
@@ -115,7 +113,16 @@ export class DebugStackFrame extends DebugStackFrameData implements TreeElement
|
|
|
115
113
|
if (!response) {
|
|
116
114
|
return [];
|
|
117
115
|
}
|
|
118
|
-
|
|
116
|
+
const scopeIds = new Set<number>();
|
|
117
|
+
return response.body.scopes.map(raw => {
|
|
118
|
+
// just as in VS Code, the id is based on the name and location to retain expansion state across multiple pauses
|
|
119
|
+
let id = 0;
|
|
120
|
+
do {
|
|
121
|
+
id = stringHash(`${raw.name}:${raw.line}:${raw.column}`, id);
|
|
122
|
+
} while (scopeIds.has(id));
|
|
123
|
+
scopeIds.add(id);
|
|
124
|
+
return new DebugScope(raw, () => this.session, id);
|
|
125
|
+
});
|
|
119
126
|
}
|
|
120
127
|
|
|
121
128
|
// https://github.com/theia-ide/vscode/blob/standalone/0.19.x/src/vs/workbench/contrib/debug/common/debugModel.ts#L324-L335
|
|
@@ -164,7 +164,7 @@ export class DebugThread extends DebugThreadData implements TreeElement {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
protected readonly _frames = new Map<
|
|
167
|
+
protected readonly _frames = new Map<string, DebugStackFrame>();
|
|
168
168
|
get frames(): IterableIterator<DebugStackFrame> {
|
|
169
169
|
return this._frames.values();
|
|
170
170
|
}
|
|
@@ -189,7 +189,7 @@ export class DebugThread extends DebugThreadData implements TreeElement {
|
|
|
189
189
|
if (cancel.isCancellationRequested) {
|
|
190
190
|
return [];
|
|
191
191
|
}
|
|
192
|
-
return this.doUpdateFrames(frames);
|
|
192
|
+
return this.doUpdateFrames(start, frames);
|
|
193
193
|
} catch (e) {
|
|
194
194
|
console.error('fetchFrames failed:', e);
|
|
195
195
|
return [];
|
|
@@ -219,15 +219,19 @@ export class DebugThread extends DebugThreadData implements TreeElement {
|
|
|
219
219
|
return [];
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
|
-
protected doUpdateFrames(frames: DebugProtocol.StackFrame[]): DebugStackFrame[] {
|
|
222
|
+
protected doUpdateFrames(startFrame: number, frames: DebugProtocol.StackFrame[]): DebugStackFrame[] {
|
|
223
223
|
const result = new Set<DebugStackFrame>();
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
224
|
+
frames.forEach((raw, index) => {
|
|
225
|
+
// Similarly to VS Code, we no longer use `raw.frameId` in computation of the DebugStackFrame id.
|
|
226
|
+
// The `raw.frameId` was changing in every step and was not allowing us to correlate stack frames between step events.
|
|
227
|
+
// Refs: https://github.com/microsoft/vscode/commit/18fc2bcf718e22265b5e09bb7fd0e9c090264cd2, https://github.com/microsoft/vscode/issues/93230#issuecomment-642558395
|
|
228
|
+
const source = raw.source && this.session.getSource(raw.source);
|
|
229
|
+
const id = `${this.id}:${startFrame + index}:${source?.name}`;
|
|
230
|
+
const frame = this._frames.get(id) || new DebugStackFrame(this, this.session, id);
|
|
227
231
|
this._frames.set(id, frame);
|
|
228
232
|
frame.update({ raw });
|
|
229
233
|
result.add(frame);
|
|
230
|
-
}
|
|
234
|
+
});
|
|
231
235
|
this.updateCurrentFrame();
|
|
232
236
|
return [...result.values()];
|
|
233
237
|
}
|
|
@@ -247,9 +251,9 @@ export class DebugThread extends DebugThreadData implements TreeElement {
|
|
|
247
251
|
}
|
|
248
252
|
protected updateCurrentFrame(): void {
|
|
249
253
|
const { currentFrame } = this;
|
|
250
|
-
const
|
|
251
|
-
this.currentFrame = typeof
|
|
252
|
-
this._frames.get(
|
|
254
|
+
const id = currentFrame && currentFrame.id;
|
|
255
|
+
this.currentFrame = typeof id === 'string' &&
|
|
256
|
+
this._frames.get(id) ||
|
|
253
257
|
this._frames.values().next().value;
|
|
254
258
|
}
|
|
255
259
|
|
|
@@ -187,6 +187,7 @@
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
.theia-debug-console-variable {
|
|
190
|
+
display: flex;
|
|
190
191
|
white-space: nowrap;
|
|
191
192
|
overflow: hidden;
|
|
192
193
|
text-overflow: ellipsis;
|
|
@@ -212,6 +213,22 @@
|
|
|
212
213
|
color: var(--theia-variable-name-color);
|
|
213
214
|
}
|
|
214
215
|
|
|
216
|
+
.theia-debug-console-variable .lazy-button {
|
|
217
|
+
margin-left: 3px;
|
|
218
|
+
border-radius: 5px;
|
|
219
|
+
cursor: pointer;
|
|
220
|
+
align-self: center;
|
|
221
|
+
color: var(--theia-icon-foreground);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.theia-debug-console-variable .lazy-button:hover {
|
|
225
|
+
background-color: var(--theia-toolbar-hoverBackground);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.theia-debug-console-variable .value {
|
|
229
|
+
margin-left: 6px;
|
|
230
|
+
}
|
|
231
|
+
|
|
215
232
|
.theia-TreeNode:not(:hover) .theia-debug-console-variable .action-label {
|
|
216
233
|
visibility: hidden;
|
|
217
234
|
}
|
|
@@ -30,6 +30,7 @@ export class DebugVariablesSource extends TreeSource {
|
|
|
30
30
|
protected init(): void {
|
|
31
31
|
this.refresh();
|
|
32
32
|
this.toDispose.push(this.model.onDidChange(() => this.refresh()));
|
|
33
|
+
this.toDispose.push(this.model.onDidResolveLazyVariable(() => this.fireDidChange()));
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
protected readonly refresh = debounce(() => this.fireDidChange(), 400);
|