diff --git a/src/main/kotlin/cn/xor7/xiaohei/leavesknife/activities/ProjectStartupActivity.kt b/src/main/kotlin/cn/xor7/xiaohei/leavesknife/activities/ProjectStartupActivity.kt index aeff409..2bb8422 100644 --- a/src/main/kotlin/cn/xor7/xiaohei/leavesknife/activities/ProjectStartupActivity.kt +++ b/src/main/kotlin/cn/xor7/xiaohei/leavesknife/activities/ProjectStartupActivity.kt @@ -1,34 +1,68 @@ package cn.xor7.xiaohei.leavesknife.activities +import cn.xor7.xiaohei.leavesknife.services.PatchType +import cn.xor7.xiaohei.leavesknife.services.PatchesInfo import cn.xor7.xiaohei.leavesknife.services.leavesknifeStoreService +import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.project.Project import com.intellij.openapi.project.guessProjectDir import com.intellij.openapi.startup.ProjectActivity +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import org.gradle.tooling.GradleConnector import org.gradle.tooling.model.idea.IdeaProject import java.io.File import java.nio.file.Files +import kotlin.io.path.inputStream class ProjectStartupActivity : ProjectActivity { - override suspend fun execute(project: Project) { - val store = project.leavesknifeStoreService - project.guessProjectDir()?.let { projectDir -> - if (Files.exists(store.configPath)) { - // TODO 检查配置文件合法性 合法则设置 enablePlugin 为 true + override suspend fun execute(project: Project) = with(project.leavesknifeStoreService) { + if (Files.exists(configPath)) { + configPath.inputStream().use { + properties.load(it) + try { + patchesInfo[PatchType.SERVER] = PatchesInfo( + properties.getProperty("patches.server.module")!!, + properties.getProperty("patches.server.path")!!, + properties.getProperty("patches.server.base")!! + ) + patchesInfo[PatchType.API] = PatchesInfo( + properties.getProperty("patches.api.module")!!, + properties.getProperty("patches.api.path")!!, + properties.getProperty("patches.api.base")!! + ) + patchesInfo[PatchType.GENERATED_API] = PatchesInfo( + properties.getProperty("patches.generated-api.module")!!, + properties.getProperty("patches.generated-api.path")!!, + properties.getProperty("patches.generated-api.base")!! + ) + enablePlugin = true + println(patchesInfo) + } catch (_: Exception) { + thisLogger().warn("Failed to read plugin config") + } } - GradleConnector.newConnector() - .forProjectDirectory(File(projectDir.path)) - .connect().use { connection -> - val ideaProject: IdeaProject = connection.getModel(IdeaProject::class.java) - store.modulePaths = ideaProject.modules.filter { - it.gradleProject.path != ":" - }.associateTo(mutableMapOf()) { - it.name to it.contentRoots.first().rootDirectory.absolutePath + } + scanModules(project) + if (!modulePaths.containsKey("paper-api-generator") && !enablePlugin) return + if (!enablePlugin) needConfigure = true + } + + private suspend fun scanModules(project: Project) { + withContext(Dispatchers.IO) { + project.guessProjectDir()?.let { projectDir -> + GradleConnector.newConnector() + .forProjectDirectory(File(projectDir.path)) + .connect().use { connection -> + val ideaProject: IdeaProject = connection.getModel(IdeaProject::class.java) + project.leavesknifeStoreService.modulePaths = ideaProject.modules.filter { + it.gradleProject.path != ":" + }.associateTo(mutableMapOf()) { + it.name to it.contentRoots.first().rootDirectory.absolutePath + } } - if (!store.modulePaths.containsKey("paper-api-generator") && !store.enablePlugin) return@let - if (!store.enablePlugin) store.needConfigure = true - } + } } } } \ No newline at end of file diff --git a/src/main/kotlin/cn/xor7/xiaohei/leavesknife/dialogs/PluginConfigurationDialog.kt b/src/main/kotlin/cn/xor7/xiaohei/leavesknife/dialogs/PluginConfigurationDialog.kt index c3b8a6b..e7babf2 100644 --- a/src/main/kotlin/cn/xor7/xiaohei/leavesknife/dialogs/PluginConfigurationDialog.kt +++ b/src/main/kotlin/cn/xor7/xiaohei/leavesknife/dialogs/PluginConfigurationDialog.kt @@ -13,7 +13,6 @@ import com.intellij.openapi.ui.TextFieldWithBrowseButton import com.intellij.openapi.ui.ValidationInfo import com.intellij.ui.dsl.builder.* import org.jetbrains.annotations.Nullable -import java.io.FileInputStream import java.util.* import javax.swing.DefaultComboBoxModel import javax.swing.JComponent @@ -21,7 +20,7 @@ import javax.swing.JComponent class PluginConfigurationDialog(private val project: Project) : DialogWrapper(true) { private val store = project.leavesknifeStoreService - private val baseTextFields = mutableMapOf>() + private val pathTextFields = mutableMapOf>() private val moduleComboBoxes = mutableMapOf>>() init { @@ -39,27 +38,27 @@ class PluginConfigurationDialog(private val project: Project) : DialogWrapper(tr @Suppress("DialogTitleCapitalization") private fun Panel.createPatchGroup(patchType: PatchType, name: String) { + if (!store.patchesInfo.containsKey(patchType)) { + store.patchesInfo[patchType] = PatchesInfo(getFallbackOption(patchType), "", "") + } group("$name Patches") { row(CommonBundle.message("dialog.configure.common.module")) { - val comboBoxModel = DefaultComboBoxModel(store.modulePaths.keys.toTypedArray()) - moduleComboBoxes[patchType] = comboBox(comboBoxModel).bindItem( - getter = { - if (!store.patchesInfo.containsKey(patchType)) { - store.patchesInfo[patchType] = PatchesInfo(getFallbackOption(patchType), "") + moduleComboBoxes[patchType] = + comboBox(DefaultComboBoxModel(store.modulePaths.keys.toTypedArray())).bindItem( + getter = { + store.patchesInfo[patchType]?.module ?: getFallbackOption(patchType) + }, + setter = { + store.patchesInfo[patchType]?.module = it ?: getFallbackOption(patchType) } - store.patchesInfo[patchType]?.moduleName ?: getFallbackOption(patchType) - }, - setter = { - store.patchesInfo[patchType]?.moduleName = it ?: getFallbackOption(patchType) + ).validationOnInput { component -> + validateModule(patchType, component) + }.validationOnApply { component -> + validateModule(patchType, component) } - ).validationOnInput { component -> - validateModule(patchType, component) - }.validationOnApply { component -> - validateModule(patchType, component) - } } - row(CommonBundle.message("dialog.configure.common.base")) { - baseTextFields[patchType] = textFieldWithBrowseButton( + row(CommonBundle.message("dialog.configure.common.path")) { + pathTextFields[patchType] = textFieldWithBrowseButton( browseDialogTitle = CommonBundle.message( "dialog.configure.${patchType.name.lowercase(Locale.getDefault())}.browse.title" ), @@ -68,29 +67,29 @@ class PluginConfigurationDialog(private val project: Project) : DialogWrapper(tr fileChosen = { chosenFile -> chosenFile.path } ).bindText( getter = { - store.patchesInfo[patchType]?.base ?: "" + store.patchesInfo[patchType]?.path ?: "" }, setter = { - store.patchesInfo[patchType]?.base = it + store.patchesInfo[patchType]?.path = it } ).validationOnInput { component -> - if (component.text.isEmpty()) error(CommonBundle.message("dialog.configure.common.base.error.empty")) + if (component.text.isEmpty()) error(CommonBundle.message("dialog.configure.common.path.error.empty")) else when (patchType) { PatchType.SERVER -> null PatchType.API -> - if (component.text == baseTextFields[PatchType.SERVER]?.component?.text) { - error(CommonBundle.message("dialog.configure.common.base.error.same")) + if (component.text == pathTextFields[PatchType.SERVER]?.component?.text) { + error(CommonBundle.message("dialog.configure.common.path.error.same")) } else null PatchType.GENERATED_API -> - if (component.text == baseTextFields[PatchType.SERVER]?.component?.text || - component.text == baseTextFields[PatchType.API]?.component?.text + if (component.text == pathTextFields[PatchType.SERVER]?.component?.text || + component.text == pathTextFields[PatchType.API]?.component?.text ) { - error(CommonBundle.message("dialog.configure.common.base.error.same")) + error(CommonBundle.message("dialog.configure.common.path.error.same")) } else null } }.validationOnApply { - if (it.text.isEmpty()) error(CommonBundle.message("dialog.configure.common.base.error.empty")) + if (it.text.isEmpty()) error(CommonBundle.message("dialog.configure.common.path.error.empty")) else null } } @@ -104,27 +103,27 @@ class PluginConfigurationDialog(private val project: Project) : DialogWrapper(tr needConfigure = false val configFile = configPath.toFile() if (!configFile.exists()) configFile.createNewFile() - FileInputStream(configFile).use { fileInputStream -> - with(properties) { - load(fileInputStream) - val serverPatchesInfo = patchesInfo[PatchType.SERVER]!! - setProperty("patches.server.module", serverPatchesInfo.moduleName) - setProperty("patches.server.base", serverPatchesInfo.base) - setProperty("patches.server.path", modulePaths[serverPatchesInfo.moduleName]) - val apiPatchesInfo = patchesInfo[PatchType.API]!! - setProperty("patches.api.module", apiPatchesInfo.moduleName) - setProperty("patches.api.base", apiPatchesInfo.base) - setProperty("patches.api.path", modulePaths[apiPatchesInfo.moduleName]) - val generatedApiPatchesInfo = patchesInfo[PatchType.GENERATED_API]!! - setProperty("patches.generated-api.module", generatedApiPatchesInfo.moduleName) - setProperty("patches.generated-api.base", generatedApiPatchesInfo.base) - setProperty("patches.generated-api.path", modulePaths[generatedApiPatchesInfo.moduleName]) - } - configFile.outputStream().use { fileOutputStream -> - properties.store(fileOutputStream, null) - } - project.guessProjectDir()?.refresh(true, false) + with(properties) { + val serverPatchesInfo = patchesInfo[PatchType.SERVER]!! + serverPatchesInfo.base = modulePaths[serverPatchesInfo.module]!! + setProperty("patches.server.module", serverPatchesInfo.module) + setProperty("patches.server.path", serverPatchesInfo.path) + setProperty("patches.server.base", serverPatchesInfo.base) + val apiPatchesInfo = patchesInfo[PatchType.API]!! + apiPatchesInfo.base = serverPatchesInfo.base + setProperty("patches.api.module", apiPatchesInfo.module) + setProperty("patches.api.path", apiPatchesInfo.path) + setProperty("patches.api.base", serverPatchesInfo.base) + val generatedApiPatchesInfo = patchesInfo[PatchType.GENERATED_API]!! + generatedApiPatchesInfo.base = modulePaths[generatedApiPatchesInfo.module]!! + setProperty("patches.generated-api.module", generatedApiPatchesInfo.module) + setProperty("patches.generated-api.path", generatedApiPatchesInfo.path) + setProperty("patches.generated-api.base", serverPatchesInfo.base) + } + configFile.outputStream().use { fileOutputStream -> + properties.store(fileOutputStream, null) } + project.guessProjectDir()?.refresh(true, false) } } diff --git a/src/main/kotlin/cn/xor7/xiaohei/leavesknife/services/ProjectStoreService.kt b/src/main/kotlin/cn/xor7/xiaohei/leavesknife/services/ProjectStoreService.kt index 0bfd803..c50e297 100644 --- a/src/main/kotlin/cn/xor7/xiaohei/leavesknife/services/ProjectStoreService.kt +++ b/src/main/kotlin/cn/xor7/xiaohei/leavesknife/services/ProjectStoreService.kt @@ -61,7 +61,7 @@ class ProjectStoreService(private val project: Project) { val Project.leavesknifeStoreService: ProjectStoreService get() = this.getService(ProjectStoreService::class.java) -data class PatchesInfo(var moduleName: String, var base: String) +data class PatchesInfo(var module: String, var path: String, var base: String) enum class PatchType { SERVER, API, GENERATED_API diff --git a/src/main/resources/messages/CommonBundle.properties b/src/main/resources/messages/CommonBundle.properties index eadd83d..e5b16f4 100644 --- a/src/main/resources/messages/CommonBundle.properties +++ b/src/main/resources/messages/CommonBundle.properties @@ -2,13 +2,13 @@ notification.configure.title=\u7F3A\u5931 LeavesKnife \u914D\u7F6E notification.configure.action=\u914D\u7F6E dialog.configure.title=LeavesKnife \u914D\u7F6E # suppress inspection "UnusedProperty" -dialog.configure.server.browse.title=\u9009\u62E9 Server Patches \u57FA\u76EE\u5F55 +dialog.configure.server.browse.title=\u9009\u62E9 Server Patches \u8865\u4E01\u76EE\u5F55 # suppress inspection "UnusedProperty" -dialog.configure.api.browse.title=\u9009\u62E9 API Patches \u57FA\u76EE\u5F55 +dialog.configure.api.browse.title=\u9009\u62E9 API Patches \u8865\u4E01\u76EE\u5F55 # suppress inspection "UnusedProperty" -dialog.configure.generated_api.browse.title=\u9009\u62E9 Generated API \u57FA\u76EE\u5F55 +dialog.configure.generated_api.browse.title=\u9009\u62E9 Generated API \u8865\u4E01\u76EE\u5F55 dialog.configure.common.module=\u6A21\u5757 -dialog.configure.common.base=\u57FA\u76EE\u5F55 -dialog.configure.common.base.error.empty=\u57FA\u76EE\u5F55\u4E0D\u80FD\u4E3A\u7A7A -dialog.configure.common.base.error.same=\u4E0D\u5141\u8BB8\u51FA\u73B0\u540C\u6837\u7684\u57FA\u76EE\u5F55 +dialog.configure.common.path=\u8865\u4E01\u76EE\u5F55 +dialog.configure.common.path.error.empty=\u8865\u4E01\u76EE\u5F55\u4E0D\u80FD\u4E3A\u7A7A +dialog.configure.common.path.error.same=\u4E0D\u5141\u8BB8\u51FA\u73B0\u540C\u6837\u7684\u8865\u4E01\u76EE\u5F55 dialog.configure.common.module.error.same=\u4E0D\u5141\u8BB8\u51FA\u73B0\u540C\u6837\u7684\u6A21\u5757 \ No newline at end of file