@@ -8,11 +8,9 @@ import aicoder.actions.BaseAction
88import aicoder.actions.SessionProxyServer
99import com.intellij.openapi.actionSystem.ActionUpdateThread
1010import com.intellij.openapi.actionSystem.AnActionEvent
11- import com.intellij.openapi.actionSystem.PlatformDataKeys
1211import com.intellij.openapi.project.Project
1312import com.intellij.openapi.ui.ComboBox
1413import com.intellij.openapi.ui.DialogWrapper
15- import com.intellij.openapi.vfs.VirtualFile
1614import com.simiacryptus.aicoder.AppServer
1715import com.simiacryptus.aicoder.config.AppSettingsState
1816import com.simiacryptus.aicoder.util.BrowseUtil.browse
@@ -21,12 +19,13 @@ import com.simiacryptus.jopenai.models.chatModel
2119import com.simiacryptus.skyenet.apps.general.CmdPatchApp
2220import com.simiacryptus.skyenet.apps.general.PatchApp
2321import com.simiacryptus.skyenet.core.platform.Session
22+ import com.simiacryptus.skyenet.core.util.FileValidationUtils
23+ import com.simiacryptus.skyenet.core.util.commonRoot
2424import com.simiacryptus.skyenet.webui.application.AppInfoData
2525import com.simiacryptus.skyenet.webui.application.ApplicationServer
2626import org.slf4j.LoggerFactory
2727import java.awt.BorderLayout
2828import java.io.File
29- import java.nio.file.Files
3029import java.text.SimpleDateFormat
3130import javax.swing.*
3231import kotlin.collections.set
@@ -50,61 +49,81 @@ class CommandAutofixAction : BaseAction() {
5049 UITools .runAsync(event.project, " Initializing Command Autofix" , true ) { progress ->
5150 progress.isIndeterminate = true
5251 progress.text = " Getting settings..."
53- val settings = getUserSettings(event) ? : return @runAsync
54- val dataContext = event.dataContext
55- val virtualFiles = PlatformDataKeys .VIRTUAL_FILE_ARRAY .getData(dataContext)
56- setupAndLaunchSession(event, settings, virtualFiles)
52+ val folders = UITools .getSelectedFolders(event).map { it.toFile.toPath() }
53+ val root = folders.toTypedArray().commonRoot()
54+ val files = folders.flatMap { FileValidationUtils .expandFileList(it.toFile()).toList() }.distinct().sorted().toTypedArray()
55+ val settings = run {
56+ var settings1: PatchApp .Settings ? = null
57+ SwingUtilities .invokeAndWait {
58+ val settingsUI = SettingsUI (workingDirectory = root.toFile())
59+ val dialog = CommandSettingsDialog (event.project, settingsUI)
60+ dialog.show()
61+ settings1 = if (dialog.isOK) {
62+ val executable = File (settingsUI.commandField.selectedItem?.toString() ? : throw IllegalArgumentException (" No executable selected" ))
63+ AppSettingsState .instance.executables + = executable.absolutePath
64+ val argument = settingsUI.argumentsField.selectedItem?.toString() ? : " "
65+ AppSettingsState .instance.recentArguments.remove(argument)
66+ AppSettingsState .instance.recentArguments.add(0 , argument)
67+ AppSettingsState .instance.recentArguments =
68+ AppSettingsState .instance.recentArguments.take(MAX_RECENT_ARGUMENTS ).toMutableList()
69+ val workingDir = settingsUI.workingDirectoryField.selectedItem?.toString() ? : " "
70+ AppSettingsState .instance.recentWorkingDirs.remove(workingDir)
71+ AppSettingsState .instance.recentWorkingDirs.add(0 , workingDir)
72+ AppSettingsState .instance.recentWorkingDirs =
73+ AppSettingsState .instance.recentWorkingDirs.take(MAX_RECENT_DIRS ).toMutableList()
74+ PatchApp .Settings (
75+ executable = executable,
76+ arguments = argument,
77+ workingDirectory = File (workingDir),
78+ exitCodeOption = if (settingsUI.exitCodeZero.isSelected) " 0" else if (settingsUI.exitCodeAny.isSelected) " any" else " nonzero" ,
79+ additionalInstructions = settingsUI.additionalInstructionsField.text,
80+ autoFix = settingsUI.autoFixCheckBox.isSelected,
81+ maxRetries = settingsUI.maxRetriesField.value as Int ,
82+ )
83+ } else {
84+ null
85+ }
86+ }
87+ settings1
88+ } ? : return @runAsync
89+ require(settings.executable.exists()) { " Executable file does not exist: ${settings.executable} " }
90+ val patchApp = CmdPatchApp (
91+ root = root,
92+ settings = settings,
93+ api = api,
94+ files = files,
95+ model = AppSettingsState .instance.smartModel.chatModel()
96+ )
97+ val session = Session .newGlobalID()
98+ SessionProxyServer .chats[session] = patchApp
99+ ApplicationServer .appInfoMap[session] = AppInfoData (
100+ applicationName = " Code Chat" ,
101+ singleInput = true ,
102+ stickyInput = false ,
103+ loadImages = false ,
104+ showMenubar = false
105+ )
106+ val dateFormat = SimpleDateFormat (" HH:mm:ss" )
107+ val sessionName = " ${javaClass.simpleName} @ ${dateFormat.format(System .currentTimeMillis())} "
108+ SessionProxyServer .metadataStorage.setSessionName(null , session, sessionName)
109+ val server = AppServer .getServer(event.project)
110+ Thread {
111+ Thread .sleep(500 )
112+ try {
113+ val uri = server.server.uri.resolve(" /#$session " )
114+ BaseAction .log.info(" Opening browser to $uri " )
115+ browse(uri)
116+ } catch (e: Throwable ) {
117+ log.warn(" Error opening browser" , e)
118+ }
119+ }.start()
57120 }
58121 } catch (e: Throwable ) {
59122 log.error(" Failed to execute command autofix" , e)
60123 UITools .showErrorDialog(" Failed to execute command autofix: ${e.message} " , " Error" )
61124 }
62125 }
63126
64- /* *
65- * Sets up and launches the patch app session
66- */
67- private fun setupAndLaunchSession (event : AnActionEvent , settings : PatchApp .Settings , virtualFiles : Array <VirtualFile >? ) {
68- val folder = UITools .getSelectedFolder(event)
69- val root = if (null != folder) {
70- folder.toFile.toPath()
71- } else {
72- event.project?.basePath?.let { File (it).toPath() }
73- }!!
74- // Validate input parameters
75- require(settings.executable.exists()) { " Executable file does not exist: ${settings.executable} " }
76- val patchApp = CmdPatchApp (
77- root,
78- settings,
79- api,
80- virtualFiles?.map { it.toFile }?.toTypedArray(),
81- AppSettingsState .instance.smartModel.chatModel()
82- )
83- val session = Session .newGlobalID()
84- SessionProxyServer .chats[session] = patchApp
85- ApplicationServer .appInfoMap[session] = AppInfoData (
86- applicationName = " Code Chat" ,
87- singleInput = true ,
88- stickyInput = false ,
89- loadImages = false ,
90- showMenubar = false
91- )
92- val dateFormat = SimpleDateFormat (" HH:mm:ss" )
93- val sessionName = " ${javaClass.simpleName} @ ${dateFormat.format(System .currentTimeMillis())} "
94- SessionProxyServer .metadataStorage.setSessionName(null , session, sessionName)
95- val server = AppServer .getServer(event.project)
96- Thread {
97- Thread .sleep(500 )
98- try {
99- val uri = server.server.uri.resolve(" /#$session " )
100- BaseAction .log.info(" Opening browser to $uri " )
101- browse(uri)
102- } catch (e: Throwable ) {
103- log.warn(" Error opening browser" , e)
104- }
105- }.start()
106- }
107-
108127 /* *
109128 * Checks if the action should be enabled
110129 */
@@ -119,50 +138,14 @@ class CommandAutofixAction : BaseAction() {
119138 private val log = LoggerFactory .getLogger(CommandAutofixAction ::class .java)
120139 private const val DEFAULT_ARGUMENT = " run build"
121140 private const val MAX_RECENT_ARGUMENTS = 10
141+ private const val MAX_RECENT_DIRS = 10
122142 private const val TEXT_AREA_ROWS = 3
123143
124- private fun getUserSettings (event : AnActionEvent ? ): PatchApp .Settings ? {
125- val root = UITools .getSelectedFolder(event ? : return null )?.toNioPath() ? : event.project?.basePath?.let {
126- File (it).toPath()
127- }
128- val files = UITools .getSelectedFiles(event).map { it.path.let { File (it).toPath() } }.toMutableSet()
129- if (files.isEmpty()) Files .walk(root)
130- .filter { Files .isRegularFile(it) && ! Files .isDirectory(it) }
131- .toList().filterNotNull().forEach { files.add(it) }
132- var settings: PatchApp .Settings ? = null
133- SwingUtilities .invokeAndWait {
134- val settingsUI = SettingsUI (root!! .toFile())
135- val dialog = CommandSettingsDialog (event.project, settingsUI)
136- dialog.show()
137- settings = if (dialog.isOK) {
138- val executable = File (settingsUI.commandField.selectedItem?.toString() ? : throw IllegalArgumentException (" No executable selected" ))
139- AppSettingsState .instance.executables + = executable.absolutePath
140- val argument = settingsUI.argumentsField.selectedItem?.toString() ? : " "
141- AppSettingsState .instance.recentArguments.remove(argument)
142- AppSettingsState .instance.recentArguments.add(0 , argument)
143- AppSettingsState .instance.recentArguments =
144- AppSettingsState .instance.recentArguments.take(MAX_RECENT_ARGUMENTS ).toMutableList()
145- PatchApp .Settings (
146- executable = executable,
147- arguments = argument,
148- workingDirectory = File (settingsUI.workingDirectoryField.text),
149- exitCodeOption = if (settingsUI.exitCodeZero.isSelected) " 0" else if (settingsUI.exitCodeAny.isSelected) " any" else " nonzero" ,
150- additionalInstructions = settingsUI.additionalInstructionsField.text,
151- autoFix = settingsUI.autoFixCheckBox.isSelected,
152- maxRetries = settingsUI.maxRetriesField.value as Int ,
153- )
154- } else {
155- null
156- }
157- }
158- return settings
159- }
160-
161144 /* *
162145 * UI component class for command settings dialog
163146 */
164147
165- class SettingsUI (root : File ) {
148+ class SettingsUI (workingDirectory : File ) {
166149 val maxRetriesField = JSpinner (SpinnerNumberModel (3 , 0 , 10 , 1 )).apply {
167150 toolTipText = " Maximum number of auto-retry attempts (0-10)"
168151 }
@@ -187,18 +170,23 @@ class CommandAutofixAction : BaseAction() {
187170 }
188171 }
189172 }
190- val workingDirectoryField = JTextField (root.absolutePath ).apply {
173+ val workingDirectoryField = ComboBox < String >( ).apply {
191174 isEditable = true
175+ AppSettingsState .instance.recentWorkingDirs.forEach { addItem(it) }
176+ if (AppSettingsState .instance.recentWorkingDirs.isEmpty()) {
177+ addItem(workingDirectory.absolutePath)
178+ }
179+ selectedItem = workingDirectory.absolutePath
192180 }
193181 val workingDirectoryButton = JButton (" ..." ).apply {
194182 addActionListener {
195183 val fileChooser = JFileChooser ().apply {
196184 fileSelectionMode = JFileChooser .DIRECTORIES_ONLY
197185 isMultiSelectionEnabled = false
198- this .selectedFile = File (workingDirectoryField.text )
186+ this .selectedFile = File (workingDirectoryField.selectedItem?.toString() ? : workingDirectory.absolutePath )
199187 }
200188 if (fileChooser.showOpenDialog(null ) == JFileChooser .APPROVE_OPTION ) {
201- workingDirectoryField.text = fileChooser.selectedFile.absolutePath
189+ workingDirectoryField.selectedItem = fileChooser.selectedFile.absolutePath
202190 }
203191 }
204192 }
0 commit comments