@theia/debug 1.53.0-next.5 → 1.53.0-next.55
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/README.md +62 -62
- package/lib/browser/debug-configuration-manager.js +6 -6
- package/lib/browser/debug-frontend-application-contribution.d.ts.map +1 -1
- package/lib/browser/debug-frontend-application-contribution.js.map +1 -1
- package/lib/common/inline-debug-adapter.d.ts +1 -0
- package/lib/common/inline-debug-adapter.d.ts.map +1 -1
- package/package.json +16 -16
- package/src/browser/breakpoint/breakpoint-manager.ts +369 -369
- package/src/browser/breakpoint/breakpoint-marker.ts +104 -104
- package/src/browser/console/debug-console-contribution.tsx +240 -240
- package/src/browser/console/debug-console-items.tsx +384 -384
- package/src/browser/console/debug-console-session.ts +205 -205
- package/src/browser/debug-call-stack-item-type-key.ts +20 -20
- package/src/browser/debug-configuration-manager.ts +591 -591
- package/src/browser/debug-configuration-model.ts +100 -100
- package/src/browser/debug-contribution.ts +43 -43
- package/src/browser/debug-frontend-application-contribution.ts +1551 -1551
- package/src/browser/debug-frontend-module.ts +133 -133
- package/src/browser/debug-package.spec.ts +20 -20
- package/src/browser/debug-preferences.ts +98 -98
- package/src/browser/debug-prefix-configuration.ts +195 -195
- package/src/browser/debug-resource.ts +59 -59
- package/src/browser/debug-schema-updater.ts +149 -149
- package/src/browser/debug-session-connection.ts +357 -357
- package/src/browser/debug-session-contribution.ts +157 -157
- package/src/browser/debug-session-manager.ts +683 -683
- package/src/browser/debug-session-options.ts +120 -120
- package/src/browser/debug-session.tsx +974 -974
- package/src/browser/debug-tab-bar-decorator.ts +57 -57
- package/src/browser/debug-watch-manager.ts +93 -93
- package/src/browser/disassembly-view/disassembly-view-accessibility-provider.ts +43 -43
- package/src/browser/disassembly-view/disassembly-view-breakpoint-renderer.ts +119 -119
- package/src/browser/disassembly-view/disassembly-view-contribution.ts +109 -109
- package/src/browser/disassembly-view/disassembly-view-instruction-renderer.ts +245 -245
- package/src/browser/disassembly-view/disassembly-view-table-delegate.ts +39 -39
- package/src/browser/disassembly-view/disassembly-view-utilities.ts +55 -55
- package/src/browser/disassembly-view/disassembly-view-widget.ts +463 -463
- package/src/browser/editor/debug-breakpoint-widget.tsx +293 -293
- package/src/browser/editor/debug-editor-model.ts +529 -529
- package/src/browser/editor/debug-editor-service.ts +192 -192
- package/src/browser/editor/debug-editor.ts +20 -20
- package/src/browser/editor/debug-exception-widget.tsx +122 -122
- package/src/browser/editor/debug-expression-provider.ts +78 -78
- package/src/browser/editor/debug-hover-source.tsx +105 -105
- package/src/browser/editor/debug-hover-widget.ts +298 -298
- package/src/browser/editor/debug-inline-value-decorator.ts +373 -373
- package/src/browser/model/debug-breakpoint.tsx +151 -151
- package/src/browser/model/debug-function-breakpoint.tsx +101 -101
- package/src/browser/model/debug-instruction-breakpoint.tsx +68 -68
- package/src/browser/model/debug-source-breakpoint.tsx +237 -237
- package/src/browser/model/debug-source.ts +93 -93
- package/src/browser/model/debug-stack-frame.tsx +177 -177
- package/src/browser/model/debug-thread.tsx +292 -292
- package/src/browser/preferences/launch-preferences.ts +38 -38
- package/src/browser/style/index.css +453 -453
- package/src/browser/view/debug-action.tsx +57 -57
- package/src/browser/view/debug-breakpoints-source.tsx +53 -53
- package/src/browser/view/debug-breakpoints-widget.ts +71 -71
- package/src/browser/view/debug-configuration-select.tsx +269 -269
- package/src/browser/view/debug-configuration-widget.tsx +121 -121
- package/src/browser/view/debug-exception-breakpoint.tsx +68 -68
- package/src/browser/view/debug-session-widget.ts +124 -124
- package/src/browser/view/debug-stack-frames-source.tsx +75 -75
- package/src/browser/view/debug-stack-frames-widget.ts +135 -135
- package/src/browser/view/debug-threads-source.tsx +48 -48
- package/src/browser/view/debug-threads-widget.ts +126 -126
- package/src/browser/view/debug-toolbar-widget.tsx +145 -145
- package/src/browser/view/debug-variables-source.ts +43 -43
- package/src/browser/view/debug-variables-widget.ts +61 -61
- package/src/browser/view/debug-view-model.ts +230 -230
- package/src/browser/view/debug-watch-expression.tsx +88 -88
- package/src/browser/view/debug-watch-source.ts +41 -41
- package/src/browser/view/debug-watch-widget.ts +61 -61
- package/src/browser/view/debug-widget.ts +97 -97
- package/src/common/debug-adapter-contribution-registry.ts +206 -206
- package/src/common/debug-adapter-session.ts +102 -102
- package/src/common/debug-common.ts +19 -19
- package/src/common/debug-compound.ts +33 -33
- package/src/common/debug-configuration.ts +112 -112
- package/src/common/debug-model.ts +200 -200
- package/src/common/debug-service.ts +184 -184
- package/src/common/debug-uri-utils.ts +24 -24
- package/src/common/inline-debug-adapter.ts +47 -47
- package/src/node/debug-adapter-factory.ts +107 -107
- package/src/node/debug-adapter-session-manager.ts +106 -106
- package/src/node/debug-backend-module.ts +57 -57
- package/src/node/debug-service-impl.ts +119 -119
- package/src/node/stream-debug-adapter.ts +126 -126
|
@@ -1,298 +1,298 @@
|
|
|
1
|
-
// *****************************************************************************
|
|
2
|
-
// Copyright (C) 2018 TypeFox and others.
|
|
3
|
-
//
|
|
4
|
-
// This program and the accompanying materials are made available under the
|
|
5
|
-
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
-
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
-
//
|
|
8
|
-
// This Source Code may also be made available under the following Secondary
|
|
9
|
-
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
-
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
-
// with the GNU Classpath Exception which is available at
|
|
12
|
-
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
-
//
|
|
14
|
-
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
-
// *****************************************************************************
|
|
16
|
-
|
|
17
|
-
import debounce = require('@theia/core/shared/lodash.debounce');
|
|
18
|
-
|
|
19
|
-
import { Widget } from '@theia/core/shared/@phosphor/widgets';
|
|
20
|
-
import { Message } from '@theia/core/shared/@phosphor/messaging';
|
|
21
|
-
import { injectable, postConstruct, inject, Container, interfaces } from '@theia/core/shared/inversify';
|
|
22
|
-
import { Key } from '@theia/core/lib/browser';
|
|
23
|
-
import { SourceTreeWidget } from '@theia/core/lib/browser/source-tree';
|
|
24
|
-
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
|
|
25
|
-
import { DebugSessionManager } from '../debug-session-manager';
|
|
26
|
-
import { DebugEditor } from './debug-editor';
|
|
27
|
-
import { DebugExpressionProvider } from './debug-expression-provider';
|
|
28
|
-
import { DebugHoverSource } from './debug-hover-source';
|
|
29
|
-
import { DebugVariable } from '../console/debug-console-items';
|
|
30
|
-
import * as monaco from '@theia/monaco-editor-core';
|
|
31
|
-
import { StandaloneServices } from '@theia/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices';
|
|
32
|
-
import { ILanguageFeaturesService } from '@theia/monaco-editor-core/esm/vs/editor/common/services/languageFeatures';
|
|
33
|
-
import { CancellationTokenSource } from '@theia/monaco-editor-core/esm/vs/base/common/cancellation';
|
|
34
|
-
import { Position } from '@theia/monaco-editor-core/esm/vs/editor/common/core/position';
|
|
35
|
-
import { ArrayUtils } from '@theia/core';
|
|
36
|
-
|
|
37
|
-
export interface ShowDebugHoverOptions {
|
|
38
|
-
selection: monaco.Range
|
|
39
|
-
/** default: false */
|
|
40
|
-
focus?: boolean
|
|
41
|
-
/** default: true */
|
|
42
|
-
immediate?: boolean
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface HideDebugHoverOptions {
|
|
46
|
-
/** default: true */
|
|
47
|
-
immediate?: boolean
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function createDebugHoverWidgetContainer(parent: interfaces.Container, editor: DebugEditor): Container {
|
|
51
|
-
const child = SourceTreeWidget.createContainer(parent, {
|
|
52
|
-
virtualized: false
|
|
53
|
-
});
|
|
54
|
-
child.bind(DebugEditor).toConstantValue(editor);
|
|
55
|
-
child.bind(DebugHoverSource).toSelf();
|
|
56
|
-
child.unbind(SourceTreeWidget);
|
|
57
|
-
child.bind(DebugExpressionProvider).toSelf();
|
|
58
|
-
child.bind(DebugHoverWidget).toSelf();
|
|
59
|
-
return child;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
@injectable()
|
|
63
|
-
export class DebugHoverWidget extends SourceTreeWidget implements monaco.editor.IContentWidget {
|
|
64
|
-
|
|
65
|
-
@inject(DebugEditor)
|
|
66
|
-
protected readonly editor: DebugEditor;
|
|
67
|
-
|
|
68
|
-
@inject(DebugSessionManager)
|
|
69
|
-
protected readonly sessions: DebugSessionManager;
|
|
70
|
-
|
|
71
|
-
@inject(DebugHoverSource)
|
|
72
|
-
protected readonly hoverSource: DebugHoverSource;
|
|
73
|
-
|
|
74
|
-
@inject(DebugExpressionProvider)
|
|
75
|
-
protected readonly expressionProvider: DebugExpressionProvider;
|
|
76
|
-
|
|
77
|
-
allowEditorOverflow = true;
|
|
78
|
-
|
|
79
|
-
static ID = 'debug.editor.hover';
|
|
80
|
-
getId(): string {
|
|
81
|
-
return DebugHoverWidget.ID;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
protected readonly domNode = document.createElement('div');
|
|
85
|
-
protected readonly titleNode = document.createElement('div');
|
|
86
|
-
protected readonly contentNode = document.createElement('div');
|
|
87
|
-
getDomNode(): HTMLElement {
|
|
88
|
-
return this.domNode;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
@postConstruct()
|
|
92
|
-
protected override init(): void {
|
|
93
|
-
super.init();
|
|
94
|
-
this.domNode.className = 'theia-debug-hover';
|
|
95
|
-
this.titleNode.className = 'theia-debug-hover-title';
|
|
96
|
-
this.domNode.appendChild(this.titleNode);
|
|
97
|
-
this.contentNode.className = 'theia-debug-hover-content';
|
|
98
|
-
this.domNode.appendChild(this.contentNode);
|
|
99
|
-
|
|
100
|
-
// for stopping scroll events from contentNode going to the editor
|
|
101
|
-
this.contentNode.addEventListener('wheel', e => e.stopPropagation());
|
|
102
|
-
|
|
103
|
-
this.editor.getControl().addContentWidget(this);
|
|
104
|
-
this.source = this.hoverSource;
|
|
105
|
-
this.toDispose.pushAll([
|
|
106
|
-
this.hoverSource,
|
|
107
|
-
Disposable.create(() => this.editor.getControl().removeContentWidget(this)),
|
|
108
|
-
Disposable.create(() => this.hide()),
|
|
109
|
-
this.sessions.onDidChange(() => {
|
|
110
|
-
if (!this.isEditorFrame()) {
|
|
111
|
-
this.hide();
|
|
112
|
-
}
|
|
113
|
-
})
|
|
114
|
-
]);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
override dispose(): void {
|
|
118
|
-
this.toDispose.dispose();
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
override show(options?: ShowDebugHoverOptions): void {
|
|
122
|
-
this.schedule(() => this.doShow(options), options && options.immediate);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
override hide(options?: HideDebugHoverOptions): void {
|
|
126
|
-
this.schedule(() => this.doHide(), options && options.immediate);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
protected readonly doSchedule = debounce((fn: () => void) => fn(), 300);
|
|
130
|
-
protected schedule(fn: () => void, immediate: boolean = true): void {
|
|
131
|
-
if (immediate) {
|
|
132
|
-
this.doSchedule.cancel();
|
|
133
|
-
fn();
|
|
134
|
-
} else {
|
|
135
|
-
this.doSchedule(fn);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
protected options: ShowDebugHoverOptions | undefined;
|
|
140
|
-
protected doHide(): void {
|
|
141
|
-
if (!this.isVisible) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
if (this.domNode.contains(document.activeElement)) {
|
|
145
|
-
this.editor.getControl().focus();
|
|
146
|
-
}
|
|
147
|
-
if (this.isAttached) {
|
|
148
|
-
Widget.detach(this);
|
|
149
|
-
}
|
|
150
|
-
this.hoverSource.reset();
|
|
151
|
-
super.hide();
|
|
152
|
-
this.options = undefined;
|
|
153
|
-
this.editor.getControl().layoutContentWidget(this);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
protected async doShow(options: ShowDebugHoverOptions | undefined = this.options): Promise<void> {
|
|
157
|
-
const cancellationSource = new CancellationTokenSource();
|
|
158
|
-
|
|
159
|
-
if (!this.isEditorFrame()) {
|
|
160
|
-
this.hide();
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
if (!options) {
|
|
164
|
-
this.hide();
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
if (this.options && this.options.selection.equalsRange(options.selection)) {
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
if (!this.isAttached) {
|
|
171
|
-
Widget.attach(this, this.contentNode);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
this.options = options;
|
|
175
|
-
let matchingExpression: string | undefined;
|
|
176
|
-
|
|
177
|
-
const pluginExpressionProvider = StandaloneServices.get(ILanguageFeaturesService).evaluatableExpressionProvider;
|
|
178
|
-
const textEditorModel = this.editor.document.textEditorModel;
|
|
179
|
-
|
|
180
|
-
if (pluginExpressionProvider && pluginExpressionProvider.has(textEditorModel)) {
|
|
181
|
-
const registeredProviders = pluginExpressionProvider.ordered(textEditorModel);
|
|
182
|
-
const position = new Position(this.options!.selection.startLineNumber, this.options!.selection.startColumn);
|
|
183
|
-
|
|
184
|
-
const promises = registeredProviders.map(support =>
|
|
185
|
-
Promise.resolve(support.provideEvaluatableExpression(textEditorModel, position, cancellationSource.token))
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
const results = await Promise.all(promises).then(ArrayUtils.coalesce);
|
|
189
|
-
if (results.length > 0) {
|
|
190
|
-
matchingExpression = results[0].expression;
|
|
191
|
-
const range = results[0].range;
|
|
192
|
-
|
|
193
|
-
if (!matchingExpression) {
|
|
194
|
-
const lineContent = textEditorModel.getLineContent(position.lineNumber);
|
|
195
|
-
matchingExpression = lineContent.substring(range.startColumn - 1, range.endColumn - 1);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
} else { // use fallback if no provider was registered
|
|
199
|
-
matchingExpression = this.expressionProvider.get(this.editor.getControl().getModel()!, options.selection);
|
|
200
|
-
if (matchingExpression) {
|
|
201
|
-
const expressionLineContent = this.editor
|
|
202
|
-
.getControl()
|
|
203
|
-
.getModel()!
|
|
204
|
-
.getLineContent(this.options.selection.startLineNumber);
|
|
205
|
-
const startColumn =
|
|
206
|
-
expressionLineContent.indexOf(
|
|
207
|
-
matchingExpression,
|
|
208
|
-
this.options.selection.startColumn - matchingExpression.length
|
|
209
|
-
) + 1;
|
|
210
|
-
const endColumn = startColumn + matchingExpression.length;
|
|
211
|
-
this.options.selection = new monaco.Range(
|
|
212
|
-
this.options.selection.startLineNumber,
|
|
213
|
-
startColumn,
|
|
214
|
-
this.options.selection.startLineNumber,
|
|
215
|
-
endColumn
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (!matchingExpression) {
|
|
221
|
-
this.hide();
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
const toFocus = new DisposableCollection();
|
|
225
|
-
if (this.options.focus === true) {
|
|
226
|
-
toFocus.push(this.model.onNodeRefreshed(() => {
|
|
227
|
-
toFocus.dispose();
|
|
228
|
-
this.activate();
|
|
229
|
-
}));
|
|
230
|
-
}
|
|
231
|
-
const expression = await this.hoverSource.evaluate(matchingExpression);
|
|
232
|
-
if (!expression) {
|
|
233
|
-
toFocus.dispose();
|
|
234
|
-
this.hide();
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
this.contentNode.hidden = false;
|
|
239
|
-
['number', 'boolean', 'string'].forEach(token => this.titleNode.classList.remove(token));
|
|
240
|
-
this.domNode.classList.remove('complex-value');
|
|
241
|
-
if (expression.hasElements) {
|
|
242
|
-
this.domNode.classList.add('complex-value');
|
|
243
|
-
} else {
|
|
244
|
-
this.contentNode.hidden = true;
|
|
245
|
-
if (expression.type === 'number' || expression.type === 'boolean' || expression.type === 'string') {
|
|
246
|
-
this.titleNode.classList.add(expression.type);
|
|
247
|
-
} else if (!isNaN(+expression.value)) {
|
|
248
|
-
this.titleNode.classList.add('number');
|
|
249
|
-
} else if (DebugVariable.booleanRegex.test(expression.value)) {
|
|
250
|
-
this.titleNode.classList.add('boolean');
|
|
251
|
-
} else if (DebugVariable.stringRegex.test(expression.value)) {
|
|
252
|
-
this.titleNode.classList.add('string');
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
super.show();
|
|
257
|
-
await new Promise<void>(resolve => {
|
|
258
|
-
setTimeout(() => window.requestAnimationFrame(() => {
|
|
259
|
-
this.editor.getControl().layoutContentWidget(this);
|
|
260
|
-
resolve();
|
|
261
|
-
}), 0);
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
protected isEditorFrame(): boolean {
|
|
266
|
-
return this.sessions.isCurrentEditorFrame(this.editor.getControl().getModel()!.uri);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
getPosition(): monaco.editor.IContentWidgetPosition {
|
|
270
|
-
if (!this.isVisible) {
|
|
271
|
-
return undefined!;
|
|
272
|
-
}
|
|
273
|
-
const position = this.options && this.options.selection.getStartPosition();
|
|
274
|
-
return position
|
|
275
|
-
? {
|
|
276
|
-
position: new monaco.Position(position.lineNumber, position.column),
|
|
277
|
-
preference: [
|
|
278
|
-
monaco.editor.ContentWidgetPositionPreference.ABOVE,
|
|
279
|
-
monaco.editor.ContentWidgetPositionPreference.BELOW,
|
|
280
|
-
],
|
|
281
|
-
}
|
|
282
|
-
: undefined!;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
protected override onUpdateRequest(msg: Message): void {
|
|
286
|
-
super.onUpdateRequest(msg);
|
|
287
|
-
const { expression } = this.hoverSource;
|
|
288
|
-
const value = expression && expression.value || '';
|
|
289
|
-
this.titleNode.textContent = value;
|
|
290
|
-
this.titleNode.title = value;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
protected override onAfterAttach(msg: Message): void {
|
|
294
|
-
super.onAfterAttach(msg);
|
|
295
|
-
this.addKeyListener(this.domNode, Key.ESCAPE, () => this.hide());
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
}
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2018 TypeFox and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import debounce = require('@theia/core/shared/lodash.debounce');
|
|
18
|
+
|
|
19
|
+
import { Widget } from '@theia/core/shared/@phosphor/widgets';
|
|
20
|
+
import { Message } from '@theia/core/shared/@phosphor/messaging';
|
|
21
|
+
import { injectable, postConstruct, inject, Container, interfaces } from '@theia/core/shared/inversify';
|
|
22
|
+
import { Key } from '@theia/core/lib/browser';
|
|
23
|
+
import { SourceTreeWidget } from '@theia/core/lib/browser/source-tree';
|
|
24
|
+
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
|
|
25
|
+
import { DebugSessionManager } from '../debug-session-manager';
|
|
26
|
+
import { DebugEditor } from './debug-editor';
|
|
27
|
+
import { DebugExpressionProvider } from './debug-expression-provider';
|
|
28
|
+
import { DebugHoverSource } from './debug-hover-source';
|
|
29
|
+
import { DebugVariable } from '../console/debug-console-items';
|
|
30
|
+
import * as monaco from '@theia/monaco-editor-core';
|
|
31
|
+
import { StandaloneServices } from '@theia/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices';
|
|
32
|
+
import { ILanguageFeaturesService } from '@theia/monaco-editor-core/esm/vs/editor/common/services/languageFeatures';
|
|
33
|
+
import { CancellationTokenSource } from '@theia/monaco-editor-core/esm/vs/base/common/cancellation';
|
|
34
|
+
import { Position } from '@theia/monaco-editor-core/esm/vs/editor/common/core/position';
|
|
35
|
+
import { ArrayUtils } from '@theia/core';
|
|
36
|
+
|
|
37
|
+
export interface ShowDebugHoverOptions {
|
|
38
|
+
selection: monaco.Range
|
|
39
|
+
/** default: false */
|
|
40
|
+
focus?: boolean
|
|
41
|
+
/** default: true */
|
|
42
|
+
immediate?: boolean
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface HideDebugHoverOptions {
|
|
46
|
+
/** default: true */
|
|
47
|
+
immediate?: boolean
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function createDebugHoverWidgetContainer(parent: interfaces.Container, editor: DebugEditor): Container {
|
|
51
|
+
const child = SourceTreeWidget.createContainer(parent, {
|
|
52
|
+
virtualized: false
|
|
53
|
+
});
|
|
54
|
+
child.bind(DebugEditor).toConstantValue(editor);
|
|
55
|
+
child.bind(DebugHoverSource).toSelf();
|
|
56
|
+
child.unbind(SourceTreeWidget);
|
|
57
|
+
child.bind(DebugExpressionProvider).toSelf();
|
|
58
|
+
child.bind(DebugHoverWidget).toSelf();
|
|
59
|
+
return child;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@injectable()
|
|
63
|
+
export class DebugHoverWidget extends SourceTreeWidget implements monaco.editor.IContentWidget {
|
|
64
|
+
|
|
65
|
+
@inject(DebugEditor)
|
|
66
|
+
protected readonly editor: DebugEditor;
|
|
67
|
+
|
|
68
|
+
@inject(DebugSessionManager)
|
|
69
|
+
protected readonly sessions: DebugSessionManager;
|
|
70
|
+
|
|
71
|
+
@inject(DebugHoverSource)
|
|
72
|
+
protected readonly hoverSource: DebugHoverSource;
|
|
73
|
+
|
|
74
|
+
@inject(DebugExpressionProvider)
|
|
75
|
+
protected readonly expressionProvider: DebugExpressionProvider;
|
|
76
|
+
|
|
77
|
+
allowEditorOverflow = true;
|
|
78
|
+
|
|
79
|
+
static ID = 'debug.editor.hover';
|
|
80
|
+
getId(): string {
|
|
81
|
+
return DebugHoverWidget.ID;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
protected readonly domNode = document.createElement('div');
|
|
85
|
+
protected readonly titleNode = document.createElement('div');
|
|
86
|
+
protected readonly contentNode = document.createElement('div');
|
|
87
|
+
getDomNode(): HTMLElement {
|
|
88
|
+
return this.domNode;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@postConstruct()
|
|
92
|
+
protected override init(): void {
|
|
93
|
+
super.init();
|
|
94
|
+
this.domNode.className = 'theia-debug-hover';
|
|
95
|
+
this.titleNode.className = 'theia-debug-hover-title';
|
|
96
|
+
this.domNode.appendChild(this.titleNode);
|
|
97
|
+
this.contentNode.className = 'theia-debug-hover-content';
|
|
98
|
+
this.domNode.appendChild(this.contentNode);
|
|
99
|
+
|
|
100
|
+
// for stopping scroll events from contentNode going to the editor
|
|
101
|
+
this.contentNode.addEventListener('wheel', e => e.stopPropagation());
|
|
102
|
+
|
|
103
|
+
this.editor.getControl().addContentWidget(this);
|
|
104
|
+
this.source = this.hoverSource;
|
|
105
|
+
this.toDispose.pushAll([
|
|
106
|
+
this.hoverSource,
|
|
107
|
+
Disposable.create(() => this.editor.getControl().removeContentWidget(this)),
|
|
108
|
+
Disposable.create(() => this.hide()),
|
|
109
|
+
this.sessions.onDidChange(() => {
|
|
110
|
+
if (!this.isEditorFrame()) {
|
|
111
|
+
this.hide();
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
]);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
override dispose(): void {
|
|
118
|
+
this.toDispose.dispose();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
override show(options?: ShowDebugHoverOptions): void {
|
|
122
|
+
this.schedule(() => this.doShow(options), options && options.immediate);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
override hide(options?: HideDebugHoverOptions): void {
|
|
126
|
+
this.schedule(() => this.doHide(), options && options.immediate);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
protected readonly doSchedule = debounce((fn: () => void) => fn(), 300);
|
|
130
|
+
protected schedule(fn: () => void, immediate: boolean = true): void {
|
|
131
|
+
if (immediate) {
|
|
132
|
+
this.doSchedule.cancel();
|
|
133
|
+
fn();
|
|
134
|
+
} else {
|
|
135
|
+
this.doSchedule(fn);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
protected options: ShowDebugHoverOptions | undefined;
|
|
140
|
+
protected doHide(): void {
|
|
141
|
+
if (!this.isVisible) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (this.domNode.contains(document.activeElement)) {
|
|
145
|
+
this.editor.getControl().focus();
|
|
146
|
+
}
|
|
147
|
+
if (this.isAttached) {
|
|
148
|
+
Widget.detach(this);
|
|
149
|
+
}
|
|
150
|
+
this.hoverSource.reset();
|
|
151
|
+
super.hide();
|
|
152
|
+
this.options = undefined;
|
|
153
|
+
this.editor.getControl().layoutContentWidget(this);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
protected async doShow(options: ShowDebugHoverOptions | undefined = this.options): Promise<void> {
|
|
157
|
+
const cancellationSource = new CancellationTokenSource();
|
|
158
|
+
|
|
159
|
+
if (!this.isEditorFrame()) {
|
|
160
|
+
this.hide();
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (!options) {
|
|
164
|
+
this.hide();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (this.options && this.options.selection.equalsRange(options.selection)) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (!this.isAttached) {
|
|
171
|
+
Widget.attach(this, this.contentNode);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
this.options = options;
|
|
175
|
+
let matchingExpression: string | undefined;
|
|
176
|
+
|
|
177
|
+
const pluginExpressionProvider = StandaloneServices.get(ILanguageFeaturesService).evaluatableExpressionProvider;
|
|
178
|
+
const textEditorModel = this.editor.document.textEditorModel;
|
|
179
|
+
|
|
180
|
+
if (pluginExpressionProvider && pluginExpressionProvider.has(textEditorModel)) {
|
|
181
|
+
const registeredProviders = pluginExpressionProvider.ordered(textEditorModel);
|
|
182
|
+
const position = new Position(this.options!.selection.startLineNumber, this.options!.selection.startColumn);
|
|
183
|
+
|
|
184
|
+
const promises = registeredProviders.map(support =>
|
|
185
|
+
Promise.resolve(support.provideEvaluatableExpression(textEditorModel, position, cancellationSource.token))
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const results = await Promise.all(promises).then(ArrayUtils.coalesce);
|
|
189
|
+
if (results.length > 0) {
|
|
190
|
+
matchingExpression = results[0].expression;
|
|
191
|
+
const range = results[0].range;
|
|
192
|
+
|
|
193
|
+
if (!matchingExpression) {
|
|
194
|
+
const lineContent = textEditorModel.getLineContent(position.lineNumber);
|
|
195
|
+
matchingExpression = lineContent.substring(range.startColumn - 1, range.endColumn - 1);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
} else { // use fallback if no provider was registered
|
|
199
|
+
matchingExpression = this.expressionProvider.get(this.editor.getControl().getModel()!, options.selection);
|
|
200
|
+
if (matchingExpression) {
|
|
201
|
+
const expressionLineContent = this.editor
|
|
202
|
+
.getControl()
|
|
203
|
+
.getModel()!
|
|
204
|
+
.getLineContent(this.options.selection.startLineNumber);
|
|
205
|
+
const startColumn =
|
|
206
|
+
expressionLineContent.indexOf(
|
|
207
|
+
matchingExpression,
|
|
208
|
+
this.options.selection.startColumn - matchingExpression.length
|
|
209
|
+
) + 1;
|
|
210
|
+
const endColumn = startColumn + matchingExpression.length;
|
|
211
|
+
this.options.selection = new monaco.Range(
|
|
212
|
+
this.options.selection.startLineNumber,
|
|
213
|
+
startColumn,
|
|
214
|
+
this.options.selection.startLineNumber,
|
|
215
|
+
endColumn
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (!matchingExpression) {
|
|
221
|
+
this.hide();
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const toFocus = new DisposableCollection();
|
|
225
|
+
if (this.options.focus === true) {
|
|
226
|
+
toFocus.push(this.model.onNodeRefreshed(() => {
|
|
227
|
+
toFocus.dispose();
|
|
228
|
+
this.activate();
|
|
229
|
+
}));
|
|
230
|
+
}
|
|
231
|
+
const expression = await this.hoverSource.evaluate(matchingExpression);
|
|
232
|
+
if (!expression) {
|
|
233
|
+
toFocus.dispose();
|
|
234
|
+
this.hide();
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
this.contentNode.hidden = false;
|
|
239
|
+
['number', 'boolean', 'string'].forEach(token => this.titleNode.classList.remove(token));
|
|
240
|
+
this.domNode.classList.remove('complex-value');
|
|
241
|
+
if (expression.hasElements) {
|
|
242
|
+
this.domNode.classList.add('complex-value');
|
|
243
|
+
} else {
|
|
244
|
+
this.contentNode.hidden = true;
|
|
245
|
+
if (expression.type === 'number' || expression.type === 'boolean' || expression.type === 'string') {
|
|
246
|
+
this.titleNode.classList.add(expression.type);
|
|
247
|
+
} else if (!isNaN(+expression.value)) {
|
|
248
|
+
this.titleNode.classList.add('number');
|
|
249
|
+
} else if (DebugVariable.booleanRegex.test(expression.value)) {
|
|
250
|
+
this.titleNode.classList.add('boolean');
|
|
251
|
+
} else if (DebugVariable.stringRegex.test(expression.value)) {
|
|
252
|
+
this.titleNode.classList.add('string');
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
super.show();
|
|
257
|
+
await new Promise<void>(resolve => {
|
|
258
|
+
setTimeout(() => window.requestAnimationFrame(() => {
|
|
259
|
+
this.editor.getControl().layoutContentWidget(this);
|
|
260
|
+
resolve();
|
|
261
|
+
}), 0);
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
protected isEditorFrame(): boolean {
|
|
266
|
+
return this.sessions.isCurrentEditorFrame(this.editor.getControl().getModel()!.uri);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
getPosition(): monaco.editor.IContentWidgetPosition {
|
|
270
|
+
if (!this.isVisible) {
|
|
271
|
+
return undefined!;
|
|
272
|
+
}
|
|
273
|
+
const position = this.options && this.options.selection.getStartPosition();
|
|
274
|
+
return position
|
|
275
|
+
? {
|
|
276
|
+
position: new monaco.Position(position.lineNumber, position.column),
|
|
277
|
+
preference: [
|
|
278
|
+
monaco.editor.ContentWidgetPositionPreference.ABOVE,
|
|
279
|
+
monaco.editor.ContentWidgetPositionPreference.BELOW,
|
|
280
|
+
],
|
|
281
|
+
}
|
|
282
|
+
: undefined!;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
protected override onUpdateRequest(msg: Message): void {
|
|
286
|
+
super.onUpdateRequest(msg);
|
|
287
|
+
const { expression } = this.hoverSource;
|
|
288
|
+
const value = expression && expression.value || '';
|
|
289
|
+
this.titleNode.textContent = value;
|
|
290
|
+
this.titleNode.title = value;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
protected override onAfterAttach(msg: Message): void {
|
|
294
|
+
super.onAfterAttach(msg);
|
|
295
|
+
this.addKeyListener(this.domNode, Key.ESCAPE, () => this.hide());
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
}
|