@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.
Files changed (88) hide show
  1. package/README.md +62 -62
  2. package/lib/browser/debug-configuration-manager.js +6 -6
  3. package/lib/browser/debug-frontend-application-contribution.d.ts.map +1 -1
  4. package/lib/browser/debug-frontend-application-contribution.js.map +1 -1
  5. package/lib/common/inline-debug-adapter.d.ts +1 -0
  6. package/lib/common/inline-debug-adapter.d.ts.map +1 -1
  7. package/package.json +16 -16
  8. package/src/browser/breakpoint/breakpoint-manager.ts +369 -369
  9. package/src/browser/breakpoint/breakpoint-marker.ts +104 -104
  10. package/src/browser/console/debug-console-contribution.tsx +240 -240
  11. package/src/browser/console/debug-console-items.tsx +384 -384
  12. package/src/browser/console/debug-console-session.ts +205 -205
  13. package/src/browser/debug-call-stack-item-type-key.ts +20 -20
  14. package/src/browser/debug-configuration-manager.ts +591 -591
  15. package/src/browser/debug-configuration-model.ts +100 -100
  16. package/src/browser/debug-contribution.ts +43 -43
  17. package/src/browser/debug-frontend-application-contribution.ts +1551 -1551
  18. package/src/browser/debug-frontend-module.ts +133 -133
  19. package/src/browser/debug-package.spec.ts +20 -20
  20. package/src/browser/debug-preferences.ts +98 -98
  21. package/src/browser/debug-prefix-configuration.ts +195 -195
  22. package/src/browser/debug-resource.ts +59 -59
  23. package/src/browser/debug-schema-updater.ts +149 -149
  24. package/src/browser/debug-session-connection.ts +357 -357
  25. package/src/browser/debug-session-contribution.ts +157 -157
  26. package/src/browser/debug-session-manager.ts +683 -683
  27. package/src/browser/debug-session-options.ts +120 -120
  28. package/src/browser/debug-session.tsx +974 -974
  29. package/src/browser/debug-tab-bar-decorator.ts +57 -57
  30. package/src/browser/debug-watch-manager.ts +93 -93
  31. package/src/browser/disassembly-view/disassembly-view-accessibility-provider.ts +43 -43
  32. package/src/browser/disassembly-view/disassembly-view-breakpoint-renderer.ts +119 -119
  33. package/src/browser/disassembly-view/disassembly-view-contribution.ts +109 -109
  34. package/src/browser/disassembly-view/disassembly-view-instruction-renderer.ts +245 -245
  35. package/src/browser/disassembly-view/disassembly-view-table-delegate.ts +39 -39
  36. package/src/browser/disassembly-view/disassembly-view-utilities.ts +55 -55
  37. package/src/browser/disassembly-view/disassembly-view-widget.ts +463 -463
  38. package/src/browser/editor/debug-breakpoint-widget.tsx +293 -293
  39. package/src/browser/editor/debug-editor-model.ts +529 -529
  40. package/src/browser/editor/debug-editor-service.ts +192 -192
  41. package/src/browser/editor/debug-editor.ts +20 -20
  42. package/src/browser/editor/debug-exception-widget.tsx +122 -122
  43. package/src/browser/editor/debug-expression-provider.ts +78 -78
  44. package/src/browser/editor/debug-hover-source.tsx +105 -105
  45. package/src/browser/editor/debug-hover-widget.ts +298 -298
  46. package/src/browser/editor/debug-inline-value-decorator.ts +373 -373
  47. package/src/browser/model/debug-breakpoint.tsx +151 -151
  48. package/src/browser/model/debug-function-breakpoint.tsx +101 -101
  49. package/src/browser/model/debug-instruction-breakpoint.tsx +68 -68
  50. package/src/browser/model/debug-source-breakpoint.tsx +237 -237
  51. package/src/browser/model/debug-source.ts +93 -93
  52. package/src/browser/model/debug-stack-frame.tsx +177 -177
  53. package/src/browser/model/debug-thread.tsx +292 -292
  54. package/src/browser/preferences/launch-preferences.ts +38 -38
  55. package/src/browser/style/index.css +453 -453
  56. package/src/browser/view/debug-action.tsx +57 -57
  57. package/src/browser/view/debug-breakpoints-source.tsx +53 -53
  58. package/src/browser/view/debug-breakpoints-widget.ts +71 -71
  59. package/src/browser/view/debug-configuration-select.tsx +269 -269
  60. package/src/browser/view/debug-configuration-widget.tsx +121 -121
  61. package/src/browser/view/debug-exception-breakpoint.tsx +68 -68
  62. package/src/browser/view/debug-session-widget.ts +124 -124
  63. package/src/browser/view/debug-stack-frames-source.tsx +75 -75
  64. package/src/browser/view/debug-stack-frames-widget.ts +135 -135
  65. package/src/browser/view/debug-threads-source.tsx +48 -48
  66. package/src/browser/view/debug-threads-widget.ts +126 -126
  67. package/src/browser/view/debug-toolbar-widget.tsx +145 -145
  68. package/src/browser/view/debug-variables-source.ts +43 -43
  69. package/src/browser/view/debug-variables-widget.ts +61 -61
  70. package/src/browser/view/debug-view-model.ts +230 -230
  71. package/src/browser/view/debug-watch-expression.tsx +88 -88
  72. package/src/browser/view/debug-watch-source.ts +41 -41
  73. package/src/browser/view/debug-watch-widget.ts +61 -61
  74. package/src/browser/view/debug-widget.ts +97 -97
  75. package/src/common/debug-adapter-contribution-registry.ts +206 -206
  76. package/src/common/debug-adapter-session.ts +102 -102
  77. package/src/common/debug-common.ts +19 -19
  78. package/src/common/debug-compound.ts +33 -33
  79. package/src/common/debug-configuration.ts +112 -112
  80. package/src/common/debug-model.ts +200 -200
  81. package/src/common/debug-service.ts +184 -184
  82. package/src/common/debug-uri-utils.ts +24 -24
  83. package/src/common/inline-debug-adapter.ts +47 -47
  84. package/src/node/debug-adapter-factory.ts +107 -107
  85. package/src/node/debug-adapter-session-manager.ts +106 -106
  86. package/src/node/debug-backend-module.ts +57 -57
  87. package/src/node/debug-service-impl.ts +119 -119
  88. package/src/node/stream-debug-adapter.ts +126 -126
@@ -1,369 +1,369 @@
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 * as deepEqual from 'fast-deep-equal';
18
- import { injectable, inject } from '@theia/core/shared/inversify';
19
- import { Emitter } from '@theia/core/lib/common';
20
- import { StorageService } from '@theia/core/lib/browser';
21
- import { Marker } from '@theia/markers/lib/common/marker';
22
- import { MarkerManager } from '@theia/markers/lib/browser/marker-manager';
23
- import URI from '@theia/core/lib/common/uri';
24
- import { SourceBreakpoint, BREAKPOINT_KIND, ExceptionBreakpoint, FunctionBreakpoint, BaseBreakpoint, InstructionBreakpoint } from './breakpoint-marker';
25
-
26
- export interface BreakpointsChangeEvent<T extends BaseBreakpoint> {
27
- uri: URI
28
- added: T[]
29
- removed: T[]
30
- changed: T[]
31
- }
32
- export type SourceBreakpointsChangeEvent = BreakpointsChangeEvent<SourceBreakpoint>;
33
- export type FunctionBreakpointsChangeEvent = BreakpointsChangeEvent<FunctionBreakpoint>;
34
- export type InstructionBreakpointsChangeEvent = BreakpointsChangeEvent<InstructionBreakpoint>;
35
-
36
- @injectable()
37
- export class BreakpointManager extends MarkerManager<SourceBreakpoint> {
38
-
39
- static EXCEPTION_URI = new URI('debug:exception://');
40
-
41
- static FUNCTION_URI = new URI('debug:function://');
42
-
43
- static INSTRUCTION_URI = new URI('debug:instruction://');
44
-
45
- protected readonly owner = 'breakpoint';
46
-
47
- @inject(StorageService)
48
- protected readonly storage: StorageService;
49
-
50
- getKind(): string {
51
- return BREAKPOINT_KIND;
52
- }
53
-
54
- protected readonly onDidChangeBreakpointsEmitter = new Emitter<SourceBreakpointsChangeEvent>();
55
- readonly onDidChangeBreakpoints = this.onDidChangeBreakpointsEmitter.event;
56
-
57
- protected readonly onDidChangeFunctionBreakpointsEmitter = new Emitter<FunctionBreakpointsChangeEvent>();
58
- readonly onDidChangeFunctionBreakpoints = this.onDidChangeFunctionBreakpointsEmitter.event;
59
-
60
- protected readonly onDidChangeInstructionBreakpointsEmitter = new Emitter<InstructionBreakpointsChangeEvent>();
61
- readonly onDidChangeInstructionBreakpoints = this.onDidChangeInstructionBreakpointsEmitter.event;
62
-
63
- override setMarkers(uri: URI, owner: string, newMarkers: SourceBreakpoint[]): Marker<SourceBreakpoint>[] {
64
- const result = this.findMarkers({ uri, owner });
65
- const added: SourceBreakpoint[] = [];
66
- const removed: SourceBreakpoint[] = [];
67
- const changed: SourceBreakpoint[] = [];
68
- const oldMarkers = new Map(result.map(({ data }) => [data.id, data]));
69
- const ids = new Set<string>();
70
- let didChangeMarkers = false;
71
- for (const newMarker of newMarkers) {
72
- ids.add(newMarker.id);
73
- const oldMarker = oldMarkers.get(newMarker.id);
74
- if (!oldMarker) {
75
- added.push(newMarker);
76
- } else {
77
- // We emit all existing markers as 'changed', but we only fire an event if something really did change.
78
- // We also fire an event if oldMarker === newMarker, as we cannot actually detect a change in this case
79
- // (https://github.com/eclipse-theia/theia/issues/12546).
80
- didChangeMarkers ||= !!added.length || oldMarker === newMarker || !deepEqual(oldMarker, newMarker);
81
- changed.push(newMarker);
82
- }
83
- }
84
- for (const [id, data] of oldMarkers.entries()) {
85
- if (!ids.has(id)) {
86
- removed.push(data);
87
- }
88
- }
89
- if (added.length || removed.length || didChangeMarkers) {
90
- super.setMarkers(uri, owner, newMarkers);
91
- this.onDidChangeBreakpointsEmitter.fire({ uri, added, removed, changed });
92
- }
93
- return result;
94
- }
95
-
96
- getLineBreakpoints(uri: URI, line: number): SourceBreakpoint[] {
97
- return this.findMarkers({
98
- uri,
99
- dataFilter: breakpoint => breakpoint.raw.line === line
100
- }).map(({ data }) => data);
101
- }
102
-
103
- getInlineBreakpoint(uri: URI, line: number, column: number): SourceBreakpoint | undefined {
104
- const marker = this.findMarkers({
105
- uri,
106
- dataFilter: breakpoint => breakpoint.raw.line === line && breakpoint.raw.column === column
107
- })[0];
108
- return marker && marker.data;
109
- }
110
-
111
- getBreakpoints(uri?: URI): SourceBreakpoint[] {
112
- return this.findMarkers({ uri }).map(marker => marker.data);
113
- }
114
-
115
- setBreakpoints(uri: URI, breakpoints: SourceBreakpoint[]): void {
116
- this.setMarkers(uri, this.owner, breakpoints.sort((a, b) => (a.raw.line - b.raw.line) || ((a.raw.column || 0) - (b.raw.column || 0))));
117
- }
118
-
119
- addBreakpoint(breakpoint: SourceBreakpoint): boolean {
120
- const uri = new URI(breakpoint.uri);
121
- const breakpoints = this.getBreakpoints(uri);
122
- const newBreakpoints = breakpoints.filter(({ raw }) => !(raw.line === breakpoint.raw.line && raw.column === breakpoint.raw.column));
123
- if (breakpoints.length === newBreakpoints.length) {
124
- newBreakpoints.push(breakpoint);
125
- this.setBreakpoints(uri, newBreakpoints);
126
- return true;
127
- }
128
- return false;
129
- }
130
-
131
- enableAllBreakpoints(enabled: boolean): void {
132
- for (const uriString of this.getUris()) {
133
- let didChange = false;
134
- const uri = new URI(uriString);
135
- const markers = this.findMarkers({ uri });
136
- for (const marker of markers) {
137
- if (marker.data.enabled !== enabled) {
138
- marker.data.enabled = enabled;
139
- didChange = true;
140
- }
141
- }
142
- if (didChange) {
143
- this.fireOnDidChangeMarkers(uri);
144
- }
145
- }
146
- let didChangeFunction = false;
147
- for (const breakpoint of (this.getFunctionBreakpoints() as BaseBreakpoint[]).concat(this.getInstructionBreakpoints())) {
148
- if (breakpoint.enabled !== enabled) {
149
- breakpoint.enabled = enabled;
150
- didChangeFunction = true;
151
-
152
- }
153
- }
154
- if (didChangeFunction) {
155
- this.fireOnDidChangeMarkers(BreakpointManager.FUNCTION_URI);
156
- }
157
- }
158
-
159
- protected _breakpointsEnabled = true;
160
- get breakpointsEnabled(): boolean {
161
- return this._breakpointsEnabled;
162
- }
163
- set breakpointsEnabled(breakpointsEnabled: boolean) {
164
- if (this._breakpointsEnabled !== breakpointsEnabled) {
165
- this._breakpointsEnabled = breakpointsEnabled;
166
- for (const uri of this.getUris()) {
167
- this.fireOnDidChangeMarkers(new URI(uri));
168
- }
169
- this.fireOnDidChangeMarkers(BreakpointManager.FUNCTION_URI);
170
- }
171
- }
172
-
173
- protected readonly exceptionBreakpoints = new Map<string, ExceptionBreakpoint>();
174
-
175
- getExceptionBreakpoint(filter: string): ExceptionBreakpoint | undefined {
176
- return this.exceptionBreakpoints.get(filter);
177
- }
178
-
179
- getExceptionBreakpoints(): IterableIterator<ExceptionBreakpoint> {
180
- return this.exceptionBreakpoints.values();
181
- }
182
-
183
- setExceptionBreakpoints(exceptionBreakpoints: ExceptionBreakpoint[]): void {
184
- const toRemove = new Set(this.exceptionBreakpoints.keys());
185
- for (const exceptionBreakpoint of exceptionBreakpoints) {
186
- const filter = exceptionBreakpoint.raw.filter;
187
- toRemove.delete(filter);
188
- this.exceptionBreakpoints.set(filter, exceptionBreakpoint);
189
- }
190
- for (const filter of toRemove) {
191
- this.exceptionBreakpoints.delete(filter);
192
- }
193
- if (toRemove.size || exceptionBreakpoints.length) {
194
- this.fireOnDidChangeMarkers(BreakpointManager.EXCEPTION_URI);
195
- }
196
- }
197
-
198
- toggleExceptionBreakpoint(filter: string): void {
199
- const breakpoint = this.getExceptionBreakpoint(filter);
200
- if (breakpoint) {
201
- breakpoint.enabled = !breakpoint.enabled;
202
- this.fireOnDidChangeMarkers(BreakpointManager.EXCEPTION_URI);
203
- }
204
- }
205
-
206
- updateExceptionBreakpoint(filter: string, options: Partial<Pick<ExceptionBreakpoint, 'condition' | 'enabled'>>): void {
207
- const breakpoint = this.getExceptionBreakpoint(filter);
208
- if (breakpoint) {
209
- Object.assign(breakpoint, options);
210
- this.fireOnDidChangeMarkers(BreakpointManager.EXCEPTION_URI);
211
- }
212
- }
213
-
214
- protected functionBreakpoints: FunctionBreakpoint[] = [];
215
-
216
- getFunctionBreakpoints(): FunctionBreakpoint[] {
217
- return this.functionBreakpoints;
218
- }
219
-
220
- setFunctionBreakpoints(functionBreakpoints: FunctionBreakpoint[]): void {
221
- const oldBreakpoints = new Map(this.functionBreakpoints.map(b => [b.id, b] as [string, FunctionBreakpoint]));
222
-
223
- this.functionBreakpoints = functionBreakpoints;
224
- this.fireOnDidChangeMarkers(BreakpointManager.FUNCTION_URI);
225
-
226
- const added: FunctionBreakpoint[] = [];
227
- const removed: FunctionBreakpoint[] = [];
228
- const changed: FunctionBreakpoint[] = [];
229
- const ids = new Set<string>();
230
- for (const newBreakpoint of functionBreakpoints) {
231
- ids.add(newBreakpoint.id);
232
- if (oldBreakpoints.has(newBreakpoint.id)) {
233
- changed.push(newBreakpoint);
234
- } else {
235
- added.push(newBreakpoint);
236
- }
237
- }
238
- for (const [id, breakpoint] of oldBreakpoints.entries()) {
239
- if (!ids.has(id)) {
240
- removed.push(breakpoint);
241
- }
242
- }
243
- this.onDidChangeFunctionBreakpointsEmitter.fire({ uri: BreakpointManager.FUNCTION_URI, added, removed, changed });
244
- }
245
-
246
- protected instructionBreakpoints: InstructionBreakpoint[] = [];
247
-
248
- getInstructionBreakpoints(): ReadonlyArray<InstructionBreakpoint> {
249
- return Object.freeze(this.instructionBreakpoints.slice());
250
- }
251
-
252
- hasBreakpoints(): boolean {
253
- return Boolean(this.getUris().next().value || this.functionBreakpoints.length || this.instructionBreakpoints.length);
254
- }
255
-
256
- protected setInstructionBreakpoints(newBreakpoints: InstructionBreakpoint[]): void {
257
- const oldBreakpoints = new Map(this.instructionBreakpoints.map(breakpoint => [breakpoint.id, breakpoint]));
258
- const currentBreakpoints = new Map(newBreakpoints.map(breakpoint => [breakpoint.id, breakpoint]));
259
- const added = [];
260
- const changed = [];
261
- for (const [id, breakpoint] of currentBreakpoints.entries()) {
262
- const old = oldBreakpoints.get(id);
263
- if (old) {
264
- changed.push(old);
265
- } else {
266
- added.push(breakpoint);
267
- }
268
- oldBreakpoints.delete(id);
269
- }
270
- const removed = Array.from(oldBreakpoints.values());
271
- this.instructionBreakpoints = Array.from(currentBreakpoints.values());
272
- this.fireOnDidChangeMarkers(BreakpointManager.INSTRUCTION_URI);
273
- this.onDidChangeInstructionBreakpointsEmitter.fire({ uri: BreakpointManager.INSTRUCTION_URI, added, removed, changed });
274
- }
275
-
276
- addInstructionBreakpoint(address: string, offset: number, condition?: string, hitCondition?: string): void {
277
- this.setInstructionBreakpoints(this.instructionBreakpoints.concat(InstructionBreakpoint.create({
278
- instructionReference: address,
279
- offset,
280
- condition,
281
- hitCondition,
282
- })));
283
- }
284
-
285
- updateInstructionBreakpoint(id: string, options: Partial<Pick<InstructionBreakpoint, 'condition' | 'hitCondition' | 'enabled'>>): void {
286
- const breakpoint = this.instructionBreakpoints.find(candidate => id === candidate.id);
287
- if (breakpoint) {
288
- Object.assign(breakpoint, options);
289
- this.fireOnDidChangeMarkers(BreakpointManager.INSTRUCTION_URI);
290
- this.onDidChangeInstructionBreakpointsEmitter.fire({ uri: BreakpointManager.INSTRUCTION_URI, changed: [breakpoint], added: [], removed: [] });
291
- }
292
- }
293
-
294
- removeInstructionBreakpoint(address?: string): void {
295
- if (!address) {
296
- this.clearInstructionBreakpoints();
297
- }
298
- const breakpointIndex = this.instructionBreakpoints.findIndex(breakpoint => breakpoint.instructionReference === address);
299
- if (breakpointIndex !== -1) {
300
- const removed = this.instructionBreakpoints.splice(breakpointIndex, 1);
301
- this.fireOnDidChangeMarkers(BreakpointManager.INSTRUCTION_URI);
302
- this.onDidChangeInstructionBreakpointsEmitter.fire({ uri: BreakpointManager.INSTRUCTION_URI, added: [], changed: [], removed });
303
- }
304
- }
305
-
306
- clearInstructionBreakpoints(): void {
307
- this.setInstructionBreakpoints([]);
308
- }
309
-
310
- removeBreakpoints(): void {
311
- this.cleanAllMarkers();
312
- this.setFunctionBreakpoints([]);
313
- this.setInstructionBreakpoints([]);
314
- }
315
-
316
- async load(): Promise<void> {
317
- const data = await this.storage.getData<BreakpointManager.Data>('breakpoints', {
318
- breakpointsEnabled: true,
319
- breakpoints: {}
320
- });
321
- this._breakpointsEnabled = data.breakpointsEnabled;
322
- // eslint-disable-next-line guard-for-in
323
- for (const uri in data.breakpoints) {
324
- this.setBreakpoints(new URI(uri), data.breakpoints[uri]);
325
- }
326
- if (data.functionBreakpoints) {
327
- this.setFunctionBreakpoints(data.functionBreakpoints);
328
- }
329
- if (data.exceptionBreakpoints) {
330
- this.setExceptionBreakpoints(data.exceptionBreakpoints);
331
- }
332
- if (data.instructionBreakpoints) {
333
- this.setInstructionBreakpoints(data.instructionBreakpoints);
334
- }
335
- }
336
-
337
- save(): void {
338
- const data: BreakpointManager.Data = {
339
- breakpointsEnabled: this._breakpointsEnabled,
340
- breakpoints: {}
341
- };
342
- const uris = this.getUris();
343
- for (const uri of uris) {
344
- data.breakpoints[uri] = this.findMarkers({ uri: new URI(uri) }).map(marker => marker.data);
345
- }
346
- if (this.functionBreakpoints.length) {
347
- data.functionBreakpoints = this.functionBreakpoints;
348
- }
349
- if (this.exceptionBreakpoints.size) {
350
- data.exceptionBreakpoints = [...this.exceptionBreakpoints.values()];
351
- }
352
- if (this.instructionBreakpoints.length) {
353
- data.instructionBreakpoints = this.instructionBreakpoints;
354
- }
355
- this.storage.setData('breakpoints', data);
356
- }
357
-
358
- }
359
- export namespace BreakpointManager {
360
- export interface Data {
361
- breakpointsEnabled: boolean;
362
- breakpoints: {
363
- [uri: string]: SourceBreakpoint[];
364
- }
365
- exceptionBreakpoints?: ExceptionBreakpoint[];
366
- functionBreakpoints?: FunctionBreakpoint[];
367
- instructionBreakpoints?: InstructionBreakpoint[];
368
- }
369
- }
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 * as deepEqual from 'fast-deep-equal';
18
+ import { injectable, inject } from '@theia/core/shared/inversify';
19
+ import { Emitter } from '@theia/core/lib/common';
20
+ import { StorageService } from '@theia/core/lib/browser';
21
+ import { Marker } from '@theia/markers/lib/common/marker';
22
+ import { MarkerManager } from '@theia/markers/lib/browser/marker-manager';
23
+ import URI from '@theia/core/lib/common/uri';
24
+ import { SourceBreakpoint, BREAKPOINT_KIND, ExceptionBreakpoint, FunctionBreakpoint, BaseBreakpoint, InstructionBreakpoint } from './breakpoint-marker';
25
+
26
+ export interface BreakpointsChangeEvent<T extends BaseBreakpoint> {
27
+ uri: URI
28
+ added: T[]
29
+ removed: T[]
30
+ changed: T[]
31
+ }
32
+ export type SourceBreakpointsChangeEvent = BreakpointsChangeEvent<SourceBreakpoint>;
33
+ export type FunctionBreakpointsChangeEvent = BreakpointsChangeEvent<FunctionBreakpoint>;
34
+ export type InstructionBreakpointsChangeEvent = BreakpointsChangeEvent<InstructionBreakpoint>;
35
+
36
+ @injectable()
37
+ export class BreakpointManager extends MarkerManager<SourceBreakpoint> {
38
+
39
+ static EXCEPTION_URI = new URI('debug:exception://');
40
+
41
+ static FUNCTION_URI = new URI('debug:function://');
42
+
43
+ static INSTRUCTION_URI = new URI('debug:instruction://');
44
+
45
+ protected readonly owner = 'breakpoint';
46
+
47
+ @inject(StorageService)
48
+ protected readonly storage: StorageService;
49
+
50
+ getKind(): string {
51
+ return BREAKPOINT_KIND;
52
+ }
53
+
54
+ protected readonly onDidChangeBreakpointsEmitter = new Emitter<SourceBreakpointsChangeEvent>();
55
+ readonly onDidChangeBreakpoints = this.onDidChangeBreakpointsEmitter.event;
56
+
57
+ protected readonly onDidChangeFunctionBreakpointsEmitter = new Emitter<FunctionBreakpointsChangeEvent>();
58
+ readonly onDidChangeFunctionBreakpoints = this.onDidChangeFunctionBreakpointsEmitter.event;
59
+
60
+ protected readonly onDidChangeInstructionBreakpointsEmitter = new Emitter<InstructionBreakpointsChangeEvent>();
61
+ readonly onDidChangeInstructionBreakpoints = this.onDidChangeInstructionBreakpointsEmitter.event;
62
+
63
+ override setMarkers(uri: URI, owner: string, newMarkers: SourceBreakpoint[]): Marker<SourceBreakpoint>[] {
64
+ const result = this.findMarkers({ uri, owner });
65
+ const added: SourceBreakpoint[] = [];
66
+ const removed: SourceBreakpoint[] = [];
67
+ const changed: SourceBreakpoint[] = [];
68
+ const oldMarkers = new Map(result.map(({ data }) => [data.id, data]));
69
+ const ids = new Set<string>();
70
+ let didChangeMarkers = false;
71
+ for (const newMarker of newMarkers) {
72
+ ids.add(newMarker.id);
73
+ const oldMarker = oldMarkers.get(newMarker.id);
74
+ if (!oldMarker) {
75
+ added.push(newMarker);
76
+ } else {
77
+ // We emit all existing markers as 'changed', but we only fire an event if something really did change.
78
+ // We also fire an event if oldMarker === newMarker, as we cannot actually detect a change in this case
79
+ // (https://github.com/eclipse-theia/theia/issues/12546).
80
+ didChangeMarkers ||= !!added.length || oldMarker === newMarker || !deepEqual(oldMarker, newMarker);
81
+ changed.push(newMarker);
82
+ }
83
+ }
84
+ for (const [id, data] of oldMarkers.entries()) {
85
+ if (!ids.has(id)) {
86
+ removed.push(data);
87
+ }
88
+ }
89
+ if (added.length || removed.length || didChangeMarkers) {
90
+ super.setMarkers(uri, owner, newMarkers);
91
+ this.onDidChangeBreakpointsEmitter.fire({ uri, added, removed, changed });
92
+ }
93
+ return result;
94
+ }
95
+
96
+ getLineBreakpoints(uri: URI, line: number): SourceBreakpoint[] {
97
+ return this.findMarkers({
98
+ uri,
99
+ dataFilter: breakpoint => breakpoint.raw.line === line
100
+ }).map(({ data }) => data);
101
+ }
102
+
103
+ getInlineBreakpoint(uri: URI, line: number, column: number): SourceBreakpoint | undefined {
104
+ const marker = this.findMarkers({
105
+ uri,
106
+ dataFilter: breakpoint => breakpoint.raw.line === line && breakpoint.raw.column === column
107
+ })[0];
108
+ return marker && marker.data;
109
+ }
110
+
111
+ getBreakpoints(uri?: URI): SourceBreakpoint[] {
112
+ return this.findMarkers({ uri }).map(marker => marker.data);
113
+ }
114
+
115
+ setBreakpoints(uri: URI, breakpoints: SourceBreakpoint[]): void {
116
+ this.setMarkers(uri, this.owner, breakpoints.sort((a, b) => (a.raw.line - b.raw.line) || ((a.raw.column || 0) - (b.raw.column || 0))));
117
+ }
118
+
119
+ addBreakpoint(breakpoint: SourceBreakpoint): boolean {
120
+ const uri = new URI(breakpoint.uri);
121
+ const breakpoints = this.getBreakpoints(uri);
122
+ const newBreakpoints = breakpoints.filter(({ raw }) => !(raw.line === breakpoint.raw.line && raw.column === breakpoint.raw.column));
123
+ if (breakpoints.length === newBreakpoints.length) {
124
+ newBreakpoints.push(breakpoint);
125
+ this.setBreakpoints(uri, newBreakpoints);
126
+ return true;
127
+ }
128
+ return false;
129
+ }
130
+
131
+ enableAllBreakpoints(enabled: boolean): void {
132
+ for (const uriString of this.getUris()) {
133
+ let didChange = false;
134
+ const uri = new URI(uriString);
135
+ const markers = this.findMarkers({ uri });
136
+ for (const marker of markers) {
137
+ if (marker.data.enabled !== enabled) {
138
+ marker.data.enabled = enabled;
139
+ didChange = true;
140
+ }
141
+ }
142
+ if (didChange) {
143
+ this.fireOnDidChangeMarkers(uri);
144
+ }
145
+ }
146
+ let didChangeFunction = false;
147
+ for (const breakpoint of (this.getFunctionBreakpoints() as BaseBreakpoint[]).concat(this.getInstructionBreakpoints())) {
148
+ if (breakpoint.enabled !== enabled) {
149
+ breakpoint.enabled = enabled;
150
+ didChangeFunction = true;
151
+
152
+ }
153
+ }
154
+ if (didChangeFunction) {
155
+ this.fireOnDidChangeMarkers(BreakpointManager.FUNCTION_URI);
156
+ }
157
+ }
158
+
159
+ protected _breakpointsEnabled = true;
160
+ get breakpointsEnabled(): boolean {
161
+ return this._breakpointsEnabled;
162
+ }
163
+ set breakpointsEnabled(breakpointsEnabled: boolean) {
164
+ if (this._breakpointsEnabled !== breakpointsEnabled) {
165
+ this._breakpointsEnabled = breakpointsEnabled;
166
+ for (const uri of this.getUris()) {
167
+ this.fireOnDidChangeMarkers(new URI(uri));
168
+ }
169
+ this.fireOnDidChangeMarkers(BreakpointManager.FUNCTION_URI);
170
+ }
171
+ }
172
+
173
+ protected readonly exceptionBreakpoints = new Map<string, ExceptionBreakpoint>();
174
+
175
+ getExceptionBreakpoint(filter: string): ExceptionBreakpoint | undefined {
176
+ return this.exceptionBreakpoints.get(filter);
177
+ }
178
+
179
+ getExceptionBreakpoints(): IterableIterator<ExceptionBreakpoint> {
180
+ return this.exceptionBreakpoints.values();
181
+ }
182
+
183
+ setExceptionBreakpoints(exceptionBreakpoints: ExceptionBreakpoint[]): void {
184
+ const toRemove = new Set(this.exceptionBreakpoints.keys());
185
+ for (const exceptionBreakpoint of exceptionBreakpoints) {
186
+ const filter = exceptionBreakpoint.raw.filter;
187
+ toRemove.delete(filter);
188
+ this.exceptionBreakpoints.set(filter, exceptionBreakpoint);
189
+ }
190
+ for (const filter of toRemove) {
191
+ this.exceptionBreakpoints.delete(filter);
192
+ }
193
+ if (toRemove.size || exceptionBreakpoints.length) {
194
+ this.fireOnDidChangeMarkers(BreakpointManager.EXCEPTION_URI);
195
+ }
196
+ }
197
+
198
+ toggleExceptionBreakpoint(filter: string): void {
199
+ const breakpoint = this.getExceptionBreakpoint(filter);
200
+ if (breakpoint) {
201
+ breakpoint.enabled = !breakpoint.enabled;
202
+ this.fireOnDidChangeMarkers(BreakpointManager.EXCEPTION_URI);
203
+ }
204
+ }
205
+
206
+ updateExceptionBreakpoint(filter: string, options: Partial<Pick<ExceptionBreakpoint, 'condition' | 'enabled'>>): void {
207
+ const breakpoint = this.getExceptionBreakpoint(filter);
208
+ if (breakpoint) {
209
+ Object.assign(breakpoint, options);
210
+ this.fireOnDidChangeMarkers(BreakpointManager.EXCEPTION_URI);
211
+ }
212
+ }
213
+
214
+ protected functionBreakpoints: FunctionBreakpoint[] = [];
215
+
216
+ getFunctionBreakpoints(): FunctionBreakpoint[] {
217
+ return this.functionBreakpoints;
218
+ }
219
+
220
+ setFunctionBreakpoints(functionBreakpoints: FunctionBreakpoint[]): void {
221
+ const oldBreakpoints = new Map(this.functionBreakpoints.map(b => [b.id, b] as [string, FunctionBreakpoint]));
222
+
223
+ this.functionBreakpoints = functionBreakpoints;
224
+ this.fireOnDidChangeMarkers(BreakpointManager.FUNCTION_URI);
225
+
226
+ const added: FunctionBreakpoint[] = [];
227
+ const removed: FunctionBreakpoint[] = [];
228
+ const changed: FunctionBreakpoint[] = [];
229
+ const ids = new Set<string>();
230
+ for (const newBreakpoint of functionBreakpoints) {
231
+ ids.add(newBreakpoint.id);
232
+ if (oldBreakpoints.has(newBreakpoint.id)) {
233
+ changed.push(newBreakpoint);
234
+ } else {
235
+ added.push(newBreakpoint);
236
+ }
237
+ }
238
+ for (const [id, breakpoint] of oldBreakpoints.entries()) {
239
+ if (!ids.has(id)) {
240
+ removed.push(breakpoint);
241
+ }
242
+ }
243
+ this.onDidChangeFunctionBreakpointsEmitter.fire({ uri: BreakpointManager.FUNCTION_URI, added, removed, changed });
244
+ }
245
+
246
+ protected instructionBreakpoints: InstructionBreakpoint[] = [];
247
+
248
+ getInstructionBreakpoints(): ReadonlyArray<InstructionBreakpoint> {
249
+ return Object.freeze(this.instructionBreakpoints.slice());
250
+ }
251
+
252
+ hasBreakpoints(): boolean {
253
+ return Boolean(this.getUris().next().value || this.functionBreakpoints.length || this.instructionBreakpoints.length);
254
+ }
255
+
256
+ protected setInstructionBreakpoints(newBreakpoints: InstructionBreakpoint[]): void {
257
+ const oldBreakpoints = new Map(this.instructionBreakpoints.map(breakpoint => [breakpoint.id, breakpoint]));
258
+ const currentBreakpoints = new Map(newBreakpoints.map(breakpoint => [breakpoint.id, breakpoint]));
259
+ const added = [];
260
+ const changed = [];
261
+ for (const [id, breakpoint] of currentBreakpoints.entries()) {
262
+ const old = oldBreakpoints.get(id);
263
+ if (old) {
264
+ changed.push(old);
265
+ } else {
266
+ added.push(breakpoint);
267
+ }
268
+ oldBreakpoints.delete(id);
269
+ }
270
+ const removed = Array.from(oldBreakpoints.values());
271
+ this.instructionBreakpoints = Array.from(currentBreakpoints.values());
272
+ this.fireOnDidChangeMarkers(BreakpointManager.INSTRUCTION_URI);
273
+ this.onDidChangeInstructionBreakpointsEmitter.fire({ uri: BreakpointManager.INSTRUCTION_URI, added, removed, changed });
274
+ }
275
+
276
+ addInstructionBreakpoint(address: string, offset: number, condition?: string, hitCondition?: string): void {
277
+ this.setInstructionBreakpoints(this.instructionBreakpoints.concat(InstructionBreakpoint.create({
278
+ instructionReference: address,
279
+ offset,
280
+ condition,
281
+ hitCondition,
282
+ })));
283
+ }
284
+
285
+ updateInstructionBreakpoint(id: string, options: Partial<Pick<InstructionBreakpoint, 'condition' | 'hitCondition' | 'enabled'>>): void {
286
+ const breakpoint = this.instructionBreakpoints.find(candidate => id === candidate.id);
287
+ if (breakpoint) {
288
+ Object.assign(breakpoint, options);
289
+ this.fireOnDidChangeMarkers(BreakpointManager.INSTRUCTION_URI);
290
+ this.onDidChangeInstructionBreakpointsEmitter.fire({ uri: BreakpointManager.INSTRUCTION_URI, changed: [breakpoint], added: [], removed: [] });
291
+ }
292
+ }
293
+
294
+ removeInstructionBreakpoint(address?: string): void {
295
+ if (!address) {
296
+ this.clearInstructionBreakpoints();
297
+ }
298
+ const breakpointIndex = this.instructionBreakpoints.findIndex(breakpoint => breakpoint.instructionReference === address);
299
+ if (breakpointIndex !== -1) {
300
+ const removed = this.instructionBreakpoints.splice(breakpointIndex, 1);
301
+ this.fireOnDidChangeMarkers(BreakpointManager.INSTRUCTION_URI);
302
+ this.onDidChangeInstructionBreakpointsEmitter.fire({ uri: BreakpointManager.INSTRUCTION_URI, added: [], changed: [], removed });
303
+ }
304
+ }
305
+
306
+ clearInstructionBreakpoints(): void {
307
+ this.setInstructionBreakpoints([]);
308
+ }
309
+
310
+ removeBreakpoints(): void {
311
+ this.cleanAllMarkers();
312
+ this.setFunctionBreakpoints([]);
313
+ this.setInstructionBreakpoints([]);
314
+ }
315
+
316
+ async load(): Promise<void> {
317
+ const data = await this.storage.getData<BreakpointManager.Data>('breakpoints', {
318
+ breakpointsEnabled: true,
319
+ breakpoints: {}
320
+ });
321
+ this._breakpointsEnabled = data.breakpointsEnabled;
322
+ // eslint-disable-next-line guard-for-in
323
+ for (const uri in data.breakpoints) {
324
+ this.setBreakpoints(new URI(uri), data.breakpoints[uri]);
325
+ }
326
+ if (data.functionBreakpoints) {
327
+ this.setFunctionBreakpoints(data.functionBreakpoints);
328
+ }
329
+ if (data.exceptionBreakpoints) {
330
+ this.setExceptionBreakpoints(data.exceptionBreakpoints);
331
+ }
332
+ if (data.instructionBreakpoints) {
333
+ this.setInstructionBreakpoints(data.instructionBreakpoints);
334
+ }
335
+ }
336
+
337
+ save(): void {
338
+ const data: BreakpointManager.Data = {
339
+ breakpointsEnabled: this._breakpointsEnabled,
340
+ breakpoints: {}
341
+ };
342
+ const uris = this.getUris();
343
+ for (const uri of uris) {
344
+ data.breakpoints[uri] = this.findMarkers({ uri: new URI(uri) }).map(marker => marker.data);
345
+ }
346
+ if (this.functionBreakpoints.length) {
347
+ data.functionBreakpoints = this.functionBreakpoints;
348
+ }
349
+ if (this.exceptionBreakpoints.size) {
350
+ data.exceptionBreakpoints = [...this.exceptionBreakpoints.values()];
351
+ }
352
+ if (this.instructionBreakpoints.length) {
353
+ data.instructionBreakpoints = this.instructionBreakpoints;
354
+ }
355
+ this.storage.setData('breakpoints', data);
356
+ }
357
+
358
+ }
359
+ export namespace BreakpointManager {
360
+ export interface Data {
361
+ breakpointsEnabled: boolean;
362
+ breakpoints: {
363
+ [uri: string]: SourceBreakpoint[];
364
+ }
365
+ exceptionBreakpoints?: ExceptionBreakpoint[];
366
+ functionBreakpoints?: FunctionBreakpoint[];
367
+ instructionBreakpoints?: InstructionBreakpoint[];
368
+ }
369
+ }