diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java b/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java index 5d8281e5c20b..c04893cff86b 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XLineBreakpointType.java @@ -222,6 +222,14 @@ public abstract class XLineBreakpointType

exten @Nullable public abstract TextRange getHighlightRange(); + /** + * The priority is considered when several breakpoint variants can be set on the same line, + * in this case we choose the variant with the highest priority. + */ + public int getPriority(@NotNull Project project) { + return getType().getPriority(); + } + /** * @return true iff this variant corresponds to breakpoint hitting at all line locations * (i.e., "all", "line and all lambdas") diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java index 452dbcf4fa90..cd6f8347b07a 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java @@ -308,30 +308,43 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { if (areInlineBreakpointsEnabled(file)) { return variantsAsync.then(variantsWithAll -> { var variants = variantsWithAll.stream().filter(v -> !v.isMultiVariant()).toList(); - - var breakpointOrVariant = getBestMatchingBreakpoint(selectVariantByPositionColumn ? position.getOffset() : 0, - Stream.concat( - types.stream().flatMap(t -> breakpointManager.findBreakpointsAtLine(t, file, line).stream()), - variants.stream()).iterator(), - o -> - o instanceof XLineBreakpoint b - ? b.getType().getHighlightRange(b) - : ((XLineBreakpointType.XLineBreakpointVariant)o).getHighlightRange()); - - if (breakpointOrVariant instanceof XLineBreakpoint existingBreakpoint) { - if (!temporary && canRemove) { - removeBreakpointWithConfirmation(project, existingBreakpoint); - } + if (variants.isEmpty()) { + LOG.error("Unexpected empty variants"); return null; } - if (breakpointOrVariant instanceof XLineBreakpointType.XLineBreakpointVariant variant) { - return addLineBreakpoint(breakpointManager, variant, file, line, temporary); + var breakpoints = types.stream().flatMap(t -> breakpointManager.findBreakpointsAtLine(t, file, line).stream()).toList(); + + XLineBreakpointType.XLineBreakpointVariant variant; + if (selectVariantByPositionColumn) { + var breakpointOrVariant = getBestMatchingBreakpoint(position.getOffset(), + Stream.concat(breakpoints.stream(), variants.stream()).iterator(), + o -> + o instanceof XLineBreakpoint b + ? b.getType().getHighlightRange(b) + : ((XLineBreakpointType.XLineBreakpointVariant)o).getHighlightRange()); + + if (breakpointOrVariant instanceof XLineBreakpoint existingBreakpoint) { + if (!temporary && canRemove) { + removeBreakpointWithConfirmation(project, existingBreakpoint); + } + return null; + } + + variant = (XLineBreakpointType.XLineBreakpointVariant)breakpointOrVariant; + } + else { + if (!breakpoints.isEmpty()) { + if (!temporary && canRemove) { + removeBreakpointsWithConfirmation(project, breakpoints); + } + return null; + } + + variant = variants.stream().max(Comparator.comparing(v -> v.getPriority(project))).get(); } - assert !variants.isEmpty(); - LOG.error("Unexpected breakpoint toggle state, any variant would be considered as the best one"); - return null; + return addLineBreakpoint(breakpointManager, variant, file, line, temporary); }); } @@ -503,6 +516,21 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { return removeBreakpointWithConfirmation(breakpoint.getProject(), breakpoint); } + public static > void removeBreakpointsWithConfirmation(final Project project, final List breakpoints) { + // FIXME[inline-bp]: support multiple breakpoints restore + // FIXME[inline-bp]: Reconsider this, maybe we should have single confirmation for all breakpoints. + for (XBreakpoint b : breakpoints) { + removeBreakpointWithConfirmation(project, b); + } + } + + public static > void removeBreakpointsWithConfirmation(final List breakpoints) { + if (breakpoints.isEmpty()) return; + var project = breakpoints.get(0).getProject(); + LOG.assertTrue(ContainerUtil.and(breakpoints, b -> b.getProject().equals(project))); + removeBreakpointsWithConfirmation(project, breakpoints); + } + public static void reshowInlayRunToCursor(@NotNull AnActionEvent e) { if (!(e.getInputEvent() instanceof MouseEvent)) { return; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java index f5e5e2245381..29f3004d4a71 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointBase.java @@ -695,11 +695,7 @@ public class XBreakpointBase, P extends XBreakpointP } private void removeBreakpoints() { - for (var b : breakpoints) { - // FIXME[inline-bp]: support multiple breakpoints restore - // FIXME[inline-bp]: Reconsider this, maybe we should have single confirmation for all breakpoints. - XDebuggerUtilImpl.removeBreakpointWithConfirmation(b); - } + XDebuggerUtilImpl.removeBreakpointsWithConfirmation(breakpoints); } @Override