mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 22:51:17 +07:00
[IFT] Add suggester heuristics for quick evaluation promotion
IJPL-159194 GitOrigin-RevId: ad83113d67ed9f6cd0f6f9d5d8f863c9e7a9752b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
6a1837c790
commit
4d8776250f
@@ -2579,6 +2579,7 @@ f:com.intellij.openapi.keymap.KeymapUtil
|
||||
- s:getKeyText(I):java.lang.String
|
||||
- s:getKeystrokeText(javax.swing.KeyStroke):java.lang.String
|
||||
- s:getMnemonicAsShortcut(I):com.intellij.openapi.actionSystem.CustomShortcutSet
|
||||
- s:getModifiersText(I):java.lang.String
|
||||
- s:getMouseShortcutString(com.intellij.openapi.actionSystem.MouseShortcut):java.lang.String
|
||||
- s:getMouseShortcutText(com.intellij.openapi.actionSystem.MouseShortcut):java.lang.String
|
||||
- s:getPreferredShortcutText(com.intellij.openapi.actionSystem.Shortcut[]):java.lang.String
|
||||
|
||||
@@ -90,11 +90,11 @@ public class KeymapTextContext {
|
||||
else {
|
||||
throw new IllegalStateException("unknown clickCount: " + clickCount);
|
||||
}
|
||||
return KeyMapBundle.message(resource, getModifiersText(mapNewModifiers(modifiers)), button);
|
||||
return KeyMapBundle.message(resource, getModifiersText(mapNewModifiers(modifiers), true), button);
|
||||
}
|
||||
|
||||
@JdkConstants.InputEventMask
|
||||
private static int mapNewModifiers(@JdkConstants.InputEventMask int modifiers) {
|
||||
static int mapNewModifiers(@JdkConstants.InputEventMask int modifiers) {
|
||||
if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0) {
|
||||
modifiers |= InputEvent.SHIFT_MASK;
|
||||
}
|
||||
@@ -122,7 +122,7 @@ public class KeymapTextContext {
|
||||
String acceleratorText = "";
|
||||
int modifiers = accelerator.getModifiers();
|
||||
if (modifiers > 0) {
|
||||
acceleratorText = getModifiersText(modifiers);
|
||||
acceleratorText = getModifiersText(modifiers, true);
|
||||
}
|
||||
|
||||
int code = accelerator.getKeyCode();
|
||||
@@ -158,7 +158,7 @@ public class KeymapTextContext {
|
||||
return ClientSystemInfo.isMac() && AdvancedSettings.getInstanceIfCreated() != null && AdvancedSettings.getBoolean("ide.macos.disable.native.shortcut.symbols");
|
||||
}
|
||||
|
||||
private @NotNull String getModifiersText(@JdkConstants.InputEventMask int modifiers) {
|
||||
@NotNull String getModifiersText(@JdkConstants.InputEventMask int modifiers, boolean addPlus) {
|
||||
if (isNativeMacShortcuts()) {
|
||||
//try {
|
||||
// Class appleLaf = Class.forName(APPLE_LAF_AQUA_LOOK_AND_FEEL_CLASS_NAME);
|
||||
@@ -178,7 +178,7 @@ public class KeymapTextContext {
|
||||
final String keyModifiersText = isSimplifiedMacShortcuts() ? getSimplifiedMacKeyModifiersText(modifiers)
|
||||
: KeyEvent.getKeyModifiersText(modifiers);
|
||||
|
||||
return keyModifiersText.isEmpty() ? keyModifiersText : keyModifiersText + "+";
|
||||
return !keyModifiersText.isEmpty() && addPlus ? keyModifiersText + "+" : keyModifiersText;
|
||||
}
|
||||
|
||||
private static String getSimplifiedMacKeyModifiersText(int modifiers) {
|
||||
|
||||
@@ -53,7 +53,7 @@ public final class KeymapUtil {
|
||||
return ourDefaultKeymapTextContext.getShortcutText(shortcut);
|
||||
}
|
||||
|
||||
public static @NotNull String getMouseShortcutText(@NotNull MouseShortcut shortcut) {
|
||||
public static @NotNull @NlsSafe String getMouseShortcutText(@NotNull MouseShortcut shortcut) {
|
||||
return ourDefaultKeymapTextContext.getMouseShortcutText(shortcut);
|
||||
}
|
||||
|
||||
@@ -287,6 +287,10 @@ public final class KeymapUtil {
|
||||
return toolTipText;
|
||||
}
|
||||
|
||||
public static String getModifiersText(@JdkConstants.InputEventMask int modifiers) {
|
||||
return ourDefaultKeymapTextContext.getModifiersText(KeymapTextContext.mapNewModifiers(modifiers), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that one of the mouse shortcuts assigned to the provided action has the same modifiers as provided
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.xdebugger
|
||||
|
||||
import com.intellij.util.messages.Topic
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
interface XEvaluationListener {
|
||||
companion object {
|
||||
@Topic.AppLevel
|
||||
@JvmField
|
||||
val TOPIC: Topic<XEvaluationListener> = Topic(XEvaluationListener::class.java, Topic.BroadcastDirection.NONE)
|
||||
}
|
||||
|
||||
fun inlineEvaluatorInvoked(session: XDebugSession, expression: XExpression) { }
|
||||
}
|
||||
@@ -34,10 +34,7 @@ import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import com.intellij.xdebugger.XDebugSession;
|
||||
import com.intellij.xdebugger.XDebuggerBundle;
|
||||
import com.intellij.xdebugger.XDebuggerManager;
|
||||
import com.intellij.xdebugger.XExpression;
|
||||
import com.intellij.xdebugger.*;
|
||||
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
|
||||
import com.intellij.xdebugger.frame.XStackFrame;
|
||||
import com.intellij.xdebugger.impl.XDebugSessionImpl;
|
||||
@@ -296,6 +293,13 @@ public class XWatchesViewImpl extends XVariablesView implements DnDNativeTarget,
|
||||
if (!XDebuggerUtilImpl.isEmptyExpression(expression)) {
|
||||
myEvaluateComboBox.saveTextInHistory();
|
||||
XDebugSession session = getSession(getTree());
|
||||
if (session != null) {
|
||||
ApplicationManager.getApplication().getMessageBus().syncPublisher(XEvaluationListener.TOPIC)
|
||||
.inlineEvaluatorInvoked(session, expression);
|
||||
}
|
||||
else {
|
||||
LOG.error("No session available while trying evaluate " + expression);
|
||||
}
|
||||
myRootNode.addResultNode(session != null ? session.getCurrentStackFrame() : null, expression);
|
||||
DebuggerEvaluationStatisticsCollector.INLINE_EVALUATE.log(getTree().getProject());
|
||||
}
|
||||
|
||||
@@ -167,6 +167,8 @@
|
||||
implementation="training.featuresSuggester.suggesters.IntroduceVariableSuggester"/>
|
||||
<ifs.suggester
|
||||
implementation="training.featuresSuggester.suggesters.CopyPasteSuggester"/>
|
||||
<ifs.suggester
|
||||
implementation="training.featuresSuggester.suggesters.QuickEvaluateSuggester"/>
|
||||
<ifs.suggester
|
||||
implementation="training.featuresSuggester.suggesters.SurroundWithSuggester"/>
|
||||
<ifs.suggester
|
||||
@@ -226,5 +228,7 @@
|
||||
<applicationListeners>
|
||||
<listener class="training.featuresSuggester.listeners.EditorActionsListener"
|
||||
topic="com.intellij.openapi.actionSystem.ex.AnActionListener"/>
|
||||
<listener class="training.featuresSuggester.listeners.EvaluationListener"
|
||||
topic="com.intellij.xdebugger.XEvaluationListener"/>
|
||||
</applicationListeners>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -17,6 +17,8 @@ completion.popup.name=Show the completion popup
|
||||
completion.popup.message=You can use a shortcut to call the completion popup.
|
||||
paste.from.history.name=Paste from history
|
||||
paste.from.history.message=You can preview the clipboard history.
|
||||
quick.evaluate.name=Quick Evaluate
|
||||
quick.evaluate.message=You can quickly evaluate an expression by holding {0} and clicking on it in the editor.
|
||||
edit.breakpoint.name=Edit a breakpoint
|
||||
edit.breakpoint.message=You can edit the breakpoint and make it conditional instead of waiting for the needed iteration. \
|
||||
Right-click the breakpoint.
|
||||
|
||||
@@ -3,6 +3,7 @@ package training.featuresSuggester.actions
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.xdebugger.XExpression
|
||||
import com.intellij.xdebugger.XSourcePosition
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpoint
|
||||
|
||||
@@ -54,6 +55,12 @@ data class BeforeDebugSessionResumedAction(
|
||||
override val timeMillis: Long
|
||||
) : DebugSessionAction()
|
||||
|
||||
data class InlineEvaluatorInvokedAction(
|
||||
override val project: Project,
|
||||
val expression: XExpression,
|
||||
override val timeMillis: Long
|
||||
) : DebugAction()
|
||||
|
||||
// -------------------------------------Breakpoint Actions--------------------------------------------------------------
|
||||
abstract class BreakpointAction : DebugAction() {
|
||||
abstract val breakpoint: XBreakpoint<*>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package training.featuresSuggester.listeners
|
||||
|
||||
import com.intellij.xdebugger.XDebugSession
|
||||
import com.intellij.xdebugger.XEvaluationListener
|
||||
import com.intellij.xdebugger.XExpression
|
||||
import training.featuresSuggester.SuggestingUtils.handleAction
|
||||
import training.featuresSuggester.actions.InlineEvaluatorInvokedAction
|
||||
|
||||
private class EvaluationListener : XEvaluationListener {
|
||||
override fun inlineEvaluatorInvoked(session: XDebugSession, expression: XExpression) {
|
||||
handleAction(session.project, InlineEvaluatorInvokedAction(session.project, expression, System.currentTimeMillis()))
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ abstract class AbstractFeatureSuggester : FeatureSuggester {
|
||||
}
|
||||
|
||||
@Nls
|
||||
fun getShortcutText(actionId: String): String {
|
||||
open fun getShortcutText(actionId: String): String {
|
||||
val shortcut = KeymapUtil.getShortcutText(actionId)
|
||||
return if (shortcut == "<no shortcut>") {
|
||||
FeatureSuggesterBundle.message("shortcut.not.found.message")
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package training.featuresSuggester.suggesters
|
||||
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.openapi.actionSystem.ActionManager
|
||||
import com.intellij.openapi.actionSystem.MouseShortcut
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.ide.CopyPasteManager
|
||||
import com.intellij.openapi.keymap.KeymapUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import training.featuresSuggester.FeatureSuggesterBundle
|
||||
import training.featuresSuggester.NoSuggestion
|
||||
import training.featuresSuggester.SuggestingUtils.asString
|
||||
import training.featuresSuggester.Suggestion
|
||||
import training.featuresSuggester.actions.Action
|
||||
import training.featuresSuggester.actions.EditorCopyAction
|
||||
import training.featuresSuggester.actions.InlineEvaluatorInvokedAction
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class QuickEvaluateSuggester : AbstractFeatureSuggester() {
|
||||
override val id: String = "QuickEvaluateSuggester"
|
||||
override val suggestingActionDisplayName: String = FeatureSuggesterBundle.message("quick.evaluate.name")
|
||||
|
||||
override val suggestingActionId = "QuickEvaluateExpression"
|
||||
override val suggestingDocUrl = "https://www.jetbrains.com/help/idea/examining-suspended-program.html#quick-evaluate"
|
||||
override val minSuggestingIntervalDays = 14
|
||||
|
||||
override val languages = listOf(Language.ANY.id)
|
||||
|
||||
private var lastCopyFromFile = WeakReference<VirtualFile>(null)
|
||||
private var lastCopiedText = ""
|
||||
|
||||
override fun isSuggestionNeeded(): Boolean {
|
||||
return super.isSuggestionNeeded() && getMouseShortcut() != null
|
||||
}
|
||||
|
||||
override val message: String get() {
|
||||
val modifiersText = getMouseShortcut()?.modifiers?.let { KeymapUtil.getModifiersText(it) } ?: ""
|
||||
return FeatureSuggesterBundle.message("quick.evaluate.message", modifiersText)
|
||||
}
|
||||
|
||||
override fun getSuggestion(action: Action): Suggestion {
|
||||
when (action) {
|
||||
is InlineEvaluatorInvokedAction -> {
|
||||
val clipboardContent = CopyPasteManager.getInstance().allContents.firstOrNull()?.asString()
|
||||
if (clipboardContent != lastCopiedText) return NoSuggestion
|
||||
if (action.expression.expression != lastCopiedText) return NoSuggestion
|
||||
val neededVirtualFile = lastCopyFromFile.get() ?: return NoSuggestion
|
||||
|
||||
val fileIsOpenedNow = FileEditorManager.getInstance(action.project).selectedEditors.map { it.file }.contains(neededVirtualFile)
|
||||
if (!fileIsOpenedNow) return NoSuggestion
|
||||
|
||||
return createSuggestion()
|
||||
}
|
||||
is EditorCopyAction -> {
|
||||
val virtualFile = action.editor.virtualFile ?: return NoSuggestion
|
||||
lastCopyFromFile = WeakReference<VirtualFile>(virtualFile)
|
||||
lastCopiedText = action.text
|
||||
}
|
||||
}
|
||||
return NoSuggestion
|
||||
}
|
||||
|
||||
override fun getShortcutText(actionId: String): String {
|
||||
getMouseShortcut()?.let {
|
||||
return KeymapUtil.getMouseShortcutText(it)
|
||||
}
|
||||
return super.getShortcutText(actionId)
|
||||
}
|
||||
|
||||
private fun getMouseShortcut() =
|
||||
ActionManager.getInstance().getAction(suggestingActionId)?.shortcutSet?.shortcuts?.filterIsInstance<MouseShortcut>()?.firstOrNull()
|
||||
}
|
||||
Reference in New Issue
Block a user