Skip to content

Commit 97684d8

Browse files
committed
feat: special handling for generated code blocks without the path
1 parent e418128 commit 97684d8

File tree

5 files changed

+140
-24
lines changed

5 files changed

+140
-24
lines changed

src/main/java/ee/carlrobert/codegpt/CodeGPTKeys.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import com.intellij.openapi.editor.EditorCustomElementRenderer;
44
import com.intellij.openapi.editor.Inlay;
55
import com.intellij.openapi.util.Key;
6-
import com.intellij.openapi.vfs.VirtualFile;
76
import ee.carlrobert.codegpt.predictions.CodeSuggestionDiffViewer;
7+
import ee.carlrobert.codegpt.toolwindow.chat.editor.ToolWindowEditorFileDetails;
88
import ee.carlrobert.llm.client.codegpt.CodeGPTUserDetails;
99

1010
public class CodeGPTKeys {
@@ -27,6 +27,6 @@ public class CodeGPTKeys {
2727
Key.create("codegpt.isPromptTextFieldDocument");
2828
public static final Key<CodeSuggestionDiffViewer> EDITOR_PREDICTION_DIFF_VIEWER =
2929
Key.create("codegpt.editorPredictionDiffViewer");
30-
public static final Key<VirtualFile> TOOLWINDOW_EDITOR_VIRTUAL_FILE =
31-
Key.create("proxyai.toolwindowEditorVirtualFile");
30+
public static final Key<ToolWindowEditorFileDetails> TOOLWINDOW_EDITOR_FILE_DETAILS =
31+
Key.create("proxyai.toolwindowEditorFileDetails");
3232
}

src/main/kotlin/ee/carlrobert/codegpt/toolwindow/chat/editor/HeaderPanel.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,12 @@ class HeaderPanel(
5757
if (virtualFile == null) {
5858
runInEdt {
5959
add(createLanguageLabel(extension), BorderLayout.LINE_START)
60+
CodeGPTKeys.TOOLWINDOW_EDITOR_FILE_DETAILS.set(editorEx, ToolWindowEditorFileDetails(filePath))
6061
}
6162
} else {
6263
runInEdt {
6364
add(createFileLink(virtualFile), BorderLayout.LINE_START)
64-
CodeGPTKeys.TOOLWINDOW_EDITOR_VIRTUAL_FILE.set(editorEx, virtualFile)
65+
CodeGPTKeys.TOOLWINDOW_EDITOR_FILE_DETAILS.set(editorEx, ToolWindowEditorFileDetails(filePath, virtualFile))
6566
}
6667
}
6768
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package ee.carlrobert.codegpt.toolwindow.chat.editor
2+
3+
import com.intellij.openapi.vfs.VirtualFile
4+
5+
data class ToolWindowEditorFileDetails(val path: String, val virtualFile: VirtualFile? = null) {
6+
}

src/main/kotlin/ee/carlrobert/codegpt/toolwindow/chat/editor/actions/AutoApplyAction.kt

Lines changed: 122 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ import com.intellij.openapi.application.runInEdt
1515
import com.intellij.openapi.command.WriteCommandAction
1616
import com.intellij.openapi.components.service
1717
import com.intellij.openapi.editor.Editor
18+
import com.intellij.openapi.editor.ex.EditorEx
1819
import com.intellij.openapi.fileEditor.FileEditorManager
1920
import com.intellij.openapi.progress.ProgressIndicator
2021
import com.intellij.openapi.progress.ProgressManager
2122
import com.intellij.openapi.progress.Task
2223
import com.intellij.openapi.project.Project
24+
import com.intellij.openapi.ui.Messages
2325
import com.intellij.openapi.util.Key
26+
import com.intellij.openapi.vfs.LocalFileSystem
2427
import com.intellij.openapi.vfs.VirtualFile
2528
import com.intellij.testFramework.LightVirtualFile
2629
import com.intellij.ui.JBColor
@@ -36,12 +39,14 @@ import ee.carlrobert.codegpt.completions.CompletionClientProvider
3639
import ee.carlrobert.codegpt.settings.GeneralSettings
3740
import ee.carlrobert.codegpt.settings.service.ServiceType
3841
import ee.carlrobert.codegpt.toolwindow.chat.editor.HeaderPanel
42+
import ee.carlrobert.codegpt.toolwindow.chat.editor.ToolWindowEditorFileDetails
3943
import ee.carlrobert.codegpt.ui.OverlayUtil
4044
import ee.carlrobert.codegpt.util.EditorDiffUtil.createDiffRequest
4145
import ee.carlrobert.codegpt.util.file.FileUtil
4246
import ee.carlrobert.llm.client.codegpt.request.AutoApplyRequest
4347
import ee.carlrobert.llm.client.codegpt.response.CodeGPTException
4448
import java.awt.FlowLayout
49+
import java.io.File
4550
import java.util.*
4651
import javax.swing.Icon
4752
import javax.swing.JButton
@@ -70,24 +75,13 @@ class AutoApplyAction(
7075
e.presentation.disableAction(CodeGPTBundle.get("toolwindow.chat.editor.action.autoApply.disabledTitle"))
7176
return
7277
}
73-
74-
val editorVirtualFile = CodeGPTKeys.TOOLWINDOW_EDITOR_VIRTUAL_FILE.get(toolwindowEditor)
75-
if (editorVirtualFile == null) {
76-
e.presentation.disableAction(CodeGPTBundle.get("toolwindow.chat.editor.action.autoApply.notApplicable"))
77-
}
7878
}
7979

80-
override fun handleAction(event: AnActionEvent) {
81-
val editorVirtualFile = CodeGPTKeys.TOOLWINDOW_EDITOR_VIRTUAL_FILE.get(toolwindowEditor)
82-
?: return
83-
84-
val request = AutoApplyRequest().apply {
85-
suggestedChanges = toolwindowEditor.document.text
86-
fileContent = FileUtil.readContent(editorVirtualFile)
87-
}
88-
89-
val acceptLink = createDisabledActionLink(CodeGPTBundle.get("toolwindow.chat.editor.action.autoApply.accept"))
90-
val rejectLink = createDisabledActionLink(CodeGPTBundle.get("toolwindow.chat.editor.action.autoApply.reject"))
80+
private fun handleApply(request: AutoApplyRequest, editorVirtualFile: VirtualFile) {
81+
val acceptLink =
82+
createDisabledActionLink(CodeGPTBundle.get("toolwindow.chat.editor.action.autoApply.accept"))
83+
val rejectLink =
84+
createDisabledActionLink(CodeGPTBundle.get("toolwindow.chat.editor.action.autoApply.reject"))
9185

9286
val newLinksPanel = JPanel(FlowLayout(FlowLayout.TRAILING, 8, 0)).apply {
9387
isOpaque = false
@@ -108,7 +102,9 @@ class AutoApplyAction(
108102
acceptLink.isEnabled = true
109103
acceptLink.addActionListener {
110104
WriteCommandAction.runWriteCommandAction(project) {
111-
editorVirtualFile.setBinaryContent(modifiedFileContent.toByteArray(editorVirtualFile.charset))
105+
editorVirtualFile.setBinaryContent(
106+
modifiedFileContent.toByteArray(editorVirtualFile.charset)
107+
)
112108
}
113109
resetState(editorVirtualFile)
114110
}
@@ -137,6 +133,25 @@ class AutoApplyAction(
137133
)
138134
}
139135

136+
override fun handleAction(event: AnActionEvent) {
137+
val fileDetails = CodeGPTKeys.TOOLWINDOW_EDITOR_FILE_DETAILS.get(toolwindowEditor)
138+
?: return
139+
140+
if (fileDetails.virtualFile == null || fileDetails.virtualFile.isDirectory) {
141+
showAdditionalOptionsDialog(fileDetails, toolwindowEditor.document.text)
142+
return
143+
}
144+
145+
val editorVirtualFile = fileDetails.virtualFile
146+
147+
val request = AutoApplyRequest().apply {
148+
suggestedChanges = toolwindowEditor.document.text
149+
fileContent = FileUtil.readContent(editorVirtualFile)
150+
}
151+
152+
handleApply(request, editorVirtualFile)
153+
}
154+
140155
override fun getActionUpdateThread(): ActionUpdateThread {
141156
return ActionUpdateThread.EDT
142157
}
@@ -182,7 +197,6 @@ class AutoApplyAction(
182197
}
183198

184199
private fun resetState(virtualFile: VirtualFile) {
185-
// Restore the action toolbar
186200
headerPanel.restoreActionToolbar()
187201
linksPanel = null
188202

@@ -238,6 +252,95 @@ class AutoApplyAction(
238252
}
239253
}
240254
}
255+
256+
private fun createNewFile(filePath: String, content: String) {
257+
258+
ProgressManager.getInstance().run(object : Task.Backgroundable(
259+
project,
260+
CodeGPTBundle.get("toolwindow.chat.editor.action.autoApply.creatingFile"),
261+
true
262+
) {
263+
override fun run(indicator: ProgressIndicator) {
264+
try {
265+
val file = File(filePath)
266+
file.parentFile?.mkdirs()
267+
268+
WriteCommandAction.runWriteCommandAction(project) {
269+
file.writeText(content)
270+
271+
val virtualFile =
272+
LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file)
273+
274+
if (virtualFile != null) {
275+
runInEdt {
276+
FileEditorManager.getInstance(project).openFile(virtualFile, true)
277+
}
278+
}
279+
}
280+
} catch (ex: Exception) {
281+
runInEdt {
282+
OverlayUtil.showNotification(
283+
CodeGPTBundle.get(
284+
"toolwindow.chat.editor.action.autoApply.fileCreationError",
285+
ex.message ?: ""
286+
),
287+
NotificationType.ERROR
288+
)
289+
}
290+
}
291+
}
292+
})
293+
}
294+
295+
private fun applyToExistingFile(content: String) {
296+
val editor =
297+
(FileEditorManager.getInstance(project).selectedTextEditor as? EditorEx) ?: return
298+
val request = AutoApplyRequest().apply {
299+
suggestedChanges = content
300+
fileContent = FileUtil.readContent(editor.virtualFile)
301+
}
302+
303+
handleApply(request, editor.virtualFile)
304+
}
305+
306+
private fun showAdditionalOptionsDialog(
307+
fileDetails: ToolWindowEditorFileDetails,
308+
content: String
309+
) {
310+
val actions = mutableListOf<Pair<String, () -> Unit>>()
311+
val canCreateNewFile =
312+
fileDetails.virtualFile == null || !fileDetails.virtualFile.isDirectory
313+
314+
if (canCreateNewFile) {
315+
actions.add(CodeGPTBundle.get("toolwindow.chat.editor.action.autoApply.dialog.createNew") to {
316+
createNewFile(fileDetails.path, content)
317+
})
318+
}
319+
actions.add(CodeGPTBundle.get("toolwindow.chat.editor.action.autoApply.dialog.applyToOpenFile") to {
320+
applyToExistingFile(content)
321+
})
322+
actions.add(CodeGPTBundle.get("toolwindow.chat.editor.action.autoApply.dialog.cancel") to {})
323+
324+
val optionTexts = actions.map { it.first }.toTypedArray()
325+
val defaultOptionIndex = 0
326+
327+
val result = Messages.showDialog(
328+
project,
329+
CodeGPTBundle.get(
330+
"toolwindow.chat.editor.action.autoApply.dialog.message",
331+
fileDetails.path
332+
),
333+
CodeGPTBundle.get("toolwindow.chat.editor.action.autoApply.dialog.title"),
334+
optionTexts,
335+
defaultOptionIndex,
336+
Messages.getQuestionIcon()
337+
)
338+
339+
if (result >= 0 && result < actions.size) {
340+
actions[result].second.invoke()
341+
}
342+
}
343+
241344
}
242345

243346
internal class ApplyChangesBackgroundTask(
@@ -265,4 +368,4 @@ internal class ApplyChangesBackgroundTask(
265368
onFailure(ex)
266369
}
267370
}
268-
}
371+
}

src/main/resources/messages/codegpt.properties

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,4 +337,10 @@ tagPopupMenuItem.closeOthers=Close Other Tags
337337
tagPopupMenuItem.closeAll=Close All Tags
338338
tagPopupMenuItem.closeTagsToLeft=Close Tags to the Left
339339
tagPopupMenuItem.closeTagsToRight=Close Tags to the Right
340-
toolwindow.chat.editor.action.autoApply.notApplicable=Unable to locate file for applying changes
340+
toolwindow.chat.editor.action.autoApply.dialog.title=File Not Found
341+
toolwindow.chat.editor.action.autoApply.dialog.message=Oops! The file can't be found. How do you want to handle this?
342+
toolwindow.chat.editor.action.autoApply.dialog.createNew=Create New File
343+
toolwindow.chat.editor.action.autoApply.dialog.applyToOpenFile=Apply to Open File
344+
toolwindow.chat.editor.action.autoApply.dialog.cancel=Cancel
345+
toolwindow.chat.editor.action.autoApply.creatingFile=Creating new file...
346+
toolwindow.chat.editor.action.autoApply.fileCreationError=Error creating file: {0}

0 commit comments

Comments
 (0)