Просмотр исходного кода

Merge pull request #51 from windchargerj/feature-xmake_multi_configuration

Support multiplatforms XMake configurations
ruki 1 год назад
Родитель
Сommit
e93d0eea59

+ 27 - 12
src/main/kotlin/io/xmake/actions/BuildAction.kt

@@ -2,11 +2,15 @@ package io.xmake.actions
 
 import com.intellij.execution.process.ProcessAdapter
 import com.intellij.execution.process.ProcessEvent
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.notification.NotificationGroupManager
+import com.intellij.notification.NotificationType
 import com.intellij.openapi.actionSystem.AnAction
 import com.intellij.openapi.actionSystem.AnActionEvent
 import io.xmake.project.xmakeConsoleView
 import io.xmake.shared.xmakeConfiguration
 import io.xmake.utils.SystemUtils
+import io.xmake.utils.exception.XMakeRunConfigurationNotSetException
 
 class BuildAction : AnAction() {
 
@@ -18,18 +22,29 @@ class BuildAction : AnAction() {
         // clear console first
         project.xmakeConsoleView.clear()
 
-        // configure and build it
-        val xmakeConfiguration = project.xmakeConfiguration
-        if (xmakeConfiguration.changed) {
-            SystemUtils.runvInConsole(project, xmakeConfiguration.configurationCommandLine)
-                ?.addProcessListener(object : ProcessAdapter() {
-                override fun processTerminated(e: ProcessEvent) {
-                    SystemUtils.runvInConsole(project, xmakeConfiguration.buildCommandLine, false, true, true)
-                }
-            })
-            xmakeConfiguration.changed = false
-        } else {
-            SystemUtils.runvInConsole(project, xmakeConfiguration.buildCommandLine, true, true, true)
+        try {
+            // configure and build it
+            val xmakeConfiguration = project.xmakeConfiguration
+            if (xmakeConfiguration.changed) {
+                SystemUtils.runvInConsole(project, xmakeConfiguration.configurationCommandLine)
+                    ?.addProcessListener(object : ProcessAdapter() {
+                        override fun processTerminated(e: ProcessEvent) {
+                            SystemUtils.runvInConsole(project, xmakeConfiguration.buildCommandLine, false, true, true)
+                        }
+                    })
+                xmakeConfiguration.changed = false
+            } else {
+                SystemUtils.runvInConsole(project, xmakeConfiguration.buildCommandLine, true, true, true)
+            }
+        } catch (e: XMakeRunConfigurationNotSetException) {
+            project.xmakeConsoleView.print(
+                "Please select a xmake run configuration first!\n",
+                ConsoleViewContentType.ERROR_OUTPUT
+            )
+            NotificationGroupManager.getInstance()
+                .getNotificationGroup("XMake")
+                .createNotification("Error with XMake Configuration", e.message ?: "", NotificationType.ERROR)
+                .notify(project)
         }
     }
 }

+ 27 - 12
src/main/kotlin/io/xmake/actions/CleanAction.kt

@@ -2,11 +2,15 @@ package io.xmake.actions
 
 import com.intellij.execution.process.ProcessAdapter
 import com.intellij.execution.process.ProcessEvent
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.notification.NotificationGroupManager
+import com.intellij.notification.NotificationType
 import com.intellij.openapi.actionSystem.AnAction
 import com.intellij.openapi.actionSystem.AnActionEvent
 import io.xmake.project.xmakeConsoleView
 import io.xmake.shared.xmakeConfiguration
 import io.xmake.utils.SystemUtils
+import io.xmake.utils.exception.XMakeRunConfigurationNotSetException
 
 class CleanAction : AnAction() {
 
@@ -18,18 +22,29 @@ class CleanAction : AnAction() {
         // clear console first
         project.xmakeConsoleView.clear()
 
-        // configure and clean it
-        val xmakeConfiguration = project.xmakeConfiguration
-        if (xmakeConfiguration.changed) {
-            SystemUtils.runvInConsole(project, xmakeConfiguration.configurationCommandLine)
-                ?.addProcessListener(object : ProcessAdapter() {
-                override fun processTerminated(e: ProcessEvent) {
-                    SystemUtils.runvInConsole(project, xmakeConfiguration.cleanCommandLine, false, false, true)
-                }
-            })
-            xmakeConfiguration.changed = false
-        } else {
-            SystemUtils.runvInConsole(project, xmakeConfiguration.cleanCommandLine, true, false, true)
+        try {
+            // configure and clean it
+            val xmakeConfiguration = project.xmakeConfiguration
+            if (xmakeConfiguration.changed) {
+                SystemUtils.runvInConsole(project, xmakeConfiguration.configurationCommandLine)
+                    ?.addProcessListener(object : ProcessAdapter() {
+                        override fun processTerminated(e: ProcessEvent) {
+                            SystemUtils.runvInConsole(project, xmakeConfiguration.cleanCommandLine, false, false, true)
+                        }
+                    })
+                xmakeConfiguration.changed = false
+            } else {
+                SystemUtils.runvInConsole(project, xmakeConfiguration.cleanCommandLine, true, false, true)
+            }
+        } catch (e: XMakeRunConfigurationNotSetException) {
+            project.xmakeConsoleView.print(
+                "Please select a xmake run configuration first!\n",
+                ConsoleViewContentType.ERROR_OUTPUT
+            )
+            NotificationGroupManager.getInstance()
+                .getNotificationGroup("XMake")
+                .createNotification("Error with XMake Configuration", e.message ?: "", NotificationType.ERROR)
+                .notify(project)
         }
     }
 }

+ 21 - 5
src/main/kotlin/io/xmake/actions/CleanConfigurationAction.kt

@@ -1,10 +1,14 @@
 package io.xmake.actions
 
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.notification.NotificationGroupManager
+import com.intellij.notification.NotificationType
 import com.intellij.openapi.actionSystem.AnAction
 import com.intellij.openapi.actionSystem.AnActionEvent
 import io.xmake.project.xmakeConsoleView
-import io.xmake.utils.SystemUtils
 import io.xmake.shared.xmakeConfiguration
+import io.xmake.utils.SystemUtils
+import io.xmake.utils.exception.XMakeRunConfigurationNotSetException
 
 class CleanConfigurationAction : AnAction() {
 
@@ -16,9 +20,21 @@ class CleanConfigurationAction : AnAction() {
         // clear console first
         project.xmakeConsoleView.clear()
 
-        // clear configure
-        val xmakeConfiguration = project.xmakeConfiguration
-        SystemUtils.runvInConsole(project, xmakeConfiguration.cleanConfigurationCommandLine, true, false, true)
-        xmakeConfiguration.changed = false
+        try {
+            // clear configure
+            val xmakeConfiguration = project.xmakeConfiguration
+            SystemUtils.runvInConsole(project, xmakeConfiguration.cleanConfigurationCommandLine, true, false, true)
+            xmakeConfiguration.changed = false
+        } catch (e: XMakeRunConfigurationNotSetException) {
+            project.xmakeConsoleView.print(
+                "Please select a xmake run configuration first!\n",
+                ConsoleViewContentType.ERROR_OUTPUT
+            )
+            NotificationGroupManager.getInstance()
+                .getNotificationGroup("XMake")
+                .createNotification("Error with XMake Configuration", e.message ?: "", NotificationType.ERROR)
+                .notify(project)
+        }
+
     }
 }

+ 19 - 3
src/main/kotlin/io/xmake/actions/QuickStartAction.kt

@@ -1,10 +1,14 @@
 package io.xmake.actions
 
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.notification.NotificationGroupManager
+import com.intellij.notification.NotificationType
 import com.intellij.openapi.actionSystem.AnAction
 import com.intellij.openapi.actionSystem.AnActionEvent
 import io.xmake.project.xmakeConsoleView
-import io.xmake.utils.SystemUtils
 import io.xmake.shared.xmakeConfiguration
+import io.xmake.utils.SystemUtils
+import io.xmake.utils.exception.XMakeRunConfigurationNotSetException
 
 class QuickStartAction : AnAction() {
 
@@ -16,7 +20,19 @@ class QuickStartAction : AnAction() {
         // clear console first
         project.xmakeConsoleView.clear()
 
-        // quick start
-        SystemUtils.runvInConsole(project, project.xmakeConfiguration.quickStartCommandLine, true, false, true)
+        try {
+            // quick start
+            SystemUtils.runvInConsole(project, project.xmakeConfiguration.quickStartCommandLine, true, false, true)
+        } catch (e: XMakeRunConfigurationNotSetException) {
+            project.xmakeConsoleView.print(
+                "Please select a xmake run configuration first!\n",
+                ConsoleViewContentType.ERROR_OUTPUT
+            )
+            NotificationGroupManager.getInstance()
+                .getNotificationGroup("XMake")
+                .createNotification("Error with XMake Configuration", e.message ?: "", NotificationType.ERROR)
+                .notify(project)
+        }
+
     }
 }

+ 27 - 12
src/main/kotlin/io/xmake/actions/RebuildAction.kt

@@ -2,11 +2,15 @@ package io.xmake.actions
 
 import com.intellij.execution.process.ProcessAdapter
 import com.intellij.execution.process.ProcessEvent
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.notification.NotificationGroupManager
+import com.intellij.notification.NotificationType
 import com.intellij.openapi.actionSystem.AnAction
 import com.intellij.openapi.actionSystem.AnActionEvent
 import io.xmake.project.xmakeConsoleView
 import io.xmake.shared.xmakeConfiguration
 import io.xmake.utils.SystemUtils
+import io.xmake.utils.exception.XMakeRunConfigurationNotSetException
 
 class RebuildAction : AnAction() {
 
@@ -18,18 +22,29 @@ class RebuildAction : AnAction() {
         // clear console first
         project.xmakeConsoleView.clear()
 
-        // configure and rebuild it
-        val xmakeConfiguration = project.xmakeConfiguration
-        if (xmakeConfiguration.changed) {
-            SystemUtils.runvInConsole(project, xmakeConfiguration.configurationCommandLine)
-                ?.addProcessListener(object : ProcessAdapter() {
-                override fun processTerminated(e: ProcessEvent) {
-                    SystemUtils.runvInConsole(project, xmakeConfiguration.rebuildCommandLine, false, true, true)
-                }
-            })
-            xmakeConfiguration.changed = false
-        } else {
-            SystemUtils.runvInConsole(project, xmakeConfiguration.rebuildCommandLine, true, true, true)
+        try {
+            // configure and rebuild it
+            val xmakeConfiguration = project.xmakeConfiguration
+            if (xmakeConfiguration.changed) {
+                SystemUtils.runvInConsole(project, xmakeConfiguration.configurationCommandLine)
+                    ?.addProcessListener(object : ProcessAdapter() {
+                        override fun processTerminated(e: ProcessEvent) {
+                            SystemUtils.runvInConsole(project, xmakeConfiguration.rebuildCommandLine, false, true, true)
+                        }
+                    })
+                xmakeConfiguration.changed = false
+            } else {
+                SystemUtils.runvInConsole(project, xmakeConfiguration.rebuildCommandLine, true, true, true)
+            }
+        } catch (e: XMakeRunConfigurationNotSetException) {
+            project.xmakeConsoleView.print(
+                "Please select a xmake run configuration first!\n",
+                ConsoleViewContentType.ERROR_OUTPUT
+            )
+            NotificationGroupManager.getInstance()
+                .getNotificationGroup("XMake")
+                .createNotification("Error with XMake Configuration", e.message ?: "", NotificationType.ERROR)
+                .notify(project)
         }
     }
 }

+ 26 - 17
src/main/kotlin/io/xmake/actions/RunAction.kt

@@ -1,15 +1,16 @@
 package io.xmake.actions
 
-import com.intellij.execution.RunManager
 import com.intellij.execution.process.ProcessAdapter
 import com.intellij.execution.process.ProcessEvent
 import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.notification.NotificationGroupManager
+import com.intellij.notification.NotificationType
 import com.intellij.openapi.actionSystem.AnAction
 import com.intellij.openapi.actionSystem.AnActionEvent
 import io.xmake.project.xmakeConsoleView
-import io.xmake.run.XMakeRunConfiguration
 import io.xmake.shared.xmakeConfiguration
 import io.xmake.utils.SystemUtils
+import io.xmake.utils.exception.XMakeRunConfigurationNotSetException
 
 class RunAction : AnAction() {
 
@@ -18,31 +19,39 @@ class RunAction : AnAction() {
         // the project
         val project = e.project ?: return
 
-        // get selected run configuration
-        val runConfiguration = RunManager.getInstance(project).selectedConfiguration?.configuration
-        if (runConfiguration is XMakeRunConfiguration) {
-
-            // clear console first
-            project.xmakeConsoleView.clear()
+        // clear console first
+        project.xmakeConsoleView.clear()
 
+        try {
             // configure and run it
             val xmakeConfiguration = project.xmakeConfiguration
             if (xmakeConfiguration.changed) {
                 SystemUtils.runvInConsole(project, xmakeConfiguration.configurationCommandLine)
                     ?.addProcessListener(object : ProcessAdapter() {
-                    override fun processTerminated(e: ProcessEvent) {
-                        SystemUtils.runvInConsole(project, runConfiguration.runCommandLine, false, true, true)
-                    }
-                })
+                        override fun processTerminated(e: ProcessEvent) {
+                            SystemUtils.runvInConsole(
+                                project,
+                                xmakeConfiguration.configuration.runCommandLine,
+                                false,
+                                true,
+                                true
+                            )
+                        }
+                    })
                 xmakeConfiguration.changed = false
             } else {
-                SystemUtils.runvInConsole(project, runConfiguration.runCommandLine, true, true, true)
+                SystemUtils.runvInConsole(project, xmakeConfiguration.configuration.runCommandLine, true, true, true)
             }
 
-        } else {
-
-            // show tips
-            project.xmakeConsoleView.print("Please select a xmake run configuration first!\n", ConsoleViewContentType.ERROR_OUTPUT)
+        } catch (e: XMakeRunConfigurationNotSetException) {
+            project.xmakeConsoleView.print(
+                "Please select a xmake run configuration first!\n",
+                ConsoleViewContentType.ERROR_OUTPUT
+            )
+            NotificationGroupManager.getInstance()
+                .getNotificationGroup("XMake")
+                .createNotification("Error with XMake Configuration", e.message ?: "", NotificationType.ERROR)
+                .notify(project)
         }
     }
 }

+ 54 - 27
src/main/kotlin/io/xmake/actions/UpdateCmakeListsAction.kt

@@ -2,12 +2,16 @@ package io.xmake.actions
 
 import com.intellij.execution.process.ProcessAdapter
 import com.intellij.execution.process.ProcessEvent
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.notification.NotificationGroupManager
+import com.intellij.notification.NotificationType
 import com.intellij.openapi.actionSystem.AnAction
 import com.intellij.openapi.actionSystem.AnActionEvent
 import io.xmake.project.toolkit.activatedToolkit
 import io.xmake.project.xmakeConsoleView
 import io.xmake.shared.xmakeConfiguration
 import io.xmake.utils.SystemUtils
+import io.xmake.utils.exception.XMakeRunConfigurationNotSetException
 import io.xmake.utils.execute.SyncDirection
 import io.xmake.utils.execute.syncFileByToolkit
 import kotlinx.coroutines.GlobalScope
@@ -20,38 +24,61 @@ class UpdateCmakeListsAction : AnAction() {
         // clear console first
         project.xmakeConsoleView.clear()
 
-        // configure and build it
-        val xmakeConfiguration = project.xmakeConfiguration
-        if (xmakeConfiguration.changed) {
-            SystemUtils.runvInConsole(project, xmakeConfiguration.configurationCommandLine)
-                ?.addProcessListener(object : ProcessAdapter() {
-                override fun processTerminated(e: ProcessEvent) {
-                    SystemUtils.runvInConsole(
-                        project,
-                        xmakeConfiguration.updateCmakeListsCommandLine,
-                        false,
-                        true,
-                        true
-                    )?.addProcessListener(
-                        object: ProcessAdapter() {
+        try {
+            // configure and build it
+            val xmakeConfiguration = project.xmakeConfiguration
+            if (xmakeConfiguration.changed) {
+                SystemUtils.runvInConsole(project, xmakeConfiguration.configurationCommandLine)
+                    ?.addProcessListener(object : ProcessAdapter() {
+                        override fun processTerminated(e: ProcessEvent) {
+                            SystemUtils.runvInConsole(
+                                project,
+                                xmakeConfiguration.updateCmakeListsCommandLine,
+                                false,
+                                true,
+                                true
+                            )?.addProcessListener(
+                                object : ProcessAdapter() {
+                                    override fun processTerminated(e: ProcessEvent) {
+                                        syncFileByToolkit(
+                                            GlobalScope,
+                                            project,
+                                            project.activatedToolkit!!,
+                                            "CMakeLists.txt",
+                                            SyncDirection.UPSTREAM_TO_LOCAL
+                                        )
+                                        // Todo: Reload from disks after download from remote.
+                                    }
+                                }
+                            )
+                        }
+                    })
+                xmakeConfiguration.changed = false
+            } else {
+                SystemUtils.runvInConsole(project, xmakeConfiguration.updateCmakeListsCommandLine, false, true, true)
+                    ?.addProcessListener(
+                        object : ProcessAdapter() {
                             override fun processTerminated(e: ProcessEvent) {
-                                syncFileByToolkit(GlobalScope, project, project.activatedToolkit!!, "CMakeLists.txt", SyncDirection.UPSTREAM_TO_LOCAL)
-                                // Todo: Reload from disks after download from remote.
+                                syncFileByToolkit(
+                                    GlobalScope,
+                                    project,
+                                    project.activatedToolkit!!,
+                                    "CMakeLists.txt",
+                                    SyncDirection.UPSTREAM_TO_LOCAL
+                                )
                             }
                         }
                     )
-                }
-            })
-            xmakeConfiguration.changed = false
-        } else {
-            SystemUtils.runvInConsole(project, xmakeConfiguration.updateCmakeListsCommandLine, false, true, true)
-                ?.addProcessListener(
-                object: ProcessAdapter() {
-                    override fun processTerminated(e: ProcessEvent) {
-                        syncFileByToolkit(GlobalScope, project, project.activatedToolkit!!, "CMakeLists.txt", SyncDirection.UPSTREAM_TO_LOCAL)
-                    }
-                }
+            }
+        } catch (e: XMakeRunConfigurationNotSetException) {
+            project.xmakeConsoleView.print(
+                "Please select a xmake run configuration first!\n",
+                ConsoleViewContentType.ERROR_OUTPUT
             )
+            NotificationGroupManager.getInstance()
+                .getNotificationGroup("XMake")
+                .createNotification("Error with XMake Configuration", e.message ?: "", NotificationType.ERROR)
+                .notify(project)
         }
     }
 }

+ 55 - 22
src/main/kotlin/io/xmake/actions/UpdateCompileCommandsAction.kt

@@ -2,12 +2,16 @@ package io.xmake.actions
 
 import com.intellij.execution.process.ProcessAdapter
 import com.intellij.execution.process.ProcessEvent
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.notification.NotificationGroupManager
+import com.intellij.notification.NotificationType
 import com.intellij.openapi.actionSystem.AnAction
 import com.intellij.openapi.actionSystem.AnActionEvent
 import io.xmake.project.toolkit.activatedToolkit
 import io.xmake.project.xmakeConsoleView
 import io.xmake.shared.xmakeConfiguration
 import io.xmake.utils.SystemUtils
+import io.xmake.utils.exception.XMakeRunConfigurationNotSetException
 import io.xmake.utils.execute.SyncDirection
 import io.xmake.utils.execute.syncFileByToolkit
 import kotlinx.coroutines.GlobalScope
@@ -20,33 +24,62 @@ class UpdateCompileCommandsAction : AnAction() {
         // clear console first
         project.xmakeConsoleView.clear()
 
-        // configure and build it
-        val xmakeConfiguration = project.xmakeConfiguration
-        if (xmakeConfiguration.changed) {
-            SystemUtils.runvInConsole(project, xmakeConfiguration.configurationCommandLine)
-                ?.addProcessListener(object : ProcessAdapter() {
-                override fun processTerminated(e: ProcessEvent) {
-                    SystemUtils.runvInConsole(project, xmakeConfiguration.updateCompileCommansLine, false, true, true)
-                        ?.addProcessListener(
-                        object: ProcessAdapter() {
+        try {
+            // configure and build it
+            val xmakeConfiguration = project.xmakeConfiguration
+            if (xmakeConfiguration.changed) {
+                SystemUtils.runvInConsole(project, xmakeConfiguration.configurationCommandLine)
+                    ?.addProcessListener(object : ProcessAdapter() {
+                        override fun processTerminated(e: ProcessEvent) {
+                            SystemUtils.runvInConsole(
+                                project,
+                                xmakeConfiguration.updateCompileCommansLine,
+                                false,
+                                true,
+                                true
+                            )
+                                ?.addProcessListener(
+                                    object : ProcessAdapter() {
+                                        override fun processTerminated(e: ProcessEvent) {
+                                            syncFileByToolkit(
+                                                GlobalScope,
+                                                project,
+                                                project.activatedToolkit!!,
+                                                "compile_commands.json",
+                                                SyncDirection.UPSTREAM_TO_LOCAL
+                                            )
+                                            // Todo: Reload from disks after download from remote.
+                                        }
+                                    }
+                                )
+                        }
+                    })
+                xmakeConfiguration.changed = false
+            } else {
+                SystemUtils.runvInConsole(project, xmakeConfiguration.updateCompileCommansLine, false, true, true)
+                    ?.addProcessListener(
+                        object : ProcessAdapter() {
                             override fun processTerminated(e: ProcessEvent) {
-                                syncFileByToolkit(GlobalScope, project, project.activatedToolkit!!, "compile_commands.json", SyncDirection.UPSTREAM_TO_LOCAL)
-                                // Todo: Reload from disks after download from remote.
+                                syncFileByToolkit(
+                                    GlobalScope,
+                                    project,
+                                    project.activatedToolkit!!,
+                                    "compile_commands.json",
+                                    SyncDirection.UPSTREAM_TO_LOCAL
+                                )
                             }
                         }
                     )
-                }
-            })
-            xmakeConfiguration.changed = false
-        } else {
-            SystemUtils.runvInConsole(project, xmakeConfiguration.updateCompileCommansLine, false, true, true)
-                ?.addProcessListener(
-                object: ProcessAdapter() {
-                    override fun processTerminated(e: ProcessEvent) {
-                        syncFileByToolkit(GlobalScope, project, project.activatedToolkit!!, "compile_commands.json", SyncDirection.UPSTREAM_TO_LOCAL)
-                    }
-                }
+            }
+        } catch (e: XMakeRunConfigurationNotSetException) {
+            project.xmakeConsoleView.print(
+                "Please select a xmake run configuration first!\n",
+                ConsoleViewContentType.ERROR_OUTPUT
             )
+            NotificationGroupManager.getInstance()
+                .getNotificationGroup("XMake")
+                .createNotification("Error with XMake Configuration", e.message ?: "", NotificationType.ERROR)
+                .notify(project)
         }
     }
 }

+ 4 - 27
src/main/kotlin/io/xmake/project/XMakeProjectConfigurable.kt

@@ -1,34 +1,11 @@
 package io.xmake.project
 
-import com.intellij.execution.ExecutionBundle
-import com.intellij.openapi.diagnostic.Logger
-import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
-import com.intellij.openapi.options.Configurable
-import com.intellij.openapi.options.ConfigurationException
 import com.intellij.openapi.project.Project
-import com.intellij.openapi.ui.LabeledComponent
-import com.intellij.openapi.ui.TextFieldWithBrowseButton
-import com.intellij.ui.*
-import com.intellij.ui.components.JBCheckBox
-import com.intellij.ui.components.JBTextField
-import com.intellij.ui.dsl.builder.*
-import com.intellij.util.ui.JBFont
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.UIUtil
-import io.xmake.shared.XMakeConfiguration
-import io.xmake.shared.xmakeConfigurationOrNull
-import java.awt.Dimension
-import java.awt.event.ItemEvent
-import java.awt.event.ItemListener
-import java.awt.event.KeyEvent
-import java.awt.event.KeyListener
-import javax.swing.*
-import javax.swing.event.ListDataEvent
-import javax.swing.event.ListDataListener
 
+@Deprecated("Migrate to Run Configuration Editor.")
 class XMakeProjectConfigurable(
-    private val project: Project
-) : Configurable, Configurable.NoScroll {
+    private val project: Project,
+)/* : Configurable, Configurable.NoScroll {
     private val platformsModel = DefaultComboBoxModel<String>()
 
     // the architectures ui
@@ -290,4 +267,4 @@ class XMakeProjectConfigurable(
     companion object {
         private val Log = Logger.getInstance(XMakeProjectConfigurable::class.java.getName())
     }
-}
+}*/

+ 21 - 0
src/main/kotlin/io/xmake/run/XMakeRunConfiguration.kt

@@ -32,6 +32,15 @@ class XMakeRunConfiguration(
     @OptionTag(tag = "target")
     var runTarget: String = "default"
 
+    @OptionTag(tag = "platform")
+    var runPlatform: String = SystemUtils.platform()
+
+    @OptionTag(tag = "architecture")
+    var runArchitecture: String = ""
+
+    @OptionTag(tag = "mode")
+    var runMode: String = "release"
+
     // the run arguments
     @OptionTag(tag = "arguments")
     var runArguments: String = ""
@@ -43,6 +52,18 @@ class XMakeRunConfiguration(
     @OptionTag(tag = "workingDirectory")
     var runWorkingDir: String = ""
 
+    @OptionTag(tag = "buildDirectory")
+    var buildDirectory: String = ""
+
+    @OptionTag(tag = "androidNDKDirectory")
+    var androidNDKDirectory: String = ""
+
+    @OptionTag(tag = "enableVerbose")
+    var enableVerbose: Boolean = false
+
+    @OptionTag(tag = "additionalConfiguration")
+    var additionalConfiguration: String = ""
+
     // the run command line
     val runCommandLine: GeneralCommandLine
         get() {

+ 158 - 21
src/main/kotlin/io/xmake/run/XMakeRunConfigurationEditor.kt

@@ -1,6 +1,6 @@
 package io.xmake.run
 
-import com.intellij.execution.configuration.EnvironmentVariablesComponent
+import com.intellij.execution.configuration.EnvironmentVariablesTextFieldWithBrowseButton
 import com.intellij.execution.wsl.WSLDistribution
 import com.intellij.openapi.diagnostic.Logger
 import com.intellij.openapi.options.SettingsEditor
@@ -9,14 +9,19 @@ import com.intellij.openapi.ui.ComboBox
 import com.intellij.ssh.config.unified.SshConfig
 import com.intellij.ui.PopupMenuListenerAdapter
 import com.intellij.ui.RawCommandLineEditor
+import com.intellij.ui.components.CheckBox
 import com.intellij.ui.dsl.builder.AlignX
+import com.intellij.ui.dsl.builder.AlignY
+import com.intellij.ui.dsl.builder.RowLayout
 import com.intellij.ui.dsl.builder.panel
 import com.intellij.ui.layout.ComboBoxPredicate
 import io.xmake.project.directory.ui.DirectoryBrowser
 import io.xmake.project.target.TargetManager
+import io.xmake.project.toolkit.Toolkit
 import io.xmake.project.toolkit.ToolkitHostType.*
 import io.xmake.project.toolkit.ui.ToolkitComboBox
 import io.xmake.project.toolkit.ui.ToolkitListItem
+import io.xmake.shared.xmakeConfiguration
 import io.xmake.utils.execute.SyncDirection
 import io.xmake.utils.execute.syncProjectBySftp
 import io.xmake.utils.execute.syncProjectByWslSync
@@ -36,43 +41,99 @@ class XMakeRunConfigurationEditor(
 
     private val scope = CoroutineScope(Dispatchers.Default)
 
-    private val toolkitComboBox = ToolkitComboBox(runConfiguration::runToolkit)
+    private var toolkit: Toolkit? = runConfiguration.runToolkit
+    private val toolkitComboBox = ToolkitComboBox(::toolkit)
 
     // the targets ui
     private val targetsModel = DefaultComboBoxModel<String>()
-    private val targetsComboBox = ComboBox(targetsModel)
+    private val targetsComboBox = ComboBox(targetsModel).apply { item = runConfiguration.runTarget }
+
+    private val platformsModel = DefaultComboBoxModel(project.xmakeConfiguration.platforms)
+    private val platformsComboBox = ComboBox(platformsModel).apply { item = runConfiguration.runPlatform }
+
+    private val architecturesModel = DefaultComboBoxModel(project.xmakeConfiguration.architectures)
+    private val architecturesComboBox = ComboBox(architecturesModel).apply { item = runConfiguration.runArchitecture }
+
+    private val modesModel = DefaultComboBoxModel(project.xmakeConfiguration.modes)
+    private val modesComboBox = ComboBox(modesModel).apply { item = runConfiguration.runMode }
 
-    // the run arguments
     private val runArguments = RawCommandLineEditor()
 
-    // the environment variables
-    private val environmentVariables = EnvironmentVariablesComponent()
+    private val environmentVariables = EnvironmentVariablesTextFieldWithBrowseButton()
+
+    private val workingDirectoryBrowser = DirectoryBrowser(project).apply { text = runConfiguration.runWorkingDir }
+
+    private val buildDirectoryBrowser = DirectoryBrowser(project).apply { text = runConfiguration.buildDirectory }
+
+    private val androidNDKDirectoryBrowser =
+        DirectoryBrowser(project).apply { text = runConfiguration.androidNDKDirectory }
+
+    private var enableVerbose: Boolean = runConfiguration.enableVerbose
 
-    private val browser = DirectoryBrowser(project)
+    private val enableVerboseCheckBox = CheckBox("Enable verbose output", enableVerbose)
+
+    private val additionalConfiguration = RawCommandLineEditor()
 
     // reset editor from configuration
     override fun resetEditorFrom(configuration: XMakeRunConfiguration) {
 
+        toolkit = configuration.runToolkit
+
         // reset targets
         targetsModel.removeAllElements()
         targetsModel.selectedItem = configuration.runTarget
 
+        platformsComboBox.item = configuration.runPlatform
+
+        architecturesComboBox.item = configuration.runArchitecture
+
+        modesComboBox.item = configuration.runMode
+
         // reset run arguments
         runArguments.text = configuration.runArguments
 
         // reset environment variables
-        environmentVariables.envData = configuration.runEnvironment
+        environmentVariables.data = configuration.runEnvironment
+
+        workingDirectoryBrowser.text = configuration.runWorkingDir
 
-        browser.text = configuration.runWorkingDir
+        buildDirectoryBrowser.text = configuration.buildDirectory
+
+        androidNDKDirectoryBrowser.text = configuration.androidNDKDirectory
+
+        enableVerbose = configuration.enableVerbose
+
+        additionalConfiguration.text = configuration.additionalConfiguration
     }
 
     // apply editor to configuration
     override fun applyEditorTo(configuration: XMakeRunConfiguration) {
 
+        configuration.runToolkit = toolkit
+
         configuration.runTarget = (targetsModel.selectedItem ?: "").toString()
+
+        configuration.runPlatform = platformsComboBox.item
+
+        configuration.runArchitecture = architecturesComboBox.item
+
+        configuration.runMode = modesComboBox.item
+
         configuration.runArguments = runArguments.text
-        configuration.runEnvironment = environmentVariables.envData
-        configuration.runWorkingDir = browser.text
+
+        configuration.runEnvironment = environmentVariables.data
+
+        configuration.runWorkingDir = workingDirectoryBrowser.text
+
+        configuration.buildDirectory = buildDirectoryBrowser.text
+
+        configuration.androidNDKDirectory = androidNDKDirectoryBrowser.text
+
+        configuration.enableVerbose = enableVerbose
+
+        configuration.additionalConfiguration = additionalConfiguration.text
+
+        project.xmakeConfiguration.changed = true
     }
 
     // create editor
@@ -82,23 +143,66 @@ class XMakeRunConfigurationEditor(
             cell(toolkitComboBox).align(AlignX.FILL).applyToComponent {
                 // Todo: Store previously selected toolkit to restore it if not applied.
                 addToolkitChangedListener { toolkit ->
-                    browser.removeBrowserAllListener()
+                    workingDirectoryBrowser.removeBrowserAllListener()
+                    buildDirectoryBrowser.removeBrowserAllListener()
+                    androidNDKDirectoryBrowser.removeBrowserAllListener()
                     toolkit?.let {
-                        browser.addBrowserListenerByToolkit(it)
+                        workingDirectoryBrowser.addBrowserListenerByToolkit(it)
+                        buildDirectoryBrowser.addBrowserListenerByToolkit(it)
+                        androidNDKDirectoryBrowser.addBrowserListenerByToolkit(it)
                     }
                 }
-                activatedToolkit?.let { browser.addBrowserListenerByToolkit(it) }
+                activatedToolkit?.let {
+                    workingDirectoryBrowser.addBrowserListenerByToolkit(it)
+                    buildDirectoryBrowser.addBrowserListenerByToolkit(it)
+                    androidNDKDirectoryBrowser.addBrowserListenerByToolkit(it)
+                }
             }
         }
 
+        row {
+            label("Configuration:").align(AlignY.TOP)
+            panel {
+                row {
+                    label("Platform:")
+                }
+                row {
+                    cell(platformsComboBox).applyToComponent {
+                        addItemListener {
+                            architecturesModel.removeAllElements()
+                            architecturesModel.addAll(project.xmakeConfiguration.architectures.toMutableList())
+                        }
+                    }.align(AlignX.FILL)
+                }
+            }.resizableColumn()
+            panel {
+                row {
+                    label("Architecture:")
+                }
+                row {
+                    cell(architecturesComboBox).align(AlignX.FILL)
+                }
+            }.resizableColumn()
+            panel {
+                row {
+                    label("Mode:")
+                }
+                row {
+                    cell(modesComboBox).align(AlignX.FILL)
+                }
+            }.resizableColumn()
+        }.layout(RowLayout.PARENT_GRID)
+
+        separator()
+
         row("Target:") {
             cell(targetsComboBox).applyToComponent {
                 addPopupMenuListener(object : PopupMenuListenerAdapter() {
                     override fun popupMenuWillBecomeVisible(e: PopupMenuEvent?) {
                         super.popupMenuWillBecomeVisible(e)
                         targetsModel.removeAllElements()
-                        with(runConfiguration){
-                            if (runToolkit != null && runWorkingDir.isNotEmpty()){
+                        with(runConfiguration) {
+                            if (runToolkit != null && runWorkingDir.isNotEmpty()) {
                                 TargetManager.getInstance(project)
                                     .detectXmakeTarget(runToolkit!!, runConfiguration.runWorkingDir).forEach { target ->
                                         targetsModel.addElement(target)
@@ -113,29 +217,62 @@ class XMakeRunConfigurationEditor(
         row("Program arguments:") {
             cell(runArguments).align(AlignX.FILL)
         }
-        row(environmentVariables.label) {
+//        environmentVariables.label
+        row("Environment variables") {
             cell(environmentVariables).align(AlignX.FILL)
         }
+
         row("Working directory") {
-            cell(browser).align(AlignX.FILL)
+            cell(workingDirectoryBrowser).align(AlignX.FILL)
+        }
+
+        collapsibleGroup("Additional Configurations") {
+            row("Build directory") {
+                cell(buildDirectoryBrowser).align(AlignX.FILL)
+            }
+
+            row("Android NDK directory") {
+                cell(androidNDKDirectoryBrowser).align(AlignX.FILL)
+            }
+
+            row("Additional Configuration") {
+                cell(additionalConfiguration).align(AlignX.FILL)
+            }
+
+            row("") {
+                cell(enableVerboseCheckBox)
+            }
         }
 
+
         row("Sync Directory:") {
             button("Upload") {
                 toolkitComboBox.activatedToolkit?.let { toolkit ->
-                    val workingDirectoryPath = browser.text
+                    val workingDirectoryPath = workingDirectoryBrowser.text
 
                     scope.launch(Dispatchers.IO) {
                         when (toolkit.host.type) {
                             LOCAL -> {}
                             WSL -> {
                                 val wslDistribution = toolkit.host.target as? WSLDistribution
-                                syncProjectByWslSync(scope, project, wslDistribution!!, workingDirectoryPath, SyncDirection.LOCAL_TO_UPSTREAM)
+                                syncProjectByWslSync(
+                                    scope,
+                                    project,
+                                    wslDistribution!!,
+                                    workingDirectoryPath,
+                                    SyncDirection.LOCAL_TO_UPSTREAM
+                                )
                             }
 
                             SSH -> {
                                 val sshConfig = toolkit.host.target as? SshConfig
-                                syncProjectBySftp(scope, project, sshConfig!!, workingDirectoryPath, SyncDirection.LOCAL_TO_UPSTREAM)
+                                syncProjectBySftp(
+                                    scope,
+                                    project,
+                                    sshConfig!!,
+                                    workingDirectoryPath,
+                                    SyncDirection.LOCAL_TO_UPSTREAM
+                                )
                             }
                         }
                     }

+ 37 - 75
src/main/kotlin/io/xmake/shared/XMakeConfiguration.kt

@@ -3,39 +3,39 @@ package io.xmake.shared
 import com.intellij.execution.RunManager
 import com.intellij.execution.configuration.EnvironmentVariablesData
 import com.intellij.execution.configurations.GeneralCommandLine
-import com.intellij.openapi.components.PersistentStateComponent
 import com.intellij.openapi.components.Service
-import com.intellij.openapi.components.State
 import com.intellij.openapi.diagnostic.Logger
 import com.intellij.openapi.project.Project
-import com.intellij.openapi.startup.ProjectActivity
 import io.xmake.project.toolkit.activatedToolkit
 import io.xmake.run.XMakeRunConfiguration
-import io.xmake.utils.SystemUtils
+import io.xmake.utils.exception.XMakeRunConfigurationNotSetException
 
 @Service(Service.Level.PROJECT)
-@State(name = "XMakeProjectSettings")
-class XMakeConfiguration(// the project
-    val project: Project
-) : PersistentStateComponent<XMakeConfiguration.State>, ProjectActivity {
+class XMakeConfiguration(val project: Project) {
 
     // the platforms
     val platforms = arrayOf("macosx", "linux", "windows", "android", "iphoneos", "watchos", "mingw")
 
     // the architectures
     val architectures: Array<String>
-        get() = getArchitecturesByPlatform(data.currentPlatform)
+        get() = getArchitecturesByPlatform(configuration.runPlatform)
 
     // the modes
     val modes = arrayOf("release", "debug")
 
+    val configuration: XMakeRunConfiguration
+        get() {
+            return RunManager.getInstance(project).selectedConfiguration?.configuration as? XMakeRunConfiguration
+                ?: throw XMakeRunConfigurationNotSetException()
+        }
+
     // the build command line
     val buildCommandLine: GeneralCommandLine
         get() {
 
             // make parameters
-            val parameters = mutableListOf<String>("-y")
-            if (data.verboseOutput) {
+            val parameters = mutableListOf("-y")
+            if (configuration.enableVerbose) {
                 parameters.add("-v")
             }
 
@@ -49,7 +49,7 @@ class XMakeConfiguration(// the project
 
             // make parameters
             val parameters = mutableListOf("-r", "-y")
-            if (data.verboseOutput) {
+            if (configuration.enableVerbose) {
                 parameters.add("-v")
             }
 
@@ -63,7 +63,7 @@ class XMakeConfiguration(// the project
 
             // make parameters
             val parameters = mutableListOf("c")
-            if (data.verboseOutput) {
+            if (configuration.enableVerbose) {
                 parameters.add("-v")
             }
 
@@ -77,12 +77,12 @@ class XMakeConfiguration(// the project
 
             // make parameters
             val parameters = mutableListOf("f", "-c", "-y")
-            if (data.verboseOutput) {
+            if (configuration.enableVerbose) {
                 parameters.add("-v")
             }
-            if (data.buildOutputDirectory != "") {
+            if (configuration.buildDirectory != "") {
                 parameters.add("-o")
-                parameters.add(data.buildOutputDirectory)
+                parameters.add(configuration.buildDirectory)
             }
 
             // make command line
@@ -95,19 +95,28 @@ class XMakeConfiguration(// the project
 
             // make parameters
             val parameters =
-                mutableListOf("f", "-y", "-p", data.currentPlatform, "-a", data.currentArchitecture, "-m", data.currentMode)
-            if (data.currentPlatform == "android" && data.androidNDKDirectory != "") {
-                parameters.add("--ndk=\"${data.androidNDKDirectory}\"")
+                mutableListOf(
+                    "f",
+                    "-y",
+                    "-p",
+                    configuration.runPlatform,
+                    "-a",
+                    configuration.runArchitecture,
+                    "-m",
+                    configuration.runMode
+                )
+            if (configuration.runPlatform == "android" && configuration.androidNDKDirectory != "") {
+                parameters.add("--ndk=\"${configuration.androidNDKDirectory}\"")
             }
-            if (data.verboseOutput) {
+            if (configuration.enableVerbose) {
                 parameters.add("-v")
             }
-            if (data.buildOutputDirectory != "") {
+            if (configuration.buildDirectory != "") {
                 parameters.add("-o")
-                parameters.add(data.buildOutputDirectory)
+                parameters.add(configuration.buildDirectory)
             }
-            if (data.additionalConfiguration != "") {
-                parameters.add(data.additionalConfiguration)
+            if (configuration.additionalConfiguration != "") {
+                parameters.add(configuration.additionalConfiguration)
             }
 
             // make command line
@@ -120,7 +129,7 @@ class XMakeConfiguration(// the project
 
             // make parameters
             val parameters = mutableListOf("f", "-y")
-            if (data.verboseOutput) {
+            if (configuration.enableVerbose) {
                 parameters.add("-v")
             }
 
@@ -138,24 +147,6 @@ class XMakeConfiguration(// the project
     // configuration is changed?
     var changed = true
 
-    // the state data
-    var data: State = State()
-        set(value) {
-            val newState = State(
-                currentPlatform = value.currentPlatform,
-                currentArchitecture = value.currentArchitecture,
-                currentMode = value.currentMode,
-                androidNDKDirectory = value.androidNDKDirectory,
-                buildOutputDirectory = value.buildOutputDirectory,
-                verboseOutput = value.verboseOutput,
-                additionalConfiguration = value.additionalConfiguration
-            )
-            if (field != newState) {
-                field = newState
-                changed = true
-            }
-        }
-
     // make command line
     fun makeCommandLine(
         parameters: List<String>,
@@ -168,48 +159,19 @@ class XMakeConfiguration(// the project
             .withCharset(Charsets.UTF_8)
             // Todo: Check if correct.
             .withWorkDirectory(
-                (RunManager.getInstance(project).selectedConfiguration?.configuration as XMakeRunConfiguration).runWorkingDir
+                configuration.runWorkingDir
             )
             .withEnvironment(environmentVariables.envs)
             .withRedirectErrorStream(true)
     }
 
-    data class State(
-        var currentPlatform: String = SystemUtils.platform(),
-        var currentArchitecture: String = "",
-        var currentMode: String = "release",
-        var androidNDKDirectory: String = "",
-        var buildOutputDirectory: String = "",
-        var verboseOutput: Boolean = false,
-        var additionalConfiguration: String = ""
-    )
-
     // ensure state
     private fun ensureState() {
-        if (data.currentArchitecture == "" && architectures.isNotEmpty()) {
-            data.currentArchitecture = architectures[0]
+        if (configuration.runArchitecture == "" && architectures.isNotEmpty()) {
+            configuration.runArchitecture = architectures[0]
         }
     }
 
-    // get and save state to file
-    override fun getState(): State {
-        return data
-    }
-
-    // load state from file
-    override fun loadState(state: State) {
-        data = state
-        ensureState()
-    }
-
-    override fun initializeComponent() {
-        ensureState()
-    }
-
-    override suspend fun execute(project: Project) {
-        ensureState()
-    }
-
     companion object {
 
         // get architectures by platform

+ 5 - 0
src/main/kotlin/io/xmake/utils/exception/XMakeRunConfigurationNotSetException.kt

@@ -0,0 +1,5 @@
+package io.xmake.utils.exception
+
+import com.intellij.execution.ExecutionException
+
+class XMakeRunConfigurationNotSetException : ExecutionException("XMake configuration is not selected!")

+ 12 - 2
src/main/kotlin/io/xmake/utils/execute/CommandEx.kt

@@ -13,6 +13,7 @@ import com.intellij.openapi.util.Key
 import com.intellij.ssh.ConnectionBuilder
 import com.intellij.ssh.config.unified.SshConfig
 import com.intellij.ssh.interaction.PlatformSshPasswordProvider
+import com.intellij.ssh.processBuilder
 import com.intellij.util.io.awaitExit
 import io.xmake.project.toolkit.Toolkit
 import io.xmake.project.toolkit.ToolkitHostType.*
@@ -58,9 +59,18 @@ fun GeneralCommandLine.createSshProcess(sshConfig: SshConfig): Process {
     val builder = ConnectionBuilder(sshConfig.host)
         .withSshPasswordProvider(PlatformSshPasswordProvider(sshConfig.copyToCredentials()))
 
+    val command = GeneralCommandLine("sh").withParameters("-c")
+        .withParameters(this.commandLineString)
+        .withWorkDirectory(workDirectory)
+        .withCharset(charset)
+        .withEnvironment(environment)
+        .withInput(inputFile)
+        .withRedirectErrorStream(isRedirectErrorStream)
+
     return builder
-        .also { Log.info("commandOnRemote: ${this.commandLineString}") }
-        .execBuilder(this.commandLineString).execute()
+        .also { Log.info("commandOnRemote: ${command.commandLineString}") }
+        .processBuilder(command)
+        .start()
 }
 
 fun GeneralCommandLine.createProcess(toolkit: Toolkit): Process {

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

@@ -32,10 +32,10 @@
         <!-- directory-based IDE-->
         <directoryProjectGenerator implementation="io.xmake.project.wizard.XMakeProjectDirectoryGenerator"/>
 
-        <!-- project configurations -->
-        <projectConfigurable instance="io.xmake.project.XMakeProjectConfigurable" displayName="XMake" groupId="build">
-            <configurable instance="io.xmake.project.XMakeProjectToolkitConfigurable" displayName="XMake Toolkit"/>
-        </projectConfigurable>
+        <!-- xmake toolkit configurations -->
+        <applicationConfigurable instance="io.xmake.project.XMakeProjectToolkitConfigurable"
+                                 displayName="XMake Toolkit" groupId="build"/>
+
         <toolWindow id="XMake" anchor="bottom" factoryClass="io.xmake.project.XMakeToolWindowFactory"
                     icon="/icons/xmake-dark.svg"/>