override fun beforeActionPerformed()

in src/main/java/com/maddyhome/idea/vim/listener/IdeaSpecifics.kt [75:151]


    override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
      if (VimPlugin.isNotEnabled()) return

      val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
      if (hostEditor != null) {
        editor = hostEditor
      }

      val isVimAction = (action as? AnActionWrapper)?.delegate is VimShortcutKeyAction
      if (!isVimAction && injector.vimState.mode == Mode.INSERT && action !is EnterAction) {
        val undoService = injector.undo as VimTimestampBasedUndoService
        val nanoTime = System.nanoTime()
        editor?.vim?.nativeCarets()?.forEach { undoService.endInsertSequence(it, it.offset, nanoTime) }
      }
      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
          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()
          }
         val intentionName = if (action is ApplyIntentionAction) {
            action.name
          }
          else null

          // 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, intentionName)
        }
      }

      if (hostEditor != null && action is ChooseItemAction && injector.registerGroup.isRecording) {
        val lookup = LookupManager.getActiveLookup(hostEditor)
        val lookupItem = lookup?.currentItem
        if (lookup is LookupImpl && lookupItem != null) {
          val caretOffset = hostEditor.caretModel.primaryCaret.offset
          val completionPrefixLength = lookup.itemMatcher(lookupItem).prefix.length + lookup.additionalPrefix.length
          val completionStartOffset = caretOffset - completionPrefixLength
          val documentLength = hostEditor.document.textLength
          val charsToRemove = caretOffset - completionStartOffset

          val register = VimPlugin.getRegister()

          if (charsToRemove > 0) {
            val backSpaceKey = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0)
            repeat(charsToRemove) {
              register.recordKeyStroke(backSpaceKey)
            }
          }

          val completionStartMarker = hostEditor.document.createRangeMarker(
            completionStartOffset,
            completionStartOffset
          ).apply {
            isGreedyToLeft = true
          }

          completionData = CompletionData(
            completionStartMarker,
            completionStartOffset,
            caretOffset,
            documentLength - charsToRemove
          )
        }
      }
    }