Skip to content

Commit 6f1d168

Browse files
committed
feat: enable conditional breakpoints
1 parent 82d21f5 commit 6f1d168

9 files changed

Lines changed: 803 additions & 4 deletions

File tree

org.eclipse.lsp4e.debug/META-INF/MANIFEST.MF

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@ Require-Bundle: org.eclipse.ui,
1919
org.eclipse.jface.text,
2020
org.eclipse.ui.genericeditor,
2121
org.eclipse.core.variables,
22-
org.eclipse.lsp4e;bundle-version="0.18.13"
22+
org.eclipse.lsp4e;bundle-version="0.19.0",
23+
org.eclipse.tm4e.core;resolution:=optional,
24+
org.eclipse.tm4e.registry;resolution:=optional,
25+
org.eclipse.tm4e.ui;resolution:=optional
2326
Bundle-RequiredExecutionEnvironment: JavaSE-21
2427
Bundle-ActivationPolicy: lazy
2528
Import-Package: com.google.gson,
2629
com.google.gson.reflect;version="2.7.0"
2730
Export-Package: org.eclipse.lsp4e.debug;x-internal:=true,
28-
org.eclipse.lsp4e.debug.breakpoints;x-internal:=true,
31+
org.eclipse.lsp4e.debug.breakpoints;x-friends:="org.eclipse.lsp4e.test",
2932
org.eclipse.lsp4e.debug.console;x-internal:=true,
3033
org.eclipse.lsp4e.debug.debugmodel;x-friends:="org.eclipse.lsp4e.test",
3134
org.eclipse.lsp4e.debug.launcher,

org.eclipse.lsp4e.debug/plugin.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,20 @@
113113
delegateClass="org.eclipse.lsp4e.debug.presentation.DAPWatchExpression">
114114
</watchExpressionDelegate>
115115
</extension>
116+
<extension point="org.eclipse.debug.ui.detailPaneFactories">
117+
<detailFactories
118+
id="org.eclipse.lsp4e.debug.detailPaneFactory"
119+
class="org.eclipse.lsp4e.debug.presentation.DSPBreakpointDetailPaneFactory">
120+
<enablement>
121+
<with variable="selection">
122+
<count value="1"/>
123+
<iterate>
124+
<adapt type="org.eclipse.debug.core.model.IBreakpoint">
125+
<instanceof value="org.eclipse.lsp4e.debug.breakpoints.DSPLineBreakpoint"/>
126+
</adapt>
127+
</iterate>
128+
</with>
129+
</enablement>
130+
</detailFactories>
131+
</extension>
116132
</plugin>

org.eclipse.lsp4e.debug/src/org/eclipse/lsp4e/debug/breakpoints/DSPLineBreakpoint.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,22 @@
1313
import org.eclipse.core.runtime.CoreException;
1414
import org.eclipse.debug.core.model.IBreakpoint;
1515
import org.eclipse.debug.core.model.LineBreakpoint;
16+
import org.eclipse.jdt.annotation.Nullable;
1617
import org.eclipse.lsp4e.debug.DSPPlugin;
1718

1819
public class DSPLineBreakpoint extends LineBreakpoint {
1920

2021
public static final String ID = "org.eclipse.lsp4e.debug.breakpoints.markerType.lineBreakpoint";
2122

23+
/** Marker attribute key for a conditional expression. */
24+
public static final String ATTR_CONDITION = "org.eclipse.lsp4e.debug.breakpoints.condition";
25+
26+
/** Marker attribute key for inline breakpoint column (1-based). */
27+
public static final String ATTR_COLUMN = "org.eclipse.lsp4e.debug.breakpoints.column";
28+
29+
/** Marker attribute key for hit condition expression. */
30+
public static final String ATTR_HIT_CONDITION = "org.eclipse.lsp4e.debug.breakpoints.hitCondition";
31+
2232
public DSPLineBreakpoint() {
2333
}
2434

@@ -48,4 +58,59 @@ public DSPLineBreakpoint(final IResource resource, String fileName, final int li
4858
public String getModelIdentifier() {
4959
return DSPPlugin.ID_DSP_DEBUG_MODEL;
5060
}
61+
62+
/**
63+
* @return the inline breakpoint column (1-based) or {@code -1} if unset.
64+
*/
65+
public int getColumn() {
66+
final IMarker m = getMarker();
67+
return m == null ? -1 : m.getAttribute(ATTR_COLUMN, -1);
68+
}
69+
70+
/**
71+
* Sets or clears the inline breakpoint column. Values <= 0 clear the column.
72+
*/
73+
public void setColumn(final int column) throws CoreException {
74+
final IMarker m = getMarker();
75+
if (m != null) {
76+
m.setAttribute(ATTR_COLUMN, column <= 0 ? null : column);
77+
}
78+
}
79+
80+
/**
81+
* @return the breakpoint condition or {@code null} if none.
82+
*/
83+
public @Nullable String getCondition() {
84+
final IMarker m = getMarker();
85+
return m == null ? null : m.getAttribute(ATTR_CONDITION, (String) null);
86+
}
87+
88+
/**
89+
* Sets or clears the breakpoint condition. A {@code null} or blank value clears
90+
* the condition.
91+
*/
92+
public void setCondition(final @Nullable String condition) throws CoreException {
93+
final IMarker m = getMarker();
94+
if (m != null) {
95+
m.setAttribute(ATTR_CONDITION, condition == null || condition.isBlank() ? null : condition);
96+
}
97+
}
98+
99+
/**
100+
* @return the hit condition or {@code null} if none.
101+
*/
102+
public @Nullable String getHitCondition() {
103+
final IMarker m = getMarker();
104+
return m == null ? null : m.getAttribute(ATTR_HIT_CONDITION, (String) null);
105+
}
106+
107+
/**
108+
* Sets or clears the hit condition. A {@code null} or blank value clears it.
109+
*/
110+
public void setHitCondition(final @Nullable String hitCondition) throws CoreException {
111+
final IMarker m = getMarker();
112+
if (m != null) {
113+
m.setAttribute(ATTR_HIT_CONDITION, hitCondition == null || hitCondition.isBlank() ? null : hitCondition);
114+
}
115+
}
51116
}

org.eclipse.lsp4e.debug/src/org/eclipse/lsp4e/debug/debugmodel/DSPBreakpointManager.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.eclipse.debug.core.model.ILineBreakpoint;
3131
import org.eclipse.jdt.annotation.Nullable;
3232
import org.eclipse.lsp4e.debug.DSPPlugin;
33+
import org.eclipse.lsp4e.debug.breakpoints.DSPLineBreakpoint;
3334
import org.eclipse.lsp4j.debug.BreakpointEventArguments;
3435
import org.eclipse.lsp4j.debug.Capabilities;
3536
import org.eclipse.lsp4j.debug.SetBreakpointsArguments;
@@ -179,6 +180,25 @@ private void addBreakpointToMap(IBreakpoint breakpoint) {
179180
s -> new ArrayList<>());
180181
final var sourceBreakpoint = new SourceBreakpoint();
181182
sourceBreakpoint.setLine(lineNumber);
183+
184+
// inline (column) breakpoint support
185+
final int column = marker.getAttribute(DSPLineBreakpoint.ATTR_COLUMN, -1);
186+
if (column > 0) {
187+
sourceBreakpoint.setColumn(column);
188+
}
189+
190+
// conditional breakpoint support
191+
final String condition = marker.getAttribute(DSPLineBreakpoint.ATTR_CONDITION, (String) null);
192+
if (condition != null && !condition.isBlank()) {
193+
sourceBreakpoint.setCondition(condition);
194+
}
195+
196+
// hit condition support
197+
final String hitCondition = marker.getAttribute(DSPLineBreakpoint.ATTR_HIT_CONDITION, (String) null);
198+
if (hitCondition != null && !hitCondition.isBlank()) {
199+
sourceBreakpoint.setHitCondition(hitCondition);
200+
}
201+
182202
sourceBreakpoints.add(sourceBreakpoint);
183203
}
184204
}
@@ -202,7 +222,16 @@ private void deleteBreakpointFromMap(IBreakpoint breakpoint) {
202222
List<SourceBreakpoint> bps = entry.getValue();
203223
for (Iterator<SourceBreakpoint> iterator = bps.iterator(); iterator.hasNext();) {
204224
SourceBreakpoint sourceBreakpoint = iterator.next();
205-
if (Objects.equals(lineNumber, sourceBreakpoint.getLine())) {
225+
226+
// Match by line and (if present) column
227+
Integer bpColumn = sourceBreakpoint.getColumn();
228+
int markerColumn = lineBreakpoint.getMarker().getAttribute(DSPLineBreakpoint.ATTR_COLUMN, -1);
229+
final boolean lineMatches = Objects.equals(lineNumber, sourceBreakpoint.getLine());
230+
final boolean columnMatches = (markerColumn <= 0
231+
&& (bpColumn == null || bpColumn.intValue() <= 0))
232+
|| (markerColumn > 0 && bpColumn != null && bpColumn.intValue() == markerColumn);
233+
234+
if (lineMatches && columnMatches) {
206235
iterator.remove();
207236
}
208237
}

0 commit comments

Comments
 (0)