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

New Project Wizard for IDEA 221 (#1979)

* NewProjectWizard

* dependencies and validations

* Implement checkers

* Implement project generator

* Add new template RunTerminal.run.xml for Run Configuration

* Set supported IDEA version to 221

* Fix localization

* Fix since-until

* Rearrange files
Him188 3 лет назад
Родитель
Сommit
481973d5e6
70 измененных файлов с 1052 добавлено и 1446 удалено
  1. 4 4
      buildSrc/src/main/kotlin/Versions.kt
  2. 2 2
      mirai-console/tools/intellij-plugin/build.gradle.kts
  3. 7 7
      mirai-console/tools/intellij-plugin/resources/META-INF/plugin.xml
  4. 0 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/.gitignore.ft
  5. 14 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/.gitignore.html
  6. 0 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Gradle gradle.properties.ft
  7. 14 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Gradle gradle.properties.html
  8. 0 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin build.gradle.ft
  9. 14 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin build.gradle.html
  10. 0 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin build.gradle.kts.ft
  11. 14 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin build.gradle.kts.html
  12. 0 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main class Java.java.ft
  13. 0 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main class Java.java.ft.back
  14. 14 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main class Java.java.html
  15. 0 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main class Kotlin.kt.ft
  16. 14 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main class Kotlin.kt.html
  17. 1 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main service.txt.ft
  18. 14 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main service.txt.html
  19. 0 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin settings.gradle.kts.ft
  20. 14 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin settings.gradle.kts.html
  21. 5 9
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/RunTerminal.kt.ft
  22. 14 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/RunTerminal.kt.html
  23. 11 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/RunTerminal.run.xml.ft
  24. 14 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/RunTerminal.run.xml.html
  25. 2 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/account.properties.ft
  26. 14 0
      mirai-console/tools/intellij-plugin/resources/fileTemplates/code/account.properties.html
  27. 0 14
      mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/.gitignore.html
  28. 0 14
      mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Gradle gradle.properties.html
  29. 0 14
      mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin build.gradle.html
  30. 0 14
      mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin build.gradle.kts.html
  31. 0 14
      mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin main class Java.java.html
  32. 0 14
      mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin main class Kotlin.kt.html
  33. 0 14
      mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin settings.gradle.kts.html
  34. 0 14
      mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/RunTerminal.kt.html
  35. 39 0
      mirai-console/tools/intellij-plugin/resources/messages/MiraiProjectWizardBundle.properties
  36. 39 0
      mirai-console/tools/intellij-plugin/resources/messages/MiraiProjectWizardBundle_zh.properties
  37. 8 4
      mirai-console/tools/intellij-plugin/src/assets/Assets.kt
  38. 6 4
      mirai-console/tools/intellij-plugin/src/assets/FileTemplateRegistrar.kt
  39. 0 121
      mirai-console/tools/intellij-plugin/src/creator/MiraiModuleBuilder.kt
  40. 0 121
      mirai-console/tools/intellij-plugin/src/creator/MiraiProjectModel.kt
  41. 0 113
      mirai-console/tools/intellij-plugin/src/creator/build/ProjectCreator.kt
  42. 0 111
      mirai-console/tools/intellij-plugin/src/creator/steps/BuildSystemStep.form
  43. 0 80
      mirai-console/tools/intellij-plugin/src/creator/steps/BuildSystemStep.kt
  44. 0 38
      mirai-console/tools/intellij-plugin/src/creator/steps/BuildSystemType.kt
  45. 0 12
      mirai-console/tools/intellij-plugin/src/creator/steps/OptionsStep.form
  46. 0 26
      mirai-console/tools/intellij-plugin/src/creator/steps/OptionsStep.kt
  47. 0 215
      mirai-console/tools/intellij-plugin/src/creator/steps/PluginCoordinatesStep.form
  48. 0 148
      mirai-console/tools/intellij-plugin/src/creator/steps/PluginCoordinatesStep.kt
  49. 0 129
      mirai-console/tools/intellij-plugin/src/creator/steps/ValidationUtil.kt
  50. 0 68
      mirai-console/tools/intellij-plugin/src/creator/tasks/CreateProjectTask.kt
  51. 7 6
      mirai-console/tools/intellij-plugin/src/diagnostics/PluginMainServiceNotConfiguredInspection.kt
  52. 3 3
      mirai-console/tools/intellij-plugin/src/diagnostics/ResourceNotClosedInspection.kt
  53. 1 65
      mirai-console/tools/intellij-plugin/src/diagnostics/TaskUtils.kt
  54. 2 2
      mirai-console/tools/intellij-plugin/src/diagnostics/UsingStringPlusMessageInspection.kt
  55. 5 5
      mirai-console/tools/intellij-plugin/src/diagnostics/diagnosticsUtil.kt
  56. 3 3
      mirai-console/tools/intellij-plugin/src/diagnostics/fix/ConfigurePluginMainServiceFix.kt
  57. 1 1
      mirai-console/tools/intellij-plugin/src/resolve/FunctionSignature.kt
  58. 10 10
      mirai-console/tools/intellij-plugin/src/resolve/resolveIdea.kt
  59. 27 0
      mirai-console/tools/intellij-plugin/src/wizard/BuildSystemType.kt
  60. 9 12
      mirai-console/tools/intellij-plugin/src/wizard/LanguageType.kt
  61. 139 0
      mirai-console/tools/intellij-plugin/src/wizard/MiraiModuleBuilder.kt
  62. 8 8
      mirai-console/tools/intellij-plugin/src/wizard/MiraiModuleType.kt
  63. 56 0
      mirai-console/tools/intellij-plugin/src/wizard/MiraiProjectModel.kt
  64. 264 0
      mirai-console/tools/intellij-plugin/src/wizard/MiraiProjectWizardInitialStep.kt
  65. 115 0
      mirai-console/tools/intellij-plugin/src/wizard/MiraiValidations.kt
  66. 2 2
      mirai-console/tools/intellij-plugin/src/wizard/MiraiVersion.kt
  67. 31 0
      mirai-console/tools/intellij-plugin/src/wizard/MiraiWizardBundle.kt
  68. 82 0
      mirai-console/tools/intellij-plugin/src/wizard/ProjectAssetsProvider.kt
  69. 1 1
      mirai-console/tools/intellij-plugin/test/creator/MiraiVersionKindTest.kt
  70. 8 4
      mirai-console/tools/intellij-plugin/test/creator/tasks/TaskUtilsKtTest.kt

+ 4 - 4
buildSrc/src/main/kotlin/Versions.kt

@@ -19,14 +19,14 @@ object Versions {
 
     val core = project
     val console = project
-    val consoleIntellij = "213-$project-160-1" // idea-mirai-kotlin-patch
+    val consoleIntellij = "221-$project-162-1" // idea-mirai-kotlin-patch
     val consoleTerminal = project
 
     const val kotlinCompiler = "1.6.0"
     const val kotlinStdlib = kotlinCompiler
     const val dokka = "1.6.0"
 
-    const val kotlinCompilerForIdeaPlugin = "1.6.20-M1"
+    const val kotlinCompilerForIdeaPlugin = "1.6.20"
 
     const val coroutines = "1.6.0"
     const val atomicFU = "0.17.0"
@@ -61,10 +61,10 @@ object Versions {
     // If you the versions below, you need to sync changes to mirai-console/buildSrc/src/main/kotlin/Versions.kt
 
     const val yamlkt = "0.10.2"
-    const val intellijGradlePlugin = "1.3.0"
+    const val intellijGradlePlugin = "1.5.3"
 
     //    const val kotlinIntellijPlugin = "211-1.5.20-release-284-IJ7442.40" // keep to newest as kotlinCompiler
-    const val intellij = "2021.3.2" // don't update easily unless you want your disk space -= 500MB
+    const val intellij = "2022.1" // don't update easily unless you want your disk space -= 500MB
 
 }
 

+ 2 - 2
mirai-console/tools/intellij-plugin/build.gradle.kts

@@ -71,8 +71,8 @@ kotlin.target.compilations.all {
 
 // https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library
 tasks.withType<org.jetbrains.intellij.tasks.PatchPluginXmlTask> {
-    sinceBuild.set("212.*")
-    untilBuild.set("225.*")
+    sinceBuild.set("221.0")
+    untilBuild.set("221.999999")
     pluginDescription.set(
         """
         Plugin development support for <a href='https://github.com/mamoe/mirai'>Mirai Console</a>

+ 7 - 7
mirai-console/tools/intellij-plugin/resources/META-INF/plugin.xml

@@ -1,10 +1,10 @@
 <!--
-  ~ Copyright 2019-2021 Mamoe Technologies and contributors.
+  ~ Copyright 2019-2022 Mamoe Technologies and contributors.
   ~
-  ~  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
-  ~  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+  ~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+  ~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
   ~
-  ~  https://github.com/mamoe/mirai/blob/master/LICENSE
+  ~ https://github.com/mamoe/mirai/blob/dev/LICENSE
   -->
 
 <idea-plugin>
@@ -25,9 +25,9 @@
     <depends>com.intellij.gradle</depends>
 
     <extensions defaultExtensionNs="com.intellij">
-        <moduleType id="MIRAI_MODULE_TYPE"
-                    implementationClass="net.mamoe.mirai.console.intellij.creator.MiraiModuleType"/>
-        <moduleBuilder id="MIRAI_MODULE" builderClass="net.mamoe.mirai.console.intellij.creator.MiraiModuleBuilder"/>
+        <moduleType id="MIRAI_CONSOLE_PLUGIN_MODULE"
+                    implementationClass="net.mamoe.mirai.console.intellij.wizard.MiraiModuleType"/>
+        <moduleBuilder id="MIRAI_MODULE" builderClass="net.mamoe.mirai.console.intellij.wizard.MiraiModuleBuilder"/>
 
         <fileTemplateGroup implementation="net.mamoe.mirai.console.intellij.assets.FileTemplateRegistrar"/>
         <codeInsight.lineMarkerProvider language="JAVA"

+ 0 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/.gitignore.ft → mirai-console/tools/intellij-plugin/resources/fileTemplates/code/.gitignore.ft


+ 14 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/.gitignore.html

@@ -0,0 +1,14 @@
+<!--
+  ~ Copyright 2019-2022 Mamoe Technologies and contributors.
+  ~
+  ~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+  ~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+  ~
+  ~ https://github.com/mamoe/mirai/blob/dev/LICENSE
+  -->
+
+<html>
+<body>
+<p>This is a built-in file template used to create a new .gitignore for Gradle projects.</p>
+</body>
+</html>

+ 0 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Gradle gradle.properties.ft → mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Gradle gradle.properties.ft


+ 14 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Gradle gradle.properties.html

@@ -0,0 +1,14 @@
+<!--
+  ~ Copyright 2019-2022 Mamoe Technologies and contributors.
+  ~
+  ~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+  ~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+  ~
+  ~ https://github.com/mamoe/mirai/blob/dev/LICENSE
+  -->
+
+<html>
+<body>
+<p>This is a built-in file template used to create a new gradle.properties for Mirai Console Plugin projects.</p>
+</body>
+</html>

+ 0 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin build.gradle.ft → mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin build.gradle.ft


+ 14 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin build.gradle.html

@@ -0,0 +1,14 @@
+<!--
+  ~ Copyright 2019-2022 Mamoe Technologies and contributors.
+  ~
+  ~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+  ~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+  ~
+  ~ https://github.com/mamoe/mirai/blob/dev/LICENSE
+  -->
+
+<html>
+<body>
+<p>This is a built-in file template used to create a new build.gradle for Mirai Console Plugin projects.</p>
+</body>
+</html>

+ 0 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin build.gradle.kts.ft → mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin build.gradle.kts.ft


+ 14 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin build.gradle.kts.html

@@ -0,0 +1,14 @@
+<!--
+  ~ Copyright 2019-2022 Mamoe Technologies and contributors.
+  ~
+  ~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+  ~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+  ~
+  ~ https://github.com/mamoe/mirai/blob/dev/LICENSE
+  -->
+
+<html>
+<body>
+<p>This is a built-in file template used to create a new build.gradle.kts for Mirai Console Plugin projects.</p>
+</body>
+</html>

+ 0 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin main class Java.java.ft → mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main class Java.java.ft


+ 0 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin main class Java.java.ft.back → mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main class Java.java.ft.back


+ 14 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main class Java.java.html

@@ -0,0 +1,14 @@
+<!--
+  ~ Copyright 2019-2022 Mamoe Technologies and contributors.
+  ~
+  ~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+  ~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+  ~
+  ~ https://github.com/mamoe/mirai/blob/dev/LICENSE
+  -->
+
+<html>
+<body>
+<p>This is a built-in file template used to create a new plugin main class for Mirai Console Plugin projects.</p>
+</body>
+</html>

+ 0 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin main class Kotlin.kt.ft → mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main class Kotlin.kt.ft


+ 14 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main class Kotlin.kt.html

@@ -0,0 +1,14 @@
+<!--
+  ~ Copyright 2019-2022 Mamoe Technologies and contributors.
+  ~
+  ~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+  ~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+  ~
+  ~ https://github.com/mamoe/mirai/blob/dev/LICENSE
+  -->
+
+<html>
+<body>
+<p>This is a built-in file template used to create a new plugin main class for Mirai Console Plugin projects.</p>
+</body>
+</html>

+ 1 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main service.txt.ft

@@ -0,0 +1 @@
+${PACKAGE_NAME}.${CLASS_NAME}

+ 14 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin main service.txt.html

@@ -0,0 +1,14 @@
+<!--
+  ~ Copyright 2019-2022 Mamoe Technologies and contributors.
+  ~
+  ~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+  ~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+  ~
+  ~ https://github.com/mamoe/mirai/blob/dev/LICENSE
+  -->
+
+<html>
+<body>
+<p>This is a built-in file template used to create a new plugin main class for Mirai Console Plugin projects.</p>
+</body>
+</html>

+ 0 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin settings.gradle.kts.ft → mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin settings.gradle.kts.ft


+ 14 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/Plugin settings.gradle.kts.html

@@ -0,0 +1,14 @@
+<!--
+  ~ Copyright 2019-2022 Mamoe Technologies and contributors.
+  ~
+  ~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+  ~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+  ~
+  ~ https://github.com/mamoe/mirai/blob/dev/LICENSE
+  -->
+
+<html>
+<body>
+<p>This is a built-in file template used to create a new settings.gradle.kts for Mirai Console Plugin projects.</p>
+</body>
+</html>

+ 5 - 9
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/RunTerminal.kt.ft → mirai-console/tools/intellij-plugin/resources/fileTemplates/code/RunTerminal.kt.ft

@@ -1,20 +1,14 @@
 package $PACKAGE_NAME
 
-import java.io.File
 import net.mamoe.mirai.alsoLogin
 import net.mamoe.mirai.console.MiraiConsole
 import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.enable
 import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.load
 import net.mamoe.mirai.console.terminal.MiraiConsoleTerminalLoader
-
-fun setupWorkingDir() {
-    // see: net.mamoe.mirai.console.terminal.MiraiConsoleImplementationTerminal
-    System.setProperty("user.dir", File("debug-sandbox").absolutePath)
-}
+import java.io.File
+import java.util.Properties
 
 suspend fun main() {
-    setupWorkingDir()
-
     MiraiConsoleTerminalLoader.startAsDaemon()
 
     val pluginInstance = ${CLASS_NAME}#if (${LANGUAGE_TYPE} != "Kotlin").INSTANCE #end
@@ -23,7 +17,9 @@ suspend fun main() {
     pluginInstance.load() // 主动加载插件, Console 会调用 ${CLASS_NAME}.onLoad
     pluginInstance.enable() // 主动启用插件, Console 会调用 ${CLASS_NAME}.onEnable
 
-    val bot = MiraiConsole.addBot(123456, "").alsoLogin() // 登录一个测试环境的 Bot
+    val properties = Properties().apply { File("account.properties").inputStream().use { load(it) } }
+
+    val bot = MiraiConsole.addBot(properties.getProperty("id").toLong(), properties.getProperty("password")).alsoLogin() // 登录一个测试环境的 Bot
 
     MiraiConsole.job.join()
 }

+ 14 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/RunTerminal.kt.html

@@ -0,0 +1,14 @@
+<!--
+  ~ Copyright 2019-2022 Mamoe Technologies and contributors.
+  ~
+  ~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+  ~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+  ~
+  ~ https://github.com/mamoe/mirai/blob/dev/LICENSE
+  -->
+
+<html>
+<body>
+<p>This is a built-in file template used to create a new settings.gradle.kts for Mirai Console Plugin projects.</p>
+</body>
+</html>

+ 11 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/RunTerminal.run.xml.ft

@@ -0,0 +1,11 @@
+<component name="ProjectRunConfigurationManager">
+    <configuration default="false" name="RunTerminal" type="JetRunConfigurationType" nameIsGenerated="false">
+        <option name="MAIN_CLASS_NAME" value="${PACKAGE_NAME}.RunTerminalKt"/>
+        <module name="${MODULE_NAME}.test"/>
+        <shortenClasspath name="NONE"/>
+        <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/debug-sandbox"/>
+        <method v="2">
+            <option name="Make" enabled="true"/>
+        </method>
+    </configuration>
+</component>

+ 14 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/RunTerminal.run.xml.html

@@ -0,0 +1,14 @@
+<!--
+  ~ Copyright 2019-2022 Mamoe Technologies and contributors.
+  ~
+  ~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+  ~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+  ~
+  ~ https://github.com/mamoe/mirai/blob/dev/LICENSE
+  -->
+
+<html>
+<body>
+<p>This is a built-in file template used to create a new settings.gradle.kts for Mirai Console Plugin projects.</p>
+</body>
+</html>

+ 2 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/account.properties.ft

@@ -0,0 +1,2 @@
+id=123456
+password=pwd

+ 14 - 0
mirai-console/tools/intellij-plugin/resources/fileTemplates/code/account.properties.html

@@ -0,0 +1,14 @@
+<!--
+  ~ Copyright 2019-2022 Mamoe Technologies and contributors.
+  ~
+  ~ 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+  ~ Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+  ~
+  ~ https://github.com/mamoe/mirai/blob/dev/LICENSE
+  -->
+
+<html>
+<body>
+<p>This is a built-in file template used to create a new gradle.properties for Mirai Console Plugin projects.</p>
+</body>
+</html>

+ 0 - 14
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/.gitignore.html

@@ -1,14 +0,0 @@
-<!--
-  ~ Copyright 2019-2021 Mamoe Technologies and contributors.
-  ~
-  ~  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
-  ~  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
-  ~
-  ~  https://github.com/mamoe/mirai/blob/master/LICENSE
-  -->
-
-<html>
-<body>
-<p>This is a built-in file template used to create a new .gitignore for Gradle projects.</p>
-</body>
-</html>

+ 0 - 14
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Gradle gradle.properties.html

@@ -1,14 +0,0 @@
-<!--
-  ~ Copyright 2019-2021 Mamoe Technologies and contributors.
-  ~
-  ~  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
-  ~  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
-  ~
-  ~  https://github.com/mamoe/mirai/blob/master/LICENSE
-  -->
-
-<html>
-<body>
-<p>This is a built-in file template used to create a new gradle.properties for Mirai Console Plugin projects.</p>
-</body>
-</html>

+ 0 - 14
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin build.gradle.html

@@ -1,14 +0,0 @@
-<!--
-  ~ Copyright 2019-2021 Mamoe Technologies and contributors.
-  ~
-  ~  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
-  ~  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
-  ~
-  ~  https://github.com/mamoe/mirai/blob/master/LICENSE
-  -->
-
-<html>
-<body>
-<p>This is a built-in file template used to create a new build.gradle for Mirai Console Plugin projects.</p>
-</body>
-</html>

+ 0 - 14
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin build.gradle.kts.html

@@ -1,14 +0,0 @@
-<!--
-  ~ Copyright 2019-2021 Mamoe Technologies and contributors.
-  ~
-  ~  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
-  ~  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
-  ~
-  ~  https://github.com/mamoe/mirai/blob/master/LICENSE
-  -->
-
-<html>
-<body>
-<p>This is a built-in file template used to create a new build.gradle.kts for Mirai Console Plugin projects.</p>
-</body>
-</html>

+ 0 - 14
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin main class Java.java.html

@@ -1,14 +0,0 @@
-<!--
-  ~ Copyright 2019-2021 Mamoe Technologies and contributors.
-  ~
-  ~  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
-  ~  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
-  ~
-  ~  https://github.com/mamoe/mirai/blob/master/LICENSE
-  -->
-
-<html>
-<body>
-<p>This is a built-in file template used to create a new plugin main class for Mirai Console Plugin projects.</p>
-</body>
-</html>

+ 0 - 14
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin main class Kotlin.kt.html

@@ -1,14 +0,0 @@
-<!--
-  ~ Copyright 2019-2021 Mamoe Technologies and contributors.
-  ~
-  ~  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
-  ~  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
-  ~
-  ~  https://github.com/mamoe/mirai/blob/master/LICENSE
-  -->
-
-<html>
-<body>
-<p>This is a built-in file template used to create a new plugin main class for Mirai Console Plugin projects.</p>
-</body>
-</html>

+ 0 - 14
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/Plugin settings.gradle.kts.html

@@ -1,14 +0,0 @@
-<!--
-  ~ Copyright 2019-2021 Mamoe Technologies and contributors.
-  ~
-  ~  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
-  ~  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
-  ~
-  ~  https://github.com/mamoe/mirai/blob/master/LICENSE
-  -->
-
-<html>
-<body>
-<p>This is a built-in file template used to create a new settings.gradle.kts for Mirai Console Plugin projects.</p>
-</body>
-</html>

+ 0 - 14
mirai-console/tools/intellij-plugin/resources/fileTemplates/j2ee/RunTerminal.kt.html

@@ -1,14 +0,0 @@
-<!--
-  ~ Copyright 2019-2021 Mamoe Technologies and contributors.
-  ~
-  ~  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
-  ~  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
-  ~
-  ~  https://github.com/mamoe/mirai/blob/master/LICENSE
-  -->
-
-<html>
-<body>
-<p>This is a built-in file template used to create a new settings.gradle.kts for Mirai Console Plugin projects.</p>
-</body>
-</html>

+ 39 - 0
mirai-console/tools/intellij-plugin/resources/messages/MiraiProjectWizardBundle.properties

@@ -0,0 +1,39 @@
+#
+# Copyright 2019-2022 Mamoe Technologies and contributors.
+#
+# ???????? GNU AFFERO GENERAL PUBLIC LICENSE version 3 ??????, ?????????????.
+# Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+#
+# https://github.com/mamoe/mirai/blob/dev/LICENSE
+#
+module.presentation.name=Mirai Console Plugin
+module.description="Template for building plugins for <b>Mirai Console</b>"
+title.plugin.description=Plugin Description
+label.plugin.version=Plugin Version:
+label.version.stable=Stable
+label.version.prerelease=Prerelease
+label.version.nightly=Nightly
+label.plugin.id=Plugin ID:
+label.plugin.name=Plugin Name:
+label.mirai.version.loading=Loading...
+label.mirai.version=Mirai Version:
+error.failed.to.download.mirai.version=Failed to download version list, please select a version manually
+error.please.wait.for.mirai.version=Please wait for downloading version list
+label.plugin.author=Plugin Author:
+comment.plugin.id=Should consist of English characters and/or numbers, '.', ':', '-'. Example: "net.mamoe:chat-command".
+comment.plugin.name=Example: "Chat Command".
+comment.plugin.version=Should comply <a href="https://semver.org/">Semantic Versioning</a>, not including 'v'. Example: "0.1.0".
+comment.mirai.version=Minimum version of Mirai Console this plugin requires on.
+label.plugin.dependencies=Plugin Dependencies:
+label.plugin.info=Plugin Info:
+comment.plugin.dependencies=Each dependency is in format "id:VersionRequirement" (not including quotation marks). To declare optional dependency, add "?" at the end. \
+  Example: "net.mamoe.chat-command:[1.0.0, 2.0.0)?" declares and optional dependency on "net.mamoe.chat-command", requiring its version to be greater or equal to 1.0.0 and smaller than 2.0.0. \
+  Separate multiple dependencies into liens. \
+  Syntax for "VersionRequirement" can be found at <a href="https://ant.apache.org/ivy/history/latest-milestone/settings/version-matchers.html">Apache Ivy version-matchers</a>.
+comment.plugin.info=Introductory information about this plugin.
+text.hint.plugin.info=Optional
+text.hint.plugin.dependencies=Optional
+validation.plugin.name.forbidden.character="{0}" is forbidden in plugin name
+validation.illegal.plugin.id=Invalid plugin id "{0}"
+validation.illegal.version=Invalid version.\n{0}
+no.error.message=No error message

+ 39 - 0
mirai-console/tools/intellij-plugin/resources/messages/MiraiProjectWizardBundle_zh.properties

@@ -0,0 +1,39 @@
+#
+# Copyright 2019-2022 Mamoe Technologies and contributors.
+#
+# ???????? GNU AFFERO GENERAL PUBLIC LICENSE version 3 ??????, ?????????????.
+# Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+#
+# https://github.com/mamoe/mirai/blob/dev/LICENSE
+#
+module.presentation.name=Mirai Console 插件
+module.description="构建 <b>Mirai Console</b> 插件的模板"
+title.plugin.description=插件信息
+label.plugin.version=插件版本号:
+label.version.stable=稳定版
+label.version.prerelease=预览版
+label.version.nightly=开发版
+label.plugin.id=插件 ID:
+label.plugin.name=插件名称:
+label.mirai.version.loading=加载中...
+label.mirai.version=Mirai 版本号:
+error.failed.to.download.mirai.version=下载版本列表失败, 请手动选择版本号
+error.please.wait.for.mirai.version=请等待下载版本列表
+label.plugin.author=插件作者:
+comment.plugin.id=只能包含以下内容: 英文字母, 数字, '.', ':', '-'. 示例: "net.mamoe.chat-command".
+comment.plugin.name=示例: "Chat Command".
+comment.plugin.version=需遵循 <a href="https://semver.org/">语义化版本</a>, 不包含 'v'. 示例: "0.1.0".
+comment.mirai.version=插件依赖的最低 Mirai Console 版本号
+label.plugin.dependencies=插件依赖:
+label.plugin.info=插件描述:
+comment.plugin.dependencies=每个依赖格式为 "id:版本要求" (不包括引号). 若要定义可选依赖, 请在末尾添加 "?". \
+  示例: "net.mamoe.chat-command:[1.0.0, 2.0.0)?" 定义对 "net.mamoe.chat-command" 的可选依赖, 要求其版本大于或等于 1.0.0 且小于 2.0.0. \
+  多个依赖以换行符分割. \
+  "版本要求" 语法可在 <a href="https://ant.apache.org/ivy/history/latest-milestone/settings/version-matchers.html">Apache Ivy version-matchers</a> 查看.
+comment.plugin.info=对该插件的介绍信息.
+text.hint.plugin.info=可留空
+text.hint.plugin.dependencies=可留空
+validation.plugin.name.forbidden.character=插件名称中不允许存在 "{0}"
+validation.illegal.plugin.id=插件 ID 无效: "{0}"
+validation.illegal.version=插件版本无效\n{0}
+no.error.message=无错误信息

+ 8 - 4
mirai-console/tools/intellij-plugin/src/assets/Assets.kt

@@ -1,10 +1,10 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
 package net.mamoe.mirai.console.intellij.assets
@@ -31,7 +31,11 @@ object FT { // file template
     const val PluginMainKt = "Plugin main class Kotlin.kt"
     const val PluginMainJava = "Plugin main class Java.java"
 
+    const val PluginMainService = "Plugin main service.txt"
+
     const val Gitignore = ".gitignore"
 
     const val RunTerminal = "RunTerminal.kt"
+    const val RunTerminalRun = "RunTerminal.run.xml"
+    const val AccountProperties = "account.properties"
 }

+ 6 - 4
mirai-console/tools/intellij-plugin/src/assets/FileTemplateRegistrar.kt

@@ -1,10 +1,10 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
 
@@ -21,6 +21,7 @@ class FileTemplateRegistrar : com.intellij.ide.fileTemplates.FileTemplateGroupDe
 
             addTemplate(FileTemplateDescriptor(FT.PluginMainKt))
             addTemplate(FileTemplateDescriptor(FT.PluginMainJava))
+            addTemplate(FileTemplateDescriptor(FT.PluginMainService))
 
             addTemplate(FileTemplateDescriptor(FT.GradleProperties))
 
@@ -30,6 +31,7 @@ class FileTemplateRegistrar : com.intellij.ide.fileTemplates.FileTemplateGroupDe
             addTemplate(FileTemplateDescriptor(FT.Gitignore))
 
             addTemplate(FileTemplateDescriptor(FT.RunTerminal))
+            addTemplate(FileTemplateDescriptor(FT.RunTerminalRun))
         }
     }
 

+ 0 - 121
mirai-console/tools/intellij-plugin/src/creator/MiraiModuleBuilder.kt

@@ -1,121 +0,0 @@
-/*
- * Copyright 2019-2022 Mamoe Technologies and contributors.
- *
- * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
- *
- * https://github.com/mamoe/mirai/blob/dev/LICENSE
- */
-
-
-package net.mamoe.mirai.console.intellij.creator
-
-import com.intellij.ide.util.projectWizard.JavaModuleBuilder
-import com.intellij.ide.util.projectWizard.ModuleWizardStep
-import com.intellij.ide.util.projectWizard.WizardContext
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.module.JavaModuleType
-import com.intellij.openapi.module.ModuleType
-import com.intellij.openapi.progress.ProgressManager
-import com.intellij.openapi.project.DumbAwareRunnable
-import com.intellij.openapi.project.DumbService
-import com.intellij.openapi.roots.ModifiableRootModel
-import com.intellij.openapi.roots.ui.configuration.ModulesProvider
-import com.intellij.openapi.startup.StartupManager
-import com.intellij.openapi.util.io.FileUtil
-import com.intellij.openapi.vfs.LocalFileSystem
-import com.intellij.openapi.vfs.VirtualFile
-import net.mamoe.mirai.console.intellij.assets.Icons
-import net.mamoe.mirai.console.intellij.creator.steps.BuildSystemStep
-import net.mamoe.mirai.console.intellij.creator.steps.OptionsStep
-import net.mamoe.mirai.console.intellij.creator.steps.PluginCoordinatesStep
-import net.mamoe.mirai.console.intellij.creator.tasks.CreateProjectTask
-import java.nio.file.Files
-import java.nio.file.Path
-import java.nio.file.Paths
-import java.util.concurrent.Executors
-
-class MiraiModuleBuilder : JavaModuleBuilder() {
-    override fun getPresentableName() = MiraiModuleType.NAME
-    override fun getNodeIcon() = Icons.MainIcon
-    override fun getGroupName() = MiraiModuleType.NAME
-    override fun getWeight() = BUILD_SYSTEM_WEIGHT - 1
-    override fun getBuilderId() = ID
-    override fun getModuleType(): ModuleType<*> = JavaModuleType.getModuleType()
-    override fun getParentGroup() = MiraiModuleType.NAME
-
-    override fun setupRootModel(rootModel: ModifiableRootModel) {
-        val project = rootModel.project
-        val (root, vFile) = createAndGetRoot()
-        rootModel.addContentEntry(vFile)
-
-        if (moduleJdk != null) {
-            rootModel.sdk = moduleJdk
-        } else {
-            rootModel.inheritSdk()
-        }
-
-        val r = DumbAwareRunnable {
-            ProgressManager.getInstance().run(CreateProjectTask(root, rootModel.module, model))
-        }
-
-        if (project.isDisposed) return
-
-        if (
-            ApplicationManager.getApplication().isUnitTestMode ||
-            ApplicationManager.getApplication().isHeadlessEnvironment
-        ) {
-            r.run()
-            return
-        }
-
-        if (!project.isInitialized) {
-            StartupManager.getInstance(project).registerPostStartupActivity(r)
-            return
-        }
-
-        DumbService.getInstance(project).runWhenSmart(r)
-    }
-
-    private fun createAndGetRoot(): Pair<Path, VirtualFile> {
-        val temp = contentEntryPath ?: throw IllegalStateException("Failed to get content entry path")
-
-        val pathName = FileUtil.toSystemIndependentName(temp)
-
-        val path = Paths.get(pathName)
-        Files.createDirectories(path)
-        val vFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(pathName)
-            ?: throw IllegalStateException("Failed to refresh and file file: $path")
-
-
-
-        return path to vFile
-    }
-
-    //    private val scope = CoroutineScope(SupervisorJob())
-    private val scope = Executors.newFixedThreadPool(2)
-    private val model = MiraiProjectModel.create(scope)
-
-    override fun cleanup() {
-        super.cleanup()
-        scope.shutdownNow()
-    }
-
-    override fun createWizardSteps(
-        wizardContext: WizardContext,
-        modulesProvider: ModulesProvider
-    ): Array<ModuleWizardStep> {
-        return arrayOf(
-            BuildSystemStep(model),
-            PluginCoordinatesStep(model, scope),
-        )
-    }
-
-    override fun getCustomOptionsStep(context: WizardContext?, parentDisposable: Disposable?): ModuleWizardStep =
-        OptionsStep()
-
-    companion object {
-        const val ID = "MIRAI_MODULE"
-    }
-}

+ 0 - 121
mirai-console/tools/intellij-plugin/src/creator/MiraiProjectModel.kt

@@ -1,121 +0,0 @@
-/*
- * Copyright 2019-2022 Mamoe Technologies and contributors.
- *
- * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
- *
- * https://github.com/mamoe/mirai/blob/dev/LICENSE
- */
-
-
-package net.mamoe.mirai.console.intellij.creator
-
-import net.mamoe.mirai.console.intellij.creator.steps.BuildSystemType
-import net.mamoe.mirai.console.intellij.creator.steps.LanguageType
-import net.mamoe.mirai.console.intellij.creator.tasks.adjustToClassName
-import net.mamoe.mirai.console.intellij.creator.tasks.lateinitReadWriteProperty
-import java.util.concurrent.CompletableFuture
-import java.util.concurrent.ExecutorService
-import kotlin.contracts.contract
-
-data class ProjectCoordinates(
-    val groupId: String, // already checked by pattern
-    val artifactId: String,
-    val version: String
-) {
-    val packageName: String get() = groupId
-}
-
-data class PluginCoordinates(
-    val id: String?,
-    val name: String?,
-    val author: String?,
-    val info: String?,
-    val dependsOn: String?,
-)
-
-class MiraiProjectModel private constructor() {
-    // STEP: ProjectCreator
-
-    var projectCoordinates: ProjectCoordinates? = null
-    var buildSystemType: BuildSystemType = BuildSystemType.DEFAULT
-    var languageType: LanguageType = LanguageType.DEFAULT
-
-    var miraiVersion: String? = null
-    var pluginCoordinates: PluginCoordinates? = null
-
-    var mainClassQualifiedName: String by lateinitReadWriteProperty { "$packageName.$mainClassSimpleName" }
-    var mainClassSimpleName: String by lateinitReadWriteProperty {
-        pluginCoordinates?.run {
-            name?.adjustToClassName() ?: id?.substringAfterLast('.')?.adjustToClassName()
-        } ?: "PluginMain"
-    }
-    var packageName: String by lateinitReadWriteProperty { projectCoordinates.checkNotNull("projectCoordinates").groupId }
-
-
-    var availableMiraiVersions: CompletableFuture<Set<MiraiVersion>>? = null
-    val availableMiraiVersionsOrFail get() = availableMiraiVersions.checkNotNull("availableMiraiVersions")
-
-    fun checkValuesNotNull() {
-        checkNotNull(miraiVersion) { "miraiVersion" }
-        checkNotNull(pluginCoordinates) { "pluginCoordinates" }
-        checkNotNull(projectCoordinates) { "projectCoordinates" }
-    }
-
-    companion object {
-        fun create(scope: ExecutorService): MiraiProjectModel {
-            return MiraiProjectModel().apply {
-                availableMiraiVersions = scope.async { MiraiVersionKind.getMiraiVersionList() }
-            }
-        }
-
-        fun <T> ExecutorService.async(block: () -> T): CompletableFuture<T> {
-            val future = CompletableFuture<T>()
-            submit {
-                try {
-                    future.complete(block())
-                } catch (e: Throwable) {
-                    future.completeExceptionally(e)
-                }
-            }
-            return future
-        }
-    }
-
-}
-
-val MiraiProjectModel.templateProperties: Map<String, String?>
-    get() {
-        val projectCoordinates = projectCoordinates!!
-        val pluginCoordinates = pluginCoordinates!!
-        return mapOf(
-            "KOTLIN_VERSION" to KotlinVersion.CURRENT.toString(),
-            "MIRAI_VERSION" to miraiVersion!!,
-            "GROUP_ID" to projectCoordinates.groupId,
-            "VERSION" to projectCoordinates.version,
-            "USE_PROXY_REPO" to "true",
-            "ARTIFACT_ID" to projectCoordinates.artifactId,
-
-            "PLUGIN_ID" to pluginCoordinates.id,
-            "PLUGIN_NAME" to languageType.escapeString(pluginCoordinates.name),
-            "PLUGIN_AUTHOR" to languageType.escapeString(pluginCoordinates.author),
-            "PLUGIN_INFO" to languageType.escapeRawString(pluginCoordinates.info),
-            "PLUGIN_DEPENDS_ON" to pluginCoordinates.dependsOn,
-            "PLUGIN_VERSION" to projectCoordinates.version,
-
-            "PACKAGE_NAME" to packageName,
-            "CLASS_NAME" to mainClassSimpleName,
-
-            "LANGUAGE_TYPE" to languageType.toString(),
-        )
-    }
-
-fun <T : Any> T?.checkNotNull(name: String): T {
-    contract {
-        returns() implies (this@checkNotNull != null)
-    }
-    checkNotNull(this) {
-        "$name is not yet initialized."
-    }
-    return this
-}

+ 0 - 113
mirai-console/tools/intellij-plugin/src/creator/build/ProjectCreator.kt

@@ -1,113 +0,0 @@
-/*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
- *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
- *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
- */
-
-
-package net.mamoe.mirai.console.intellij.creator.build
-
-import com.intellij.codeInsight.actions.ReformatCodeProcessor
-import com.intellij.openapi.module.Module
-import com.intellij.openapi.progress.ProgressIndicator
-import com.intellij.openapi.vfs.VfsUtil
-import com.intellij.openapi.vfs.VirtualFile
-import net.mamoe.mirai.console.intellij.assets.FT
-import net.mamoe.mirai.console.intellij.creator.MiraiProjectModel
-import net.mamoe.mirai.console.intellij.creator.tasks.getTemplate
-import net.mamoe.mirai.console.intellij.creator.tasks.invokeAndWait
-import net.mamoe.mirai.console.intellij.creator.tasks.runWriteActionAndWait
-import net.mamoe.mirai.console.intellij.creator.tasks.writeChild
-import net.mamoe.mirai.console.intellij.creator.templateProperties
-import org.jetbrains.kotlin.idea.core.util.toPsiFile
-import java.nio.file.Path
-
-sealed class ProjectCreator(
-    val module: Module,
-    val root: VirtualFile,
-    val model: MiraiProjectModel,
-) {
-    val project get() = module.project
-
-    init {
-        model.checkValuesNotNull()
-    }
-
-    protected val filesChanged = mutableListOf<Path>()
-
-    @Synchronized
-    protected fun addFileChanged(path: Path) {
-        filesChanged.add(path)
-    }
-
-    protected fun getTemplate(name: String) = project.getTemplate(name, model.templateProperties)
-
-    fun doFinish(indicator: ProgressIndicator) {
-        indicator.text2 = "Reformatting files"
-        invokeAndWait {
-            for (file in filesChanged) {
-                val psi = file.toFile().toPsiFile(project) ?: continue
-                ReformatCodeProcessor(psi, false).run()
-            }
-        }
-    }
-
-    abstract fun createProject(
-        module: Module,
-        root: VirtualFile,
-        model: MiraiProjectModel,
-    )
-}
-
-sealed class GradleProjectCreator(
-    module: Module, root: VirtualFile, model: MiraiProjectModel,
-) : ProjectCreator(module, root, model) {
-    override fun createProject(module: Module, root: VirtualFile, model: MiraiProjectModel) {
-        runWriteActionAndWait {
-            VfsUtil.createDirectoryIfMissing(root, "src/main/${model.languageType.sourceSetDirName}")
-            VfsUtil.createDirectoryIfMissing(root, "src/main/resources")
-            addFileChanged(root.writeChild(model.languageType.pluginMainClassFile(this)))
-            addFileChanged(
-                root.writeChild(
-                    "src/main/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin",
-                    model.mainClassQualifiedName
-                )
-            )
-            addFileChanged(root.writeChild(".gitignore", getTemplate(FT.Gitignore)))
-            addFileChanged(root.writeChild("gradle.properties", getTemplate(FT.GradleProperties)))
-            addFileChanged(root.writeChild("src/test/kotlin/RunTerminal.kt", getTemplate(FT.RunTerminal)))
-        }
-    }
-}
-
-
-class GradleKotlinProjectCreator(
-    module: Module, root: VirtualFile, model: MiraiProjectModel,
-) : GradleProjectCreator(
-    module, root, model,
-) {
-    override fun createProject(module: Module, root: VirtualFile, model: MiraiProjectModel) {
-        super.createProject(module, root, model)
-        runWriteActionAndWait {
-            addFileChanged(root.writeChild("build.gradle.kts", getTemplate(FT.BuildGradleKts)))
-            addFileChanged(root.writeChild("settings.gradle.kts", getTemplate(FT.SettingsGradleKts)))
-        }
-    }
-}
-
-class GradleGroovyProjectCreator(
-    module: Module, root: VirtualFile, model: MiraiProjectModel,
-) : GradleProjectCreator(
-    module, root, model,
-) {
-    override fun createProject(module: Module, root: VirtualFile, model: MiraiProjectModel) {
-        super.createProject(module, root, model)
-        runWriteActionAndWait {
-            addFileChanged(root.writeChild("build.gradle", getTemplate(FT.BuildGradle)))
-            addFileChanged(root.writeChild("settings.gradle", getTemplate(FT.SettingsGradle)))
-        }
-    }
-}

+ 0 - 111
mirai-console/tools/intellij-plugin/src/creator/steps/BuildSystemStep.form

@@ -1,111 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="net.mamoe.mirai.console.intellij.creator.steps.BuildSystemStep">
-  <grid id="27dc6" binding="panel" layout-manager="GridLayoutManager" row-count="5" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="10" vgap="10">
-    <margin top="10" left="10" bottom="10" right="10"/>
-    <constraints>
-      <xy x="20" y="20" width="589" height="400"/>
-    </constraints>
-    <properties/>
-    <border type="none" title-justification="1" title-position="3"/>
-    <children>
-      <component id="539d6" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <text value="ArtifactId:"/>
-        </properties>
-      </component>
-      <component id="f1b7a" class="javax.swing.JTextField" binding="artifactIdField">
-        <constraints>
-          <grid row="1" column="1" row-span="1" col-span="3" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
-            <preferred-size width="150" height="-1"/>
-          </grid>
-        </constraints>
-        <properties>
-          <text value="plugin"/>
-        </properties>
-      </component>
-      <component id="2c1ec" class="javax.swing.JTextField" binding="groupIdField">
-        <constraints>
-          <grid row="0" column="1" row-span="1" col-span="3" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
-            <preferred-size width="150" height="-1"/>
-          </grid>
-        </constraints>
-        <properties>
-          <text value="org.example"/>
-        </properties>
-      </component>
-      <component id="2e485" class="javax.swing.JTextField" binding="versionField">
-        <constraints>
-          <grid row="2" column="1" row-span="1" col-span="3" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
-            <preferred-size width="150" height="-1"/>
-          </grid>
-        </constraints>
-        <properties>
-          <text value="1.0-SNAPSHOT"/>
-        </properties>
-      </component>
-      <component id="6d341" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <text value="Version:"/>
-        </properties>
-      </component>
-      <vspacer id="3151a">
-        <constraints>
-          <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
-        </constraints>
-      </vspacer>
-      <hspacer id="8d42b">
-        <constraints>
-          <grid row="3" column="1" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false">
-            <preferred-size width="229" height="11"/>
-          </grid>
-        </constraints>
-      </hspacer>
-      <component id="33f22" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <text value="GroupId:"/>
-        </properties>
-      </component>
-      <component id="452df" class="javax.swing.JComboBox" binding="buildSystemBox">
-        <constraints>
-          <grid row="3" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <model/>
-          <toolTipText value="Build system"/>
-        </properties>
-      </component>
-      <component id="45fb1" class="javax.swing.JComboBox" binding="languageBox">
-        <constraints>
-          <grid row="3" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <model/>
-          <toolTipText value="Language"/>
-        </properties>
-      </component>
-      <component id="303a9" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="4" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <text value=""/>
-        </properties>
-      </component>
-    </children>
-  </grid>
-  <buttonGroups>
-    <group name="radioButtonGroup">
-      <member id="80d0b"/>
-      <member id="9d2d8"/>
-    </group>
-  </buttonGroups>
-</form>

+ 0 - 80
mirai-console/tools/intellij-plugin/src/creator/steps/BuildSystemStep.kt

@@ -1,80 +0,0 @@
-/*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
- *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
- *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
- */
-
-
-package net.mamoe.mirai.console.intellij.creator.steps
-
-import com.intellij.ide.util.projectWizard.ModuleWizardStep
-import net.mamoe.mirai.console.intellij.creator.MiraiProjectModel
-import net.mamoe.mirai.console.intellij.creator.ProjectCoordinates
-import net.mamoe.mirai.console.intellij.creator.tasks.PACKAGE_PATTERN
-import net.mamoe.mirai.console.intellij.diagnostics.ContextualParametersChecker.Companion.SEMANTIC_VERSIONING_PATTERN
-import javax.swing.JComboBox
-import javax.swing.JPanel
-import javax.swing.JTextField
-
-/**
- * @see MiraiProjectModel.projectCoordinates
- * @see MiraiProjectModel.languageType
- * @see MiraiProjectModel.buildSystemType
- */
-class BuildSystemStep(
-    private val model: MiraiProjectModel
-) : ModuleWizardStep() {
-
-    private lateinit var panel: JPanel
-
-    @field:Validation.NotBlank("Group ID")
-    @field:Validation.Pattern("Group ID", PACKAGE_PATTERN)
-    private lateinit var groupIdField: JTextField
-
-    @field:Validation.NotBlank("Artifact ID")
-    @field:Validation.Pattern("Artifact ID", PACKAGE_PATTERN)
-    private lateinit var artifactIdField: JTextField
-
-    @field:Validation.NotBlank("Version")
-    @field:Validation.Pattern("Version", SEMANTIC_VERSIONING_PATTERN)
-    private lateinit var versionField: JTextField
-
-    private lateinit var buildSystemBox: JComboBox<BuildSystemType>
-    private lateinit var languageBox: JComboBox<LanguageType>
-
-    override fun getComponent() = panel
-
-    override fun updateStep() {
-        buildSystemBox.removeAllItems()
-        buildSystemBox.isEnabled = true
-        BuildSystemType.values().forEach { buildSystemBox.addItem(it) }
-        buildSystemBox.selectedItem = BuildSystemType.DEFAULT
-        buildSystemBox.toolTipText = """
-            Gradle Kotlin DSL: build.gradle.kts <br/>
-            Gradle Groovy DSL: build.gradle
-        """.trimIndent()
-
-        languageBox.removeAllItems()
-        languageBox.isEnabled = true
-        LanguageType.values().forEach { languageBox.addItem(it) }
-        languageBox.selectedItem = LanguageType.DEFAULT
-        buildSystemBox.toolTipText = """
-            Language for main class.
-        """.trimIndent()
-    }
-
-    override fun updateDataModel() {
-        model.buildSystemType = this.buildSystemBox.selectedItem as BuildSystemType
-        model.languageType = this.languageBox.selectedItem as LanguageType
-        model.projectCoordinates = ProjectCoordinates(
-            groupId = groupIdField.text,
-            artifactId = artifactIdField.text,
-            version = versionField.text
-        )
-    }
-
-    override fun validate() = Validation.doValidation(this)
-}

+ 0 - 38
mirai-console/tools/intellij-plugin/src/creator/steps/BuildSystemType.kt

@@ -1,38 +0,0 @@
-/*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
- *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
- *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
- */
-
-package net.mamoe.mirai.console.intellij.creator.steps
-
-import com.intellij.openapi.module.Module
-import com.intellij.openapi.vfs.VirtualFile
-import net.mamoe.mirai.console.intellij.creator.MiraiProjectModel
-import net.mamoe.mirai.console.intellij.creator.build.GradleGroovyProjectCreator
-import net.mamoe.mirai.console.intellij.creator.build.GradleKotlinProjectCreator
-import net.mamoe.mirai.console.intellij.creator.build.ProjectCreator
-
-enum class BuildSystemType {
-    GradleKt {
-        override fun createBuildSystem(module: Module, root: VirtualFile, model: MiraiProjectModel): ProjectCreator =
-            GradleKotlinProjectCreator(module, root, model)
-
-        override fun toString(): String = "Gradle Kotlin DSL"
-    },
-    GradleGroovy {
-        override fun createBuildSystem(module: Module, root: VirtualFile, model: MiraiProjectModel): ProjectCreator =
-            GradleGroovyProjectCreator(module, root, model)
-
-        override fun toString(): String = "Gradle Groovy DSL"
-    }, ;
-
-    abstract fun createBuildSystem(module: Module, root: VirtualFile, model: MiraiProjectModel): ProjectCreator
-
-    companion object {
-        val DEFAULT = GradleKt
-    }
-}

+ 0 - 12
mirai-console/tools/intellij-plugin/src/creator/steps/OptionsStep.form

@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="net.mamoe.mirai.console.intellij.creator.steps.OptionsStep">
-  <grid id="27dc6" binding="panel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
-    <margin top="0" left="0" bottom="0" right="0"/>
-    <constraints>
-      <xy x="20" y="20" width="500" height="400"/>
-    </constraints>
-    <properties/>
-    <border type="none"/>
-    <children/>
-  </grid>
-</form>

+ 0 - 26
mirai-console/tools/intellij-plugin/src/creator/steps/OptionsStep.kt

@@ -1,26 +0,0 @@
-/*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
- *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
- *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
- */
-
-
-package net.mamoe.mirai.console.intellij.creator.steps
-
-import com.intellij.ide.util.projectWizard.ModuleWizardStep
-import javax.swing.JComponent
-import javax.swing.JPanel
-
-class OptionsStep : ModuleWizardStep() {
-    private lateinit var panel: JPanel
-
-    override fun getComponent(): JComponent {
-        return panel
-    }
-
-    override fun updateDataModel() {
-    }
-}

+ 0 - 215
mirai-console/tools/intellij-plugin/src/creator/steps/PluginCoordinatesStep.form

@@ -1,215 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="net.mamoe.mirai.console.intellij.creator.steps.PluginCoordinatesStep">
-  <grid id="27dc6" binding="panel" layout-manager="GridLayoutManager" row-count="11" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="10" vgap="10">
-    <margin top="10" left="10" bottom="10" right="10"/>
-    <constraints>
-      <xy x="20" y="20" width="531" height="541"/>
-    </constraints>
-    <properties/>
-    <border type="none" title-justification="1" title-position="3"/>
-    <children>
-      <vspacer id="3151a">
-        <constraints>
-          <grid row="10" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
-        </constraints>
-      </vspacer>
-      <component id="303a9" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="10" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <text value=""/>
-          <visible value="false"/>
-        </properties>
-      </component>
-      <component id="539d6" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="10" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <text value=""/>
-          <toolTipText value=""/>
-          <visible value="false"/>
-        </properties>
-      </component>
-      <component id="33f22" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="8" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="9" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <text value="Info:"/>
-          <toolTipText value="描述"/>
-        </properties>
-      </component>
-      <vspacer id="b4a73">
-        <constraints>
-          <grid row="9" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
-        </constraints>
-      </vspacer>
-      <component id="980c2" class="javax.swing.JTextArea" binding="infoArea">
-        <constraints>
-          <grid row="8" column="1" row-span="1" col-span="2" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false">
-            <preferred-size width="150" height="119"/>
-          </grid>
-        </constraints>
-        <properties>
-          <dragEnabled value="true"/>
-          <text value=""/>
-          <toolTipText value="描述, 可选"/>
-        </properties>
-      </component>
-      <component id="3ca24" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="6" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <text value="Author:"/>
-          <toolTipText value="作者"/>
-        </properties>
-      </component>
-      <component id="45051" class="javax.swing.JTextField" binding="authorField">
-        <constraints>
-          <grid row="6" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
-            <preferred-size width="150" height="-1"/>
-          </grid>
-        </constraints>
-        <properties>
-          <text value=""/>
-          <toolTipText value="作者名称, 可选"/>
-        </properties>
-      </component>
-      <component id="c6d49" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <text value="Name:"/>
-          <toolTipText value="显示名称"/>
-        </properties>
-      </component>
-      <component id="27fb6" class="javax.swing.JTextField" binding="nameField">
-        <constraints>
-          <grid row="5" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
-            <preferred-size width="150" height="-1"/>
-          </grid>
-        </constraints>
-        <properties>
-          <text value=""/>
-          <toolTipText value="显示名称, 可选"/>
-        </properties>
-      </component>
-      <component id="28e8e" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="7" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <text value="Depends on:"/>
-          <toolTipText value="依赖的插件列表"/>
-        </properties>
-      </component>
-      <component id="44e5c" class="javax.swing.JTextField" binding="dependsOnField">
-        <constraints>
-          <grid row="7" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
-            <preferred-size width="150" height="-1"/>
-          </grid>
-        </constraints>
-        <properties>
-          <enabled value="false"/>
-          <text value=""/>
-          <toolTipText value="依赖的插件列表, 还不支持编辑, 请在创建项目后修改"/>
-        </properties>
-      </component>
-      <component id="53007" class="javax.swing.JSeparator">
-        <constraints>
-          <grid row="1" column="0" row-span="1" col-span="3" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties/>
-      </component>
-      <component id="45fb1" class="javax.swing.JComboBox" binding="miraiVersionBox">
-        <constraints>
-          <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <editable value="true"/>
-          <enabled value="false"/>
-          <model>
-            <item value="Loading..."/>
-          </model>
-        </properties>
-      </component>
-      <component id="6d341" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <opaque value="true"/>
-          <text value="Mirai version:"/>
-        </properties>
-      </component>
-      <component id="452df" class="javax.swing.JComboBox" binding="miraiVersionKindBox">
-        <constraints>
-          <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <enabled value="false"/>
-          <model>
-            <item value="Stable"/>
-            <item value="Prerelease"/>
-          </model>
-          <toolTipText value="Mirai 版本类型 &lt;br/&gt; Stable: 稳定 Prerelease: -M 和 -RC 测试版" noi18n="true"/>
-        </properties>
-      </component>
-      <component id="6ddd1" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <text value="*ID:"/>
-          <toolTipText value=""/>
-        </properties>
-      </component>
-      <component id="a76eb" class="javax.swing.JTextField" binding="idField">
-        <constraints>
-          <grid row="2" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
-            <preferred-size width="150" height="-1"/>
-          </grid>
-        </constraints>
-        <properties>
-          <text value=""/>
-        </properties>
-      </component>
-      <component id="9ee7e" class="javax.swing.JTextField" binding="mainClassField">
-        <constraints>
-          <grid row="3" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
-            <preferred-size width="150" height="-1"/>
-          </grid>
-        </constraints>
-        <properties>
-          <text value=""/>
-          <toolTipText value="依赖的插件列表, 可选"/>
-        </properties>
-      </component>
-      <component id="f4c2b" class="javax.swing.JLabel">
-        <constraints>
-          <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties>
-          <text value="*Main class:"/>
-          <toolTipText value="依赖的插件列表"/>
-        </properties>
-      </component>
-      <component id="f7d3f" class="javax.swing.JSeparator">
-        <constraints>
-          <grid row="4" column="0" row-span="1" col-span="3" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
-        </constraints>
-        <properties/>
-      </component>
-    </children>
-  </grid>
-  <buttonGroups>
-    <group name="radioButtonGroup">
-      <member id="80d0b"/>
-      <member id="9d2d8"/>
-    </group>
-  </buttonGroups>
-</form>

+ 0 - 148
mirai-console/tools/intellij-plugin/src/creator/steps/PluginCoordinatesStep.kt

@@ -1,148 +0,0 @@
-/*
- * Copyright 2019-2022 Mamoe Technologies and contributors.
- *
- * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
- *
- * https://github.com/mamoe/mirai/blob/dev/LICENSE
- */
-
-
-package net.mamoe.mirai.console.intellij.creator.steps
-
-import com.intellij.ide.util.projectWizard.ModuleWizardStep
-import com.intellij.openapi.diagnostic.Logger
-import com.intellij.vcs.log.submitSafe
-import net.mamoe.mirai.console.compiler.common.CheckerConstants.PLUGIN_ID_PATTERN
-import net.mamoe.mirai.console.intellij.creator.MiraiProjectModel
-import net.mamoe.mirai.console.intellij.creator.MiraiVersionKind
-import net.mamoe.mirai.console.intellij.creator.PluginCoordinates
-import net.mamoe.mirai.console.intellij.creator.checkNotNull
-import net.mamoe.mirai.console.intellij.creator.steps.Validation.NotBlank
-import net.mamoe.mirai.console.intellij.creator.steps.Validation.Pattern
-import net.mamoe.mirai.console.intellij.creator.tasks.QUALIFIED_CLASS_NAME_PATTERN
-import net.mamoe.mirai.console.intellij.creator.tasks.adjustToClassName
-import net.mamoe.mirai.console.intellij.diagnostics.ContextualParametersChecker
-import java.awt.event.ItemEvent
-import java.awt.event.ItemListener
-import java.util.concurrent.ExecutorService
-import javax.swing.*
-
-class PluginCoordinatesStep(
-    private val model: MiraiProjectModel,
-    private val scope: ExecutorService,
-) : ModuleWizardStep() {
-
-    private lateinit var panel: JPanel
-
-    @field:NotBlank("ID")
-    @field:Pattern("ID", PLUGIN_ID_PATTERN)
-    private lateinit var idField: JTextField
-
-    @field:NotBlank("Main class")
-    @field:Pattern("Main class", QUALIFIED_CLASS_NAME_PATTERN)
-    private lateinit var mainClassField: JTextField
-    private lateinit var nameField: JTextField
-    private lateinit var authorField: JTextField
-    private lateinit var dependsOnField: JTextField
-    private lateinit var infoArea: JTextArea
-    private lateinit var miraiVersionKindBox: JComboBox<MiraiVersionKind>
-
-    @field:NotBlank("Mirai version")
-    @field:Pattern("Mirai version", ContextualParametersChecker.SEMANTIC_VERSIONING_PATTERN)
-    private lateinit var miraiVersionBox: JComboBox<String>
-
-    override fun getComponent() = panel
-
-    private val versionKindChangeListener: ItemListener = ItemListener { event ->
-        if (event.stateChange != ItemEvent.SELECTED) return@ItemListener
-
-        updateVersionItemsAsync()
-    }
-
-    override fun getPreferredFocusedComponent(): JComponent = idField
-
-    override fun updateStep() {
-        miraiVersionKindBox.removeAllItems()
-        miraiVersionKindBox.isEnabled = true
-        MiraiVersionKind.values().forEach { miraiVersionKindBox.addItem(it) }
-        miraiVersionKindBox.selectedItem = MiraiVersionKind.DEFAULT
-        miraiVersionKindBox.addItemListener(versionKindChangeListener) // when selected, change versions
-
-        miraiVersionBox.removeAllItems()
-        miraiVersionBox.addItem(VERSION_LOADING_PLACEHOLDER)
-        miraiVersionBox.selectedItem = VERSION_LOADING_PLACEHOLDER
-
-        model.availableMiraiVersionsOrFail.whenComplete { _, _ ->
-            updateVersionItemsAsync()
-        }
-
-        if (idField.text.isNullOrEmpty()) {
-            model.projectCoordinates.checkNotNull("projectCoordinates").run {
-                idField.text = "$groupId.$artifactId"
-            }
-        }
-
-        if (mainClassField.text.isNullOrEmpty()) {
-            model.projectCoordinates.checkNotNull("projectCoordinates").run {
-                mainClassField.text = "$groupId.${artifactId.adjustToClassName()}"
-            }
-        }
-    }
-
-    private fun updateVersionItemsAsync() {
-        scope.submitSafe(LOG) {
-            if (!model.availableMiraiVersionsOrFail.isDone) return@submitSafe
-            miraiVersionBox.removeAllItems()
-            val expectingKind = miraiVersionKindBox.selectedItem as? MiraiVersionKind ?: MiraiVersionKind.DEFAULT
-            kotlin.runCatching { model.availableMiraiVersionsOrFail.join() }
-                .fold(
-                    onSuccess = { versions ->
-                        versions
-                            .filter { v -> expectingKind.isThatKind(v) }
-                            .forEach { v -> miraiVersionBox.addItem(v) }
-                    },
-                    onFailure = { e ->
-                        Validation.popup(
-                            "Failed to download version list, please select a version by yourself. \nCause: ${e.cause ?: e}",
-                            miraiVersionBox
-                        )
-                    }
-                )
-
-            miraiVersionBox.isEnabled = true
-        }
-    }
-
-    override fun updateDataModel() {
-        model.pluginCoordinates = PluginCoordinates(
-            id = idField.text.trim(),
-            author = authorField.text,
-            name = nameField.text?.trim(),
-            info = infoArea.text?.trim(),
-            dependsOn = dependsOnField.text?.trim(),
-        )
-        model.miraiVersion = miraiVersionBox.selectedItem?.toString()?.trim() ?: "+"
-        model.packageName = mainClassField.text.substringBeforeLast('.')
-        model.mainClassSimpleName = mainClassField.text.substringAfterLast('.')
-        model.mainClassQualifiedName = mainClassField.text
-    }
-
-    override fun validate(): Boolean {
-        if (miraiVersionBox.selectedItem?.toString() == VERSION_LOADING_PLACEHOLDER) {
-            Validation.popup("请等待获取版本号", miraiVersionBox)
-            return false
-        }
-        if (!Validation.doValidation(this)) return false
-        if (!mainClassField.text.contains('.')) {
-            Validation.popup("Main class 需要包含包名", mainClassField)
-            return false
-        }
-        return true
-    }
-
-    companion object {
-        const val VERSION_LOADING_PLACEHOLDER = "Loading..."
-        private val LOG = Logger.getInstance(PluginCoordinatesStep::class.java)
-    }
-}

+ 0 - 129
mirai-console/tools/intellij-plugin/src/creator/steps/ValidationUtil.kt

@@ -1,129 +0,0 @@
-/*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
- *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
- *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
- */
-
-
-package net.mamoe.mirai.console.intellij.creator.steps
-
-import com.intellij.ide.util.projectWizard.ModuleWizardStep
-import com.intellij.openapi.ui.MessageType
-import com.intellij.openapi.ui.popup.Balloon
-import com.intellij.openapi.ui.popup.JBPopupFactory
-import com.intellij.ui.awt.RelativePoint
-import net.mamoe.mirai.console.compiler.common.cast
-import org.intellij.lang.annotations.Language
-import java.lang.reflect.Field
-import java.util.concurrent.ConcurrentLinkedQueue
-import javax.swing.JComponent
-import javax.swing.text.JTextComponent
-import kotlin.reflect.KClass
-import kotlin.reflect.full.createInstance
-
-
-class Validation {
-
-    annotation class WithValidator(val clazz: KClass<out Validator<WithValidator>>) {
-        companion object {
-            init {
-                registerValidator<WithValidator> { annotation, component ->
-                    val instance = annotation.clazz.objectInstance ?: annotation.clazz.createInstance()
-                    instance.validate(annotation, component)
-                }
-            }
-        }
-    }
-
-    annotation class NotBlank(val tipName: String) {
-        companion object {
-            init {
-                registerValidator<NotBlank> { annotation, component ->
-                    if (component.text.isNullOrBlank()) {
-                        report("请填写 ${annotation.tipName}")
-                    }
-                }
-            }
-        }
-    }
-
-    annotation class Pattern(val tipName: String, @Language("RegExp") val value: String) {
-        companion object {
-            init {
-                registerValidator<Pattern> { annotation, component ->
-                    if (component.text?.matches(Regex(annotation.value)) != true) {
-                        report("请正确填写 ${annotation.tipName}")
-                    }
-                }
-            }
-        }
-    }
-
-    fun interface Validator<in A : Annotation> {
-        @Throws(ValidationException::class)
-        fun ValidationContext.validate(annotation: A, component: JTextComponent)
-
-        @Throws(ValidationException::class)
-        fun validate(annotation: A, component: JTextComponent) {
-            ValidationContext.run { validate(annotation, component) }
-        }
-
-        object ValidationContext {
-            fun report(message: String): Nothing = throw ValidationException(message)
-        }
-    }
-
-    class ValidationException(message: String) : Exception(message)
-
-    companion object {
-        private data class RegisteredValidator<A : Annotation>(val type: KClass<A>, val validator: Validator<A>)
-
-        private val validators: MutableCollection<RegisteredValidator<*>> = ConcurrentLinkedQueue()
-
-        private inline fun <reified A : Annotation> registerValidator(validator: Validator<A>) {
-            validators.add(RegisteredValidator(A::class, validator))
-        }
-
-        fun popup(message: String, component: JComponent) {
-            JBPopupFactory.getInstance()
-                .createHtmlTextBalloonBuilder(message, MessageType.ERROR, null)
-                .setFadeoutTime(2000)
-                .createBalloon()
-                .show(RelativePoint.getSouthWestOf(component), Balloon.Position.below)
-        }
-
-        /**
-         * @return `true` if no error
-         */
-        fun doValidation(step: ModuleWizardStep): Boolean {
-            fun validateProperty(field: Field): Boolean {
-                field.isAccessible = true
-                val annotationsToValidate =
-                    validators.associateBy { (type: KClass<out Annotation>) ->
-                        field.annotations.find { it::class == type }
-                    }
-
-                for ((annotation, validator) in annotationsToValidate) {
-                    if (annotation == null) continue
-                    val component = field.get(step) as JTextComponent
-                    try {
-                        validator.validator.cast<Validator<Annotation>>().validate(annotation, component)
-                    } catch (e: ValidationException) {
-                        popup(e.message ?: e.toString(), component)
-                        return false // report one error only
-                    }
-                }
-                return true
-            }
-
-            var result = true
-            for (prop in step::class.java.declaredFields) {
-                if (!validateProperty(prop)) result = false
-            }
-            return result
-        }
-    }
-}

+ 0 - 68
mirai-console/tools/intellij-plugin/src/creator/tasks/CreateProjectTask.kt

@@ -1,68 +0,0 @@
-/*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
- *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
- *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
- */
-
-
-package net.mamoe.mirai.console.intellij.creator.tasks
-
-import com.intellij.ide.ui.UISettings
-import com.intellij.openapi.module.Module
-import com.intellij.openapi.progress.ProgressIndicator
-import com.intellij.openapi.progress.Task
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.vfs.VfsUtil
-import com.intellij.openapi.wm.WindowManager
-import com.intellij.openapi.wm.ex.StatusBarEx
-import net.mamoe.mirai.console.intellij.creator.MiraiProjectModel
-import org.jetbrains.kotlin.idea.util.application.invokeLater
-import org.jetbrains.plugins.gradle.service.project.open.linkAndRefreshGradleProject
-import java.nio.file.Files
-import java.nio.file.Path
-
-class CreateProjectTask(
-    private val root: Path,
-    private val module: Module,
-    private val model: MiraiProjectModel,
-) : Task.Backgroundable(module.project, "Creating project", false) {
-    override fun shouldStartInBackground() = false
-
-    override fun run(indicator: ProgressIndicator) {
-        if (module.isDisposed || project.isDisposed) return
-
-        Files.createDirectories(root)
-
-        invokeAndWait {
-            VfsUtil.markDirtyAndRefresh(false, true, true, root.vf)
-        }
-
-        val build = model.buildSystemType.createBuildSystem(module, root.vf, model)
-
-        build.createProject(module, root.vf, model)
-
-        invokeLater {
-            VfsUtil.markDirtyAndRefresh(false, true, true, root.vf)
-        }
-
-        invokeLater {
-            linkAndRefreshGradleProject(root.toAbsolutePath().toString(), project)
-            showProgress(project)
-        }
-
-        build.doFinish(indicator)
-    }
-
-}
-
-private fun showProgress(project: Project) {
-    if (!UISettings.instance.showStatusBar || UISettings.instance.presentationMode) {
-        return
-    }
-
-    val statusBar = WindowManager.getInstance().getStatusBar(project) as? StatusBarEx ?: return
-    statusBar.isProcessWindowOpen = true
-}

+ 7 - 6
mirai-console/tools/intellij-plugin/src/diagnostics/PluginMainServiceNotConfiguredInspection.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -22,12 +22,12 @@ import net.mamoe.mirai.console.intellij.diagnostics.fix.ConfigurePluginMainServi
 import net.mamoe.mirai.console.intellij.resolve.allSuperNames
 import net.mamoe.mirai.console.intellij.resolve.hasAnnotation
 import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
-import org.jetbrains.kotlin.idea.debugger.readAction
-import org.jetbrains.kotlin.idea.util.*
+import org.jetbrains.kotlin.idea.util.application.runReadAction
+import org.jetbrains.kotlin.idea.util.module
+import org.jetbrains.kotlin.idea.util.rootManager
 import org.jetbrains.kotlin.psi.KtClassOrObject
 import org.jetbrains.kotlin.psi.KtObjectDeclaration
 import org.jetbrains.kotlin.psi.classOrObjectVisitor
-import java.util.*
 
 /*
 private val bundle by lazy {
@@ -107,8 +107,9 @@ class PluginMainServiceNotConfiguredInspection : AbstractKotlinInspection() {
                 }
             }
             return@runWithCancellationCheck services.any { serviceFile ->
-                serviceFile.readAction { f ->
-                    f.inputStream.bufferedReader().use { reader -> reader.lineSequence().any { it == fqName } }
+                runReadAction {
+                    serviceFile.inputStream.bufferedReader()
+                        .use { reader -> reader.lineSequence().any { it == fqName } }
                 }
             }
         }

+ 3 - 3
mirai-console/tools/intellij-plugin/src/diagnostics/ResourceNotClosedInspection.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -16,11 +16,11 @@ import com.intellij.openapi.editor.Editor
 import com.intellij.openapi.project.Project
 import com.intellij.psi.*
 import net.mamoe.mirai.console.intellij.resolve.*
+import org.jetbrains.kotlin.idea.base.utils.fqname.getKotlinFqName
 import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
 import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
 import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
 import org.jetbrains.kotlin.idea.quickfix.KotlinCrossLanguageQuickFixAction
-import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
 import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
 import org.jetbrains.kotlin.idea.util.ImportInsertHelper
 import org.jetbrains.kotlin.name.FqName
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.nj2k.postProcessing.resolve
 import org.jetbrains.kotlin.psi.*
 import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
 import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
-import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
+import org.jetbrains.kotlin.resolve.calls.util.getCalleeExpressionIfAny
 import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
 import kotlin.contracts.contract
 

+ 1 - 65
mirai-console/tools/intellij-plugin/src/creator/tasks/TaskUtils.kt → mirai-console/tools/intellij-plugin/src/diagnostics/TaskUtils.kt

@@ -8,23 +8,14 @@
  */
 
 
-package net.mamoe.mirai.console.intellij.creator.tasks
+package net.mamoe.mirai.console.intellij.diagnostics
 
-import com.intellij.ide.fileTemplates.FileTemplateManager
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.application.ModalityState
-import com.intellij.openapi.application.runWriteAction
-import com.intellij.openapi.project.Project
 import com.intellij.openapi.vfs.LocalFileSystem
 import com.intellij.openapi.vfs.VfsUtil
 import com.intellij.openapi.vfs.VirtualFile
 import com.intellij.util.io.writeChild
-import net.mamoe.mirai.console.intellij.creator.steps.NamedFile
 import org.intellij.lang.annotations.Language
 import java.nio.file.Path
-import java.util.concurrent.atomic.AtomicReference
-import kotlin.properties.ReadWriteProperty
-import kotlin.reflect.KProperty
 
 val Path.vfOrNull: VirtualFile?
     get() = LocalFileSystem.getInstance().refreshAndFindFileByPath(this.toAbsolutePath().toString())
@@ -42,20 +33,6 @@ fun VirtualFile.resolve(relative: String): VirtualFile? = VfsUtil.findRelativeFi
     *relative.replace('\\', '/').split('/').toTypedArray()
 )
 
-fun <T> invokeAndWait(modalityState: ModalityState? = null, runnable: () -> T): T {
-    val app = ApplicationManager.getApplication()
-    if (app.isDispatchThread) return runnable()
-    return computeDelegated {
-        app.invokeAndWait({ it(runnable()) }, modalityState ?: ModalityState.defaultModalityState())
-    }
-}
-
-fun <T> runWriteActionAndWait(modalityState: ModalityState? = null, runnable: () -> T) {
-    invokeAndWait(modalityState) {
-        runWriteAction(runnable)
-    }
-}
-
 @PublishedApi
 internal inline fun <T> computeDelegated(executor: (setter: (T) -> Unit) -> Unit): T {
     var resultRef: T? = null
@@ -64,29 +41,6 @@ internal inline fun <T> computeDelegated(executor: (setter: (T) -> Unit) -> Unit
     return resultRef as T
 }
 
-fun Project.getTemplate(
-    templateName: String,
-    properties: Map<String, String?>? = null
-): String {
-    val manager = FileTemplateManager.getInstance(this)
-    val template = manager.getJ2eeTemplate(templateName)
-
-    val allProperties = manager.defaultProperties
-    properties?.let { prop -> allProperties.putAll(prop.mapValues { it.value.orEmpty() }) }
-
-    return template.getText(allProperties)
-}
-
-fun Project.getTemplate(
-    templateName: String,
-    vararg properties: Pair<String, String?>
-): String = getTemplate(templateName, properties.toMap())
-
-
-internal fun VirtualFile.writeChild(pluginMainClassFile: NamedFile): Path {
-    return writeChild(pluginMainClassFile.path, pluginMainClassFile.content)
-}
-
 internal fun VirtualFile.writeChild(path: String, content: String): Path {
     return toNioPath().writeChild(path, content)
 }
@@ -136,22 +90,4 @@ fun String.adjustToClassName(): String? {
     if (result.isValidSimpleClassName()) return result
 
     return null
-}
-
-@Suppress("RedundantNullableReturnType")
-private val UNINITIALIZED: Any? = Any()
-
-@Suppress("UNCHECKED_CAST")
-fun <T, R> lateinitReadWriteProperty(initializer: () -> R) = object : ReadWriteProperty<T, R> {
-    private var field = AtomicReference(UNINITIALIZED)
-    override fun setValue(thisRef: T, property: KProperty<*>, value: R) {
-        field.set(value)
-    }
-
-    override tailrec fun getValue(thisRef: T, property: KProperty<*>): R {
-        val v = field.get()
-        if (v !== UNINITIALIZED) return v as R
-        field.compareAndSet(UNINITIALIZED, initializer())
-        return getValue(thisRef, property)
-    }
 }

+ 2 - 2
mirai-console/tools/intellij-plugin/src/diagnostics/UsingStringPlusMessageInspection.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.psi.*
 import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
 import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForReceiver
 import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
-import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
+import org.jetbrains.kotlin.resolve.calls.util.getCalleeExpressionIfAny
 
 /*
 private val bundle by lazy {

+ 5 - 5
mirai-console/tools/intellij-plugin/src/diagnostics/diagnosticsUtil.kt

@@ -1,10 +1,10 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
 package net.mamoe.mirai.console.intellij.diagnostics
@@ -15,7 +15,7 @@ import net.mamoe.mirai.console.compiler.common.resolve.READ_ONLY_PLUGIN_DATA_FQ_
 import net.mamoe.mirai.console.intellij.resolve.getResolvedCall
 import org.jetbrains.kotlin.descriptors.CallableDescriptor
 import org.jetbrains.kotlin.diagnostics.Diagnostic
-import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
+import org.jetbrains.kotlin.idea.base.utils.fqname.getKotlinFqName
 import org.jetbrains.kotlin.idea.references.mainReference
 import org.jetbrains.kotlin.name.FqName
 import org.jetbrains.kotlin.psi.KtElement

+ 3 - 3
mirai-console/tools/intellij-plugin/src/diagnostics/fix/ConfigurePluginMainServiceFix.kt

@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
  * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -16,8 +16,8 @@ import com.intellij.openapi.project.rootManager
 import com.intellij.openapi.vfs.VfsUtil
 import com.intellij.psi.PsiElement
 import com.intellij.psi.PsiFile
-import net.mamoe.mirai.console.intellij.creator.tasks.readChildText
-import net.mamoe.mirai.console.intellij.creator.tasks.writeChild
+import net.mamoe.mirai.console.intellij.diagnostics.readChildText
+import net.mamoe.mirai.console.intellij.diagnostics.writeChild
 import org.jetbrains.kotlin.idea.core.isAndroidModule
 import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
 import org.jetbrains.kotlin.idea.quickfix.KotlinCrossLanguageQuickFixAction

+ 1 - 1
mirai-console/tools/intellij-plugin/src/resolve/FunctionSignature.kt

@@ -14,10 +14,10 @@ import com.intellij.psi.PsiModifier
 import net.mamoe.mirai.console.intellij.diagnostics.resolveReferencedType
 import org.jetbrains.kotlin.asJava.elements.KtLightMethod
 import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.idea.base.utils.fqname.getKotlinFqName
 import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
 import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getReturnTypeReference
 import org.jetbrains.kotlin.idea.refactoring.fqName.fqName
-import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
 import org.jetbrains.kotlin.name.FqName
 import org.jetbrains.kotlin.nj2k.postProcessing.type
 import org.jetbrains.kotlin.psi.KtExpression

+ 10 - 10
mirai-console/tools/intellij-plugin/src/resolve/resolveIdea.kt

@@ -1,22 +1,23 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
 package net.mamoe.mirai.console.intellij.resolve
 
 import com.intellij.openapi.project.Project
 import com.intellij.psi.*
-import net.mamoe.mirai.console.compiler.common.resolve.*
+import net.mamoe.mirai.console.compiler.common.resolve.COMPOSITE_COMMAND_SUB_COMMAND_FQ_NAME
+import net.mamoe.mirai.console.compiler.common.resolve.SIMPLE_COMMAND_HANDLER_COMMAND_FQ_NAME
+import net.mamoe.mirai.console.compiler.common.resolve.findParent
 import org.jetbrains.kotlin.descriptors.*
-import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.base.utils.fqname.getKotlinFqName
 import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
 import org.jetbrains.kotlin.idea.refactoring.fqName.fqName
-import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
 import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
 import org.jetbrains.kotlin.idea.references.resolveToDescriptors
 import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -26,10 +27,9 @@ import org.jetbrains.kotlin.nj2k.postProcessing.resolve
 import org.jetbrains.kotlin.psi.*
 import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
 import org.jetbrains.kotlin.resolve.BindingContext
-import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
-import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
-import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
 import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
+import org.jetbrains.kotlin.resolve.calls.util.getCall
+import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
 import org.jetbrains.kotlin.resolve.constants.ArrayValue
 import org.jetbrains.kotlin.resolve.constants.ConstantValue
 import org.jetbrains.kotlin.resolve.constants.StringValue

+ 27 - 0
mirai-console/tools/intellij-plugin/src/wizard/BuildSystemType.kt

@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+package net.mamoe.mirai.console.intellij.wizard
+
+enum class BuildSystemType {
+    GradleKt {
+        override fun createBuildSystem(model: MiraiProjectModel): ProjectCreator =
+            GradleKotlinProjectCreator(model)
+
+        override fun toString(): String = "Gradle Kotlin DSL"
+    },
+    GradleGroovy {
+        override fun createBuildSystem(model: MiraiProjectModel): ProjectCreator =
+            GradleGroovyProjectCreator(model)
+
+        override fun toString(): String = "Gradle Groovy DSL"
+    }, ;
+
+    abstract fun createBuildSystem(model: MiraiProjectModel): ProjectCreator
+}

+ 9 - 12
mirai-console/tools/intellij-plugin/src/creator/steps/LanguageType.kt → mirai-console/tools/intellij-plugin/src/wizard/LanguageType.kt

@@ -1,22 +1,20 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
-package net.mamoe.mirai.console.intellij.creator.steps
+package net.mamoe.mirai.console.intellij.wizard
 
+import com.intellij.ide.fileTemplates.FileTemplate
 import net.mamoe.mirai.console.intellij.assets.FT
-import net.mamoe.mirai.console.intellij.creator.build.ProjectCreator
-import net.mamoe.mirai.console.intellij.creator.tasks.getTemplate
-import net.mamoe.mirai.console.intellij.creator.templateProperties
 
 data class NamedFile(
     val path: String,
-    val content: String
+    val template: FileTemplate
 )
 
 interface ILanguageType {
@@ -37,7 +35,6 @@ sealed class LanguageType : ILanguageType {
     abstract fun <T : String?> escapeRawString(string: T): T
 
     companion object {
-        val DEFAULT = Kotlin
         fun values() = arrayOf(Kotlin, Java)
     }
 
@@ -47,7 +44,7 @@ sealed class LanguageType : ILanguageType {
         override fun pluginMainClassFile(creator: ProjectCreator): NamedFile = creator.model.run {
             return NamedFile(
                 path = "src/main/kotlin/$mainClassSimpleName.kt",
-                content = creator.project.getTemplate(FT.PluginMainKt, templateProperties)
+                template = creator.getTemplate(FT.PluginMainKt)
             )
         }
 
@@ -64,7 +61,7 @@ sealed class LanguageType : ILanguageType {
         override fun pluginMainClassFile(creator: ProjectCreator): NamedFile = creator.model.run {
             return NamedFile(
                 path = "src/main/java/${packageName.replace('.', '/')}/$mainClassSimpleName.java",
-                content = creator.project.getTemplate(FT.PluginMainJava, templateProperties)
+                template = creator.getTemplate(FT.PluginMainJava)
             )
         }
 

+ 139 - 0
mirai-console/tools/intellij-plugin/src/wizard/MiraiModuleBuilder.kt

@@ -0,0 +1,139 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+
+package net.mamoe.mirai.console.intellij.wizard
+
+import com.intellij.ide.fileTemplates.FileTemplateManager
+import com.intellij.ide.starters.local.*
+import com.intellij.ide.starters.local.wizard.StarterInitialStep
+import com.intellij.ide.starters.shared.*
+import com.intellij.ide.util.projectWizard.ModuleWizardStep
+import com.intellij.ide.util.projectWizard.WizardContext
+import com.intellij.openapi.module.Module
+import com.intellij.openapi.project.ProjectManager
+import com.intellij.openapi.roots.ui.configuration.ModulesProvider
+import com.intellij.openapi.util.Key
+import com.intellij.pom.java.LanguageLevel
+import com.intellij.util.lang.JavaVersion
+import net.mamoe.mirai.console.intellij.assets.FT
+import net.mamoe.mirai.console.intellij.assets.Icons
+
+class MiraiModuleBuilder : StarterModuleBuilder() {
+    companion object {
+        val MIRAI_PROJECT_MODEL_KEY = Key.create<MiraiProjectModel>("mirai.project.model")
+
+        val GRADLE_GROOVY_PROJECT: StarterProjectType = StarterProjectType("gradleGroovy", "Gradle Groovy DSL")
+        val GRADLE_KTS_PROJECT: StarterProjectType = StarterProjectType("gradleKts", "Gradle Kotlin DSL")
+    }
+
+    override fun getBuilderId() = "MiraiModuleBuilder"
+    override fun getPresentableName() = MiraiProjectWizardBundle.message("module.presentation.name")
+    override fun getWeight() = KOTLIN_WEIGHT - 2
+    override fun getNodeIcon() = Icons.MainIcon
+    override fun getDescription(): String = MiraiProjectWizardBundle.message("module.description")
+
+    override fun getProjectTypes(): List<StarterProjectType> = listOf(GRADLE_GROOVY_PROJECT, GRADLE_KTS_PROJECT)
+    override fun getTestFrameworks(): List<StarterTestRunner> = listOf(JUNIT_TEST_RUNNER)
+    override fun getMinJavaVersion(): JavaVersion = LanguageLevel.JDK_1_8.toJavaVersion()
+
+    override fun getStarterPack(): StarterPack {
+        return StarterPack(
+            "mirai", listOf(
+                Starter("mirai", "Mirai Console", getDependencyConfig("/starters/compose.pom"), emptyList())
+            )
+        )
+    }
+
+    override fun getLanguages(): List<StarterLanguage> = listOf(JAVA_STARTER_LANGUAGE, KOTLIN_STARTER_LANGUAGE)
+
+
+    override fun createWizardSteps(
+        wizardContext: WizardContext,
+        modulesProvider: ModulesProvider
+    ): Array<ModuleWizardStep> = emptyArray()
+
+    override fun createOptionsStep(contextProvider: StarterContextProvider): StarterInitialStep {
+        return MiraiProjectWizardInitialStep(contextProvider)
+    }
+
+    override fun setupModule(module: Module) {
+        // manually set, we do not show the second page with libraries
+        starterContext.starter = starterContext.starterPack.starters.first()
+        starterContext.starterDependencyConfig = loadDependencyConfig()[starterContext.starter?.id]
+
+        super.setupModule(module)
+    }
+
+    override fun getTemplateProperties(): Map<String, Any> {
+        val model = starterContext.getUserData(MIRAI_PROJECT_MODEL_KEY)!!
+        model.run {
+            val projectCoordinates = projectCoordinates
+            val pluginCoordinates = pluginCoordinates
+            return mapOf<String, Any>(
+                "KOTLIN_VERSION" to KotlinVersion.CURRENT.toString(),
+                "MIRAI_VERSION" to miraiVersion,
+                "GROUP_ID" to projectCoordinates.groupId,
+                "VERSION" to projectCoordinates.version,
+                "PROJECT_NAME" to starterContext,
+                "USE_PROXY_REPO" to "true",
+                "ARTIFACT_ID" to projectCoordinates.artifactId,
+                "MODULE_NAME" to projectCoordinates.moduleName,
+
+                "PLUGIN_ID" to pluginCoordinates.id,
+                "PLUGIN_NAME" to languageType.escapeString(pluginCoordinates.name),
+                "PLUGIN_AUTHOR" to languageType.escapeString(pluginCoordinates.author),
+                "PLUGIN_INFO" to languageType.escapeRawString(pluginCoordinates.info),
+                "PLUGIN_DEPENDS_ON" to pluginCoordinates.dependsOn,
+                "PLUGIN_VERSION" to projectCoordinates.version,
+
+                "PACKAGE_NAME" to packageName,
+                "CLASS_NAME" to mainClassSimpleName,
+
+                "LANGUAGE_TYPE" to languageType.toString(),
+            )
+        }
+    }
+
+    override fun getAssets(starter: Starter): List<GeneratorAsset> {
+        val ftManager = FileTemplateManager.getInstance(ProjectManager.getInstance().defaultProject)
+        val assets = mutableListOf<GeneratorAsset>()
+
+        val model = starterContext.getUserData(MIRAI_PROJECT_MODEL_KEY)!!
+
+        val standardAssetsProvider = StandardAssetsProvider()
+        assets.addAll(standardAssetsProvider.getGradlewAssets())
+
+        model.buildSystemType.createBuildSystem(model)
+            .collectAssets { assets.add(it) }
+
+        assets.add(
+            GeneratorTemplateFile(
+                "src/main/resources/META-INF/services/net.mamoe.mirai.console.plugin.jvm.JvmPlugin",
+                ftManager.getCodeTemplate(FT.PluginMainService)
+            )
+        )
+
+        assets.add(GeneratorEmptyDirectory("debug-sandbox"))
+        assets.add(GeneratorEmptyDirectory("debug-sandbox/plugins"))
+        assets.add(GeneratorEmptyDirectory("debug-sandbox/data"))
+        assets.add(GeneratorEmptyDirectory("debug-sandbox/config"))
+        assets.add(
+            GeneratorTemplateFile(
+                "debug-sandbox/account.properties",
+                ftManager.getCodeTemplate(FT.AccountProperties)
+            )
+        )
+
+        assets.add(GeneratorTemplateFile(".run/RunTerminal.run.xml", ftManager.getCodeTemplate(FT.RunTerminalRun)))
+
+        return assets
+    }
+
+}

+ 8 - 8
mirai-console/tools/intellij-plugin/src/creator/MiraiModuleType.kt → mirai-console/tools/intellij-plugin/src/wizard/MiraiModuleType.kt

@@ -1,20 +1,20 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
 
-package net.mamoe.mirai.console.intellij.creator
+package net.mamoe.mirai.console.intellij.wizard
 
-import com.intellij.openapi.module.JavaModuleType
+import com.intellij.openapi.module.ModuleType
 import com.intellij.openapi.module.ModuleTypeManager
 import net.mamoe.mirai.console.intellij.assets.Icons
 
-class MiraiModuleType : JavaModuleType() {
+class MiraiModuleType : ModuleType<MiraiModuleBuilder>("MIRAI_CONSOLE_PLUGIN_MODULE") {
     override fun createModuleBuilder() = MiraiModuleBuilder()
     override fun getIcon() = Icons.MainIcon
     override fun getNodeIcon(isOpened: Boolean) = Icons.MainIcon
@@ -23,7 +23,7 @@ class MiraiModuleType : JavaModuleType() {
         "Modules used for developing plugins for <b>Mirai Console</b>"
 
     companion object {
-        private const val ID = "MIRAI_MODULE_TYPE"
+        private const val ID = "MIRAI_CONSOLE_PLUGIN_MODULE"
         const val NAME = "Mirai"
 
         val instance: MiraiModuleType

+ 56 - 0
mirai-console/tools/intellij-plugin/src/wizard/MiraiProjectModel.kt

@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+
+package net.mamoe.mirai.console.intellij.wizard
+
+import net.mamoe.mirai.console.intellij.diagnostics.adjustToClassName
+import kotlin.contracts.contract
+
+data class ProjectCoordinates(
+    val groupId: String, // already checked by pattern
+    val artifactId: String,
+    val version: String,
+    val moduleName: String
+) {
+    val packageName: String get() = groupId
+}
+
+data class PluginCoordinates(
+    val id: String,
+    val name: String,
+    val author: String,
+    val info: String,
+    val dependsOn: String,
+)
+
+class MiraiProjectModel(
+    val projectCoordinates: ProjectCoordinates,
+    val pluginCoordinates: PluginCoordinates,
+    val miraiVersion: String,
+
+    val buildSystemType: BuildSystemType,
+    val languageType: LanguageType,
+
+
+    val mainClassSimpleName: String = pluginCoordinates.run {
+        name.adjustToClassName() ?: id.substringAfterLast('.').adjustToClassName()
+    } ?: "PluginMain",
+    val packageName: String = projectCoordinates.checkNotNull("projectCoordinates").groupId,
+)
+
+fun <T : Any> T?.checkNotNull(name: String): T {
+    contract {
+        returns() implies (this@checkNotNull != null)
+    }
+    checkNotNull(this) {
+        "$name is not yet initialized."
+    }
+    return this
+}

+ 264 - 0
mirai-console/tools/intellij-plugin/src/wizard/MiraiProjectWizardInitialStep.kt

@@ -0,0 +1,264 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+package net.mamoe.mirai.console.intellij.wizard
+
+import com.intellij.ide.starters.local.StarterContextProvider
+import com.intellij.ide.starters.local.wizard.StarterInitialStep
+import com.intellij.ide.starters.shared.JAVA_STARTER_LANGUAGE
+import com.intellij.ide.starters.shared.KOTLIN_STARTER_LANGUAGE
+import com.intellij.ide.starters.shared.ValidationFunctions
+import com.intellij.openapi.diagnostic.logger
+import com.intellij.openapi.observable.util.trim
+import com.intellij.openapi.ui.ComboBox
+import com.intellij.openapi.ui.MessageType
+import com.intellij.openapi.ui.popup.Balloon
+import com.intellij.openapi.ui.popup.JBPopupFactory
+import com.intellij.ui.SimpleTextAttributes.GRAYED_ITALIC_ATTRIBUTES
+import com.intellij.ui.awt.RelativePoint
+import com.intellij.ui.dsl.builder.*
+import net.mamoe.mirai.console.intellij.wizard.MiraiProjectWizardBundle.message
+import org.jetbrains.concurrency.Promise
+import org.jetbrains.concurrency.runAsync
+
+private val log = logger<MiraiProjectWizardInitialStep>()
+
+class MiraiProjectWizardInitialStep(contextProvider: StarterContextProvider) : StarterInitialStep(contextProvider) {
+    private val pluginVersionProperty = propertyGraph.property("0.1.0")
+    private val pluginNameProperty = propertyGraph.lazyProperty { "" }
+    private val pluginIdProperty = propertyGraph.lazyProperty { "" }
+    private val pluginAuthorProperty = propertyGraph.lazyProperty { System.getProperty("user.name") }
+    private val pluginDependenciesProperty = propertyGraph.lazyProperty { "" }
+    private val pluginInfoProperty = propertyGraph.lazyProperty { "" }
+    private val miraiVersionKindProperty = propertyGraph.property(MiraiVersionKind.Stable)
+    private val miraiVersionProperty = propertyGraph.property("0.1.0")
+
+    var pluginVersion by pluginVersionProperty.trim()
+    var pluginName by pluginNameProperty.trim()
+    var pluginId by pluginIdProperty.trim()
+    var pluginAuthor by pluginAuthorProperty.trim()
+    var pluginDependencies by pluginDependenciesProperty.trim()
+    var pluginInfo by pluginInfoProperty.trim()
+
+    var miraiVersionKind by miraiVersionKindProperty
+    var miraiVersion by miraiVersionProperty
+
+    private lateinit var miraiVersionCell: Cell<ComboBox<String>>
+
+    override fun addFieldsAfter(layout: Panel) {
+        layout.group(message("title.plugin.description")) {
+            row(message("label.plugin.id")) {
+                textField()
+                    .withSpecialValidation(
+                        ValidationFunctions.CHECK_NOT_EMPTY,
+                    )
+                    .bindText(pluginIdProperty)
+                rowComment(message("comment.plugin.id"))
+
+                pluginIdProperty.dependsOn(groupIdProperty) { "$groupId.$artifactId" }
+                pluginIdProperty.dependsOn(artifactIdProperty) { "$groupId.$artifactId" }
+            }
+
+            row(message("label.plugin.name")) {
+                textField()
+                    .withSpecialValidation(
+                        ValidationFunctions.CHECK_NOT_EMPTY,
+                        MiraiValidations.CHECK_FORBIDDEN_PLUGIN_NAME,
+                    )
+                    .bindText(pluginNameProperty)
+
+                pluginNameProperty.dependsOn(artifactIdProperty) {
+                    artifactId.adjustToPresentationName()
+                }
+
+                rowComment(message("comment.plugin.name"))
+            }
+
+            row(message("label.plugin.version")) {
+                textField()
+                    .withSpecialValidation(
+                        ValidationFunctions.CHECK_NOT_EMPTY,
+                        MiraiValidations.CHECK_ILLEGAL_VERSION_LINE
+                    )
+                    .bindText(pluginVersionProperty)
+                rowComment(message("comment.plugin.version"))
+            }
+            row(message("label.plugin.author")) {
+                textField().bindText(pluginAuthorProperty)
+            }
+            row(message("label.plugin.dependencies")) {
+                expandableTextField()
+                    .withSpecialValidation(MiraiValidations.CHECK_PLUGIN_DEPENDENCIES_SEGMENT)
+                    .bindText(pluginDependenciesProperty)
+                    .component.emptyText.setText(message("text.hint.plugin.dependencies"), GRAYED_ITALIC_ATTRIBUTES)
+                rowComment(message("comment.plugin.dependencies"))
+            }
+            row(message("label.plugin.info")) {
+                expandableTextField().bindText(pluginInfoProperty)
+                    .component.emptyText.setText(message("text.hint.plugin.info"), GRAYED_ITALIC_ATTRIBUTES)
+                rowComment(message("comment.plugin.info"))
+            }
+            row(message("label.mirai.version")) {
+                val miraiVersionKindCell = segmentedButton(MiraiVersionKind.values().toList()) { kind ->
+                    when (kind) {
+                        MiraiVersionKind.Stable -> message("label.version.stable")
+                        MiraiVersionKind.Prerelease -> message("label.version.prerelease")
+                        MiraiVersionKind.Nightly -> message("label.version.nightly")
+                    }
+                }.bind(miraiVersionKindProperty)
+
+                miraiVersionCell = comboBox(listOf<String>())
+                    .enabled(false)
+                    .bindItem(miraiVersionProperty)
+
+                miraiVersionKindProperty.afterChange {
+                    if (!miraiVersionCell.component.isEnabled) return@afterChange
+
+                    updateVersionItems(miraiVersionKindCell, miraiVersionCell)
+                }
+
+                updateVersionItems(miraiVersionKindCell, miraiVersionCell)
+                rowComment(message("comment.mirai.version"))
+            }
+        }
+
+        // Update default values
+
+        languageProperty.set(KOTLIN_STARTER_LANGUAGE)
+        projectTypeProperty.set(MiraiModuleBuilder.GRADLE_KTS_PROJECT)
+        pluginIdProperty.set("$groupId.$artifactId")
+        pluginNameProperty.set(artifactId.adjustToPresentationName())
+    }
+
+    override fun updateDataModel() {
+        super.updateDataModel()
+
+        starterContext.putUserData(
+            /* key = */ MiraiModuleBuilder.MIRAI_PROJECT_MODEL_KEY,
+            /* value = */ MiraiProjectModel(
+                projectCoordinates = ProjectCoordinates(
+                    groupId = groupId.trim(),
+                    artifactId = artifactId.trim(),
+                    version = pluginVersion.trim(),
+                    moduleName = entityName
+                ),
+                pluginCoordinates = PluginCoordinates(
+                    id = pluginId.trim(),
+                    name = pluginName.trim(),
+                    author = pluginAuthor.trim(),
+                    info = pluginInfo.trim(),
+                    dependsOn = pluginDependencies.trim()
+                ),
+                miraiVersion = miraiVersion,
+                buildSystemType = when (val projectType = projectTypeProperty.get()) {
+                    MiraiModuleBuilder.GRADLE_KTS_PROJECT -> BuildSystemType.GradleKt
+                    MiraiModuleBuilder.GRADLE_GROOVY_PROJECT -> BuildSystemType.GradleGroovy
+                    else -> error("Unsupported project type: $projectType")
+                },
+                languageType = when (val language = languageProperty.get()) {
+                    KOTLIN_STARTER_LANGUAGE -> LanguageType.Kotlin
+                    JAVA_STARTER_LANGUAGE -> LanguageType.Java
+                    else -> error("Unsupported language type: $language")
+                }
+            )
+        )
+    }
+
+    override fun validate(): Boolean {
+        if (miraiVersion == message("label.mirai.version.loading")) {
+            JBPopupFactory.getInstance()
+                .createHtmlTextBalloonBuilder(
+                    message("error.please.wait.for.mirai.version"),
+                    MessageType.WARNING, null
+                )
+                .setFadeoutTime(3000)
+                .createBalloon()
+                .show(
+                    RelativePoint.getSouthWestOf(
+                        miraiVersionCell.component
+                    ), Balloon.Position.atLeft
+                )
+            return false
+        }
+
+        return super.validate()
+    }
+
+    private fun updateVersionItems(
+        miraiVersionKindCell: SegmentedButton<MiraiVersionKind>,
+        miraiVersionCell: Cell<ComboBox<MiraiVersion>>
+    ): Promise<Set<MiraiVersion>?> {
+        miraiVersionCell.component.isEditable = false
+        miraiVersionKindCell.enabled(false) // disable the kind selector until the async operation finishes
+        miraiVersionCell.enabled(false)
+
+        miraiVersionCell.component.removeAllItems()
+        miraiVersionCell.component.addItem(message("label.mirai.version.loading"))
+
+        return runAsync {
+            try {
+                val list = MiraiVersionKind.getMiraiVersionList()
+                miraiVersionCell.component.removeAllItems()
+                list.filter { miraiVersionKind.isThatKind(it) }
+                    .forEach { v -> miraiVersionCell.component.addItem(v) }
+                list
+            } catch (e: Throwable) {
+                JBPopupFactory.getInstance()
+                    .createHtmlTextBalloonBuilder(
+                        message("error.failed.to.download.mirai.version"),
+                        MessageType.ERROR, null
+                    )
+                    .setFadeoutTime(2000)
+                    .createBalloon()
+                    .show(
+                        RelativePoint.getSouthOf(
+                            miraiVersionCell.component
+                        ), Balloon.Position.below
+                    )
+                null
+            }
+        }.onError { log.error(it) }
+            .onProcessed { versions ->
+                miraiVersionCell.component.isEditable = versions == null
+                miraiVersionKindCell.enabled(true)
+                miraiVersionCell.enabled(true)
+            }
+    }
+}
+
+private fun String.adjustToPresentationName(): String {
+    val result = buildString {
+        var doCapitalization = true
+
+        fun Char.isAllowed() = isLetterOrDigit() || this in "_- "
+
+        for (char in this@adjustToPresentationName) {
+            if (!char.isAllowed()) continue
+
+            if (doCapitalization) {
+                when {
+                    char.isLetter() -> append(char.uppercase())
+                    char == '_' -> {}
+                    char == '-' -> {}
+                    else -> append(char)
+                }
+                doCapitalization = false
+            } else {
+                if (char in "_- ") {
+                    doCapitalization = true
+                    append(' ')
+                } else {
+                    append(char)
+                }
+            }
+        }
+    }.trim()
+
+    return result
+}

+ 115 - 0
mirai-console/tools/intellij-plugin/src/wizard/MiraiValidations.kt

@@ -0,0 +1,115 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+package net.mamoe.mirai.console.intellij.wizard
+
+import com.intellij.ide.starters.shared.TextValidationFunction
+import net.mamoe.mirai.console.compiler.common.CheckerConstants
+import net.mamoe.mirai.console.intellij.util.RequirementHelper
+import net.mamoe.mirai.console.intellij.util.RequirementParser
+import net.mamoe.mirai.console.intellij.wizard.MiraiProjectWizardBundle.message
+
+object MiraiValidations {
+    val CHECK_FORBIDDEN_PLUGIN_NAME = TextValidationFunction { text ->
+        val lowercaseName = text.lowercase().trim()
+        val illegal =
+            CheckerConstants.PLUGIN_FORBIDDEN_NAMES.firstOrNull { it == lowercaseName }
+        if (illegal != null) {
+            message("validation.plugin.name.forbidden.character", illegal)
+        } else null
+    }
+
+    val CHECK_PLUGIN_ID = TextValidationFunction { text ->
+        if (!CheckerConstants.PLUGIN_ID_REGEX.matches(text.trim())) {
+            message("validation.illegal.plugin.id", text)
+        } else null
+    }
+
+    val CHECK_ILLEGAL_VERSION_LINE = TextValidationFunction { text ->
+        checkVersionLine(text)?.let {
+            message("validation.illegal.version", text, it)
+        }
+    }
+
+    val CHECK_PLUGIN_DEPENDENCIES_LINE = TextValidationFunction { text ->
+        try {
+            val trim = text.trim()
+            val dep = PluginDependency.parseFromString(trim)
+            if (!CheckerConstants.PLUGIN_ID_REGEX.matches(dep.id)) {
+                return@TextValidationFunction message("validation.illegal.plugin.id", dep.id)
+            }
+
+            dep.versionRequirement?.let { checkVersionRequirementLine(it) }?.let {
+                return@TextValidationFunction message("validation.illegal.version", it)
+            }
+
+            null // no error
+        } catch (e: IllegalArgumentException) {
+            message("validation.illegal.version", text, e.message ?: message("no.error.message"))
+        }
+    }
+
+    val CHECK_PLUGIN_DEPENDENCIES_SEGMENT = TextValidationFunction { text ->
+        text.lineSequence()
+            .map { it.trim() }
+            .filter { it.isNotEmpty() }
+            .map { CHECK_PLUGIN_DEPENDENCIES_LINE.checkText(it) }
+            .firstOrNull()
+    }
+
+    /**
+     * Check multiple lines and returns information about the first illegal one.
+     */
+    val CHECK_ILLEGAL_VERSION_SEGMENT = TextValidationFunction { text ->
+        text.lineSequence()
+            .map { it.trim() }
+            .filter { it.isNotEmpty() }
+            .mapNotNull { CHECK_ILLEGAL_VERSION_LINE.checkText(text) }
+            .firstOrNull()
+    }
+
+    private class PluginDependency @JvmOverloads constructor(
+        val id: String,
+        val versionRequirement: String? = null,
+    ) {
+        companion object {
+
+            /**
+             * Frozen version of [net.mamoe.mirai.console.plugin.description.PluginDescription.Companion.parseFromString] from `2.11.0-M2.2`.
+             */
+            @JvmStatic
+            fun parseFromString(string: String): PluginDependency {
+//                val optional = string.endsWith('?')
+                val (id, version) = string.removeSuffix("?").let { rule ->
+                    if (rule.contains(':')) {
+                        rule.substringBeforeLast(':') to rule.substringAfterLast(':')
+                    } else {
+                        rule to null
+                    }
+                }
+                return PluginDependency(id, version)
+            }
+        }
+    }
+
+    private fun checkVersionLine(version: String): String? {
+        return checkVersionRequirementLine(version) // for simplicity
+    }
+
+    private fun checkVersionRequirementLine(versionRequirement: String): String? {
+        kotlin.runCatching {
+            RequirementHelper.RequirementChecker.processLine(
+                RequirementParser.TokenReader(
+                    versionRequirement
+                )
+            )
+        }.onFailure { return it.message ?: message("no.error.message") }
+        return null
+    }
+}

+ 2 - 2
mirai-console/tools/intellij-plugin/src/creator/MiraiVersion.kt → mirai-console/tools/intellij-plugin/src/wizard/MiraiVersion.kt

@@ -8,7 +8,7 @@
  */
 
 
-package net.mamoe.mirai.console.intellij.creator
+package net.mamoe.mirai.console.intellij.wizard
 
 import com.intellij.openapi.diagnostic.Logger
 import com.intellij.util.text.SemVer
@@ -24,7 +24,7 @@ enum class MiraiVersionKind {
     },
     Prerelease {
         override fun isThatKind(version: String): Boolean =
-            version.contains("-M") || version.contains("-RC")
+            Stable.isThatKind(version) || version.contains("-M") || version.contains("-RC")
     },
     Nightly {
         override fun isThatKind(version: String): Boolean = true // version.contains("-dev")

+ 31 - 0
mirai-console/tools/intellij-plugin/src/wizard/MiraiWizardBundle.kt

@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+package net.mamoe.mirai.console.intellij.wizard
+
+import com.intellij.AbstractBundle
+import org.jetbrains.annotations.Nls
+import org.jetbrains.annotations.NonNls
+import org.jetbrains.annotations.PropertyKey
+import java.util.function.Supplier
+
+@NonNls
+private const val BUNDLE = "messages.MiraiProjectWizardBundle"
+
+object MiraiProjectWizardBundle : AbstractBundle(BUNDLE) {
+    @Nls
+    @JvmStatic
+    fun message(@NonNls @PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): String =
+        getMessage(key, *params)
+
+    @JvmStatic
+    fun messagePointer(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): Supplier<String> {
+        return getLazyMessage(key, *params)
+    }
+}

+ 82 - 0
mirai-console/tools/intellij-plugin/src/wizard/ProjectAssetsProvider.kt

@@ -0,0 +1,82 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+
+package net.mamoe.mirai.console.intellij.wizard
+
+import com.intellij.ide.fileTemplates.FileTemplate
+import com.intellij.ide.fileTemplates.FileTemplateManager
+import com.intellij.ide.starters.local.GeneratorAsset
+import com.intellij.ide.starters.local.GeneratorEmptyDirectory
+import com.intellij.ide.starters.local.GeneratorTemplateFile
+import com.intellij.openapi.project.ProjectManager
+import net.mamoe.mirai.console.intellij.assets.FT
+
+sealed class ProjectCreator(
+    val model: MiraiProjectModel,
+) {
+    private val manager get() = FileTemplateManager.getInstance(ProjectManager.getInstance().defaultProject)
+
+    fun getTemplate(name: String): FileTemplate = manager.getCodeTemplate(name)
+
+    abstract fun collectAssets(
+        collect: (GeneratorAsset) -> Unit,
+    )
+}
+
+sealed class GradleProjectCreator(
+    model: MiraiProjectModel,
+) : ProjectCreator(model) {
+    override fun collectAssets(
+        collect: (GeneratorAsset) -> Unit
+    ) {
+        collect(GeneratorEmptyDirectory("src/main/${model.languageType.sourceSetDirName}"))
+        collect(GeneratorEmptyDirectory("src/main/resources"))
+
+        collect(GeneratorTemplateFile(model.languageType.pluginMainClassFile(this)))
+
+        collect(GeneratorTemplateFile(".gitignore", getTemplate(FT.Gitignore)))
+        collect(GeneratorTemplateFile("gradle.properties", getTemplate(FT.GradleProperties)))
+        collect(GeneratorTemplateFile("src/test/kotlin/RunTerminal.kt", getTemplate(FT.RunTerminal)))
+    }
+
+}
+
+private fun GeneratorTemplateFile(targetFileName: NamedFile): GeneratorTemplateFile {
+    return GeneratorTemplateFile(targetFileName.path, targetFileName.template)
+}
+
+
+class GradleKotlinProjectCreator(
+    model: MiraiProjectModel,
+) : GradleProjectCreator(
+    model,
+) {
+    override fun collectAssets(
+        collect: (GeneratorAsset) -> Unit
+    ) {
+        super.collectAssets(collect)
+        collect(GeneratorTemplateFile("build.gradle.kts", getTemplate(FT.BuildGradleKts)))
+        collect(GeneratorTemplateFile("settings.gradle.kts", getTemplate(FT.SettingsGradleKts)))
+    }
+}
+
+class GradleGroovyProjectCreator(
+    model: MiraiProjectModel,
+) : GradleProjectCreator(
+    model,
+) {
+    override fun collectAssets(
+        collect: (GeneratorAsset) -> Unit
+    ) {
+        super.collectAssets(collect)
+        collect(GeneratorTemplateFile("build.gradle", getTemplate(FT.BuildGradle)))
+        collect(GeneratorTemplateFile("settings.gradle", getTemplate(FT.SettingsGradle)))
+    }
+}

+ 1 - 1
mirai-console/tools/intellij-plugin/test/creator/MiraiVersionKindTest.kt

@@ -8,7 +8,7 @@
  */
 package creator
 
-import net.mamoe.mirai.console.intellij.creator.sortVersionsDescending
+import net.mamoe.mirai.console.intellij.wizard.sortVersionsDescending
 import org.junit.jupiter.api.Test
 import kotlin.test.assertEquals
 

+ 8 - 4
mirai-console/tools/intellij-plugin/test/creator/tasks/TaskUtilsKtTest.kt

@@ -1,14 +1,18 @@
 /*
- * Copyright 2019-2021 Mamoe Technologies and contributors.
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
  *
- *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
- *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  *
- *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
  */
 
 package net.mamoe.mirai.console.intellij.creator.tasks
 
+import net.mamoe.mirai.console.intellij.diagnostics.adjustToClassName
+import net.mamoe.mirai.console.intellij.diagnostics.isValidPackageName
+import net.mamoe.mirai.console.intellij.diagnostics.isValidQualifiedClassName
+import net.mamoe.mirai.console.intellij.diagnostics.isValidSimpleClassName
 import org.junit.jupiter.api.Test
 import kotlin.test.assertEquals
 import kotlin.test.assertTrue