@theia/debug 1.67.0-next.86 → 1.68.0-next.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 (95) hide show
  1. package/lib/browser/breakpoint/breakpoint-manager.js +1 -1
  2. package/lib/browser/breakpoint/breakpoint-manager.js.map +1 -1
  3. package/lib/browser/debug-commands.d.ts +153 -0
  4. package/lib/browser/debug-commands.d.ts.map +1 -0
  5. package/lib/browser/debug-commands.js +399 -0
  6. package/lib/browser/debug-commands.js.map +1 -0
  7. package/lib/browser/debug-frontend-application-contribution.d.ts +1 -150
  8. package/lib/browser/debug-frontend-application-contribution.d.ts.map +1 -1
  9. package/lib/browser/debug-frontend-application-contribution.js +155 -532
  10. package/lib/browser/debug-frontend-application-contribution.js.map +1 -1
  11. package/lib/browser/debug-prefix-configuration.js +3 -3
  12. package/lib/browser/debug-prefix-configuration.js.map +1 -1
  13. package/lib/browser/debug-session-contribution.d.ts +2 -1
  14. package/lib/browser/debug-session-contribution.d.ts.map +1 -1
  15. package/lib/browser/debug-session-contribution.js +5 -1
  16. package/lib/browser/debug-session-contribution.js.map +1 -1
  17. package/lib/browser/debug-session-manager.d.ts +4 -3
  18. package/lib/browser/debug-session-manager.d.ts.map +1 -1
  19. package/lib/browser/debug-session-manager.js +46 -8
  20. package/lib/browser/debug-session-manager.js.map +1 -1
  21. package/lib/browser/debug-session.d.ts +3 -2
  22. package/lib/browser/debug-session.d.ts.map +1 -1
  23. package/lib/browser/debug-session.js +4 -3
  24. package/lib/browser/debug-session.js.map +1 -1
  25. package/lib/browser/model/debug-breakpoint.d.ts +4 -2
  26. package/lib/browser/model/debug-breakpoint.d.ts.map +1 -1
  27. package/lib/browser/model/debug-breakpoint.js +10 -2
  28. package/lib/browser/model/debug-breakpoint.js.map +1 -1
  29. package/lib/browser/model/debug-data-breakpoint.d.ts +2 -0
  30. package/lib/browser/model/debug-data-breakpoint.d.ts.map +1 -1
  31. package/lib/browser/model/debug-data-breakpoint.js +16 -5
  32. package/lib/browser/model/debug-data-breakpoint.js.map +1 -1
  33. package/lib/browser/model/debug-function-breakpoint.d.ts +3 -0
  34. package/lib/browser/model/debug-function-breakpoint.d.ts.map +1 -1
  35. package/lib/browser/model/debug-function-breakpoint.js +17 -1
  36. package/lib/browser/model/debug-function-breakpoint.js.map +1 -1
  37. package/lib/browser/model/debug-instruction-breakpoint.d.ts +2 -0
  38. package/lib/browser/model/debug-instruction-breakpoint.d.ts.map +1 -1
  39. package/lib/browser/model/debug-instruction-breakpoint.js +13 -1
  40. package/lib/browser/model/debug-instruction-breakpoint.js.map +1 -1
  41. package/lib/browser/model/debug-source-breakpoint.d.ts +6 -1
  42. package/lib/browser/model/debug-source-breakpoint.d.ts.map +1 -1
  43. package/lib/browser/model/debug-source-breakpoint.js +17 -1
  44. package/lib/browser/model/debug-source-breakpoint.js.map +1 -1
  45. package/lib/browser/view/debug-action.d.ts +1 -0
  46. package/lib/browser/view/debug-action.d.ts.map +1 -1
  47. package/lib/browser/view/debug-action.js +2 -2
  48. package/lib/browser/view/debug-action.js.map +1 -1
  49. package/lib/browser/view/debug-breakpoints-source.d.ts +2 -0
  50. package/lib/browser/view/debug-breakpoints-source.d.ts.map +1 -1
  51. package/lib/browser/view/debug-breakpoints-source.js +6 -1
  52. package/lib/browser/view/debug-breakpoints-source.js.map +1 -1
  53. package/lib/browser/view/debug-configuration-widget.js +2 -2
  54. package/lib/browser/view/debug-configuration-widget.js.map +1 -1
  55. package/lib/browser/view/debug-exception-breakpoint.d.ts +9 -2
  56. package/lib/browser/view/debug-exception-breakpoint.d.ts.map +1 -1
  57. package/lib/browser/view/debug-exception-breakpoint.js +26 -5
  58. package/lib/browser/view/debug-exception-breakpoint.js.map +1 -1
  59. package/lib/browser/view/debug-session-widget.d.ts +0 -1
  60. package/lib/browser/view/debug-session-widget.d.ts.map +1 -1
  61. package/lib/browser/view/debug-session-widget.js +0 -4
  62. package/lib/browser/view/debug-session-widget.js.map +1 -1
  63. package/lib/browser/view/debug-threads-widget.d.ts +6 -1
  64. package/lib/browser/view/debug-threads-widget.d.ts.map +1 -1
  65. package/lib/browser/view/debug-threads-widget.js +69 -5
  66. package/lib/browser/view/debug-threads-widget.js.map +1 -1
  67. package/lib/browser/view/debug-toolbar-widget.d.ts +5 -18
  68. package/lib/browser/view/debug-toolbar-widget.d.ts.map +1 -1
  69. package/lib/browser/view/debug-toolbar-widget.js +14 -58
  70. package/lib/browser/view/debug-toolbar-widget.js.map +1 -1
  71. package/lib/browser/view/debug-view-model.d.ts.map +1 -1
  72. package/lib/browser/view/debug-view-model.js +8 -9
  73. package/lib/browser/view/debug-view-model.js.map +1 -1
  74. package/package.json +16 -16
  75. package/src/browser/breakpoint/breakpoint-manager.ts +1 -1
  76. package/src/browser/debug-commands.ts +402 -0
  77. package/src/browser/debug-frontend-application-contribution.ts +35 -410
  78. package/src/browser/debug-prefix-configuration.ts +1 -1
  79. package/src/browser/debug-session-contribution.ts +5 -2
  80. package/src/browser/debug-session-manager.ts +52 -9
  81. package/src/browser/debug-session.tsx +4 -3
  82. package/src/browser/model/debug-breakpoint.tsx +12 -3
  83. package/src/browser/model/debug-data-breakpoint.tsx +21 -6
  84. package/src/browser/model/debug-function-breakpoint.tsx +22 -1
  85. package/src/browser/model/debug-instruction-breakpoint.tsx +16 -1
  86. package/src/browser/model/debug-source-breakpoint.tsx +24 -3
  87. package/src/browser/style/index.css +13 -5
  88. package/src/browser/view/debug-action.tsx +3 -2
  89. package/src/browser/view/debug-breakpoints-source.tsx +5 -1
  90. package/src/browser/view/debug-configuration-widget.tsx +1 -1
  91. package/src/browser/view/debug-exception-breakpoint.tsx +30 -5
  92. package/src/browser/view/debug-session-widget.ts +0 -5
  93. package/src/browser/view/debug-threads-widget.ts +84 -6
  94. package/src/browser/view/debug-toolbar-widget.tsx +13 -60
  95. package/src/browser/view/debug-view-model.ts +8 -9
@@ -14,7 +14,7 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { DisposableCollection, Emitter, Event, MessageService, nls, ProgressService, WaitUntilEvent } from '@theia/core';
17
+ import { CommandService, DisposableCollection, Emitter, Event, MessageService, nls, ProgressService, WaitUntilEvent } from '@theia/core';
18
18
  import { LabelProvider, ApplicationShell, ConfirmDialog } from '@theia/core/lib/browser';
19
19
  import { ContextKey, ContextKeyService } from '@theia/core/lib/browser/context-key-service';
20
20
  import URI from '@theia/core/lib/common/uri';
@@ -133,6 +133,9 @@ export class DebugSessionManager {
133
133
  @inject(EditorManager)
134
134
  protected readonly editorManager: EditorManager;
135
135
 
136
+ @inject(CommandService)
137
+ protected commandService: CommandService;
138
+
136
139
  @inject(BreakpointManager)
137
140
  protected readonly breakpoints: BreakpointManager;
138
141
 
@@ -426,9 +429,15 @@ export class DebugSessionManager {
426
429
  state = session.state;
427
430
  if (state === DebugState.Stopped) {
428
431
  this.onDidStopDebugSessionEmitter.fire(session);
432
+ // Only switch to this session if a thread actually stopped (not just state change)
433
+ if (session.currentThread && session.currentThread.stopped) {
434
+ this.updateCurrentSession(session);
435
+ }
429
436
  }
430
437
  }
431
- this.updateCurrentSession(session);
438
+ // Always fire change event to update views (threads, variables, etc.)
439
+ // The selection logic in widgets will handle not jumping to non-stopped threads
440
+ this.fireDidChange(session);
432
441
  });
433
442
  session.onDidChangeBreakpoints(uri => this.fireDidChangeBreakpoints({ session, uri }));
434
443
  session.on('terminated', async event => {
@@ -447,7 +456,14 @@ export class DebugSessionManager {
447
456
  });
448
457
 
449
458
  session.onDispose(() => this.cleanup(session));
450
- session.start().then(() => this.onDidStartDebugSessionEmitter.fire(session)).catch(e => {
459
+ session.start().then(() => {
460
+ this.onDidStartDebugSessionEmitter.fire(session);
461
+ // Set as current session if no current session exists
462
+ // This ensures the UI shows the running session and buttons are enabled
463
+ if (!this.currentSession) {
464
+ this.updateCurrentSession(session);
465
+ }
466
+ }).catch(e => {
451
467
  session.stop(false, () => {
452
468
  this.debug.terminateDebugSession(session.id);
453
469
  });
@@ -608,7 +624,7 @@ export class DebugSessionManager {
608
624
  return currentThread && currentThread.topFrame;
609
625
  }
610
626
 
611
- getFunctionBreakpoints(session: DebugSession | undefined = this.currentSession): DebugFunctionBreakpoint[] {
627
+ getFunctionBreakpoints(session?: DebugSession): DebugFunctionBreakpoint[] {
612
628
  if (session && session.state > DebugState.Initializing) {
613
629
  return session.getFunctionBreakpoints();
614
630
  }
@@ -616,7 +632,7 @@ export class DebugSessionManager {
616
632
  return this.breakpoints.getFunctionBreakpoints().map(origin => new DebugFunctionBreakpoint(origin, { labelProvider, breakpoints, editorManager }));
617
633
  }
618
634
 
619
- getInstructionBreakpoints(session = this.currentSession): DebugInstructionBreakpoint[] {
635
+ getInstructionBreakpoints(session?: DebugSession): DebugInstructionBreakpoint[] {
620
636
  if (session && session.state > DebugState.Initializing) {
621
637
  return session.getInstructionBreakpoints();
622
638
  }
@@ -636,12 +652,39 @@ export class DebugSessionManager {
636
652
  getBreakpoints(uri: URI, session?: DebugSession): DebugSourceBreakpoint[];
637
653
  getBreakpoints(arg?: URI | DebugSession, arg2?: DebugSession): DebugSourceBreakpoint[] {
638
654
  const uri = arg instanceof URI ? arg : undefined;
639
- const session = arg instanceof DebugSession ? arg : arg2 instanceof DebugSession ? arg2 : this.currentSession;
655
+ const session = arg instanceof DebugSession ? arg : arg2 instanceof DebugSession ? arg2 : undefined;
640
656
  if (session && session.state > DebugState.Initializing) {
641
657
  return session.getSourceBreakpoints(uri);
642
658
  }
659
+
660
+ const activeSessions = this.sessions.filter(s => s.state > DebugState.Initializing);
661
+
662
+ // Start with all breakpoints from markers (not installed = shows as filled circle)
643
663
  const { labelProvider, breakpoints, editorManager } = this;
644
- return this.breakpoints.findMarkers({ uri }).map(({ data }) => new DebugSourceBreakpoint(data, { labelProvider, breakpoints, editorManager }));
664
+ const breakpointMap = new Map<string, DebugSourceBreakpoint>();
665
+ const markers = this.breakpoints.findMarkers({ uri });
666
+
667
+ for (const { data } of markers) {
668
+ const bp = new DebugSourceBreakpoint(data, { labelProvider, breakpoints, editorManager }, this.commandService);
669
+ breakpointMap.set(bp.id, bp);
670
+ }
671
+
672
+ // Overlay with VERIFIED breakpoints from active sessions only
673
+ // We only replace a marker-based breakpoint if the session has VERIFIED it
674
+ // This ensures breakpoints show as filled (not installed) rather than hollow (installed but unverified)
675
+ for (const activeSession of activeSessions) {
676
+ const sessionBps = activeSession.getSourceBreakpoints(uri);
677
+
678
+ for (const bp of sessionBps) {
679
+ if (bp.verified) {
680
+ // Session has verified this breakpoint - use the session's version
681
+ breakpointMap.set(bp.id, bp);
682
+ }
683
+ // If not verified, keep the marker-based one (shows as not installed = filled circle)
684
+ }
685
+ }
686
+
687
+ return Array.from(breakpointMap.values());
645
688
  }
646
689
 
647
690
  getLineBreakpoints(uri: URI, line: number): DebugSourceBreakpoint[] {
@@ -651,7 +694,7 @@ export class DebugSessionManager {
651
694
  }
652
695
  const { labelProvider, breakpoints, editorManager } = this;
653
696
  return this.breakpoints.getLineBreakpoints(uri, line).map(origin =>
654
- new DebugSourceBreakpoint(origin, { labelProvider, breakpoints, editorManager })
697
+ new DebugSourceBreakpoint(origin, { labelProvider, breakpoints, editorManager }, this.commandService)
655
698
  );
656
699
  }
657
700
 
@@ -662,7 +705,7 @@ export class DebugSessionManager {
662
705
  }
663
706
  const origin = this.breakpoints.getInlineBreakpoint(uri, line, column);
664
707
  const { labelProvider, breakpoints, editorManager } = this;
665
- return origin && new DebugSourceBreakpoint(origin, { labelProvider, breakpoints, editorManager });
708
+ return origin && new DebugSourceBreakpoint(origin, { labelProvider, breakpoints, editorManager }, this.commandService);
666
709
  }
667
710
 
668
711
  /**
@@ -19,7 +19,7 @@
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 } from '@theia/core/lib/common';
22
+ import { Emitter, Event, DisposableCollection, Disposable, MessageClient, MessageType, Mutable, ContributionProvider, CommandService } from '@theia/core/lib/common';
23
23
  import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service';
24
24
  import { EditorManager } from '@theia/editor/lib/browser';
25
25
  import { CompositeTreeElement } from '@theia/core/lib/browser/source-tree';
@@ -129,6 +129,7 @@ export class DebugSession implements CompositeTreeElement {
129
129
  protected readonly debugContributionProvider: ContributionProvider<DebugContribution>,
130
130
  protected readonly workspaceService: WorkspaceService,
131
131
  protected readonly debugPreferences: DebugPreferences,
132
+ protected readonly commandService: CommandService,
132
133
  /**
133
134
  * Number of millis after a `stop` request times out. It's 5 seconds by default.
134
135
  */
@@ -687,7 +688,7 @@ export class DebugSession implements CompositeTreeElement {
687
688
  const origin = SourceBreakpoint.create(uri, { line: raw.line, column: raw.column });
688
689
  if (this.breakpoints.addBreakpoint(origin)) {
689
690
  const breakpoints = this.getSourceBreakpoints(uri);
690
- const breakpoint = new DebugSourceBreakpoint(origin, this.asDebugBreakpointOptions());
691
+ const breakpoint = new DebugSourceBreakpoint(origin, this.asDebugBreakpointOptions(), this.commandService);
691
692
  breakpoint.update({ raw });
692
693
  breakpoints.push(breakpoint);
693
694
  this.setSourceBreakpoints(uri, breakpoints);
@@ -824,7 +825,7 @@ export class DebugSession implements CompositeTreeElement {
824
825
  const known = this._breakpoints.get(affectedUri.toString());
825
826
  const all = this.breakpoints.findMarkers({ uri: affectedUri }).map(({ data }) =>
826
827
  known?.find((candidate): candidate is DebugSourceBreakpoint => candidate instanceof DebugSourceBreakpoint && candidate.origin.id === data.id) ??
827
- new DebugSourceBreakpoint(data, this.asDebugBreakpointOptions())
828
+ new DebugSourceBreakpoint(data, this.asDebugBreakpointOptions(), this.commandService)
828
829
  );
829
830
  const enabled = all.filter(b => b.enabled);
830
831
  try {
@@ -18,8 +18,9 @@ import * as React from '@theia/core/shared/react';
18
18
  import { DebugProtocol } from '@vscode/debugprotocol/lib/debugProtocol';
19
19
  import URI from '@theia/core/lib/common/uri';
20
20
  import { EditorManager } from '@theia/editor/lib/browser';
21
- import { LabelProvider, DISABLED_CLASS } from '@theia/core/lib/browser';
21
+ import { LabelProvider, DISABLED_CLASS, TreeWidget } from '@theia/core/lib/browser';
22
22
  import { TreeElement } from '@theia/core/lib/browser/source-tree';
23
+ import { SelectableTreeNode } from '@theia/core/lib/browser/tree/tree-selection';
23
24
  import { DebugSession } from '../debug-session';
24
25
  import { BaseBreakpoint } from '../breakpoint/breakpoint-marker';
25
26
  import { BreakpointManager } from '../breakpoint/breakpoint-manager';
@@ -44,6 +45,7 @@ export class DebugBreakpointDecoration {
44
45
  export abstract class DebugBreakpoint<T extends BaseBreakpoint = BaseBreakpoint> extends DebugBreakpointOptions implements TreeElement {
45
46
 
46
47
  readonly raw?: DebugProtocol.Breakpoint;
48
+ protected treeWidget?: TreeWidget;
47
49
 
48
50
  constructor(
49
51
  readonly uri: URI,
@@ -76,7 +78,7 @@ export abstract class DebugBreakpoint<T extends BaseBreakpoint = BaseBreakpoint>
76
78
  }
77
79
 
78
80
  get verified(): boolean {
79
- return !!this.raw ? this.raw.verified : true;
81
+ return !!this.raw ? this.raw.verified : false;
80
82
  }
81
83
 
82
84
  get message(): string {
@@ -91,7 +93,8 @@ export abstract class DebugBreakpoint<T extends BaseBreakpoint = BaseBreakpoint>
91
93
  this.setEnabled(event.target.checked);
92
94
  };
93
95
 
94
- render(): React.ReactNode {
96
+ render(host: TreeWidget): React.ReactNode {
97
+ this.treeWidget = host;
95
98
  const classNames = ['theia-source-breakpoint'];
96
99
  if (!this.isEnabled()) {
97
100
  classNames.push(DISABLED_CLASS);
@@ -149,4 +152,10 @@ export abstract class DebugBreakpoint<T extends BaseBreakpoint = BaseBreakpoint>
149
152
 
150
153
  protected abstract getBreakpointDecoration(message?: string[]): DebugBreakpointDecoration;
151
154
 
155
+ protected async selectInTree(): Promise<void> {
156
+ if (this.treeWidget?.model && SelectableTreeNode.is(this)) {
157
+ this.treeWidget.model.selectNode(this);
158
+ }
159
+ }
160
+
152
161
  }
@@ -16,6 +16,7 @@
16
16
 
17
17
  import { nls } from '@theia/core';
18
18
  import * as React from '@theia/core/shared/react';
19
+ import { codicon } from '@theia/core/lib/browser';
19
20
  import { BreakpointManager } from '../breakpoint/breakpoint-manager';
20
21
  import { DataBreakpoint } from '../breakpoint/breakpoint-marker';
21
22
  import { DebugBreakpoint, DebugBreakpointDecoration, DebugBreakpointOptions } from './debug-breakpoint';
@@ -44,12 +45,26 @@ export class DebugDataBreakpoint extends DebugBreakpoint<DataBreakpoint> {
44
45
  }
45
46
 
46
47
  protected doRender(): React.ReactNode {
47
- return <span className="line-info theia-data-breakpoint" title={this.origin.info.description}>
48
- <span className="name">{this.origin.info.description}</span>
49
- <span className="theia-TreeNodeInfo theia-access-type" >{this.getAccessType()}</span>
50
- </span>;
48
+ return <>
49
+ <span className="line-info theia-data-breakpoint" title={this.origin.info.description}>
50
+ <span className="name">{this.origin.info.description}</span>
51
+ <span className="theia-TreeNodeInfo theia-access-type" >{this.getAccessType()}</span>
52
+ </span>
53
+ {this.renderActions()}
54
+ </>;
51
55
  }
52
56
 
57
+ protected renderActions(): React.ReactNode {
58
+ return <div className='theia-debug-breakpoint-actions'>
59
+ <div className={codicon('close', true)} title={nls.localizeByDefault('Remove Breakpoint')} onClick={this.onRemove} />
60
+ </div>;
61
+ }
62
+
63
+ protected onRemove = async () => {
64
+ await this.selectInTree();
65
+ this.remove();
66
+ };
67
+
53
68
  protected getAccessType(): string {
54
69
  switch (this.origin.raw.accessType) {
55
70
  case 'read': return 'Read';
@@ -62,7 +77,7 @@ export class DebugDataBreakpoint extends DebugBreakpoint<DataBreakpoint> {
62
77
  if (!this.isSupported()) {
63
78
  return {
64
79
  className: 'codicon-debug-breakpoint-unsupported',
65
- message: message ?? [nls.localize('theia/debug/data-breakpoint', 'Data Breakpoint')],
80
+ message: message ?? [nls.localizeByDefault('Data Breakpoint')],
66
81
  };
67
82
  }
68
83
  if (this.origin.raw.condition || this.origin.raw.hitCondition) {
@@ -73,7 +88,7 @@ export class DebugDataBreakpoint extends DebugBreakpoint<DataBreakpoint> {
73
88
  }
74
89
  return {
75
90
  className: 'codicon-debug-breakpoint-data',
76
- message: message || [nls.localize('theia/debug/data-breakpoint', 'Data Breakpoint')]
91
+ message: message || [nls.localizeByDefault('Data Breakpoint')]
77
92
  };
78
93
  }
79
94
  }
@@ -21,6 +21,7 @@ import { BreakpointManager } from '../breakpoint/breakpoint-manager';
21
21
  import { DebugBreakpoint, DebugBreakpointOptions, DebugBreakpointDecoration } from './debug-breakpoint';
22
22
  import { SingleTextInputDialog } from '@theia/core/lib/browser/dialogs';
23
23
  import { nls } from '@theia/core';
24
+ import { codicon } from '@theia/core/lib/browser';
24
25
 
25
26
  export class DebugFunctionBreakpoint extends DebugBreakpoint<FunctionBreakpoint> implements TreeElement {
26
27
 
@@ -59,9 +60,29 @@ export class DebugFunctionBreakpoint extends DebugBreakpoint<FunctionBreakpoint>
59
60
  }
60
61
 
61
62
  protected doRender(): React.ReactNode {
62
- return <span className='line-info'>{this.name}</span>;
63
+ return <React.Fragment>
64
+ <span className='line-info'>{this.name}</span>
65
+ {this.renderActions()}
66
+ </React.Fragment>;
63
67
  }
64
68
 
69
+ protected renderActions(): React.ReactNode {
70
+ return <div className='theia-debug-breakpoint-actions'>
71
+ <div className={codicon('edit', true)} title={nls.localizeByDefault('Edit Condition...')} onClick={this.onEdit} />
72
+ <div className={codicon('close', true)} title={nls.localizeByDefault('Remove Breakpoint')} onClick={this.onRemove} />
73
+ </div>;
74
+ }
75
+
76
+ protected onEdit = async () => {
77
+ await this.selectInTree();
78
+ this.open();
79
+ };
80
+
81
+ protected onRemove = async () => {
82
+ await this.selectInTree();
83
+ this.remove();
84
+ };
85
+
65
86
  protected override doGetDecoration(): DebugBreakpointDecoration {
66
87
  if (!this.isSupported()) {
67
88
  return this.getDisabledBreakpointDecoration(nls.localizeByDefault('Function breakpoints are not supported by this debug type'));
@@ -16,6 +16,7 @@
16
16
 
17
17
  import { nls } from '@theia/core';
18
18
  import * as React from '@theia/core/shared/react';
19
+ import { codicon } from '@theia/core/lib/browser';
19
20
  import { BreakpointManager } from '../breakpoint/breakpoint-manager';
20
21
  import { InstructionBreakpoint } from '../breakpoint/breakpoint-marker';
21
22
  import { DebugBreakpoint, DebugBreakpointDecoration, DebugBreakpointOptions } from './debug-breakpoint';
@@ -44,9 +45,23 @@ export class DebugInstructionBreakpoint extends DebugBreakpoint<InstructionBreak
44
45
  }
45
46
 
46
47
  protected doRender(): React.ReactNode {
47
- return <span className="line-info">{this.origin.instructionReference}</span>;
48
+ return <React.Fragment>
49
+ <span className="line-info">{this.origin.instructionReference}</span>;
50
+ {this.renderActions()}
51
+ </React.Fragment>;
48
52
  }
49
53
 
54
+ protected renderActions(): React.ReactNode {
55
+ return <div className='theia-debug-breakpoint-actions'>
56
+ <div className={codicon('close', true)} title={nls.localizeByDefault('Remove Breakpoint')} onClick={this.onRemove} />
57
+ </div>;
58
+ }
59
+
60
+ protected onRemove = async () => {
61
+ await this.selectInTree();
62
+ this.remove();
63
+ };
64
+
50
65
  protected getBreakpointDecoration(message?: string[]): DebugBreakpointDecoration {
51
66
  if (!this.isSupported()) {
52
67
  return {
@@ -16,14 +16,15 @@
16
16
 
17
17
  import * as React from '@theia/core/shared/react';
18
18
  import { DebugProtocol } from '@vscode/debugprotocol/lib/debugProtocol';
19
- import { nls, RecursivePartial } from '@theia/core';
19
+ import { CommandService, nls, RecursivePartial } from '@theia/core';
20
20
  import URI from '@theia/core/lib/common/uri';
21
21
  import { EditorWidget, Range } from '@theia/editor/lib/browser';
22
- import { TREE_NODE_INFO_CLASS, WidgetOpenerOptions } from '@theia/core/lib/browser';
22
+ import { TREE_NODE_INFO_CLASS, WidgetOpenerOptions, codicon } from '@theia/core/lib/browser';
23
23
  import { TreeElement } from '@theia/core/lib/browser/source-tree';
24
24
  import { SourceBreakpoint } from '../breakpoint/breakpoint-marker';
25
25
  import { DebugSource } from './debug-source';
26
26
  import { DebugBreakpoint, DebugBreakpointOptions, DebugBreakpointData, DebugBreakpointDecoration } from './debug-breakpoint';
27
+ import { DebugCommands } from '../debug-commands';
27
28
 
28
29
  export class DebugSourceBreakpointData extends DebugBreakpointData {
29
30
  readonly origins: SourceBreakpoint[];
@@ -31,11 +32,13 @@ export class DebugSourceBreakpointData extends DebugBreakpointData {
31
32
 
32
33
  export class DebugSourceBreakpoint extends DebugBreakpoint<SourceBreakpoint> implements TreeElement {
33
34
 
35
+ protected readonly commandService: CommandService;
34
36
  readonly origins: SourceBreakpoint[];
35
37
 
36
- constructor(origin: SourceBreakpoint, options: DebugBreakpointOptions) {
38
+ constructor(origin: SourceBreakpoint, options: DebugBreakpointOptions, commandService: CommandService) {
37
39
  super(new URI(origin.uri), options);
38
40
  this.origins = [origin];
41
+ this.commandService = commandService;
39
42
  }
40
43
 
41
44
  override update(data: Partial<DebugSourceBreakpointData>): void {
@@ -150,10 +153,28 @@ export class DebugSourceBreakpoint extends DebugBreakpoint<SourceBreakpoint> imp
150
153
  <span className='name'>{this.labelProvider.getName(this.uri)} </span>
151
154
  <span className={'path ' + TREE_NODE_INFO_CLASS}>{this.labelProvider.getLongName(this.uri.parent)} </span>
152
155
  </span>
156
+ {this.renderActions()}
153
157
  <span className='line'>{this.renderPosition()}</span>
154
158
  </React.Fragment>;
155
159
  }
156
160
 
161
+ protected renderActions(): React.ReactNode {
162
+ return <div className='theia-debug-breakpoint-actions'>
163
+ <div className={codicon('edit', true)} title={nls.localizeByDefault('Edit Breakpoint')} onClick={this.onEdit} />
164
+ <div className={codicon('close', true)} title={nls.localizeByDefault('Remove Breakpoint')} onClick={this.onRemove} />
165
+ </div>;
166
+ }
167
+
168
+ protected onEdit = async () => {
169
+ await this.selectInTree();
170
+ this.commandService.executeCommand(DebugCommands.EDIT_BREAKPOINT.id, this);
171
+ };
172
+
173
+ protected onRemove = async () => {
174
+ await this.selectInTree();
175
+ this.remove();
176
+ };
177
+
157
178
  renderPosition(): string {
158
179
  return this.line + (typeof this.column === 'number' ? ':' + this.column : '');
159
180
  }
@@ -69,14 +69,13 @@
69
69
  font-size: var(--theia-ui-font-size0);
70
70
  line-height: calc(var(--theia-private-horizontal-tab-height) / 2);
71
71
  border-radius: 2px;
72
+ margin-left: calc(var(--theia-ui-padding) / 2);
73
+ white-space: nowrap;
74
+ flex-shrink: 0;
72
75
  }
73
76
 
74
77
  .theia-data-breakpoint .theia-access-type {
75
- margin-left: var(--theia-ui-padding);
76
- }
77
-
78
- .theia-source-breakpoint > .theia-input {
79
- min-height: auto;
78
+ margin-left: var(--theia-ui-padding);
80
79
  }
81
80
 
82
81
  .theia-debug-session .status,
@@ -251,6 +250,15 @@
251
250
  display: flex;
252
251
  }
253
252
 
253
+ .theia-debug-breakpoint-actions {
254
+ display: none;
255
+ }
256
+
257
+ .theia-source-breakpoint:hover .theia-debug-breakpoint-actions {
258
+ display: flex;
259
+ align-items: center;
260
+ }
261
+
254
262
  /** Editor **/
255
263
 
256
264
  .theia-debug-breakpoint-icon {
@@ -21,7 +21,7 @@ import { MenuPath } from '@theia/core';
21
21
  export class DebugAction extends React.Component<DebugAction.Props> {
22
22
 
23
23
  override render(): React.ReactNode {
24
- const { enabled, label, iconClass } = this.props;
24
+ const { enabled, label, tooltip, iconClass } = this.props;
25
25
  const classNames = ['debug-action'];
26
26
  if (iconClass) {
27
27
  classNames.push(...codiconArray(iconClass, true));
@@ -31,7 +31,7 @@ export class DebugAction extends React.Component<DebugAction.Props> {
31
31
  }
32
32
  return <span tabIndex={0}
33
33
  className={classNames.join(' ')}
34
- title={label}
34
+ title={tooltip || label}
35
35
  onClick={() => { this.props.run([]); }}
36
36
  ref={this.setRef} >
37
37
  {!iconClass && <div>{label}</div>}
@@ -51,6 +51,7 @@ export class DebugAction extends React.Component<DebugAction.Props> {
51
51
  export namespace DebugAction {
52
52
  export interface Props {
53
53
  label: string
54
+ tooltip?: string
54
55
  iconClass: string
55
56
  run: (effectiveMenuPath: MenuPath) => void
56
57
  enabled?: boolean
@@ -19,6 +19,7 @@ import { TreeSource, TreeElement } from '@theia/core/lib/browser/source-tree';
19
19
  import { DebugViewModel } from './debug-view-model';
20
20
  import { BreakpointManager } from '../breakpoint/breakpoint-manager';
21
21
  import { DebugExceptionBreakpoint } from './debug-exception-breakpoint';
22
+ import { CommandService } from '@theia/core/lib/common';
22
23
 
23
24
  @injectable()
24
25
  export class DebugBreakpointsSource extends TreeSource {
@@ -29,6 +30,9 @@ export class DebugBreakpointsSource extends TreeSource {
29
30
  @inject(BreakpointManager)
30
31
  protected readonly breakpoints: BreakpointManager;
31
32
 
33
+ @inject(CommandService)
34
+ protected readonly commandService: CommandService;
35
+
32
36
  @postConstruct()
33
37
  protected init(): void {
34
38
  this.fireDidChange();
@@ -37,7 +41,7 @@ export class DebugBreakpointsSource extends TreeSource {
37
41
 
38
42
  *getElements(): IterableIterator<TreeElement> {
39
43
  for (const exceptionBreakpoint of this.breakpoints.getExceptionBreakpoints()) {
40
- yield new DebugExceptionBreakpoint(exceptionBreakpoint, this.breakpoints);
44
+ yield new DebugExceptionBreakpoint(exceptionBreakpoint, this.breakpoints, this.commandService);
41
45
  }
42
46
  yield* this.model.dataBreakpoints;
43
47
  yield* this.model.functionBreakpoints;
@@ -21,7 +21,7 @@ import * as React from '@theia/core/shared/react';
21
21
  import { WorkspaceService } from '@theia/workspace/lib/browser';
22
22
  import { DebugConsoleContribution } from '../console/debug-console-contribution';
23
23
  import { DebugConfigurationManager } from '../debug-configuration-manager';
24
- import { DebugCommands } from '../debug-frontend-application-contribution';
24
+ import { DebugCommands } from '../debug-commands';
25
25
  import { DebugSessionManager } from '../debug-session-manager';
26
26
  import { DebugAction } from './debug-action';
27
27
  import { DebugConfigurationSelect } from './debug-configuration-select';
@@ -18,22 +18,26 @@ import * as React from '@theia/core/shared/react';
18
18
  import { TreeElement } from '@theia/core/lib/browser/source-tree';
19
19
  import { BreakpointManager } from '../breakpoint/breakpoint-manager';
20
20
  import { ExceptionBreakpoint } from '../breakpoint/breakpoint-marker';
21
- import { SingleTextInputDialog } from '@theia/core/lib/browser/dialogs';
22
- import { TREE_NODE_INFO_CLASS } from '@theia/core/lib/browser';
23
- import { nls } from '@theia/core';
21
+ import { SingleTextInputDialog, TREE_NODE_INFO_CLASS, codicon, TreeWidget } from '@theia/core/lib/browser';
22
+ import { SelectableTreeNode } from '@theia/core/lib/browser/tree/tree-selection';
23
+ import { nls, CommandService } from '@theia/core';
24
+ import { DebugCommands } from '../debug-commands';
24
25
 
25
26
  export class DebugExceptionBreakpoint implements TreeElement {
26
27
 
27
28
  readonly id: string;
29
+ protected treeWidget?: TreeWidget;
28
30
 
29
31
  constructor(
30
32
  readonly data: ExceptionBreakpoint,
31
- readonly breakpoints: BreakpointManager
33
+ readonly breakpoints: BreakpointManager,
34
+ protected readonly commandService: CommandService
32
35
  ) {
33
36
  this.id = data.raw.filter + ':' + data.raw.label;
34
37
  }
35
38
 
36
- render(): React.ReactNode {
39
+ render(host: TreeWidget): React.ReactNode {
40
+ this.treeWidget = host;
37
41
  return <div title={this.data.raw.description || this.data.raw.label} className='theia-source-breakpoint'>
38
42
  <span className='theia-debug-breakpoint-icon' />
39
43
  <input type='checkbox' checked={this.data.enabled} onChange={this.toggle} />
@@ -43,9 +47,30 @@ export class DebugExceptionBreakpoint implements TreeElement {
43
47
  <span title={nls.localizeByDefault('Expression condition: {0}', this.data.condition)}
44
48
  className={'path ' + TREE_NODE_INFO_CLASS}>{this.data.condition} </span>}
45
49
  </span>
50
+ {this.renderActions()}
46
51
  </div>;
47
52
  }
48
53
 
54
+ protected renderActions(): React.ReactNode {
55
+ if (this.data.raw.supportsCondition) {
56
+ return <div className='theia-debug-breakpoint-actions'>
57
+ <div className={codicon('edit', true)} title={nls.localizeByDefault('Edit Condition...')} onClick={this.onEdit} />
58
+ </div>;
59
+ }
60
+ return undefined;
61
+ }
62
+
63
+ protected onEdit = async () => {
64
+ await this.selectInTree();
65
+ this.commandService.executeCommand(DebugCommands.EDIT_BREAKPOINT_CONDITION.id);
66
+ };
67
+
68
+ protected async selectInTree(): Promise<void> {
69
+ if (this.treeWidget?.model && SelectableTreeNode.is(this)) {
70
+ this.treeWidget.model.selectNode(this);
71
+ }
72
+ }
73
+
49
74
  protected toggle = () => this.breakpoints.toggleExceptionBreakpoint(this.data.raw.filter);
50
75
 
51
76
  async editCondition(): Promise<void> {
@@ -100,11 +100,6 @@ export class DebugSessionWidget extends BaseWidget implements StatefulWidget, Ap
100
100
  layout.addWidget(this.viewContainer);
101
101
  }
102
102
 
103
- protected override onActivateRequest(msg: Message): void {
104
- super.onActivateRequest(msg);
105
- this.toolbar.focus();
106
- }
107
-
108
103
  protected override onAfterShow(msg: Message): void {
109
104
  super.onAfterShow(msg);
110
105
  this.getTrackableWidgets().forEach(w => w.update());