From c7e33ea8deba8460780c039500be284cf8664a62 Mon Sep 17 00:00:00 2001 From: FalsePattern Date: Wed, 9 Apr 2025 23:20:40 +0200 Subject: [PATCH] modular project configurables --- .../project/newproject/ZigNewProjectPanel.kt | 2 +- ...gurationProvider.kt => ZigConfigurable.kt} | 20 +++------ .../ZigProjectConfigurationProvider.kt | 17 ++----- .../local/LocalZigToolchainProvider.kt | 14 ++++++ .../toolchain/ui/ZigToolchainEditor.kt | 11 +++-- .../toolchain/ui/ZigToolchainListEditor.kt | 35 --------------- .../zigbrains/shared/SubConfigurable.kt | 45 +++++++++++++------ .../resources/META-INF/zigbrains-core.xml | 10 +++-- .../resources/zigbrains/Bundle.properties | 1 + 9 files changed, 71 insertions(+), 84 deletions(-) rename core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/{ZigCoreProjectConfigurationProvider.kt => ZigConfigurable.kt} (63%) diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigNewProjectPanel.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigNewProjectPanel.kt index 96eee5e2..2f0cc95e 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigNewProjectPanel.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigNewProjectPanel.kt @@ -41,7 +41,7 @@ import javax.swing.ListSelectionModel class ZigNewProjectPanel(private var handleGit: Boolean): Disposable { private val git = JBCheckBox() - val panels = ZigProjectConfigurationProvider.createNewProjectSettingsPanels().onEach { Disposer.register(this, it) } + val panels = ZigProjectConfigurationProvider.createPanels(null).onEach { Disposer.register(this, it) } private val templateList = JBList(JBList.createDefaultListModel(defaultTemplates)).apply { selectionMode = ListSelectionModel.SINGLE_SELECTION selectedIndex = 0 diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigCoreProjectConfigurationProvider.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigConfigurable.kt similarity index 63% rename from core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigCoreProjectConfigurationProvider.kt rename to core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigConfigurable.kt index 47a30bec..ba957bc4 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigCoreProjectConfigurationProvider.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigConfigurable.kt @@ -22,23 +22,15 @@ package com.falsepattern.zigbrains.project.settings -import com.falsepattern.zigbrains.project.toolchain.ui.ZigToolchainEditor +import com.falsepattern.zigbrains.ZigBrainsBundle import com.falsepattern.zigbrains.shared.SubConfigurable -import com.intellij.openapi.options.Configurable import com.intellij.openapi.project.Project +import com.intellij.openapi.util.NlsContexts -class ZigCoreProjectConfigurationProvider: ZigProjectConfigurationProvider { - override fun handleMainConfigChanged(project: Project) { +class ZigConfigurable(override val context: Project) : SubConfigurable.Adapter() { + override fun instantiate(): List> { + return ZigProjectConfigurationProvider.createPanels(context) } - override fun createConfigurable(project: Project): Configurable { - return ZigToolchainEditor.Adapter(project) - } - - override fun createNewProjectSettingsPanel(): SubConfigurable { - return ZigToolchainEditor().also { it.reset(null) } - } - - override val priority: Int - get() = 0 + override fun getDisplayName() = ZigBrainsBundle.message("settings.project.display-name") } \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectConfigurationProvider.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectConfigurationProvider.kt index 9932c3a7..29dbc1e3 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectConfigurationProvider.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectConfigurationProvider.kt @@ -24,24 +24,15 @@ package com.falsepattern.zigbrains.project.settings import com.falsepattern.zigbrains.shared.SubConfigurable import com.intellij.openapi.extensions.ExtensionPointName -import com.intellij.openapi.options.Configurable import com.intellij.openapi.project.Project interface ZigProjectConfigurationProvider { - fun handleMainConfigChanged(project: Project) - fun createConfigurable(project: Project): Configurable - fun createNewProjectSettingsPanel(): SubConfigurable? - val priority: Int + fun create(project: Project?): SubConfigurable? + val index: Int companion object { private val EXTENSION_POINT_NAME = ExtensionPointName.create("com.falsepattern.zigbrains.projectConfigProvider") - fun mainConfigChanged(project: Project) { - EXTENSION_POINT_NAME.extensionList.forEach { it.handleMainConfigChanged(project) } - } - fun createConfigurables(project: Project): List { - return EXTENSION_POINT_NAME.extensionList.sortedBy { it.priority }.map { it.createConfigurable(project) } - } - fun createNewProjectSettingsPanels(): List> { - return EXTENSION_POINT_NAME.extensionList.sortedBy { it.priority }.mapNotNull { it.createNewProjectSettingsPanel() } + fun createPanels(project: Project?): List> { + return EXTENSION_POINT_NAME.extensionList.sortedBy { it.index }.mapNotNull { it.create(project) } } } } \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/local/LocalZigToolchainProvider.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/local/LocalZigToolchainProvider.kt index 7d550c57..4b12e449 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/local/LocalZigToolchainProvider.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/local/LocalZigToolchainProvider.kt @@ -150,6 +150,20 @@ fun getSuggestedLocalToolchainPath(): Path? { return getWellKnown().getOrNull(0) } +/** + * Returns the paths to the following list of folders: + * + * 1. DATA/zig + * 2. DATA/zigup + * 3. HOME/.zig + * + * Where DATA is: + * - ~/Library on macOS + * - %LOCALAPPDATA% on Windows + * - $XDG_DATA_HOME (or ~/.local/share if not set) on other OSes + * + * and HOME is the user home path + */ private fun getWellKnown(): List { val home = System.getProperty("user.home")?.toNioPathOrNull() ?: return emptyList() val xdgDataHome = when(OS.CURRENT) { diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/ui/ZigToolchainEditor.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/ui/ZigToolchainEditor.kt index 265155dd..f21fab92 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/ui/ZigToolchainEditor.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/ui/ZigToolchainEditor.kt @@ -23,6 +23,7 @@ package com.falsepattern.zigbrains.project.toolchain.ui import com.falsepattern.zigbrains.ZigBrainsBundle +import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider import com.falsepattern.zigbrains.project.toolchain.ToolchainListChangeListener import com.falsepattern.zigbrains.project.toolchain.ZigToolchainListService import com.falsepattern.zigbrains.project.toolchain.ZigToolchainService @@ -169,9 +170,13 @@ class ZigToolchainEditor(private val isForDefaultProject: Boolean = false): SubC override val newProjectBeforeInitSelector get() = true - class Adapter(override val context: Project): SubConfigurable.Adapter() { - override fun instantiate() = ZigToolchainEditor(context.isDefault) - override fun getDisplayName() = ZigBrainsBundle.message("settings.toolchain.editor.display-name") + class Provider: ZigProjectConfigurationProvider { + override fun create(project: Project?): SubConfigurable? { + return ZigToolchainEditor(project?.isDefault ?: false).also { it.reset(project) } + } + + override val index: Int get() = 0 + } } diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/ui/ZigToolchainListEditor.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/ui/ZigToolchainListEditor.kt index 0037de9a..b2db35e1 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/ui/ZigToolchainListEditor.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/ui/ZigToolchainListEditor.kt @@ -22,57 +22,30 @@ package com.falsepattern.zigbrains.project.toolchain.ui -import com.falsepattern.zigbrains.Icons import com.falsepattern.zigbrains.ZigBrainsBundle import com.falsepattern.zigbrains.project.toolchain.ToolchainListChangeListener import com.falsepattern.zigbrains.project.toolchain.ZigToolchainListService import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain import com.falsepattern.zigbrains.project.toolchain.base.createNamedConfigurable import com.falsepattern.zigbrains.project.toolchain.base.suggestZigToolchains -import com.falsepattern.zigbrains.project.toolchain.downloader.Downloader -import com.falsepattern.zigbrains.project.toolchain.local.LocalZigToolchain import com.falsepattern.zigbrains.shared.coroutine.asContextElement import com.falsepattern.zigbrains.shared.coroutine.withEDTContext import com.falsepattern.zigbrains.shared.zigCoroutineScope -import com.intellij.icons.AllIcons import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.Presentation -import com.intellij.openapi.application.EDT -import com.intellij.openapi.components.Service -import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory import com.intellij.openapi.project.DumbAwareAction -import com.intellij.openapi.ui.DialogBuilder import com.intellij.openapi.ui.MasterDetailsComponent -import com.intellij.openapi.ui.NamedConfigurable -import com.intellij.openapi.util.Disposer -import com.intellij.openapi.util.io.toNioPathOrNull -import com.intellij.ui.DocumentAdapter -import com.intellij.ui.components.JBLabel -import com.intellij.ui.components.textFieldWithBrowseButton -import com.intellij.ui.dsl.builder.AlignX -import com.intellij.ui.dsl.builder.panel -import com.intellij.util.Consumer import com.intellij.util.IconUtil import com.intellij.util.asSafely -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import java.util.UUID import javax.swing.JComponent -import javax.swing.event.DocumentEvent import javax.swing.tree.DefaultTreeModel class ZigToolchainListEditor : MasterDetailsComponent(), ToolchainListChangeListener { private var isTreeInitialized = false private var registered: Boolean = false - private var itemSelectedListeners = ArrayList>() - - fun addItemSelectedListener(c: Consumer) { - synchronized(itemSelectedListeners) { - itemSelectedListeners.add(c) - } - } override fun createComponent(): JComponent { if (!isTreeInitialized) { @@ -102,14 +75,6 @@ class ZigToolchainListEditor : MasterDetailsComponent(), ToolchainListChangeList return listOf(add, MyDeleteAction()) } - override fun updateSelection(configurable: NamedConfigurable<*>?) { - super.updateSelection(configurable) - val uuid = configurable?.editableObject as? UUID - synchronized(itemSelectedListeners) { - itemSelectedListeners.forEach { it.consume(uuid) } - } - } - override fun onItemDeleted(item: Any?) { if (item is UUID) { ZigToolchainListService.getInstance().removeToolchain(item) diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/shared/SubConfigurable.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/shared/SubConfigurable.kt index 555292e8..99397c2a 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/shared/SubConfigurable.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/shared/SubConfigurable.kt @@ -27,6 +27,7 @@ import com.intellij.openapi.options.Configurable import com.intellij.openapi.util.Disposer import com.intellij.ui.dsl.builder.Panel import com.intellij.ui.dsl.builder.panel +import java.util.ArrayList import javax.swing.JComponent interface SubConfigurable: Disposable { @@ -38,40 +39,56 @@ interface SubConfigurable: Disposable { val newProjectBeforeInitSelector: Boolean get() = false abstract class Adapter: Configurable { - private var myConfigurable: SubConfigurable? = null + private val myConfigurables: MutableList> = ArrayList() - abstract fun instantiate(): SubConfigurable + abstract fun instantiate(): List> protected abstract val context: T override fun createComponent(): JComponent? { - if (myConfigurable != null) { - disposeUIResources() + val configurables: List> + synchronized(myConfigurables) { + if (myConfigurables.isEmpty()) { + disposeConfigurables() + } + configurables = instantiate() + configurables.forEach { it.reset(context) } + myConfigurables.clear() + myConfigurables.addAll(configurables) } - val configurable = instantiate() - configurable.reset(context) - myConfigurable = configurable return panel { - configurable.attach(this) + configurables.forEach { it.attach(this) } } } override fun isModified(): Boolean { - return myConfigurable?.isModified(context) == true + synchronized(myConfigurables) { + return myConfigurables.any { it.isModified(context) } + } } override fun apply() { - myConfigurable?.apply(context) + synchronized(myConfigurables) { + myConfigurables.forEach { it.apply(context) } + } } override fun reset() { - myConfigurable?.reset(context) + synchronized(myConfigurables) { + myConfigurables.forEach { it.reset(context) } + } } override fun disposeUIResources() { - val configurable = myConfigurable - myConfigurable = null - configurable?.let { Disposer.dispose(it) } + synchronized(myConfigurables) { + disposeConfigurables() + } super.disposeUIResources() } + + private fun disposeConfigurables() { + val configurables = ArrayList(myConfigurables) + myConfigurables.clear() + configurables.forEach { Disposer.dispose(it) } + } } } \ No newline at end of file diff --git a/core/src/main/resources/META-INF/zigbrains-core.xml b/core/src/main/resources/META-INF/zigbrains-core.xml index 2c19853c..8fca23cc 100644 --- a/core/src/main/resources/META-INF/zigbrains-core.xml +++ b/core/src/main/resources/META-INF/zigbrains-core.xml @@ -140,15 +140,17 @@ /> diff --git a/core/src/main/resources/zigbrains/Bundle.properties b/core/src/main/resources/zigbrains/Bundle.properties index 0dfb36b3..d3fe1d93 100644 --- a/core/src/main/resources/zigbrains/Bundle.properties +++ b/core/src/main/resources/zigbrains/Bundle.properties @@ -110,6 +110,7 @@ build.tool.window.status.error.general=Error while running zig build -l build.tool.window.status.no-builds=No builds currently in progress build.tool.window.status.timeout=zig build -l timed out after {0} seconds. zig=Zig +settings.project.display-name=Zig settings.toolchain.base.name.label=Name settings.toolchain.local.path.label=Toolchain location settings.toolchain.local.version.label=Detected zig version