@@ -15,12 +15,15 @@ import com.intellij.openapi.application.runInEdt
1515import com.intellij.openapi.command.WriteCommandAction
1616import com.intellij.openapi.components.service
1717import com.intellij.openapi.editor.Editor
18+ import com.intellij.openapi.editor.ex.EditorEx
1819import com.intellij.openapi.fileEditor.FileEditorManager
1920import com.intellij.openapi.progress.ProgressIndicator
2021import com.intellij.openapi.progress.ProgressManager
2122import com.intellij.openapi.progress.Task
2223import com.intellij.openapi.project.Project
24+ import com.intellij.openapi.ui.Messages
2325import com.intellij.openapi.util.Key
26+ import com.intellij.openapi.vfs.LocalFileSystem
2427import com.intellij.openapi.vfs.VirtualFile
2528import com.intellij.testFramework.LightVirtualFile
2629import com.intellij.ui.JBColor
@@ -36,12 +39,14 @@ import ee.carlrobert.codegpt.completions.CompletionClientProvider
3639import ee.carlrobert.codegpt.settings.GeneralSettings
3740import ee.carlrobert.codegpt.settings.service.ServiceType
3841import ee.carlrobert.codegpt.toolwindow.chat.editor.HeaderPanel
42+ import ee.carlrobert.codegpt.toolwindow.chat.editor.ToolWindowEditorFileDetails
3943import ee.carlrobert.codegpt.ui.OverlayUtil
4044import ee.carlrobert.codegpt.util.EditorDiffUtil.createDiffRequest
4145import ee.carlrobert.codegpt.util.file.FileUtil
4246import ee.carlrobert.llm.client.codegpt.request.AutoApplyRequest
4347import ee.carlrobert.llm.client.codegpt.response.CodeGPTException
4448import java.awt.FlowLayout
49+ import java.io.File
4550import java.util.*
4651import javax.swing.Icon
4752import 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
243346internal class ApplyChangesBackgroundTask (
@@ -265,4 +368,4 @@ internal class ApplyChangesBackgroundTask(
265368 onFailure(ex)
266369 }
267370 }
268- }
371+ }
0 commit comments