@theia/debug 1.53.0-next.55 → 1.53.0-next.64

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 (86) hide show
  1. package/README.md +62 -62
  2. package/lib/browser/debug-configuration-manager.js +6 -6
  3. package/lib/common/inline-debug-adapter.d.ts +0 -1
  4. package/lib/common/inline-debug-adapter.d.ts.map +1 -1
  5. package/package.json +15 -15
  6. package/src/browser/breakpoint/breakpoint-manager.ts +369 -369
  7. package/src/browser/breakpoint/breakpoint-marker.ts +104 -104
  8. package/src/browser/console/debug-console-contribution.tsx +240 -240
  9. package/src/browser/console/debug-console-items.tsx +384 -384
  10. package/src/browser/console/debug-console-session.ts +205 -205
  11. package/src/browser/debug-call-stack-item-type-key.ts +20 -20
  12. package/src/browser/debug-configuration-manager.ts +591 -591
  13. package/src/browser/debug-configuration-model.ts +100 -100
  14. package/src/browser/debug-contribution.ts +43 -43
  15. package/src/browser/debug-frontend-application-contribution.ts +1551 -1551
  16. package/src/browser/debug-frontend-module.ts +133 -133
  17. package/src/browser/debug-package.spec.ts +20 -20
  18. package/src/browser/debug-preferences.ts +98 -98
  19. package/src/browser/debug-prefix-configuration.ts +195 -195
  20. package/src/browser/debug-resource.ts +59 -59
  21. package/src/browser/debug-schema-updater.ts +149 -149
  22. package/src/browser/debug-session-connection.ts +357 -357
  23. package/src/browser/debug-session-contribution.ts +157 -157
  24. package/src/browser/debug-session-manager.ts +683 -683
  25. package/src/browser/debug-session-options.ts +120 -120
  26. package/src/browser/debug-session.tsx +974 -974
  27. package/src/browser/debug-tab-bar-decorator.ts +57 -57
  28. package/src/browser/debug-watch-manager.ts +93 -93
  29. package/src/browser/disassembly-view/disassembly-view-accessibility-provider.ts +43 -43
  30. package/src/browser/disassembly-view/disassembly-view-breakpoint-renderer.ts +119 -119
  31. package/src/browser/disassembly-view/disassembly-view-contribution.ts +109 -109
  32. package/src/browser/disassembly-view/disassembly-view-instruction-renderer.ts +245 -245
  33. package/src/browser/disassembly-view/disassembly-view-table-delegate.ts +39 -39
  34. package/src/browser/disassembly-view/disassembly-view-utilities.ts +55 -55
  35. package/src/browser/disassembly-view/disassembly-view-widget.ts +463 -463
  36. package/src/browser/editor/debug-breakpoint-widget.tsx +293 -293
  37. package/src/browser/editor/debug-editor-model.ts +529 -529
  38. package/src/browser/editor/debug-editor-service.ts +192 -192
  39. package/src/browser/editor/debug-editor.ts +20 -20
  40. package/src/browser/editor/debug-exception-widget.tsx +122 -122
  41. package/src/browser/editor/debug-expression-provider.ts +78 -78
  42. package/src/browser/editor/debug-hover-source.tsx +105 -105
  43. package/src/browser/editor/debug-hover-widget.ts +298 -298
  44. package/src/browser/editor/debug-inline-value-decorator.ts +373 -373
  45. package/src/browser/model/debug-breakpoint.tsx +151 -151
  46. package/src/browser/model/debug-function-breakpoint.tsx +101 -101
  47. package/src/browser/model/debug-instruction-breakpoint.tsx +68 -68
  48. package/src/browser/model/debug-source-breakpoint.tsx +237 -237
  49. package/src/browser/model/debug-source.ts +93 -93
  50. package/src/browser/model/debug-stack-frame.tsx +177 -177
  51. package/src/browser/model/debug-thread.tsx +292 -292
  52. package/src/browser/preferences/launch-preferences.ts +38 -38
  53. package/src/browser/style/index.css +453 -453
  54. package/src/browser/view/debug-action.tsx +57 -57
  55. package/src/browser/view/debug-breakpoints-source.tsx +53 -53
  56. package/src/browser/view/debug-breakpoints-widget.ts +71 -71
  57. package/src/browser/view/debug-configuration-select.tsx +269 -269
  58. package/src/browser/view/debug-configuration-widget.tsx +121 -121
  59. package/src/browser/view/debug-exception-breakpoint.tsx +68 -68
  60. package/src/browser/view/debug-session-widget.ts +124 -124
  61. package/src/browser/view/debug-stack-frames-source.tsx +75 -75
  62. package/src/browser/view/debug-stack-frames-widget.ts +135 -135
  63. package/src/browser/view/debug-threads-source.tsx +48 -48
  64. package/src/browser/view/debug-threads-widget.ts +126 -126
  65. package/src/browser/view/debug-toolbar-widget.tsx +145 -145
  66. package/src/browser/view/debug-variables-source.ts +43 -43
  67. package/src/browser/view/debug-variables-widget.ts +61 -61
  68. package/src/browser/view/debug-view-model.ts +230 -230
  69. package/src/browser/view/debug-watch-expression.tsx +88 -88
  70. package/src/browser/view/debug-watch-source.ts +41 -41
  71. package/src/browser/view/debug-watch-widget.ts +61 -61
  72. package/src/browser/view/debug-widget.ts +97 -97
  73. package/src/common/debug-adapter-contribution-registry.ts +206 -206
  74. package/src/common/debug-adapter-session.ts +102 -102
  75. package/src/common/debug-common.ts +19 -19
  76. package/src/common/debug-compound.ts +33 -33
  77. package/src/common/debug-configuration.ts +112 -112
  78. package/src/common/debug-model.ts +200 -200
  79. package/src/common/debug-service.ts +184 -184
  80. package/src/common/debug-uri-utils.ts +24 -24
  81. package/src/common/inline-debug-adapter.ts +47 -47
  82. package/src/node/debug-adapter-factory.ts +107 -107
  83. package/src/node/debug-adapter-session-manager.ts +106 -106
  84. package/src/node/debug-backend-module.ts +57 -57
  85. package/src/node/debug-service-impl.ts +119 -119
  86. 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
+ }