From 82964a08f564eefe97d2981fd4af9bcde50fea94 Mon Sep 17 00:00:00 2001 From: Vladimir Parfinenko Date: Wed, 20 Mar 2024 16:07:10 +0100 Subject: [PATCH] [debugger] differentiate source of breakpoint toggling, IDEA-349250 Differentiate toggling by gutter click (automagical selection of the best breakpoint variant) and by shortcut (selection of the nearest breakpoint by caret position). Toggling from gutter doesn't move the caret and tries to choose the best breakpoint variant (not yet chooses, but work in progress). Toggling by shortcut can move the caret and chooses the nearest breakpoint variant. GitOrigin-RevId: 8f4f68b5ed57155907f1f0dd2447a6813a84e4ca --- .../fixtures/CodeInsightTestFixture.java | 7 ++- .../fixtures/EditorTestFixture.java | 7 ++- .../impl/CodeInsightTestFixtureImpl.java | 4 +- .../impl/XDebuggerLineChangeHandler.kt | 2 +- .../xdebugger/impl/XDebuggerUtilImpl.java | 32 ++++++++---- .../handlers/AddLineBreakpointAction.java | 2 +- .../XToggleLineBreakpointActionHandler.java | 1 + .../impl/breakpoints/XBreakpointUtil.java | 52 ++++++++++++++----- .../lesson/general/run/CommonDebugLesson.kt | 2 +- .../NewProjectOnboardingTipsImpl.kt | 2 +- 10 files changed, 81 insertions(+), 30 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java index cddec39ffbf0..684118a49ebc 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java @@ -19,6 +19,7 @@ import com.intellij.modcommand.ActionContext; import com.intellij.model.psi.PsiSymbolReference; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -618,7 +619,11 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { void type(@NotNull String s); - void performEditorAction(@NotNull String actionId); + default void performEditorAction(@NotNull String actionId) { + performEditorAction(actionId, null); + } + + void performEditorAction(@NotNull String actionId, @Nullable AnActionEvent actionEvent); /** * If the action is visible and enabled, perform it. diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/EditorTestFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/EditorTestFixture.java index 3fe87b76cc66..749266368a19 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/EditorTestFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/EditorTestFixture.java @@ -126,11 +126,14 @@ public class EditorTestFixture { } public boolean performEditorAction(@NotNull String actionId) { - DataContext dataContext = getEditorDataContext(); + return performEditorAction(actionId, null); + } + public boolean performEditorAction(@NotNull String actionId, @Nullable AnActionEvent actionEvent) { ActionManagerEx managerEx = ActionManagerEx.getInstanceEx(); AnAction action = managerEx.getAction(actionId); - AnActionEvent event = new AnActionEvent(null, dataContext, ActionPlaces.UNKNOWN, new Presentation(), managerEx, 0); + AnActionEvent event = actionEvent != null ? actionEvent + : new AnActionEvent(null, getEditorDataContext(), ActionPlaces.UNKNOWN, new Presentation(), managerEx, 0); PerformWithDocumentsCommitted.commitDocumentsIfNeeded(action, event); ActionUtil.performDumbAwareUpdate(action, event, false); if (event.getPresentation().isEnabled()) { diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 5f0a1d5f3010..c50f0dc37cd3 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -994,9 +994,9 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig } @Override - public void performEditorAction(@NotNull String actionId) { + public void performEditorAction(@NotNull String actionId, @Nullable AnActionEvent actionEvent) { assertInitialized(); - EdtTestUtil.runInEdtAndWait(() -> myEditorTestFixture.performEditorAction(actionId)); + EdtTestUtil.runInEdtAndWait(() -> myEditorTestFixture.performEditorAction(actionId, actionEvent)); } @NotNull diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerLineChangeHandler.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerLineChangeHandler.kt index 13ef58b32898..6a0206e2b748 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerLineChangeHandler.kt +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerLineChangeHandler.kt @@ -61,7 +61,7 @@ open class XDebuggerLineChangeIconProvider(val project: Project) { open suspend fun getIcon(position: XSourcePositionImpl, editor: Editor): Icon? { return readAction { blockingContextToIndicator { - val types = XBreakpointUtil.getAvailableLineBreakpointTypes(project, position, editor) + val types = XBreakpointUtil.getAvailableLineBreakpointTypes(project, position, false, editor) types.firstOrNull()?.enabledIcon } } 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 efa1872e9601..452dbcf4fa90 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerUtilImpl.java @@ -143,7 +143,7 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { final int line, final boolean temporary) { XSourcePositionImpl position = XSourcePositionImpl.create(file, line); - return toggleAndReturnLineBreakpoint(project, Collections.singletonList(type), position, temporary, null, true); + return toggleAndReturnLineBreakpoint(project, Collections.singletonList(type), position, false, temporary, null, true); } /** @@ -278,16 +278,30 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { return bestBreakpoint; } + /** + * @deprecated use {@link #toggleAndReturnLineBreakpoint(Project, List, XSourcePosition, boolean, boolean, Editor, boolean)} + */ + @Deprecated @NotNull public static Promise<@Nullable XLineBreakpoint> toggleAndReturnLineBreakpoint(@NotNull final Project project, - @NotNull List types, - @NotNull final XSourcePosition position, - final boolean temporary, - @Nullable final Editor editor, - boolean canRemove) { + @NotNull List types, + @NotNull final XSourcePosition position, + final boolean temporary, + @Nullable final Editor editor, + boolean canRemove) { + return toggleAndReturnLineBreakpoint(project, types, position, true, temporary, editor, canRemove); + } + + @NotNull + public static Promise<@Nullable XLineBreakpoint> toggleAndReturnLineBreakpoint(@NotNull final Project project, + @NotNull List types, + @NotNull final XSourcePosition position, + boolean selectVariantByPositionColumn, + final boolean temporary, + @Nullable final Editor editor, + boolean canRemove) { final VirtualFile file = position.getFile(); final int line = position.getLine(); - final int caretOffset = position.getOffset(); final XBreakpointManager breakpointManager = XDebuggerManager.getInstance(project).getBreakpointManager(); Promise> variantsAsync = getLineBreakpointVariants(project, types, position); @@ -295,7 +309,7 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { return variantsAsync.then(variantsWithAll -> { var variants = variantsWithAll.stream().filter(v -> !v.isMultiVariant()).toList(); - var breakpointOrVariant = getBestMatchingBreakpoint(caretOffset, + var breakpointOrVariant = getBestMatchingBreakpoint(selectVariantByPositionColumn ? position.getOffset() : 0, Stream.concat( types.stream().flatMap(t -> breakpointManager.findBreakpointsAtLine(t, file, line).stream()), variants.stream()).iterator(), @@ -381,7 +395,7 @@ public class XDebuggerUtilImpl extends XDebuggerUtil { } } - final int defaultIndex = getIndexOfBestMatchingInlineVariant(caretOffset, variants); + final int defaultIndex = getIndexOfBestMatchingInlineVariant(position.getOffset(), variants); final MySelectionListener selectionListener = new MySelectionListener(); BaseListPopupStep step = diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/AddLineBreakpointAction.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/AddLineBreakpointAction.java index f9459f8caa18..59a4edfd4978 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/AddLineBreakpointAction.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/AddLineBreakpointAction.java @@ -34,7 +34,7 @@ public class AddLineBreakpointAction extends DumbAwareAction { if (editor == null) return; XSourcePosition position = getLineBreakpointPosition(e); assert position != null; - XBreakpointUtil.toggleLineBreakpoint(project, position, editor, false, false, true) + XBreakpointUtil.toggleLineBreakpoint(project, position, false, editor, false, false, true) .onSuccess(bp -> { if (bp != null && isConditional()) { EditorGutterComponentEx gutter = (EditorGutterComponentEx)editor.getGutter(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XToggleLineBreakpointActionHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XToggleLineBreakpointActionHandler.java index 1214ba93d13b..030b52cff3f0 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XToggleLineBreakpointActionHandler.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XToggleLineBreakpointActionHandler.java @@ -73,6 +73,7 @@ public class XToggleLineBreakpointActionHandler extends DebuggerActionHandler { if (processedLines.add(position.getLine())) { XBreakpointUtil.toggleLineBreakpoint(project, position, + !isFromGutterClick, editor, isAltClick || myTemporary, !isFromGutterClick, diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointUtil.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointUtil.java index 0479ca4f5654..ea32b918bf93 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointUtil.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointUtil.java @@ -145,6 +145,24 @@ public final class XBreakpointUtil { return null; } + /** + * Toggle line breakpoint with editor support: + * - unfolds folded block on the line + * - if folded, checks if line breakpoints could be toggled inside folded text + * + * @deprecated use {@link #toggleLineBreakpoint(Project, XSourcePosition, boolean, Editor, boolean, boolean, boolean)} + */ + @Deprecated + @NotNull + public static Promise<@Nullable XLineBreakpoint> toggleLineBreakpoint(@NotNull Project project, + @NotNull XSourcePosition position, + @Nullable Editor editor, + boolean temporary, + boolean moveCaret, + boolean canRemove) { + return toggleLineBreakpoint(project, position, true, editor, temporary, moveCaret, canRemove); + } + /** * Toggle line breakpoint with editor support: * - unfolds folded block on the line @@ -152,23 +170,24 @@ public final class XBreakpointUtil { */ @NotNull public static Promise<@Nullable XLineBreakpoint> toggleLineBreakpoint(@NotNull Project project, - @NotNull XSourcePosition position, - @Nullable Editor editor, - boolean temporary, - boolean moveCaret, - boolean canRemove) { - Pair, Integer> info = getAvailableLineBreakpointInfo(project, position, editor); + @NotNull XSourcePosition position, + boolean selectVariantByPositionColumn, + @Nullable Editor editor, + boolean temporary, + boolean moveCaret, + boolean canRemove) { + Pair, Integer> info = getAvailableLineBreakpointInfo(project, position, selectVariantByPositionColumn, editor); List typeWinner = info.first; int lineWinner = info.second; - int lineStart = position.getLine(); if (typeWinner.isEmpty()) { return rejectedPromise(new RuntimeException("Cannot find appropriate type")); } + int lineStart = position.getLine(); XSourcePosition winPosition = (lineStart == lineWinner) ? position : XSourcePositionImpl.create(position.getFile(), lineWinner); Promise res = - XDebuggerUtilImpl.toggleAndReturnLineBreakpoint(project, typeWinner, winPosition, temporary, editor, canRemove); + XDebuggerUtilImpl.toggleAndReturnLineBreakpoint(project, typeWinner, winPosition, selectVariantByPositionColumn, temporary, editor, canRemove); if (editor != null && lineStart != lineWinner) { int offset = editor.getDocument().getLineStartOffset(lineWinner); @@ -181,13 +200,21 @@ public final class XBreakpointUtil { } public static List getAvailableLineBreakpointTypes(@NotNull Project project, - @NotNull XSourcePosition position, + @NotNull XSourcePosition linePosition, @Nullable Editor editor) { - return getAvailableLineBreakpointInfo(project, position, editor).first; + return getAvailableLineBreakpointTypes(project, linePosition, false, editor); + } + + public static List getAvailableLineBreakpointTypes(@NotNull Project project, + @NotNull XSourcePosition position, + boolean selectTypeByPositionColumn, + @Nullable Editor editor) { + return getAvailableLineBreakpointInfo(project, position, selectTypeByPositionColumn, editor).first; } private static Pair, Integer> getAvailableLineBreakpointInfo(@NotNull Project project, @NotNull XSourcePosition position, + boolean selectTypeByPositionColumn, @Nullable Editor editor) { int lineStart = position.getLine(); VirtualFile file = position.getFile(); @@ -196,9 +223,10 @@ public final class XBreakpointUtil { return Pair.create(Collections.emptyList(), -1); } - // for folded text check each line and find out type with the biggest priority + // for folded text check each line and find out type with the biggest priority, + // do it unless we were asked to select type strictly by caret position int linesEnd = lineStart; - if (editor != null) { + if (editor != null && !selectTypeByPositionColumn) { FoldRegion region = FoldingUtil.findFoldRegionStartingAtLine(editor, lineStart); if (region != null && !region.isExpanded()) { linesEnd = region.getDocument().getLineNumber(region.getEndOffset()); diff --git a/plugins/ide-features-trainer/src/training/learn/lesson/general/run/CommonDebugLesson.kt b/plugins/ide-features-trainer/src/training/learn/lesson/general/run/CommonDebugLesson.kt index 88d56d636aea..68180cdac8ac 100644 --- a/plugins/ide-features-trainer/src/training/learn/lesson/general/run/CommonDebugLesson.kt +++ b/plugins/ide-features-trainer/src/training/learn/lesson/general/run/CommonDebugLesson.kt @@ -341,7 +341,7 @@ abstract class CommonDebugLesson(id: String) : KLesson(id, LessonsBundle.message val line = logicalPosition.line val createPosition = XDebuggerUtil.getInstance().createPosition(virtualFile, line) ?: error("Can't create source position: $line at $virtualFile") - XBreakpointUtil.toggleLineBreakpoint(project, createPosition, editor, false, false, true) + XBreakpointUtil.toggleLineBreakpoint(project, createPosition, false, editor, false, false, true) //breakpointManager.addLineBreakpoint() } } diff --git a/plugins/ide-features-trainer/src/training/onboarding/NewProjectOnboardingTipsImpl.kt b/plugins/ide-features-trainer/src/training/onboarding/NewProjectOnboardingTipsImpl.kt index b0f95fb3f7ab..6bfea8d54a79 100644 --- a/plugins/ide-features-trainer/src/training/onboarding/NewProjectOnboardingTipsImpl.kt +++ b/plugins/ide-features-trainer/src/training/onboarding/NewProjectOnboardingTipsImpl.kt @@ -82,7 +82,7 @@ private fun installTipsInFirstEditor(editor: Editor, project: Project, info: Onb if (offset != null) { val position = XDebuggerUtil.getInstance().createPositionByOffset(file, offset) ?: return - XBreakpointUtil.toggleLineBreakpoint(project, position, editor, false, false, true) + XBreakpointUtil.toggleLineBreakpoint(project, position, true, editor, false, false, true) } val pathToRunningFile = file.path