Skip to content

Commit 6d2d70a

Browse files
committed
Add option to resume execution on Triggerpoint hit and toggle Trigger
from editor This commit introduces an option to resume virtual machine execution when a trigger breakpoint is hit. This allows trigger breakpoints to act as barriers, enabling lower-priority breakpoints to remain active without needing to be disabled. Additionally, a new option has been added to the Java editor to toggle Triggerpoints, allowing users to instantly create a Resume-Triggerpoint. Fixes #614
1 parent 88e6357 commit 6d2d70a

File tree

16 files changed

+299
-17
lines changed

16 files changed

+299
-17
lines changed

org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/TriggerPointBreakpointsTests.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2016 IBM Corporation and others.
2+
* Copyright (c) 2016, 2025 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -14,6 +14,7 @@
1414
package org.eclipse.jdt.debug.tests.breakpoints;
1515

1616
import org.eclipse.debug.core.model.IVariable;
17+
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
1718
import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
1819
import org.eclipse.jdt.debug.core.IJavaPrimitiveValue;
1920
import org.eclipse.jdt.debug.core.IJavaStackFrame;
@@ -69,4 +70,47 @@ public void testTriggerPointBreakpoint() throws Exception {
6970
removeAllBreakpoints();
7071
}
7172
}
73+
74+
public void testTriggerPointBreakpointWithResume() throws Exception {
75+
String typeName = "TriggerPoint_01";
76+
IJavaLineBreakpoint bp1 = createLineBreakpoint(20, typeName);
77+
IJavaLineBreakpoint bp2 = createLineBreakpoint(21, typeName);
78+
bp1.setTriggerPoint(true);
79+
bp1.setSuspendPolicy(IJavaBreakpoint.RESUME_THREAD); // Resume mode
80+
IJavaThread thread = null;
81+
try {
82+
thread = launchToLineBreakpoint(typeName, bp2);
83+
84+
IJavaStackFrame frame = (IJavaStackFrame) thread.getTopStackFrame();
85+
int lineNumber = frame.getLineNumber();
86+
assertEquals("Breakpoint should resume and hit next breakpoint", 21, lineNumber);
87+
bp1.delete();
88+
bp2.delete();
89+
} finally {
90+
terminateAndRemove(thread);
91+
removeAllBreakpoints();
92+
}
93+
}
94+
95+
public void testTriggerPointBreakpointWithResumeAndCondition() throws Exception {
96+
String typeName = "TriggerPoint_01";
97+
IJavaLineBreakpoint bp1 = createLineBreakpoint(20, typeName);
98+
IJavaLineBreakpoint bp2 = createLineBreakpoint(21, typeName);
99+
bp1.setTriggerPoint(true);
100+
bp1.setConditionEnabled(true);
101+
bp1.setCondition("false"); // this wont let breakpoint to resume
102+
bp1.setSuspendPolicy(IJavaBreakpoint.RESUME_THREAD); // Resume mode
103+
IJavaThread thread = null;
104+
try {
105+
thread = launchToBreakpoint(typeName);
106+
IJavaStackFrame frame = (IJavaStackFrame) thread.getTopStackFrame();
107+
int lineNumber = frame.getLineNumber();
108+
assertEquals("Breakpoint should not resume as condition is false", 20, lineNumber);
109+
bp1.delete();
110+
bp2.delete();
111+
} finally {
112+
terminateAndRemove(thread);
113+
removeAllBreakpoints();
114+
}
115+
}
72116
}

org.eclipse.jdt.debug.ui/plugin.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ ActionDefinition.breakpointproperties.name=Breakpoint P&roperties
235235
ActionDefinition.breakpointproperties.description=View and edit the properties for a given Java breakpoint
236236
CommandDefinition.breakpointproperties.name=Java Breakpoint Properties
237237

238+
ToggleTriggerpointAction.label=Toggle Triggerpoint
239+
ToggleTriggerpointCommand.description=Creates or removes a triggerpoint
240+
238241
ToggleTracepointAction.label=Toggle Tra&cepoint
239242
ToggleTracepointCommand.label=Toggle Tracepoint
240243
ToggleTracepointCommand.description=Creates or removes a tracepoint

org.eclipse.jdt.debug.ui/plugin.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,13 @@
10321032
menubarPath="debug"
10331033
id="org.eclipse.jdt.debug.ui.actions.EnableDisableBreakpointRulerActionDelegate">
10341034
</action>
1035+
<action
1036+
class="org.eclipse.jdt.internal.debug.ui.actions.RulerToggleTriggerBreakpointActionDelegate"
1037+
icon="icons/full/obj16/brkp_obj.png"
1038+
id="org.eclipse.jdt.debug.ui.actions.TriggerBreakpointRulerActionDelegate"
1039+
label="%ToggleTriggerpointAction.label"
1040+
menubarPath="debug">
1041+
</action>
10351042
<action
10361043
class="org.eclipse.debug.ui.actions.RulerToggleBreakpointActionDelegate"
10371044
helpContextId="manage_breakpoint_action_context"
@@ -1085,6 +1092,13 @@
10851092
menubarPath="debug"
10861093
id="org.eclipse.jdt.debug.ui.actions.EnableDisableBreakpointRulerActionDelegate">
10871094
</action>
1095+
<action
1096+
class="org.eclipse.jdt.internal.debug.ui.actions.RulerToggleTriggerBreakpointActionDelegate"
1097+
icon="icons/full/obj16/brkp_obj.png"
1098+
id="org.eclipse.jdt.debug.ui.actions.TriggerBreakpointRulerActionDelegate"
1099+
label="%ToggleTriggerpointAction.label"
1100+
menubarPath="debug">
1101+
</action>
10881102
<action
10891103
class="org.eclipse.debug.ui.actions.RulerToggleBreakpointActionDelegate"
10901104
helpContextId="manage_breakpoint_action_context"

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/breakpoints/JavaBreakpointConditionEditor.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.eclipse.jdt.core.IField;
3333
import org.eclipse.jdt.core.ISourceRange;
3434
import org.eclipse.jdt.core.IType;
35+
import org.eclipse.jdt.debug.core.IJavaBreakpoint;
3536
import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
3637
import org.eclipse.jdt.debug.core.IJavaWatchpoint;
3738
import org.eclipse.jdt.internal.debug.ui.BreakpointUtils;
@@ -592,6 +593,20 @@ private void disposeViewerUndoRedoActions() {
592593
* @param focus <code>true</code> if focus should be set, <code>false</code> otherwise
593594
*/
594595
private void setEnabled(boolean enabled, boolean focus) {
596+
try {
597+
if (fBreakpoint != null) {
598+
if (fBreakpoint.getSuspendPolicy() == IJavaBreakpoint.RESUME_THREAD) {
599+
fWhenTrue.setText(PropertyPageMessages.BreakpointResumeConditionalTrue);
600+
fWhenChange.setText(PropertyPageMessages.BreakpointResumeConditionalValue);
601+
} else {
602+
fWhenTrue.setText(PropertyPageMessages.JavaBreakpointConditionEditor_1);
603+
fWhenChange.setText(PropertyPageMessages.JavaBreakpointConditionEditor_2);
604+
}
605+
}
606+
} catch (CoreException e) {
607+
// Ignore
608+
}
609+
595610
fViewer.setEditable(enabled);
596611
fViewer.getTextWidget().setEnabled(enabled);
597612
fWhenChange.setEnabled(enabled);

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ public class DebugUIMessages extends NLS {
178178
public static String JDIModelPresentation_target_suspended;
179179
public static String JDIModelPresentation_thread_filtered;
180180
public static String JDIModelPresentation_uncaught_62;
181+
public static String JDIModelPresentation_Resume_VM;
181182

182183
// thread label keys are built programmatically
183184

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ JDIModelPresentation_modification_72=\ [modification]
117117
JDIModelPresentation_native_method=[native method]
118118
JDIModelPresentation_not_available=not available
119119
JDIModelPresentation_Suspend_VM=[Suspend VM]
120+
JDIModelPresentation_Resume_VM=[Ignored]
120121

121122
###############################################################################
122123
# Thread label keys are built programmatically

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIModelPresentation.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1995,6 +1995,10 @@ protected void appendSuspendPolicy(IJavaBreakpoint breakpoint, StringBuilder buf
19951995
buffer.append(' ');
19961996
buffer.append(DebugUIMessages.JDIModelPresentation_Suspend_VM);
19971997
}
1998+
if (breakpoint.getSuspendPolicy() == IJavaBreakpoint.RESUME_THREAD) {
1999+
buffer.append(' ');
2000+
buffer.append(DebugUIMessages.JDIModelPresentation_Resume_VM);
2001+
}
19982002
}
19992003

20002004
protected void appendThreadFilter(IJavaBreakpoint breakpoint, StringBuilder buffer) throws CoreException {

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/BreakpointToggleUtils.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2016, 2022 IBM Corporation and others.
2+
* Copyright (c) 2016, 2025 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -26,6 +26,7 @@ public class BreakpointToggleUtils {
2626

2727
private static boolean isTracepoint = false;
2828
private static boolean isLambdaEntryBreakpoint = false;
29+
private static boolean isTriggerpoint = false;
2930

3031

3132
public static void setUnsetTracepoints(boolean tracePoint) {
@@ -36,6 +37,14 @@ public static boolean isToggleTracepoints() {
3637
return isTracepoint;
3738
}
3839

40+
public static void setTriggerpoints(boolean triggerPoint) {
41+
isTriggerpoint = triggerPoint;
42+
}
43+
44+
public static boolean isTriggerpoints() {
45+
return isTriggerpoint;
46+
}
47+
3948
public static void setUnsetLambdaEntryBreakpoint(boolean lambdaEntryBreakpoint) {
4049
isLambdaEntryBreakpoint = lambdaEntryBreakpoint;
4150
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 IBM Corporation and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* IBM Corporation - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.jdt.internal.debug.ui.actions;
15+
16+
import org.eclipse.core.runtime.CoreException;
17+
import org.eclipse.debug.internal.ui.DebugUIPlugin;
18+
import org.eclipse.jface.action.Action;
19+
import org.eclipse.jface.action.IAction;
20+
import org.eclipse.jface.text.BadLocationException;
21+
import org.eclipse.jface.text.IDocument;
22+
import org.eclipse.jface.text.IRegion;
23+
import org.eclipse.jface.text.ITextSelection;
24+
import org.eclipse.jface.text.TextSelection;
25+
import org.eclipse.jface.text.source.IVerticalRulerInfo;
26+
import org.eclipse.jface.viewers.ISelection;
27+
import org.eclipse.jface.viewers.ISelectionProvider;
28+
import org.eclipse.swt.widgets.Event;
29+
import org.eclipse.ui.IActionDelegate2;
30+
import org.eclipse.ui.IEditorPart;
31+
import org.eclipse.ui.texteditor.AbstractRulerActionDelegate;
32+
import org.eclipse.ui.texteditor.IDocumentProvider;
33+
import org.eclipse.ui.texteditor.ITextEditor;
34+
35+
public class RulerToggleTriggerBreakpointActionDelegate extends AbstractRulerActionDelegate implements IActionDelegate2 {
36+
37+
private IEditorPart currentEditor;
38+
private IAction dummyAction;
39+
40+
@Override
41+
protected IAction createAction(ITextEditor editor, IVerticalRulerInfo rulerInfo) {
42+
dummyAction = new Action() {};
43+
return dummyAction;
44+
}
45+
46+
@Override
47+
public void setActiveEditor(IAction callerAction, IEditorPart targetEditor) {
48+
currentEditor = targetEditor;
49+
}
50+
51+
@Override
52+
public void init(IAction action) {
53+
}
54+
55+
@Override
56+
public void dispose() {
57+
currentEditor = null;
58+
dummyAction = null;
59+
super.dispose();
60+
}
61+
62+
@Override
63+
public void runWithEvent(IAction action, Event event) {
64+
if (!(currentEditor instanceof ITextEditor)) {
65+
return;
66+
}
67+
IVerticalRulerInfo rulerInfo = currentEditor.getAdapter(IVerticalRulerInfo.class);
68+
if (rulerInfo == null) {
69+
return;
70+
}
71+
int lineOfLastMouseButtonActivity = rulerInfo.getLineOfLastMouseButtonActivity();
72+
if (lineOfLastMouseButtonActivity < 0) {
73+
return;
74+
}
75+
IDocument document = getDocument((ITextEditor) currentEditor);
76+
if (document == null) {
77+
return;
78+
}
79+
ToggleBreakpointAdapter toggle = new ToggleBreakpointAdapter();
80+
try {
81+
ITextSelection selection = getTextSelection(currentEditor, document, lineOfLastMouseButtonActivity);
82+
if (toggle.canToggleLineBreakpoints(currentEditor, selection)) {
83+
BreakpointToggleUtils.setTriggerpoints(true);
84+
toggle.toggleBreakpoints(currentEditor, selection);
85+
}
86+
} catch (BadLocationException | CoreException e) {
87+
DebugUIPlugin.log(e);
88+
}
89+
}
90+
91+
private static IDocument getDocument(ITextEditor editor) {
92+
IDocumentProvider provider = editor.getDocumentProvider();
93+
if (provider != null) {
94+
return provider.getDocument(editor.getEditorInput());
95+
}
96+
IDocument doc = editor.getAdapter(IDocument.class);
97+
if (doc != null) {
98+
return doc;
99+
}
100+
return null;
101+
}
102+
103+
private static ITextSelection getTextSelection(IEditorPart editor, IDocument document, int line) throws BadLocationException {
104+
IRegion region = document.getLineInformation(line);
105+
ITextSelection textSelection = new TextSelection(document, region.getOffset(), 0);
106+
ISelectionProvider provider = editor.getSite().getSelectionProvider();
107+
if (provider != null) {
108+
ISelection selection = provider.getSelection();
109+
if (selection instanceof ITextSelection && ((ITextSelection) selection).getStartLine() <= line
110+
&& ((ITextSelection) selection).getEndLine() >= line) {
111+
textSelection = (ITextSelection) selection;
112+
}
113+
}
114+
return textSelection;
115+
}
116+
}

org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ToggleBreakpointAdapter.java

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2000, 2022 IBM Corporation and others.
2+
* Copyright (c) 2000, 2025 IBM Corporation and others.
33
*
44
* This program and the accompanying materials
55
* are made available under the terms of the Eclipse Public License 2.0
@@ -445,6 +445,11 @@ private static void doToggleMethodBreakpoint(IMethod member, String lambdaMethod
445445
}
446446
BreakpointToggleUtils.setUnsetTracepoints(false);
447447
}
448+
if (BreakpointToggleUtils.isTriggerpoints() && finalSelection instanceof ITextSelection && part instanceof JavaEditor) {
449+
methodBreakpoint.setTriggerPoint(true);
450+
methodBreakpoint.setSuspendPolicy(IJavaBreakpoint.RESUME_THREAD);
451+
BreakpointToggleUtils.setTriggerpoints(false);
452+
}
448453
}
449454

450455
/**
@@ -513,6 +518,9 @@ static IStatus doLineBreakpointToggle(ISelection selection, IWorkbenchPart part,
513518
if (BreakpointToggleUtils.isToggleTracepoints()) {
514519
deleteTracepoint(existingBreakpoint, editor, monitor);
515520
BreakpointToggleUtils.setUnsetTracepoints(false);
521+
} else if (BreakpointToggleUtils.isTriggerpoints()) {
522+
deleteBreakpoint(existingBreakpoint, editor, monitor);
523+
BreakpointToggleUtils.setTriggerpoints(false);
516524
} else {
517525
deleteBreakpoint(existingBreakpoint, editor, monitor);
518526
}
@@ -543,15 +551,22 @@ static IStatus doLineBreakpointToggle(ISelection selection, IWorkbenchPart part,
543551
breakpoint.setConditionEnabled(true);
544552
breakpoint.setConditionSuspendOnTrue(true);
545553
}
546-
547554
BreakpointToggleUtils.setUnsetTracepoints(false);
548555
}
556+
if (BreakpointToggleUtils.isTriggerpoints() && selection instanceof ITextSelection && part instanceof JavaEditor) {
557+
breakpoint.setTriggerPoint(true);
558+
breakpoint.setSuspendPolicy(IJavaBreakpoint.RESUME_THREAD); // Default action is to Resume
559+
BreakpointToggleUtils.setTriggerpoints(false);
560+
}
549561
if (locator == null) {
550562
new BreakpointLocationVerifierJob(document, parseCompilationUnit(type.getTypeRoot()), breakpoint, lnumber, tname, type, editor, bestMatch).schedule();
551563
}
552564
if (BreakpointToggleUtils.isToggleTracepoints()) {
553565
BreakpointToggleUtils.setUnsetTracepoints(false);
554566
}
567+
if (BreakpointToggleUtils.isTriggerpoints()) {
568+
BreakpointToggleUtils.setTriggerpoints(false);
569+
}
555570
} catch (CoreException ce) {
556571
return ce.getStatus();
557572
} finally {
@@ -617,7 +632,12 @@ static IStatus doToggleClassBreakpoints(IWorkbenchPart part, ISelection selectio
617632
}
618633
IResource resource = BreakpointUtils.getBreakpointResource(member);
619634
String qualifiedName = getQualifiedName(type);
620-
JDIDebugModel.createClassPrepareBreakpoint(resource, qualifiedName, IJavaClassPrepareBreakpoint.TYPE_CLASS, start, end, true, map);
635+
IJavaClassPrepareBreakpoint classBreakpoint = JDIDebugModel.createClassPrepareBreakpoint(resource, qualifiedName, IJavaClassPrepareBreakpoint.TYPE_CLASS, start, end, true, map);
636+
if (BreakpointToggleUtils.isTriggerpoints()) {
637+
classBreakpoint.setTriggerPoint(true);
638+
classBreakpoint.setSuspendPolicy(IJavaBreakpoint.RESUME_THREAD);
639+
BreakpointToggleUtils.setTriggerpoints(false);
640+
}
621641
return Status.OK_STATUS;
622642
}
623643

@@ -1116,7 +1136,12 @@ static IStatus doToggleWatchpoints(IWorkbenchPart part, ISelection finalSelectio
11161136
BreakpointUtils.addJavaBreakpointAttributes(attributes, javaField);
11171137
resource = BreakpointUtils.getBreakpointResource(type);
11181138
}
1119-
JDIDebugModel.createWatchpoint(resource, typeName, fieldName, -1, start, end, 0, true, attributes);
1139+
IJavaWatchpoint watchPoint = JDIDebugModel.createWatchpoint(resource, typeName, fieldName, -1, start, end, 0, true, attributes);
1140+
if (BreakpointToggleUtils.isTriggerpoints()) {
1141+
watchPoint.setTriggerPoint(true);
1142+
watchPoint.setSuspendPolicy(IJavaBreakpoint.RESUME_THREAD);
1143+
BreakpointToggleUtils.setTriggerpoints(false);
1144+
}
11201145
}
11211146
return Status.OK_STATUS;
11221147
}
@@ -1529,6 +1554,9 @@ private void toggleFieldOrMethodBreakpoints(IWorkbenchPart part, ISelection sele
15291554
if (BreakpointToggleUtils.isToggleTracepoints()) {
15301555
deleteTracepoint(breakpoint, part, null);
15311556
BreakpointToggleUtils.setUnsetTracepoints(false);
1557+
} else if (BreakpointToggleUtils.isTriggerpoints()) {
1558+
deleteBreakpoint(breakpoint, part, null);
1559+
BreakpointToggleUtils.setTriggerpoints(false);
15321560
} else {
15331561
deleteBreakpoint(breakpoint, part, null);
15341562
}

0 commit comments

Comments
 (0)