From b312ae476fa1da39eb1c0a96c9020fd14510d4ab Mon Sep 17 00:00:00 2001 From: Alexey Merkulov Date: Fri, 1 Sep 2023 20:07:19 +0200 Subject: [PATCH] IDEA-305434 Refactoring: Extract inlay Run-To-Cursor logic from XDebuggerManagerImpl GitOrigin-RevId: d7fa5a223a73f0b9c8f69f47ea142945f466d158 --- .../impl/InlayRunToCursorEditorListener.kt | 161 +++++++++++++++ .../xdebugger/impl/XDebuggerManagerImpl.java | 188 +----------------- 2 files changed, 170 insertions(+), 179 deletions(-) create mode 100644 platform/xdebugger-impl/src/com/intellij/xdebugger/impl/InlayRunToCursorEditorListener.kt diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/InlayRunToCursorEditorListener.kt b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/InlayRunToCursorEditorListener.kt new file mode 100644 index 000000000000..5d10672b5d52 --- /dev/null +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/InlayRunToCursorEditorListener.kt @@ -0,0 +1,161 @@ +// 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 + +import com.intellij.codeInsight.daemon.impl.IntentionsUIImpl +import com.intellij.codeInsight.hint.HintManager +import com.intellij.codeInsight.hint.HintManagerImpl +import com.intellij.codeInsight.hint.PriorityQuestionAction +import com.intellij.codeInsight.hint.QuestionAction +import com.intellij.openapi.actionSystem.* +import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl +import com.intellij.openapi.actionSystem.impl.ToolbarUtils.createImmediatelyUpdatedToolbar +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.EditorKind +import com.intellij.openapi.editor.LogicalPosition +import com.intellij.openapi.editor.event.EditorMouseEvent +import com.intellij.openapi.editor.event.EditorMouseListener +import com.intellij.openapi.editor.event.EditorMouseMotionListener +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.registry.Registry +import com.intellij.ui.HintHint +import com.intellij.ui.LightweightHint +import com.intellij.ui.components.panels.NonOpaquePanel +import com.intellij.util.ui.JBDimension +import com.intellij.util.ui.JBUI +import com.intellij.xdebugger.XDebuggerManager +import com.intellij.xdebugger.impl.actions.XDebuggerActions +import java.awt.Point +import java.lang.ref.WeakReference +import javax.swing.JComponent +import javax.swing.JPanel +import javax.swing.SwingUtilities + +internal class InlayRunToCursorEditorListener(private val project: Project) : EditorMouseMotionListener, EditorMouseListener { + private var currentHint = WeakReference(null) + private var currentEditor = WeakReference(null) + private var currentLineNumber = -1 + + override fun mouseMoved(e: EditorMouseEvent) { + if (!Registry.`is`("debugger.inlayRunToCursor")) { + IntentionsUIImpl.DISABLE_INTENTION_BULB[project] = false + return + } + val wasShown = showInlayRunToCursor(e) + if (!wasShown) { + hideHint() + } + } + + private fun reset(hint: RunToCursorHint) { + if (hint != currentHint.get()) { + return + } + currentHint.clear() + currentEditor = WeakReference(null) + currentLineNumber = -1 + } + + private fun hideHint() { + val hint = currentHint.get() + hint?.hide() + } + + private fun showInlayRunToCursor(e: EditorMouseEvent): Boolean { + val editor = e.editor + if (editor.getEditorKind() != EditorKind.MAIN_EDITOR) { + return false + } + if (editor.getScrollingModel().getHorizontalScrollOffset() != 0) { + return false + } + val session = XDebuggerManager.getInstance(project).getCurrentSession() as XDebugSessionImpl? + if (session == null || !session.isPaused || session.isReadOnly) { + IntentionsUIImpl.DISABLE_INTENTION_BULB[project] = false + return false + } + IntentionsUIImpl.DISABLE_INTENTION_BULB[project] = true + val lineNumber = XDebuggerManagerImpl.getLineNumber(e) + if (lineNumber < 0) { + return false + } + if (currentEditor.get() === editor && currentLineNumber == lineNumber) { + return true + } + currentEditor = WeakReference(editor) + currentLineNumber = lineNumber + var firstNonSpaceSymbol = editor.getDocument().getLineStartOffset(lineNumber) + val charsSequence = editor.getDocument().charsSequence + while (true) { + if (firstNonSpaceSymbol >= charsSequence.length) { + return false //end of file + } + val c = charsSequence[firstNonSpaceSymbol] + if (c == '\n') { + return false // empty line + } + if (!Character.isWhitespace(c)) { + break + } + firstNonSpaceSymbol++ + } + val firstNonSpacePos = editor.offsetToXY(firstNonSpaceSymbol) + if (firstNonSpacePos.x < JBUI.scale(16)) { + return false + } + val lineY = editor.logicalPositionToXY(LogicalPosition(lineNumber, 0)).y + val position = SwingUtilities.convertPoint(editor.getContentComponent(), Point(-JBUI.scale(6), lineY), + editor.getComponent().rootPane.layeredPane) + val group = DefaultActionGroup() + val pausePosition = session.currentPosition + if (pausePosition != null && pausePosition.getFile() == editor.virtualFile && pausePosition.getLine() == lineNumber) { + group.add(ActionManager.getInstance().getAction(XDebuggerActions.RESUME)) + } + else { + group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_RUN_TO_CURSOR)) + } + val caretLine = editor.getCaretModel().logicalPosition.line + if (editor.getSettings().isShowIntentionBulb() && caretLine == lineNumber && firstNonSpacePos.x >= JBUI.scale(4 + 22 * 2)) { + group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_SHOW_INTENTION_ACTIONS)) + } + val toolbarImpl = createImmediatelyUpdatedToolbar(group, ActionPlaces.EDITOR_HINT, editor.getComponent(), true) {} as ActionToolbarImpl + toolbarImpl.setLayoutPolicy(ActionToolbar.NOWRAP_LAYOUT_POLICY) + val sideButtonOffset = 2 + toolbarImpl.setActionButtonBorder(JBUI.Borders.empty(0, sideButtonOffset)) + toolbarImpl.setBorder(null) + toolbarImpl.setOpaque(false) + toolbarImpl.setAdditionalDataProvider { dataId: String? -> + if (XDebuggerUtilImpl.LINE_NUMBER.`is`(dataId)) { + return@setAdditionalDataProvider lineNumber + } + null + } + val justPanel: JPanel = NonOpaquePanel() + justPanel.preferredSize = JBDimension((2 * sideButtonOffset + 22) * group.childrenCount, 22) + justPanel.add(toolbarImpl.component) + val hint = RunToCursorHint(justPanel, this) + currentHint = WeakReference(hint) + val questionAction: QuestionAction = object : PriorityQuestionAction { + override fun execute(): Boolean { + return true + } + + override fun getPriority(): Int { + return PriorityQuestionAction.INTENTION_BULB_PRIORITY + } + } + val offset = editor.getCaretModel().offset + HintManagerImpl.getInstanceImpl().showQuestionHint(editor, position, offset, offset, hint, questionAction, HintManager.RIGHT) + return true + } + + private class RunToCursorHint(component: JComponent, private val listener: InlayRunToCursorEditorListener) : LightweightHint(component) { + override fun show(parentComponent: JComponent, x: Int, y: Int, focusBackComponent: JComponent, hintHint: HintHint) { + super.show(parentComponent, x, y, focusBackComponent, HintHint(parentComponent, Point(x, y))) + } + + override fun hide(ok: Boolean) { + listener.reset(this) + super.hide(ok) + } + } +} diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java index 26ef5e62b62a..b1331769a065 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java @@ -2,8 +2,9 @@ package com.intellij.xdebugger.impl; import com.intellij.AppTopics; -import com.intellij.codeInsight.daemon.impl.IntentionsUIImpl; -import com.intellij.codeInsight.hint.*; +import com.intellij.codeInsight.hint.LineTooltipRenderer; +import com.intellij.codeInsight.hint.TooltipController; +import com.intellij.codeInsight.hint.TooltipGroup; import com.intellij.execution.ExecutionException; import com.intellij.execution.Executor; import com.intellij.execution.executors.DefaultDebugExecutor; @@ -23,8 +24,6 @@ import com.intellij.notification.NotificationGroupManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionUtil; -import com.intellij.openapi.actionSystem.impl.ActionToolbarImpl; -import com.intellij.openapi.actionSystem.impl.ToolbarUtils; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.State; @@ -46,15 +45,14 @@ import com.intellij.openapi.wm.IdeGlassPaneUtil; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.ui.ExperimentalUI; import com.intellij.ui.HintHint; -import com.intellij.ui.LightweightHint; import com.intellij.ui.awt.RelativePoint; -import com.intellij.ui.components.panels.NonOpaquePanel; import com.intellij.util.DocumentUtil; import com.intellij.util.messages.MessageBusConnection; -import com.intellij.util.ui.JBDimension; -import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; -import com.intellij.xdebugger.*; +import com.intellij.xdebugger.XDebugProcess; +import com.intellij.xdebugger.XDebugProcessStarter; +import com.intellij.xdebugger.XDebugSession; +import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.XBreakpointListener; import com.intellij.xdebugger.impl.actions.XDebuggerActions; @@ -75,7 +73,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; -import java.lang.ref.WeakReference; import java.util.List; import java.util.*; import java.util.concurrent.atomic.AtomicReference; @@ -182,7 +179,7 @@ public final class XDebuggerManagerImpl extends XDebuggerManager implements Pers eventMulticaster.addEditorMouseListener(listener, this); eventMulticaster.addEditorMouseMotionListener(bpPromoter, this); if (ExperimentalUI.isNewUI()) { - InlayRunToCursorEditorListener newRunToCursorListener = new InlayRunToCursorEditorListener(); + InlayRunToCursorEditorListener newRunToCursorListener = new InlayRunToCursorEditorListener(myProject); eventMulticaster.addEditorMouseMotionListener(newRunToCursorListener, this); eventMulticaster.addEditorMouseListener(newRunToCursorListener, this); } @@ -481,173 +478,6 @@ public final class XDebuggerManagerImpl extends XDebuggerManager implements Pers } } - private static final class RunToCursorHint extends LightweightHint { - private final InlayRunToCursorEditorListener listener; - RunToCursorHint(@NotNull JComponent component, InlayRunToCursorEditorListener listener) { - super(component); - this.listener = listener; - } - - @Override - public void show(@NotNull JComponent parentComponent, int x, int y, JComponent focusBackComponent, @NotNull HintHint hintHint) { - super.show(parentComponent, x, y, focusBackComponent, new HintHint(parentComponent, new Point(x, y))); - } - - @Override - public void hide(boolean ok) { - listener.reset(this); - super.hide(ok); - } - } - - private final class InlayRunToCursorEditorListener implements EditorMouseMotionListener, EditorMouseListener { - private WeakReference myCurrentHint = new WeakReference<>(null); - private WeakReference myEditor = new WeakReference<>(null); - private int myLineNumber = -1; - - @Override - public void mouseMoved(@NotNull EditorMouseEvent e) { - if (!Registry.is("debugger.inlayRunToCursor")) { - IntentionsUIImpl.DISABLE_INTENTION_BULB.set(myProject, false); - return; - } - boolean wasShown = showInlayRunToCursor(e); - if (!wasShown) { - hideHint(); - } - } - - void reset(@NotNull RunToCursorHint hint) { - if (hint != myCurrentHint.get()) { - return; - } - myCurrentHint.clear(); - myEditor = new WeakReference<>(null); - myLineNumber = -1; - } - - private void hideHint() { - RunToCursorHint hint = myCurrentHint.get(); - if (hint != null) { - hint.hide(); - } - } - - private boolean showInlayRunToCursor(@NotNull EditorMouseEvent e) { - Editor editor = e.getEditor(); - - if (editor.getEditorKind() != EditorKind.MAIN_EDITOR) { - return false; - } - - if (editor.getScrollingModel().getHorizontalScrollOffset() != 0) { - return false; - } - - XDebugSessionImpl session = getCurrentSession(); - if (session == null || !session.isPaused() || session.isReadOnly()) { - IntentionsUIImpl.DISABLE_INTENTION_BULB.set(myProject, false); - return false; - } - IntentionsUIImpl.DISABLE_INTENTION_BULB.set(myProject, true); - - int lineNumber = getLineNumber(e); - if (lineNumber < 0) { - return false; - } - - if (myEditor.get() == editor && myLineNumber == lineNumber) { - return true; - } - - myEditor = new WeakReference<>(editor); - myLineNumber = lineNumber; - - int firstNonSpaceSymbol = editor.getDocument().getLineStartOffset(lineNumber); - CharSequence charsSequence = editor.getDocument().getCharsSequence(); - - while (true) { - if (firstNonSpaceSymbol >= charsSequence.length()) { - return false; //end of file - } - char c = charsSequence.charAt(firstNonSpaceSymbol); - if (c == '\n') { - return false; // empty line - } - if (!Character.isWhitespace(c)) { - break; - } - firstNonSpaceSymbol++; - } - - Point firstNonSpacePos = editor.offsetToXY(firstNonSpaceSymbol); - - if (firstNonSpacePos.x < JBUI.scale(16)) { - return false; - } - - int lineY = editor.logicalPositionToXY(new LogicalPosition(lineNumber, 0)).y; - - Point position = SwingUtilities.convertPoint(editor.getContentComponent(), new Point(-JBUI.scale(6), lineY), - editor.getComponent().getRootPane().getLayeredPane()); - - DefaultActionGroup group = new DefaultActionGroup(); - - XSourcePosition pausePosition = session.getCurrentPosition(); - if (pausePosition != null && pausePosition.getFile().equals(editor.getVirtualFile()) && pausePosition.getLine() == lineNumber) { - group.add(ActionManager.getInstance().getAction(XDebuggerActions.RESUME)); - } - else { - group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_RUN_TO_CURSOR)); - } - - int caretLine = editor.getCaretModel().getLogicalPosition().line; - if (editor.getSettings().isShowIntentionBulb() && caretLine == lineNumber && firstNonSpacePos.x >= JBUI.scale(4 + 22*2)) { - group.add(ActionManager.getInstance().getAction(IdeActions.ACTION_SHOW_INTENTION_ACTIONS)); - } - - ActionToolbarImpl toolbarImpl = (ActionToolbarImpl)ToolbarUtils.INSTANCE.createImmediatelyUpdatedToolbar(group, ActionPlaces.EDITOR_HINT, editor.getComponent(), true, (t) -> Unit.INSTANCE); - toolbarImpl.setLayoutPolicy(ActionToolbar.NOWRAP_LAYOUT_POLICY); - - int sideButtonOffset = 2; - toolbarImpl.setActionButtonBorder(JBUI.Borders.empty(0, sideButtonOffset)); - toolbarImpl.setBorder(null); - toolbarImpl.setOpaque(false); - toolbarImpl.setAdditionalDataProvider((dataId) -> { - if (XDebuggerUtilImpl.LINE_NUMBER.is(dataId)) { - return lineNumber; - } - return null; - }); - - JPanel justPanel = new NonOpaquePanel(); - - justPanel.setPreferredSize(new JBDimension((2 * sideButtonOffset + 22) * group.getChildrenCount(),22)); - - justPanel.add(toolbarImpl.getComponent()); - - RunToCursorHint hint = new RunToCursorHint(justPanel, this); - - myCurrentHint = new WeakReference<>(hint); - - QuestionAction questionAction = new PriorityQuestionAction() { - @Override - public boolean execute() { - return true; - } - - @Override - public int getPriority() { - return INTENTION_BULB_PRIORITY; - } - }; - int offset = editor.getCaretModel().getOffset(); - - HintManagerImpl.getInstanceImpl().showQuestionHint(editor, position, offset, offset, hint, questionAction, HintManager.RIGHT); - return true; - } - } - private final class GutterUiRunToCursorEditorListener implements EditorMouseMotionListener, EditorMouseListener { RangeHighlighter myCurrentHighlighter; @@ -730,7 +560,7 @@ public final class XDebuggerManagerImpl extends XDebuggerManager implements Pers } } - private static int getLineNumber(@NotNull EditorMouseEvent event) { + static int getLineNumber(@NotNull EditorMouseEvent event) { Editor editor = event.getEditor(); if (event.getVisualPosition().line >= ((EditorImpl)editor).getVisibleLineCount()) { return -1;