IDEA-317835 Integrate debugging action into intention light bulb

Available via the registry key debugger.inlayRunToCursor.

GitOrigin-RevId: f1835b9e8a42fd42155454c261203bd1e6374f37
This commit is contained in:
Roland Illig
2023-04-13 17:01:22 +02:00
committed by intellij-monorepo-bot
parent edce672a36
commit d736cdd099
6 changed files with 67 additions and 6 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.daemon.impl;
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
@@ -165,6 +165,8 @@ public final class ShowIntentionsPass extends TextEditorHighlightingPass {
public final List<HighlightInfo.IntentionActionDescriptor> errorFixesToShow = ContainerUtil.createLockFreeCopyOnWriteList();
public final List<HighlightInfo.IntentionActionDescriptor> inspectionFixesToShow = ContainerUtil.createLockFreeCopyOnWriteList();
public final List<AnAction> guttersToShow = ContainerUtil.createLockFreeCopyOnWriteList();
@ApiStatus.Experimental
public final List<AnAction> topLevelActions = ContainerUtil.createLockFreeCopyOnWriteList();
public final List<HighlightInfo.IntentionActionDescriptor> notificationActionsToShow = ContainerUtil.createLockFreeCopyOnWriteList();
private int myOffset;
private HighlightInfoType myHighlightInfoType;
@@ -212,6 +214,7 @@ public final class ShowIntentionsPass extends TextEditorHighlightingPass {
errorFixesToShow.isEmpty() &&
inspectionFixesToShow.isEmpty() &&
guttersToShow.isEmpty() &&
topLevelActions.isEmpty() &&
notificationActionsToShow.isEmpty();
}

View File

@@ -29,6 +29,7 @@ import com.intellij.ui.ExperimentalUI;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.EmptyIcon;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -53,6 +54,7 @@ public final class CachedIntentions {
private final @NotNull Project myProject;
private final List<AnAction> myGuttersRaw = ContainerUtil.createLockFreeCopyOnWriteList();
private final Set<AnAction> myTopLevelActions = new CopyOnWriteArraySet<>();
public CachedIntentions(@NotNull Project project, @NotNull PsiFile file, @Nullable Editor editor) {
myProject = project;
@@ -76,6 +78,11 @@ public final class CachedIntentions {
return myGutters;
}
@ApiStatus.Experimental
public @NotNull Set<AnAction> getTopLevelActions() {
return myTopLevelActions;
}
public @NotNull Set<IntentionActionWithTextCaching> getNotifications() {
return myNotifications;
}
@@ -125,6 +132,7 @@ public final class CachedIntentions {
changed |= wrapActionsTo(newInfo.inspectionFixesToShow, myInspectionFixes, callUpdate);
changed |= wrapActionsTo(newInfo.intentionsToShow, myIntentions, callUpdate);
changed |= updateGuttersRaw(newInfo);
changed |= myTopLevelActions.addAll(newInfo.topLevelActions);
changed |= wrapActionsTo(newInfo.notificationActionsToShow, myNotifications, callUpdate);
return changed;
}
@@ -140,6 +148,7 @@ public final class CachedIntentions {
changed |= addActionsTo(info.inspectionFixesToShow, myInspectionFixes);
changed |= addActionsTo(info.intentionsToShow, myIntentions);
changed |= updateGuttersRaw(info);
changed |= myTopLevelActions.addAll(info.topLevelActions);
changed |= addActionsTo(info.notificationActionsToShow, myNotifications);
return changed;
}
@@ -379,6 +388,7 @@ public final class CachedIntentions {
", myErrorFixes=" + myErrorFixes +
", myInspectionFixes=" + myInspectionFixes +
", myGutters=" + myGutters +
", myTopLevelActions=" + myTopLevelActions +
", myNotifications=" + myNotifications +
'}';
}

View File

@@ -69,6 +69,7 @@ import java.awt.event.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
/**
@@ -106,7 +107,8 @@ public final class IntentionHintComponent implements Disposable, ScrollAwareHint
myPopup = new IntentionPopup(project, file, editor, cachedIntentions);
Disposer.register(this, myPopup);
myLightBulbPanel = new LightBulbPanel(project, file, editor, LightBulbUtil.getIcon(cachedIntentions));
myLightBulbPanel =
new LightBulbPanel(project, file, editor, LightBulbUtil.getIcon(cachedIntentions), cachedIntentions.getTopLevelActions());
myComponentHint = new MyComponentHint(myLightBulbPanel);
EditorUtil.disposeWithEditor(myEditor, this);
@@ -423,19 +425,37 @@ public final class IntentionHintComponent implements Disposable, ScrollAwareHint
private final RowIcon myInactiveIcon;
private final JLabel myIconLabel;
LightBulbPanel(@NotNull Project project, @NotNull PsiFile file, @NotNull Editor editor, @NotNull Icon smartTagIcon) {
LightBulbPanel(@NotNull Project project,
@NotNull PsiFile file,
@NotNull Editor editor,
@NotNull Icon smartTagIcon,
@NotNull Set<AnAction> topLevelActions) {
setLayout(new BorderLayout());
setOpaque(false);
IconManager iconManager = IconManager.getInstance();
myHighlightedIcon = iconManager.createRowIcon(smartTagIcon, AllIcons.General.ArrowDown);
myInactiveIcon = iconManager.createRowIcon(smartTagIcon, ourInactiveArrowIcon);
if (!topLevelActions.isEmpty()) {
Icon icon = topLevelActions.iterator().next().getTemplatePresentation().getIcon();
myHighlightedIcon = iconManager.createRowIcon(icon, smartTagIcon, AllIcons.General.ArrowDown);
myInactiveIcon = iconManager.createRowIcon(icon, smartTagIcon, ourInactiveArrowIcon);
}
else {
myHighlightedIcon = iconManager.createRowIcon(smartTagIcon, AllIcons.General.ArrowDown);
myInactiveIcon = iconManager.createRowIcon(smartTagIcon, ourInactiveArrowIcon);
}
myIconLabel = new JLabel(myInactiveIcon);
myIconLabel.setOpaque(false);
myIconLabel.addMouseListener(new LightBulbMouseListener(project, file));
add(myIconLabel, BorderLayout.CENTER);
if (Registry.is("debugger.inlayRunToCursor")) {
DefaultActionGroup actions = new DefaultActionGroup(List.copyOf(topLevelActions));
ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar("Any", actions, true);
add(toolbar.getComponent(), BorderLayout.CENTER);
}
else {
add(myIconLabel, BorderLayout.CENTER);
}
setBorder(LightBulbUtil.createInactiveBorder(editor));
}

View File

@@ -595,6 +595,8 @@ debugger.preload.event.info=true
debugger.sync.commands.reschedule.delay=50
debugger.attach.dialog.enabled=false
debugger.attach.dialog.enabled.description=Show new "Attach to Process" dialog instead of popup
debugger.inlayRunToCursor=false
debugger.inlayRunToCursor.description=While debugging, show a toolbar in the editor for caret-related actions
execution.java.always.debug=false
execution.java.always.debug.description=Always run java processes with the debug agent

View File

@@ -46,6 +46,8 @@
<customizableActionGroupProvider implementation="com.intellij.xdebugger.impl.ui.XDebugTabCustomizableActionGroupProvider"/>
<intentionMenuContributor implementation="com.intellij.xdebugger.impl.ui.DebuggerIntentionMenuContributor"/>
<xdebugger.debuggerSupport implementation="com.intellij.xdebugger.impl.XDebuggerSupport" order="first" id="XDebuggerSupport"/>
<xdebugger.breakpointGroupingRule implementation="com.intellij.xdebugger.impl.breakpoints.ui.grouping.XBreakpointGroupingByTypeRule"/>

View File

@@ -0,0 +1,24 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.xdebugger.impl.ui
import com.intellij.codeInsight.daemon.impl.IntentionMenuContributor
import com.intellij.codeInsight.daemon.impl.ShowIntentionsPass.IntentionsInfo
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.PsiFile
import com.intellij.xdebugger.XDebuggerManager
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Experimental
class DebuggerIntentionMenuContributor : IntentionMenuContributor {
override fun collectActions(hostEditor: Editor,
hostFile: PsiFile,
intentions: IntentionsInfo,
passIdToShowIntentionsFor: Int,
offset: Int) {
if (Registry.`is`("debugger.inlayRunToCursor") && XDebuggerManager.getInstance(hostFile.project).currentSession != null) {
intentions.topLevelActions.add(ActionManager.getInstance().getAction("RunToCursor"))
}
}
}