@theia/debug 1.70.0-next.71 → 1.70.0

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 (100) hide show
  1. package/lib/browser/breakpoint/breakpoint-manager.d.ts +80 -45
  2. package/lib/browser/breakpoint/breakpoint-manager.d.ts.map +1 -1
  3. package/lib/browser/breakpoint/breakpoint-manager.js +553 -170
  4. package/lib/browser/breakpoint/breakpoint-manager.js.map +1 -1
  5. package/lib/browser/breakpoint/breakpoint-manager.spec.d.ts +2 -0
  6. package/lib/browser/breakpoint/breakpoint-manager.spec.d.ts.map +1 -0
  7. package/lib/browser/breakpoint/breakpoint-manager.spec.js +861 -0
  8. package/lib/browser/breakpoint/breakpoint-manager.spec.js.map +1 -0
  9. package/lib/browser/breakpoint/breakpoint-marker.d.ts +7 -10
  10. package/lib/browser/breakpoint/breakpoint-marker.d.ts.map +1 -1
  11. package/lib/browser/breakpoint/breakpoint-marker.js +14 -11
  12. package/lib/browser/breakpoint/breakpoint-marker.js.map +1 -1
  13. package/lib/browser/breakpoint/debug-data-breakpoint-actions.js +1 -1
  14. package/lib/browser/breakpoint/debug-data-breakpoint-actions.js.map +1 -1
  15. package/lib/browser/debug-frontend-application-contribution.d.ts +1 -2
  16. package/lib/browser/debug-frontend-application-contribution.d.ts.map +1 -1
  17. package/lib/browser/debug-frontend-application-contribution.js +13 -21
  18. package/lib/browser/debug-frontend-application-contribution.js.map +1 -1
  19. package/lib/browser/debug-frontend-module.d.ts.map +1 -1
  20. package/lib/browser/debug-frontend-module.js +3 -0
  21. package/lib/browser/debug-frontend-module.js.map +1 -1
  22. package/lib/browser/debug-session-manager.d.ts +8 -27
  23. package/lib/browser/debug-session-manager.d.ts.map +1 -1
  24. package/lib/browser/debug-session-manager.js +14 -132
  25. package/lib/browser/debug-session-manager.js.map +1 -1
  26. package/lib/browser/debug-session.d.ts +3 -21
  27. package/lib/browser/debug-session.d.ts.map +1 -1
  28. package/lib/browser/debug-session.js +89 -203
  29. package/lib/browser/debug-session.js.map +1 -1
  30. package/lib/browser/disassembly-view/disassembly-view-breakpoint-renderer.js +1 -1
  31. package/lib/browser/disassembly-view/disassembly-view-breakpoint-renderer.js.map +1 -1
  32. package/lib/browser/disassembly-view/disassembly-view-widget.d.ts.map +1 -1
  33. package/lib/browser/disassembly-view/disassembly-view-widget.js +17 -24
  34. package/lib/browser/disassembly-view/disassembly-view-widget.js.map +1 -1
  35. package/lib/browser/editor/debug-editor-model.d.ts +15 -5
  36. package/lib/browser/editor/debug-editor-model.d.ts.map +1 -1
  37. package/lib/browser/editor/debug-editor-model.js +56 -32
  38. package/lib/browser/editor/debug-editor-model.js.map +1 -1
  39. package/lib/browser/model/debug-breakpoint-opener.d.ts +14 -0
  40. package/lib/browser/model/debug-breakpoint-opener.d.ts.map +1 -0
  41. package/lib/browser/model/debug-breakpoint-opener.js +67 -0
  42. package/lib/browser/model/debug-breakpoint-opener.js.map +1 -0
  43. package/lib/browser/model/debug-breakpoint.d.ts +32 -13
  44. package/lib/browser/model/debug-breakpoint.d.ts.map +1 -1
  45. package/lib/browser/model/debug-breakpoint.js +76 -16
  46. package/lib/browser/model/debug-breakpoint.js.map +1 -1
  47. package/lib/browser/model/debug-data-breakpoint.d.ts +1 -0
  48. package/lib/browser/model/debug-data-breakpoint.d.ts.map +1 -1
  49. package/lib/browser/model/debug-data-breakpoint.js +6 -5
  50. package/lib/browser/model/debug-data-breakpoint.js.map +1 -1
  51. package/lib/browser/model/debug-function-breakpoint.d.ts +4 -1
  52. package/lib/browser/model/debug-function-breakpoint.d.ts.map +1 -1
  53. package/lib/browser/model/debug-function-breakpoint.js +20 -29
  54. package/lib/browser/model/debug-function-breakpoint.js.map +1 -1
  55. package/lib/browser/model/debug-instruction-breakpoint.d.ts +2 -1
  56. package/lib/browser/model/debug-instruction-breakpoint.d.ts.map +1 -1
  57. package/lib/browser/model/debug-instruction-breakpoint.js +8 -8
  58. package/lib/browser/model/debug-instruction-breakpoint.js.map +1 -1
  59. package/lib/browser/model/debug-source-breakpoint.d.ts +6 -15
  60. package/lib/browser/model/debug-source-breakpoint.d.ts.map +1 -1
  61. package/lib/browser/model/debug-source-breakpoint.js +16 -90
  62. package/lib/browser/model/debug-source-breakpoint.js.map +1 -1
  63. package/lib/browser/view/debug-breakpoints-source.d.ts +0 -2
  64. package/lib/browser/view/debug-breakpoints-source.d.ts.map +1 -1
  65. package/lib/browser/view/debug-breakpoints-source.js +2 -10
  66. package/lib/browser/view/debug-breakpoints-source.js.map +1 -1
  67. package/lib/browser/view/debug-breakpoints-widget.d.ts +2 -0
  68. package/lib/browser/view/debug-breakpoints-widget.d.ts.map +1 -1
  69. package/lib/browser/view/debug-breakpoints-widget.js +3 -0
  70. package/lib/browser/view/debug-breakpoints-widget.js.map +1 -1
  71. package/lib/browser/view/debug-exception-breakpoint.d.ts +18 -11
  72. package/lib/browser/view/debug-exception-breakpoint.d.ts.map +1 -1
  73. package/lib/browser/view/debug-exception-breakpoint.js +58 -24
  74. package/lib/browser/view/debug-exception-breakpoint.js.map +1 -1
  75. package/lib/browser/view/debug-view-model.d.ts +8 -4
  76. package/lib/browser/view/debug-view-model.d.ts.map +1 -1
  77. package/lib/browser/view/debug-view-model.js +16 -9
  78. package/lib/browser/view/debug-view-model.js.map +1 -1
  79. package/package.json +16 -16
  80. package/src/browser/breakpoint/breakpoint-manager.spec.ts +1106 -0
  81. package/src/browser/breakpoint/breakpoint-manager.ts +583 -194
  82. package/src/browser/breakpoint/breakpoint-marker.ts +21 -15
  83. package/src/browser/breakpoint/debug-data-breakpoint-actions.ts +1 -1
  84. package/src/browser/debug-frontend-application-contribution.ts +18 -23
  85. package/src/browser/debug-frontend-module.ts +5 -1
  86. package/src/browser/debug-session-manager.ts +15 -147
  87. package/src/browser/debug-session.tsx +99 -222
  88. package/src/browser/disassembly-view/disassembly-view-breakpoint-renderer.ts +1 -1
  89. package/src/browser/disassembly-view/disassembly-view-widget.ts +17 -23
  90. package/src/browser/editor/debug-editor-model.ts +58 -35
  91. package/src/browser/model/debug-breakpoint-opener.ts +51 -0
  92. package/src/browser/model/debug-breakpoint.tsx +101 -20
  93. package/src/browser/model/debug-data-breakpoint.tsx +8 -5
  94. package/src/browser/model/debug-function-breakpoint.tsx +18 -29
  95. package/src/browser/model/debug-instruction-breakpoint.tsx +10 -8
  96. package/src/browser/model/debug-source-breakpoint.tsx +23 -101
  97. package/src/browser/view/debug-breakpoints-source.tsx +2 -9
  98. package/src/browser/view/debug-breakpoints-widget.ts +6 -0
  99. package/src/browser/view/debug-exception-breakpoint.tsx +66 -27
  100. package/src/browser/view/debug-view-model.ts +21 -13
@@ -19,7 +19,18 @@
19
19
  import * as React from '@theia/core/shared/react';
20
20
  import { LabelProvider } from '@theia/core/lib/browser';
21
21
  import { DebugProtocol } from '@vscode/debugprotocol';
22
- import { Emitter, Event, DisposableCollection, Disposable, MessageClient, MessageType, Mutable, ContributionProvider, CommandService } from '@theia/core/lib/common';
22
+ import {
23
+ Emitter,
24
+ Event,
25
+ DisposableCollection,
26
+ Disposable,
27
+ MessageClient,
28
+ MessageType,
29
+ Mutable,
30
+ ContributionProvider,
31
+ CommandService,
32
+ CancellationError
33
+ } from '@theia/core/lib/common';
23
34
  import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service';
24
35
  import { EditorManager } from '@theia/editor/lib/browser';
25
36
  import { CompositeTreeElement } from '@theia/core/lib/browser/source-tree';
@@ -28,25 +39,22 @@ import { DebugThread, StoppedDetails, DebugThreadData } from './model/debug-thre
28
39
  import { DebugScope, DebugVariable } from './console/debug-console-items';
29
40
  import { DebugStackFrame } from './model/debug-stack-frame';
30
41
  import { DebugSource } from './model/debug-source';
31
- import { DebugBreakpoint, DebugBreakpointOptions } from './model/debug-breakpoint';
32
- import { DebugSourceBreakpoint } from './model/debug-source-breakpoint';
42
+ import { DebugBreakpoint } from './model/debug-breakpoint';
33
43
  import debounce = require('p-debounce');
34
44
  import URI from '@theia/core/lib/common/uri';
35
45
  import { BreakpointManager } from './breakpoint/breakpoint-manager';
36
46
  import { DebugConfigurationSessionOptions, InternalDebugSessionOptions, TestRunReference } from './debug-session-options';
37
47
  import { DebugConfiguration, DebugConsoleMode } from '../common/debug-common';
38
- import { SourceBreakpoint, ExceptionBreakpoint } from './breakpoint/breakpoint-marker';
48
+ import { SourceBreakpoint } from './breakpoint/breakpoint-marker';
39
49
  import { TerminalWidgetOptions, TerminalWidget } from '@theia/terminal/lib/browser/base/terminal-widget';
40
- import { DebugFunctionBreakpoint } from './model/debug-function-breakpoint';
41
50
  import { FileService } from '@theia/filesystem/lib/browser/file-service';
42
51
  import { DebugContribution } from './debug-contribution';
43
52
  import { Deferred, waitForEvent } from '@theia/core/lib/common/promise-util';
44
53
  import { WorkspaceService } from '@theia/workspace/lib/browser';
45
- import { DebugInstructionBreakpoint } from './model/debug-instruction-breakpoint';
46
54
  import { nls } from '@theia/core';
47
55
  import { TestService, TestServices } from '@theia/test/lib/browser/test-service';
48
56
  import { DebugSessionManager } from './debug-session-manager';
49
- import { DebugDataBreakpoint } from './model/debug-data-breakpoint';
57
+
50
58
  import { DebugPreferences } from '../common/debug-preferences';
51
59
 
52
60
  export enum DebugState {
@@ -98,12 +106,6 @@ export class DebugSession implements CompositeTreeElement {
98
106
  return this.onDidFocusThreadEmitter.event;
99
107
  }
100
108
 
101
- protected readonly onDidChangeBreakpointsEmitter = new Emitter<URI>();
102
- readonly onDidChangeBreakpoints: Event<URI> = this.onDidChangeBreakpointsEmitter.event;
103
- protected fireDidChangeBreakpoints(uri: URI): void {
104
- this.onDidChangeBreakpointsEmitter.fire(uri);
105
- }
106
-
107
109
  protected readonly onDidResolveLazyVariableEmitter = new Emitter<DebugVariable>();
108
110
  readonly onDidResolveLazyVariable: Event<DebugVariable> = this.onDidResolveLazyVariableEmitter.event;
109
111
 
@@ -112,6 +114,9 @@ export class DebugSession implements CompositeTreeElement {
112
114
 
113
115
  protected isStopping: boolean = false;
114
116
 
117
+ /** Maximum time to wait for the shell integration prompt before proceeding. */
118
+ protected readonly PROMPT_READY_TIMEOUT_MS = 3000;
119
+
115
120
  constructor(
116
121
  readonly id: string,
117
122
  readonly options: DebugConfigurationSessionOptions,
@@ -165,10 +170,8 @@ export class DebugSession implements CompositeTreeElement {
165
170
  this.onDidChangeEmitter,
166
171
  this.onDidFocusStackFrameEmitter,
167
172
  this.onDidFocusThreadEmitter,
168
- this.onDidChangeBreakpointsEmitter,
169
173
  this.onDidResolveLazyVariableEmitter,
170
174
  Disposable.create(() => {
171
- this.clearBreakpoints();
172
175
  this.doUpdateThreads([]);
173
176
  }),
174
177
  this.connection,
@@ -228,7 +231,7 @@ export class DebugSession implements CompositeTreeElement {
228
231
  sourceReference: Number(uri.query)
229
232
  };
230
233
  }
231
- const name = uri.displayName;
234
+ const name = this.labelProvider.getName(uri);
232
235
  let path;
233
236
  const underlying = await this.fileService.toUnderlyingResource(uri);
234
237
  if (underlying.scheme === 'file') {
@@ -396,12 +399,7 @@ export class DebugSession implements CompositeTreeElement {
396
399
  protected async configure(): Promise<void> {
397
400
  await this.didReceiveCapabilities.promise;
398
401
  if (this.capabilities.exceptionBreakpointFilters) {
399
- const exceptionBreakpoints = [];
400
- for (const filter of this.capabilities.exceptionBreakpointFilters) {
401
- const origin = this.breakpoints.getExceptionBreakpoint(filter.filter);
402
- exceptionBreakpoints.push(ExceptionBreakpoint.create(filter, origin));
403
- }
404
- this.breakpoints.setExceptionBreakpoints(exceptionBreakpoints);
402
+ this.breakpoints.addExceptionBreakpoints(this.capabilities.exceptionBreakpointFilters, this.id);
405
403
  }
406
404
  // mark as initialized, so updated breakpoints are shown in editor
407
405
  this.initialized = true;
@@ -520,8 +518,21 @@ export class DebugSession implements CompositeTreeElement {
520
518
  }
521
519
 
522
520
  if (!terminal) {
523
- terminal = await this.terminalServer.newTerminal(options);
521
+ terminal = await this.terminalServer.newTerminal({ ...options, kind: 'debug' });
524
522
  await terminal.start();
523
+ try {
524
+ if (terminal.commandHistoryState) {
525
+ // delay opening of the terminal until the terminal prompt appears to prevent duplicate commands in the terminal buffer
526
+ await waitForEvent(terminal.commandHistoryState.onTerminalPromptShown, this.PROMPT_READY_TIMEOUT_MS);
527
+ }
528
+ } catch (error) {
529
+ if (error instanceof CancellationError) {
530
+ console.warn('Shell integration did not emit a prompt within the timeout; proceeding anyway.');
531
+ } else {
532
+ console.error('Unexpected error while waiting for terminal prompt:', error);
533
+ throw error;
534
+ }
535
+ }
525
536
  }
526
537
  this.terminalServer.open(terminal);
527
538
  return terminal;
@@ -611,71 +622,6 @@ export class DebugSession implements CompositeTreeElement {
611
622
  this.deferredOnDidConfigureCapabilities.resolve();
612
623
  }
613
624
 
614
- protected readonly _breakpoints = new Map<string, DebugBreakpoint[]>();
615
- get breakpointUris(): IterableIterator<string> {
616
- return this._breakpoints.keys();
617
- }
618
-
619
- getSourceBreakpoints(uri?: URI): DebugSourceBreakpoint[] {
620
- const breakpoints = [];
621
- for (const breakpoint of this.getBreakpoints(uri)) {
622
- if (breakpoint instanceof DebugSourceBreakpoint) {
623
- breakpoints.push(breakpoint);
624
- }
625
- }
626
- return breakpoints;
627
- }
628
-
629
- getFunctionBreakpoints(): DebugFunctionBreakpoint[] {
630
- return this.getBreakpoints(BreakpointManager.FUNCTION_URI).filter((breakpoint): breakpoint is DebugFunctionBreakpoint => breakpoint instanceof DebugFunctionBreakpoint);
631
- }
632
-
633
- getInstructionBreakpoints(): DebugInstructionBreakpoint[] {
634
- if (this.capabilities.supportsInstructionBreakpoints) {
635
- return this.getBreakpoints(BreakpointManager.INSTRUCTION_URI)
636
- .filter((breakpoint): breakpoint is DebugInstructionBreakpoint => breakpoint instanceof DebugInstructionBreakpoint);
637
- }
638
- return this.breakpoints.getInstructionBreakpoints().map(origin => new DebugInstructionBreakpoint(origin, this.asDebugBreakpointOptions()));
639
- }
640
-
641
- getDataBreakpoints(): DebugDataBreakpoint[] {
642
- if (this.capabilities.supportsDataBreakpoints) {
643
- return this.getBreakpoints(BreakpointManager.DATA_URI)
644
- .filter((breakpoint): breakpoint is DebugDataBreakpoint => breakpoint instanceof DebugDataBreakpoint);
645
- }
646
- return this.breakpoints.getDataBreakpoints().map(origin => new DebugDataBreakpoint(origin, this.asDebugBreakpointOptions()));
647
- }
648
-
649
- getBreakpoints(uri?: URI): DebugBreakpoint[] {
650
- if (uri) {
651
- return this._breakpoints.get(uri.toString()) || [];
652
- }
653
- const result = [];
654
- for (const breakpoints of this._breakpoints.values()) {
655
- result.push(...breakpoints);
656
- }
657
- return result;
658
- }
659
-
660
- getBreakpoint(id: string): DebugBreakpoint | undefined {
661
- for (const breakpoints of this._breakpoints.values()) {
662
- const breakpoint = breakpoints.find(b => b.id === id);
663
- if (breakpoint) {
664
- return breakpoint;
665
- }
666
-
667
- }
668
- return undefined;
669
- }
670
-
671
- protected clearBreakpoints(): void {
672
- const uris = [...this._breakpoints.keys()];
673
- this._breakpoints.clear();
674
- for (const uri of uris) {
675
- this.fireDidChangeBreakpoints(new URI(uri));
676
- }
677
- }
678
-
679
625
  protected updatingBreakpoints = false;
680
626
 
681
627
  protected updateBreakpoint(body: DebugProtocol.BreakpointEvent['body']): void {
@@ -686,54 +632,33 @@ export class DebugSession implements CompositeTreeElement {
686
632
  if (raw.source && typeof raw.line === 'number') {
687
633
  const uri = DebugSource.toUri(raw.source);
688
634
  const origin = SourceBreakpoint.create(uri, { line: raw.line, column: raw.column });
689
- if (this.breakpoints.addBreakpoint(origin)) {
690
- const breakpoints = this.getSourceBreakpoints(uri);
691
- const breakpoint = new DebugSourceBreakpoint(origin, this.asDebugBreakpointOptions(), this.commandService);
692
- breakpoint.update({ raw });
693
- breakpoints.push(breakpoint);
694
- this.setSourceBreakpoints(uri, breakpoints);
695
- }
635
+ const breakpoint = this.breakpoints.addBreakpoint(origin);
636
+ this.breakpoints.updateSessionData(this.id, this.capabilities, new Map<string, DebugProtocol.Breakpoint>([[breakpoint.id, raw]]));
696
637
  }
697
638
  }
698
639
  if (body.reason === 'removed' && typeof raw.id === 'number') {
699
- const toRemove = this.findBreakpoint(b => b.idFromAdapter === raw.id);
640
+ const toRemove = this.findBreakpoint(b => b.getIdForSession(this.id) === raw.id);
700
641
  if (toRemove) {
701
642
  toRemove.remove();
702
- const breakpoints = this.getBreakpoints(toRemove.uri);
703
- const index = breakpoints.indexOf(toRemove);
704
- if (index !== -1) {
705
- breakpoints.splice(index, 1);
706
- this.setBreakpoints(toRemove.uri, breakpoints);
707
- }
708
643
  }
709
644
  }
710
645
  if (body.reason === 'changed' && typeof raw.id === 'number') {
711
- const toUpdate = this.findBreakpoint(b => b.idFromAdapter === raw.id);
646
+ const toUpdate = this.findBreakpoint(b => b.getIdForSession(this.id) === raw.id);
712
647
  if (toUpdate) {
713
- toUpdate.update({ raw });
714
- if (toUpdate instanceof DebugSourceBreakpoint) {
715
- const sourceBreakpoints = this.getSourceBreakpoints(toUpdate.uri);
716
- // in order to dedup again if a debugger converted line breakpoint to inline breakpoint
717
- // i.e. assigned a column to a line breakpoint
718
- this.setSourceBreakpoints(toUpdate.uri, sourceBreakpoints);
719
- } else {
720
- this.fireDidChangeBreakpoints(toUpdate.uri);
721
- }
648
+ this.breakpoints.updateSessionData(this.id, this.capabilities, new Map([[toUpdate.id, raw]]));
722
649
  }
723
650
  }
724
651
  } finally {
725
652
  this.updatingBreakpoints = false;
726
653
  }
727
654
  }
655
+
728
656
  protected findBreakpoint(match: (breakpoint: DebugBreakpoint) => boolean): DebugBreakpoint | undefined {
729
- for (const [, breakpoints] of this._breakpoints) {
730
- for (const breakpoint of breakpoints) {
731
- if (match(breakpoint)) {
732
- return breakpoint;
733
- }
657
+ for (const bp of this.breakpoints.allBreakpoints()) {
658
+ if (match(bp)) {
659
+ return bp;
734
660
  }
735
661
  }
736
- return undefined;
737
662
  }
738
663
 
739
664
  protected async updateBreakpoints(options: {
@@ -763,71 +688,61 @@ export class DebugSession implements CompositeTreeElement {
763
688
  protected async sendExceptionBreakpoints(): Promise<void> {
764
689
  const filters: string[] = [];
765
690
  const filterOptions: DebugProtocol.ExceptionFilterOptions[] | undefined = this.capabilities.supportsExceptionFilterOptions ? [] : undefined;
766
- for (const breakpoint of this.breakpoints.getExceptionBreakpoints()) {
767
- if (breakpoint.enabled) {
768
- if (filterOptions) {
769
- filterOptions.push({
770
- filterId: breakpoint.raw.filter,
771
- condition: breakpoint.condition
772
- });
773
- } else {
774
- filters.push(breakpoint.raw.filter);
775
- }
691
+ const toSend = this.breakpoints.getExceptionBreakpoints().filter(candidate => candidate.origin.enabled);
692
+ const updates = new Map<string, DebugProtocol.Breakpoint>();
693
+ for (const breakpoint of toSend) {
694
+ if (filterOptions) {
695
+ filterOptions.push({
696
+ filterId: breakpoint.origin.raw.filter,
697
+ condition: breakpoint.origin.condition
698
+ });
699
+ } else {
700
+ filters.push(breakpoint.origin.raw.filter);
776
701
  }
777
702
  }
778
- await this.sendRequest('setExceptionBreakpoints', { filters, filterOptions });
703
+ try {
704
+ const res = await this.sendRequest('setExceptionBreakpoints', { filters, filterOptions });
705
+ res.body?.breakpoints?.forEach((bp, index) => toSend[index] && updates.set(toSend[index].id, bp));
706
+ } catch (err) {
707
+ console.error('Failed to set exception breakpoints:', err);
708
+ const message = (err as Error)?.message ? `${err.message}` : 'Failed to set exception breakpoints.';
709
+ toSend.forEach(bp => updates.set(bp.id, { verified: false, message }));
710
+ }
711
+ this.breakpoints.updateSessionData(this.id, this.capabilities, updates);
779
712
  }
780
713
 
781
714
  protected async sendFunctionBreakpoints(affectedUri: URI): Promise<void> {
782
- const all = this.breakpoints.getFunctionBreakpoints().map(origin =>
783
- new DebugFunctionBreakpoint(origin, this.asDebugBreakpointOptions())
784
- );
715
+ if (!this.capabilities.supportsFunctionBreakpoints) { return; }
716
+ const all = this.breakpoints.getFunctionBreakpoints();
785
717
  const enabled = all.filter(b => b.enabled);
786
- if (this.capabilities.supportsFunctionBreakpoints) {
787
- try {
788
- const response = await this.sendRequest('setFunctionBreakpoints', {
789
- breakpoints: enabled.map(b => b.origin.raw)
790
- });
791
- // Apparently, `body` and `breakpoints` can be missing.
792
- // https://github.com/eclipse-theia/theia/issues/11885
793
- // https://github.com/microsoft/vscode/blob/80004351ccf0884b58359f7c8c801c91bb827d83/src/vs/workbench/contrib/debug/browser/debugSession.ts#L448-L449
794
- if (response && response.body) {
795
- response.body.breakpoints.forEach((raw, index) => {
796
- // node debug adapter returns more breakpoints sometimes
797
- if (enabled[index]) {
798
- enabled[index].update({ raw });
799
- }
800
- });
801
- }
802
- } catch (error) {
803
- // could be error or promise rejection of DebugProtocol.SetFunctionBreakpoints
804
- if (error instanceof Error) {
805
- console.error(`Error setting breakpoints: ${error.message}`);
806
- } else {
807
- // handle adapters that send failed DebugProtocol.SetFunctionBreakpoints for invalid breakpoints
808
- const genericMessage: string = 'Function breakpoint not valid for current debug session';
809
- const message: string = error.message ? `${error.message}` : genericMessage;
810
- console.warn(`Could not handle function breakpoints: ${message}, disabling...`);
811
- enabled.forEach(b => b.update({
812
- raw: {
813
- verified: false,
814
- message
815
- }
816
- }));
718
+ const updates = new Map<string, DebugProtocol.Breakpoint>();
719
+ try {
720
+ const response = await this.sendRequest('setFunctionBreakpoints', {
721
+ breakpoints: enabled.map(b => b.origin.raw)
722
+ });
723
+ // Apparently, `body` and `breakpoints` can be missing.
724
+ // https://github.com/eclipse-theia/theia/issues/11885
725
+ // https://github.com/microsoft/vscode/blob/80004351ccf0884b58359f7c8c801c91bb827d83/src/vs/workbench/contrib/debug/browser/debugSession.ts#L448-L449
726
+ response?.body?.breakpoints.forEach((raw, index) => {
727
+ // node debug adapter returns more breakpoints sometimes
728
+ if (enabled[index]) {
729
+ updates.set(enabled[index].id, raw);
817
730
  }
818
- }
731
+ });
732
+ } catch (error) {
733
+ const genericMessage: string = 'Function breakpoint not valid for current debug session';
734
+ const message: string = error.message ? `${error.message}` : genericMessage;
735
+ console.warn(`Could not handle function breakpoints: ${message}, disabling...`);
736
+ enabled.forEach(b => updates.set(b.id, { verified: false, message }));
819
737
  }
820
- this.setBreakpoints(affectedUri, all);
738
+ this.breakpoints.updateSessionData(this.id, this.capabilities, updates);
821
739
  }
822
740
 
823
741
  protected async sendSourceBreakpoints(affectedUri: URI, sourceModified?: boolean): Promise<void> {
824
742
  const source = await this.toSource(affectedUri);
825
- const known = this._breakpoints.get(affectedUri.toString());
826
- const all = this.breakpoints.findMarkers({ uri: affectedUri }).map(({ data }) =>
827
- known?.find((candidate): candidate is DebugSourceBreakpoint => candidate instanceof DebugSourceBreakpoint && candidate.origin.id === data.id) ??
828
- new DebugSourceBreakpoint(data, this.asDebugBreakpointOptions(), this.commandService)
829
- );
743
+ const all = this.breakpoints.getBreakpoints(affectedUri);
830
744
  const enabled = all.filter(b => b.enabled);
745
+ const updates = new Map<string, DebugProtocol.Breakpoint>();
831
746
  try {
832
747
  const breakpoints = enabled.map(({ origin }) => origin.raw);
833
748
  const response = await this.sendRequest('setBreakpoints', {
@@ -839,7 +754,7 @@ export class DebugSession implements CompositeTreeElement {
839
754
  response.body.breakpoints.forEach((raw, index) => {
840
755
  // node debug adapter returns more breakpoints sometimes
841
756
  if (enabled[index]) {
842
- enabled[index].update({ raw });
757
+ updates.set(enabled[index].id, raw);
843
758
  }
844
759
  });
845
760
  } catch (error) {
@@ -851,77 +766,44 @@ export class DebugSession implements CompositeTreeElement {
851
766
  const genericMessage: string = 'Breakpoint not valid for current debug session';
852
767
  const message: string = error.message ? `${error.message}` : genericMessage;
853
768
  console.warn(`Could not handle breakpoints for ${affectedUri}: ${message}, disabling...`);
854
- enabled.forEach(b => b.update({
855
- raw: {
856
- verified: false,
857
- message
858
- }
859
- }));
769
+ enabled.forEach(b => updates.set(b.id, { verified: false, message }));
860
770
  }
861
771
  }
862
- this.setSourceBreakpoints(affectedUri, all);
772
+ this.breakpoints.updateSessionData(this.id, this.capabilities, updates);
863
773
  }
864
774
 
865
775
  protected async sendInstructionBreakpoints(): Promise<void> {
866
776
  if (!this.capabilities.supportsInstructionBreakpoints) {
867
777
  return;
868
778
  }
869
- const all = this.breakpoints.getInstructionBreakpoints().map(breakpoint => new DebugInstructionBreakpoint(breakpoint, this.asDebugBreakpointOptions()));
779
+ const all = this.breakpoints.getInstructionBreakpoints();
870
780
  const enabled = all.filter(breakpoint => breakpoint.enabled);
781
+ const updates = new Map<string, DebugProtocol.Breakpoint>();
871
782
  try {
872
783
  const response = await this.sendRequest('setInstructionBreakpoints', {
873
- breakpoints: enabled.map(renderable => renderable.origin),
784
+ breakpoints: enabled.map(renderable => renderable.origin.raw),
874
785
  });
875
- response.body.breakpoints.forEach((raw, index) => enabled[index]?.update({ raw }));
786
+ response.body.breakpoints.forEach((raw, index) => enabled[index] && updates.set(enabled[index].id, raw));
876
787
  } catch {
877
- enabled.forEach(breakpoint => breakpoint.update({ raw: { verified: false } }));
788
+ enabled.forEach(breakpoint => updates.set(breakpoint.id, { verified: false }));
878
789
  }
879
- this.setBreakpoints(BreakpointManager.INSTRUCTION_URI, all);
790
+ this.breakpoints.updateSessionData(this.id, this.capabilities, updates);
880
791
  }
881
792
 
882
793
  protected async sendDataBreakpoints(): Promise<void> {
883
794
  if (!this.capabilities.supportsDataBreakpoints) { return; }
884
- const known = this._breakpoints.get(BreakpointManager.DATA_URI.toString());
885
- const all = this.breakpoints.getDataBreakpoints().map<DebugDataBreakpoint>(bp =>
886
- known?.find((candidate): candidate is DebugDataBreakpoint => candidate instanceof DebugDataBreakpoint && candidate.id === bp.id)
887
- ?? new DebugDataBreakpoint(bp, this.asDebugBreakpointOptions())
888
- );
795
+ const all = this.breakpoints.getDataBreakpoints();
889
796
  const enabled = all.filter(bp => bp.enabled);
797
+ const updates = new Map<string, DebugProtocol.Breakpoint>();
890
798
  try {
891
799
  const response = await this.sendRequest('setDataBreakpoints', {
892
800
  breakpoints: enabled.map(({ origin }) => origin.raw)
893
801
  });
894
- response.body.breakpoints.forEach((raw, index) => enabled[index].update({ raw }));
802
+ response.body.breakpoints.forEach((raw, index) => enabled[index] && updates.set(enabled[index].id, raw));
895
803
  } catch {
896
- enabled.forEach(breakpoint => breakpoint.update({ raw: { verified: false } }));
804
+ enabled.forEach(breakpoint => updates.set(breakpoint.id, { verified: false }));
897
805
  }
898
- this.setBreakpoints(BreakpointManager.DATA_URI, all);
899
- }
900
-
901
- protected setBreakpoints(uri: URI, breakpoints: DebugBreakpoint[]): void {
902
- this._breakpoints.set(uri.toString(), breakpoints);
903
- this.fireDidChangeBreakpoints(uri);
904
- }
905
-
906
- protected setSourceBreakpoints(uri: URI, breakpoints: DebugSourceBreakpoint[]): void {
907
- const distinct = this.dedupSourceBreakpoints(breakpoints);
908
- this.setBreakpoints(uri, distinct);
909
- }
910
-
911
- protected dedupSourceBreakpoints(all: DebugSourceBreakpoint[]): DebugSourceBreakpoint[] {
912
- const positions = new Map<string, DebugSourceBreakpoint>();
913
- for (const breakpoint of all) {
914
- let primary = positions.get(breakpoint.renderPosition()) || breakpoint;
915
- if (primary !== breakpoint) {
916
- let secondary = breakpoint;
917
- if (secondary.raw && secondary.raw.line === secondary.origin.raw.line && secondary.raw.column === secondary.origin.raw.column) {
918
- [primary, secondary] = [breakpoint, primary];
919
- }
920
- primary.origins.push(...secondary.origins);
921
- }
922
- positions.set(primary.renderPosition(), primary);
923
- }
924
- return [...positions.values()];
806
+ this.breakpoints.updateSessionData(this.id, this.capabilities, updates);
925
807
  }
926
808
 
927
809
  protected *getAffectedUris(uri?: URI): IterableIterator<URI> {
@@ -937,11 +819,6 @@ export class DebugSession implements CompositeTreeElement {
937
819
  }
938
820
  }
939
821
 
940
- protected asDebugBreakpointOptions(): DebugBreakpointOptions {
941
- const { labelProvider, breakpoints, editorManager } = this;
942
- return { labelProvider, breakpoints, editorManager, session: this };
943
- }
944
-
945
822
  get label(): string {
946
823
  const suffixes = [];
947
824
  if (InternalDebugSessionOptions.is(this.options) && this.options.id) {
@@ -69,7 +69,7 @@ export class BreakpointRenderer implements ITableRenderer<DisassembledInstructio
69
69
  // click show hint while waiting for BP to resolve.
70
70
  icon.classList.add(this._breakpointHintIcon);
71
71
  if (currentElement.element.isBreakpointSet) {
72
- this._debugService.removeInstructionBreakpoint(currentElement.element.instruction.address);
72
+ this._debugService.removeInstructionBreakpointAt(currentElement.element.instruction.address);
73
73
 
74
74
  } else if (currentElement.element.allowBreakpoint && !currentElement.element.isBreakpointSet) {
75
75
  this._debugService.addInstructionBreakpoint(currentElement.element.instruction.address, 0);
@@ -168,40 +168,34 @@ export class DisassemblyViewWidget extends BaseWidget {
168
168
  // draw viewable BP
169
169
  let changed = false;
170
170
  bpEvent.added?.forEach(bp => {
171
- if (InstructionBreakpoint.is(bp)) {
172
- const index = this.getIndexFromAddress(bp.instructionReference);
173
- if (index >= 0) {
174
- this._disassembledInstructions!.row(index).isBreakpointSet = true;
175
- this._disassembledInstructions!.row(index).isBreakpointEnabled = bp.enabled;
176
- changed = true;
177
- }
171
+ const index = this.getIndexFromAddress(bp.origin.raw.instructionReference);
172
+ if (index >= 0) {
173
+ this._disassembledInstructions!.row(index).isBreakpointSet = true;
174
+ this._disassembledInstructions!.row(index).isBreakpointEnabled = bp.enabled;
175
+ changed = true;
178
176
  }
179
177
  });
180
178
 
181
179
  bpEvent.removed?.forEach(bp => {
182
- if (InstructionBreakpoint.is(bp)) {
183
- const index = this.getIndexFromAddress(bp.instructionReference);
184
- if (index >= 0) {
185
- this._disassembledInstructions!.row(index).isBreakpointSet = false;
186
- changed = true;
187
- }
180
+ const index = this.getIndexFromAddress(bp.origin.raw.instructionReference);
181
+ if (index >= 0) {
182
+ this._disassembledInstructions!.row(index).isBreakpointSet = false;
183
+ changed = true;
188
184
  }
189
185
  });
190
186
 
191
187
  bpEvent.changed?.forEach(bp => {
192
- if (InstructionBreakpoint.is(bp)) {
193
- const index = this.getIndexFromAddress(bp.instructionReference);
194
- if (index >= 0) {
195
- if (this._disassembledInstructions!.row(index).isBreakpointEnabled !== bp.enabled) {
196
- this._disassembledInstructions!.row(index).isBreakpointEnabled = bp.enabled;
197
- changed = true;
198
- }
188
+ const index = this.getIndexFromAddress(bp.origin.raw.instructionReference);
189
+ if (index >= 0) {
190
+ if (this._disassembledInstructions!.row(index).isBreakpointEnabled !== bp.enabled) {
191
+ this._disassembledInstructions!.row(index).isBreakpointEnabled = bp.enabled;
192
+ changed = true;
199
193
  }
200
194
  }
201
195
  });
202
196
 
203
197
  // get an updated list so that items beyond the current range would render when reached.
204
- this._instructionBpList = this.breakpointManager.getInstructionBreakpoints();
198
+ this._instructionBpList = this.breakpointManager.getInstructionBreakpoints().map(({ origin }) => origin);
205
199
 
206
200
  if (changed) {
207
201
  this._onDidChangeStackFrame.fire();
@@ -344,7 +338,7 @@ export class DisassemblyViewWidget extends BaseWidget {
344
338
  let lastLocation: DebugProtocol.Source | undefined;
345
339
  let lastLine: IRange | undefined;
346
340
  for (let i = 0; i < resultEntries.length; i++) {
347
- const found = this._instructionBpList.find(p => p.instructionReference === resultEntries[i].address);
341
+ const found = this._instructionBpList.find(p => p.raw.instructionReference === resultEntries[i].address);
348
342
  const instruction = resultEntries[i];
349
343
 
350
344
  // Forward fill the missing location as detailed in the DAP spec.
@@ -424,7 +418,7 @@ export class DisassemblyViewWidget extends BaseWidget {
424
418
  if (this._disassembledInstructions) {
425
419
  this._loadingLock = true; // stop scrolling during the load.
426
420
  this._disassembledInstructions.splice(0, this._disassembledInstructions.length, [disassemblyNotAvailable]);
427
- this._instructionBpList = this.breakpointManager.getInstructionBreakpoints();
421
+ this._instructionBpList = this.breakpointManager.getInstructionBreakpoints().map(({ origin }) => origin);
428
422
  this.loadDisassembledInstructions(targetAddress, -DisassemblyViewWidget.NUM_INSTRUCTIONS_TO_LOAD * 4, DisassemblyViewWidget.NUM_INSTRUCTIONS_TO_LOAD * 8).then(() => {
429
423
  // on load, set the target instruction in the middle of the page.
430
424
  if (this._disassembledInstructions!.length > 0) {