[debugger] engine to choose breakpoint variant by priority, IDEA-349250

Toggling breakpoint via gutter now chooses a breakpoint variant by its priority,
which can be customized by overriding `getPriority()` method.

Also now all existing breakpoints are removed on click at empty gutter area.

GitOrigin-RevId: b70d1a0add18f7dd247071952351b1bd960a75a6
This commit is contained in:
Vladimir Parfinenko
2024-03-28 15:13:23 +00:00
committed by intellij-monorepo-bot
parent 8c37123021
commit 4cc512584b
3 changed files with 56 additions and 24 deletions
@@ -222,6 +222,14 @@ public abstract class XLineBreakpointType<P extends XBreakpointProperties> 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")
@@ -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 <B extends XBreakpoint<?>> void removeBreakpointsWithConfirmation(final Project project, final List<B> 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 <B extends XBreakpointBase<?, ?, ?>> void removeBreakpointsWithConfirmation(final List<B> 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;
@@ -695,11 +695,7 @@ public class XBreakpointBase<Self extends XBreakpoint<P>, 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