Skip to content

Commit 6a5b891

Browse files
committed
placeholder find-replace action
1 parent 0514d76 commit 6a5b891

File tree

3 files changed

+166
-2
lines changed

3 files changed

+166
-2
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.github.simiacryptus.aicoder.actions.find
2+
3+
import com.intellij.openapi.project.Project
4+
import com.intellij.openapi.ui.ComboBox
5+
import com.intellij.openapi.ui.DialogWrapper
6+
import com.intellij.openapi.ui.ValidationInfo
7+
import com.intellij.ui.components.JBLabel
8+
import com.intellij.ui.components.JBScrollPane
9+
import com.intellij.ui.components.JBTextArea
10+
import com.intellij.util.ui.FormBuilder
11+
import javax.swing.JCheckBox
12+
import javax.swing.JComponent
13+
import javax.swing.JTextField
14+
15+
class FindResultsModificationDialog(
16+
project: Project,
17+
matchCount: Int
18+
) : DialogWrapper(project) {
19+
20+
private val replacementTextArea = JBTextArea().apply {
21+
rows = 5
22+
lineWrap = true
23+
wrapStyleWord = true
24+
}
25+
private val matchCountLabel = JBLabel("Found $matchCount matches")
26+
27+
init {
28+
title = "Configure Find Results Modification"
29+
init()
30+
}
31+
32+
override fun createCenterPanel(): JComponent {
33+
val formBuilder = FormBuilder.createFormBuilder()
34+
formBuilder.addComponent(matchCountLabel)
35+
formBuilder.addLabeledComponent("Instructions:", JBScrollPane(replacementTextArea))
36+
return formBuilder.panel
37+
}
38+
39+
override fun doValidate(): ValidationInfo? {
40+
if (replacementTextArea.text.isBlank()) {
41+
return ValidationInfo("Replacement text cannot be empty", replacementTextArea)
42+
}
43+
return null
44+
}
45+
46+
data class ConfigData(
47+
val replacementText: String?
48+
)
49+
50+
fun showAndGetConfig(): ConfigData? {
51+
if (showAndGet()) {
52+
return ConfigData(
53+
replacementText = replacementTextArea.text
54+
)
55+
}
56+
return null
57+
}
58+
59+
}
60+

src/main/resources/META-INF/plugin.xml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
class="com.intellij.openapi.actionSystem.DefaultActionGroup"
2727
popup="true"
2828
icon="MyIcons.icon"
29-
text="AI Coder"
29+
text="_AI Coder"
3030
description="AI coding assistant tools">
3131
<add-to-group group-id="ToolsMenu" anchor="first"/>
3232
<action class="com.github.simiacryptus.aicoder.actions.generic.GenericChatAction"
@@ -55,7 +55,7 @@
5555
class="com.intellij.openapi.actionSystem.DefaultActionGroup"
5656
popup="true"
5757
icon="MyIcons.icon"
58-
text="AI Editor"
58+
text="_AI Coder"
5959
description="AI coding assistant tools">
6060
<add-to-group group-id="EditorPopupMenu" anchor="before" relative-to-action="EditorToggleColumnMode"/>
6161
<action class="com.github.simiacryptus.aicoder.actions.generic.CodeChatAction"
@@ -313,6 +313,19 @@
313313
description="Replicate Commit">
314314
</action>
315315
</group>
316+
<group id="com.github.simiacryptus.aicoder.ui.FindResultsMenu"
317+
class="com.intellij.openapi.actionSystem.DefaultActionGroup"
318+
popup="true"
319+
icon="MyIcons.icon"
320+
text="_AI Coder"
321+
description="AI-powered file modification tools">
322+
<add-to-group group-id="UsageView.Popup" anchor="last"/>
323+
<action id="AICoderPlugin.FindResultsModification"
324+
class="com.github.simiacryptus.aicoder.actions.FindResultsModificationAction"
325+
text="Modify Find Results"
326+
description="Modify files based on find results">
327+
</action>
328+
</group>
316329

317330
<action id="com.github.simiacryptus.aicoder.actions.test.ChatWithTestResultAction"
318331
class="com.github.simiacryptus.aicoder.actions.test.TestResultAutofixAction"

0 commit comments

Comments
 (0)