From 0d2dce03e4b72a90af3af843e333a55041f8fb24 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Fri, 12 Jul 2024 08:54:25 +0100 Subject: [PATCH] Show possible IDs based on the action's shortcuts Fixes VIM-3499 --- README.md | 6 ++-- doc/marketplace-plugin-example.md | 4 +-- .../idea/vim/group/NotificationService.kt | 31 +++++++++++++------ .../idea/vim/listener/IdeaSpecifics.kt | 21 ++++++++++++- .../messages/IdeaVimBundle.properties | 4 +-- 5 files changed, 48 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 214013c9a8..b2963169d9 100644 --- a/README.md +++ b/README.md @@ -222,13 +222,13 @@ Ex commands or via `:map` command mappings: * Execute an action by `{action_id}`. Works from Ex command line. * Please don't use `:action` in mappings. Use `` instead. -### Finding action ids: +### Finding action IDs: -* IJ provides `IdeaVim: track action Ids` command to show the id of the executed actions. +* IJ provides `IdeaVim: track action IDs` command to show the id of the executed actions. This command can be found in "Search everywhere" (double `shift`).
- "Track action Ids" Details (click to see) + "Track action IDs" Details (click to see) track action ids diff --git a/doc/marketplace-plugin-example.md b/doc/marketplace-plugin-example.md index 52b1ac42d9..7325f23e82 100644 --- a/doc/marketplace-plugin-example.md +++ b/doc/marketplace-plugin-example.md @@ -5,9 +5,9 @@ Using actions from external plugins is the same, as tracking and reusing any IDE 1. Install the plugin via Marketplace 2. Enable action tracking. You can enable it by one of the following ways: * Execute `:set trackactionids` ex command or just `:set tai` - * Open the "Find actions" window by pressing `Ctrl-Shift-A` and search for "Track Action Ids" to find the toggle that enables and disables action tracking + * Open the "Find actions" window by pressing `Ctrl-Shift-A` and search for "Track Action IDs" to find the toggle that enables and disables action tracking 3. Execute the plugin action the way intended by plugin author "See Edit menu or use ⇧ + ⌥ + U / Shift + Alt + U" or just find the `Toggle Camel Case` action in the "Find actions" window (`Ctrl-Shift-A`). If you action tracking is on, you will see this notification in your right bottom corner: Notification 4. Copy the action id from the notification to create the following mapping in your .ideavimrc -```map t (de.netnexus.CamelCasePlugin.ToggleCamelCase)``` \ No newline at end of file +```map t (de.netnexus.CamelCasePlugin.ToggleCamelCase)``` diff --git a/src/main/java/com/maddyhome/idea/vim/group/NotificationService.kt b/src/main/java/com/maddyhome/idea/vim/group/NotificationService.kt index 31c6fd4dfc..b9680d0ad4 100644 --- a/src/main/java/com/maddyhome/idea/vim/group/NotificationService.kt +++ b/src/main/java/com/maddyhome/idea/vim/group/NotificationService.kt @@ -182,8 +182,8 @@ internal class NotificationService(private val project: Project?) { ).notify(project) } - fun notifyActionId(id: String?) { - ActionIdNotifier.notifyActionId(id, project) + fun notifyActionId(id: String?, candidates: List? = null) { + ActionIdNotifier.notifyActionId(id, project, candidates) } fun notifyKeymapIssues(issues: ArrayList) { @@ -259,20 +259,31 @@ internal class NotificationService(private val project: Project?) { object ActionIdNotifier { private var notification: Notification? = null - private const val NO_ID = "Cannot detect action id" - fun notifyActionId(id: String?, project: Project?) { + fun notifyActionId(id: String?, project: Project?, candidates: List? = null) { notification?.expire() - val content = if (id != null) "Action id: $id" else NO_ID - Notification(IDEAVIM_NOTIFICATION_ID, IDEAVIM_NOTIFICATION_TITLE, content, NotificationType.INFORMATION).let { - notification = it - it.whenExpired { notification = null } - it.setContent(it.content + "

Use ${ActionCenter.getToolwindowName()} to see previous ids") + val possibleIDs = candidates?.distinct()?.sorted() + val content = when { + id != null -> "Action ID: $id

" + possibleIDs.isNullOrEmpty() -> "Cannot detect action ID

" + possibleIDs.size == 1 -> "Possible action ID: ${possibleIDs[0]}

" + else -> { + buildString { + append("

Multiple possible action IDs. Candidates include:

    ") + possibleIDs.forEach { append("
  • $it
  • ") } + append("

") + } + } + } + "See the ${ActionCenter.getToolwindowName()} tool window for previous IDs" + notification = Notification(IDEAVIM_NOTIFICATION_ID, IDEAVIM_NOTIFICATION_TITLE, content, NotificationType.INFORMATION).also { + it.whenExpired { notification = null } it.addAction(StopTracking()) - if (id != null) it.addAction(CopyActionId(id, project)) + if (id != null || possibleIDs?.size == 1) { + it.addAction(CopyActionId(id ?: possibleIDs?.get(0), project)) + } it.notify(project) } diff --git a/src/main/java/com/maddyhome/idea/vim/listener/IdeaSpecifics.kt b/src/main/java/com/maddyhome/idea/vim/listener/IdeaSpecifics.kt index 74278c214a..f21d0c1b32 100644 --- a/src/main/java/com/maddyhome/idea/vim/listener/IdeaSpecifics.kt +++ b/src/main/java/com/maddyhome/idea/vim/listener/IdeaSpecifics.kt @@ -28,6 +28,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.ex.AnActionListener import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet import com.intellij.openapi.editor.Editor +import com.intellij.openapi.keymap.KeymapManager import com.intellij.openapi.project.DumbAwareToggleAction import com.intellij.openapi.util.TextRange import com.maddyhome.idea.vim.KeyHandler @@ -58,6 +59,7 @@ internal object IdeaSpecifics { private var editor: Editor? = null private var completionPrevDocumentLength: Int? = null private var completionPrevDocumentOffset: Int? = null + override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) { if (VimPlugin.isNotEnabled()) return @@ -70,7 +72,24 @@ internal object IdeaSpecifics { if (!isVimAction && injector.globalIjOptions().trackactionids) { if (action !is NotificationService.ActionIdNotifier.CopyActionId && action !is NotificationService.ActionIdNotifier.StopTracking) { val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId - VimPlugin.getNotifications(event.dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id) + val candidates = if (id == null) { + // Some actions are specific to the component they're registered for, and are copies of a global action, + // reusing the action ID and shortcuts (e.g. `NextTab` is different for editor tabs and tool window tabs). + // Unfortunately, ActionManager doesn't know about these "local" actions, so can't return the action ID. + // However, the new "local" action does copy the shortcuts of the global template action, so we can look up + // all actions with matching shortcuts. We might return more action IDs than expected, so this is a list of + // candidates, not a definite match of the action being executed, but the list should include our target + // action. Note that we might return duplicate IDs because the keymap might have multiple shortcuts mapped + // to the same action. The notifier will handle de-duplication and sorting as a presentation detail. + action.shortcutSet.shortcuts.flatMap { KeymapManager.getInstance().activeKeymap.getActionIdList(it) } + } + else { + emptyList() + } + + // We can still get empty ID and empty candidates. Notably, for the tool window toggle buttons on the new UI. + // We could filter out action events with `place == ActionPlaces.TOOLWINDOW_TOOLBAR_BAR` + VimPlugin.getNotifications(event.dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id, candidates) } } diff --git a/src/main/resources/messages/IdeaVimBundle.properties b/src/main/resources/messages/IdeaVimBundle.properties index c17e91b3d7..c847b750c5 100644 --- a/src/main/resources/messages/IdeaVimBundle.properties +++ b/src/main/resources/messages/IdeaVimBundle.properties @@ -100,8 +100,8 @@ action.not.found.0=Action not found: {0} action.CustomizeModeWidget.text=Mode Widget Settings -action.VimFindActionIdAction.text=IdeaVim: Track Action Ids -action.VimFindActionIdAction.description=Starts tracking ids of executed actions +action.VimFindActionIdAction.text=IdeaVim: Track Action IDs +action.VimFindActionIdAction.description=Starts tracking IDs of executed actions ex.show.all.actions.0.1=--- Actions ---{0}{1}