1+ package com.github.simiacryptus.aicoder.actions
2+
3+ import com.github.simiacryptus.aicoder.actions.find.FindResultsModificationDialog
4+ import com.github.simiacryptus.aicoder.util.UITools
5+ import com.intellij.openapi.actionSystem.AnActionEvent
6+ import com.intellij.openapi.command.WriteCommandAction
7+ import com.intellij.openapi.editor.Document
8+ import com.intellij.openapi.project.Project
9+ import com.intellij.openapi.util.TextRange
10+ import com.intellij.openapi.vfs.VirtualFile
11+ import com.intellij.openapi.vfs.findPsiFile
12+ import com.intellij.psi.PsiDocumentManager
13+ import com.intellij.usages.Usage
14+ import com.intellij.usages.UsageInfoAdapter
15+ import com.intellij.usages.UsageView
16+ import javax.swing.Icon
17+
18+ class FindResultsModificationAction (
19+ name : String? = " Modify Find Results" ,
20+ description : String? = " Modify files based on find results" ,
21+ icon : Icon ? = null
22+ ) : BaseAction(name, description, icon) {
23+
24+ override fun handle (e : AnActionEvent ) {
25+ val project = e.project ? : return
26+ val usageView = e.getData(UsageView .USAGE_VIEW_KEY ) ? : return
27+ val usages = usageView.usages.toTypedArray()
28+ if (usages.isEmpty()) {
29+ UITools .showWarning(project, " No find results selected for modification" )
30+ return
31+ }
32+ val modificationParams = showModificationDialog(project, * usages) ? : return
33+ WriteCommandAction .runWriteCommandAction(project) {
34+ try {
35+ modifyUsages(project, usages, modificationParams)
36+ } catch (ex: Exception ) {
37+ UITools .error(log, " Error modifying files" , ex)
38+ }
39+ }
40+ UITools .showInfoMessage(
41+ project,
42+ " Modification complete" ,
43+ " File Modification Complete"
44+ )
45+ }
46+
47+ private fun modifyUsages (project : Project , usages : Array <Usage >, params : ModificationParams ) {
48+ val psiDocumentManager = PsiDocumentManager .getInstance(project)
49+ val map = usages.groupBy {
50+ it.location?.editor?.file
51+ }
52+ map.entries.forEach { (file, usages) ->
53+ for (usage in usages) {
54+ val file = usage.location?.editor?.file ? : return @forEach
55+ val document = getDocument(project, file) ? : return @forEach
56+ var startOffset = usage.navigationOffset
57+ var endOffset = usage.presentation.plainText.length + startOffset
58+ val prevText = document.getText(TextRange (startOffset, endOffset))
59+ val newText = prevText // This is where the modification might happen
60+ if (newText != prevText) {
61+ document.replaceString(startOffset, endOffset, newText)
62+ psiDocumentManager.commitDocument(document)
63+ }
64+ }
65+ }
66+ }
67+
68+ private fun getDocument (project : Project , file : VirtualFile ): Document ? {
69+ return PsiDocumentManager .getInstance(project).getDocument(file.findPsiFile(project) ? : return null )
70+ }
71+
72+ override fun isEnabled (event : AnActionEvent ): Boolean {
73+ val usageView = event.getData(UsageView .USAGE_VIEW_KEY )
74+ return usageView != null && usageView.usages.isNotEmpty()
75+ }
76+
77+ private fun showModificationDialog (project : Project , vararg usages : Usage ): ModificationParams ? {
78+ val dialog = FindResultsModificationDialog (project, usages.size)
79+ val config = dialog.showAndGetConfig()
80+ return if (config != null ) {
81+ ModificationParams (
82+ config.replacementText ? : " "
83+ )
84+ } else null
85+ }
86+
87+ private data class ModificationParams (
88+ val replacementText : String
89+ )
90+
91+ }
0 commit comments