From a1639d80b0452733ee3acaf666dd82224cbf024c Mon Sep 17 00:00:00 2001
From: chylex <contact@chylex.com>
Date: Sun, 3 Dec 2023 09:31:15 +0100
Subject: [PATCH] Automatically add unambiguous imports after running a macro

---
 .../idea/vim/group/MacroAutoImport.kt         | 68 +++++++++++++++++++
 .../maddyhome/idea/vim/group/MacroGroup.kt    |  4 ++
 2 files changed, 72 insertions(+)
 create mode 100644 src/main/java/com/maddyhome/idea/vim/group/MacroAutoImport.kt

diff --git a/src/main/java/com/maddyhome/idea/vim/group/MacroAutoImport.kt b/src/main/java/com/maddyhome/idea/vim/group/MacroAutoImport.kt
new file mode 100644
index 000000000..2ee4ee8ac
--- /dev/null
+++ b/src/main/java/com/maddyhome/idea/vim/group/MacroAutoImport.kt
@@ -0,0 +1,68 @@
+package com.maddyhome.idea.vim.group
+
+import com.intellij.codeInsight.daemon.ReferenceImporter
+import com.intellij.openapi.actionSystem.CommonDataKeys
+import com.intellij.openapi.actionSystem.DataContext
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.application.ReadAction
+import com.intellij.openapi.command.WriteCommandAction
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.fileEditor.FileDocumentManager
+import com.intellij.openapi.progress.ProgressIndicator
+import com.intellij.openapi.progress.ProgressManager
+import com.intellij.openapi.progress.Task
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiRecursiveElementWalkingVisitor
+import java.util.function.BooleanSupplier
+
+internal object MacroAutoImport {
+  fun run(editor: Editor, dataContext: DataContext) {
+    val project = CommonDataKeys.PROJECT.getData(dataContext) ?: return
+    val file = PsiDocumentManager.getInstance(project).getPsiFile(editor.document) ?: return
+
+    if (!FileDocumentManager.getInstance().requestWriting(editor.document, project)) {
+      return
+    }
+
+    val importers = ReferenceImporter.EP_NAME.extensionList
+    if (importers.isEmpty()) {
+      return
+    }
+
+    ProgressManager.getInstance().run(object : Task.Backgroundable(project, "Auto import", true) {
+      override fun run(indicator: ProgressIndicator) {
+        val fixes = ReadAction.nonBlocking<List<BooleanSupplier>> {
+          val fixes = mutableListOf<BooleanSupplier>()
+
+          file.accept(object : PsiRecursiveElementWalkingVisitor() {
+            override fun visitElement(element: PsiElement) {
+              for (reference in element.references) {
+                if (reference.resolve() != null) {
+                  continue
+                }
+                for (importer in importers) {
+                  importer.computeAutoImportAtOffset(editor, file, element.textRange.startOffset, true)
+                    ?.let(fixes::add)
+                }
+              }
+              super.visitElement(element)
+            }
+          })
+
+          return@nonBlocking fixes
+        }.executeSynchronously()
+
+        ApplicationManager.getApplication().invokeAndWait {
+          WriteCommandAction.writeCommandAction(project)
+            .withName("Auto Import")
+            .withGroupId("IdeaVimAutoImportAfterMacro")
+            .shouldRecordActionForActiveDocument(true)
+            .run<RuntimeException> {
+              fixes.forEach { it.asBoolean }
+            }
+        }
+      }
+    })
+  }
+}
diff --git a/src/main/java/com/maddyhome/idea/vim/group/MacroGroup.kt b/src/main/java/com/maddyhome/idea/vim/group/MacroGroup.kt
index 5598764b6..2001c86ae 100644
--- a/src/main/java/com/maddyhome/idea/vim/group/MacroGroup.kt
+++ b/src/main/java/com/maddyhome/idea/vim/group/MacroGroup.kt
@@ -21,6 +21,7 @@ import com.maddyhome.idea.vim.api.injector
 import com.maddyhome.idea.vim.helper.MessageHelper.message
 import com.maddyhome.idea.vim.macro.VimMacroBase
 import com.maddyhome.idea.vim.newapi.IjVimEditor
+import com.maddyhome.idea.vim.newapi.ij
 
 /**
  * Used to handle playback of macros
@@ -89,6 +90,9 @@ internal class MacroGroup : VimMacroBase() {
         } finally {
           keyStack.removeFirst()
         }
+        if (!isInternalMacro) {
+          MacroAutoImport.run(editor.ij, context.ij)
+        }
       }
 
       if (isInternalMacro) {