diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/ZigToolchainListService.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/ZigToolchainListService.kt index 7358067e..b599b6cb 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/ZigToolchainListService.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/ZigToolchainListService.kt @@ -26,9 +26,6 @@ import com.falsepattern.zigbrains.project.toolchain.ZigToolchainListService.MySt import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain import com.falsepattern.zigbrains.project.toolchain.base.resolve import com.falsepattern.zigbrains.project.toolchain.base.toRef -import com.falsepattern.zigbrains.shared.AccessibleStorage -import com.falsepattern.zigbrains.shared.ChangeTrackingStorage -import com.falsepattern.zigbrains.shared.IterableStorage import com.falsepattern.zigbrains.shared.UUIDMapSerializable import com.falsepattern.zigbrains.shared.UUIDStorage import com.intellij.openapi.components.* @@ -38,25 +35,20 @@ import com.intellij.openapi.components.* name = "ZigToolchainList", storages = [Storage("zigbrains.xml")] ) -class ZigToolchainListService: UUIDMapSerializable.Converting(MyState()), IZigToolchainListService { +class ZigToolchainListService: UUIDMapSerializable.Converting(MyState()) { override fun serialize(value: ZigToolchain) = value.toRef() override fun deserialize(value: ZigToolchain.Ref) = value.resolve() override fun getStorage(state: MyState) = state.toolchains override fun updateStorage(state: MyState, storage: ToolchainStorage) = state.copy(toolchains = storage) - data class MyState( - @JvmField - val toolchains: ToolchainStorage = emptyMap(), - ) + data class MyState(@JvmField val toolchains: ToolchainStorage = emptyMap()) companion object { @JvmStatic - fun getInstance(): IZigToolchainListService = service() + fun getInstance(): ZigToolchainListService = service() } } -inline val zigToolchainList: IZigToolchainListService get() = ZigToolchainListService.getInstance() - -sealed interface IZigToolchainListService: ChangeTrackingStorage, AccessibleStorage, IterableStorage +inline val zigToolchainList: ZigToolchainListService get() = ZigToolchainListService.getInstance() private typealias ToolchainStorage = UUIDStorage diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainConfigurable.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainConfigurable.kt index 0746c934..9de48994 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainConfigurable.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainConfigurable.kt @@ -22,7 +22,6 @@ package com.falsepattern.zigbrains.project.toolchain.base -import com.falsepattern.zigbrains.project.toolchain.ZigToolchainListService import com.falsepattern.zigbrains.project.toolchain.zigToolchainList import com.intellij.openapi.ui.NamedConfigurable import com.intellij.openapi.util.NlsContexts @@ -39,19 +38,21 @@ abstract class ZigToolchainConfigurable( zigToolchainList[uuid] = value field = value } - private var myView: ZigToolchainPanel? = null + private var myViews: List> = emptyList() abstract fun createPanel(): ZigToolchainPanel override fun createOptionsPanel(): JComponent? { - var view = myView - if (view == null) { - view = createPanel() - view.reset(toolchain) - myView = view + var views = myViews + if (views.isEmpty()) { + views = ArrayList>() + views.add(createPanel()) + views.addAll(createZigToolchainExtensionPanels()) + views.forEach { it.reset(toolchain) } + myViews = views } return panel { - view.attach(this) + views.forEach { it.attach(this@panel) } }.withMinimumWidth(20) } @@ -68,20 +69,20 @@ abstract class ZigToolchainConfigurable( } override fun isModified(): Boolean { - return myView?.isModified(toolchain) == true + return myViews.any { it.isModified(toolchain) } } override fun apply() { - myView?.apply(toolchain)?.let { toolchain = it } + toolchain = myViews.fold(toolchain) { tc, view -> view.apply(tc) ?: tc } } override fun reset() { - myView?.reset(toolchain) + myViews.forEach { it.reset(toolchain) } } override fun disposeUIResources() { - myView?.dispose() - myView = null + myViews.forEach { it.dispose() } + myViews = emptyList() super.disposeUIResources() } } \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainExtensionsProvider.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainExtensionsProvider.kt new file mode 100644 index 00000000..75ba7c5e --- /dev/null +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainExtensionsProvider.kt @@ -0,0 +1,38 @@ +/* + * This file is part of ZigBrains. + * + * Copyright (C) 2023-2025 FalsePattern + * All Rights Reserved + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * ZigBrains is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, only version 3 of the License. + * + * ZigBrains is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with ZigBrains. If not, see . + */ + +package com.falsepattern.zigbrains.project.toolchain.base + +import com.intellij.openapi.extensions.ExtensionPointName + +private val EXTENSION_POINT_NAME = ExtensionPointName.create("com.falsepattern.zigbrains.toolchainExtensionsProvider") + +internal interface ZigToolchainExtensionsProvider { + fun createExtensionPanel(): ZigToolchainPanel? + val index: Int +} + +fun createZigToolchainExtensionPanels(): List> { + return EXTENSION_POINT_NAME.extensionList.sortedBy{ it.index }.mapNotNull { + it.createExtensionPanel() + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainPanel.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainPanel.kt index ab765d0c..109f9c1a 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainPanel.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainPanel.kt @@ -22,29 +22,15 @@ package com.falsepattern.zigbrains.project.toolchain.base -import com.falsepattern.zigbrains.ZigBrainsBundle import com.intellij.openapi.Disposable -import com.intellij.ui.components.JBTextField -import com.intellij.ui.dsl.builder.AlignX import com.intellij.ui.dsl.builder.Panel -import com.intellij.ui.util.preferredHeight -import java.awt.Dimension -abstract class ZigToolchainPanel: Disposable { - private val nameField = JBTextField(25) - - protected var nameFieldValue: String? - get() = nameField.text.ifBlank { null } - set(value) {nameField.text = value ?: ""} - - open fun attach(p: Panel): Unit = with(p) { - row(ZigBrainsBundle.message("settings.toolchain.base.name.label")) { - cell(nameField).resizableColumn().align(AlignX.FILL) - } - separator() - } - - abstract fun isModified(toolchain: T): Boolean - abstract fun apply(toolchain: T): T? - abstract fun reset(toolchain: T) +interface ZigToolchainPanel: Disposable { + fun attach(p: Panel) + fun isModified(toolchain: T): Boolean + /** + * Returned object must be the exact same class as the provided one. + */ + fun apply(toolchain: T): T? + fun reset(toolchain: T) } \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainPanelBase.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainPanelBase.kt new file mode 100644 index 00000000..5d2543bd --- /dev/null +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/base/ZigToolchainPanelBase.kt @@ -0,0 +1,46 @@ +/* + * This file is part of ZigBrains. + * + * Copyright (C) 2023-2025 FalsePattern + * All Rights Reserved + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * ZigBrains is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, only version 3 of the License. + * + * ZigBrains is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with ZigBrains. If not, see . + */ + +package com.falsepattern.zigbrains.project.toolchain.base + +import com.falsepattern.zigbrains.ZigBrainsBundle +import com.intellij.openapi.Disposable +import com.intellij.ui.components.JBTextField +import com.intellij.ui.dsl.builder.AlignX +import com.intellij.ui.dsl.builder.Panel +import com.intellij.ui.util.preferredHeight +import java.awt.Dimension + +abstract class ZigToolchainPanelBase: ZigToolchainPanel { + private val nameField = JBTextField(25) + + protected var nameFieldValue: String? + get() = nameField.text.ifBlank { null } + set(value) {nameField.text = value ?: ""} + + override fun attach(p: Panel): Unit = with(p) { + row(ZigBrainsBundle.message("settings.toolchain.base.name.label")) { + cell(nameField).resizableColumn().align(AlignX.FILL) + } + separator() + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/local/LocalZigToolchainPanel.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/local/LocalZigToolchainPanel.kt index 111172c5..f5b4f612 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/local/LocalZigToolchainPanel.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/local/LocalZigToolchainPanel.kt @@ -23,10 +23,9 @@ package com.falsepattern.zigbrains.project.toolchain.local import com.falsepattern.zigbrains.ZigBrainsBundle -import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchainPanel +import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchainPanelBase import com.falsepattern.zigbrains.shared.coroutine.withEDTContext import com.falsepattern.zigbrains.shared.zigCoroutineScope -import com.intellij.openapi.Disposable import com.intellij.openapi.application.ModalityState import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory import com.intellij.openapi.util.Disposer @@ -35,7 +34,6 @@ import com.intellij.ui.DocumentAdapter import com.intellij.ui.JBColor import com.intellij.ui.components.JBCheckBox import com.intellij.ui.components.JBTextArea -import com.intellij.ui.components.JBTextField import com.intellij.ui.components.textFieldWithBrowseButton import com.intellij.ui.dsl.builder.AlignX import com.intellij.ui.dsl.builder.Panel @@ -46,7 +44,7 @@ import kotlinx.coroutines.launch import javax.swing.event.DocumentEvent import kotlin.io.path.pathString -class LocalZigToolchainPanel() : ZigToolchainPanel() { +class LocalZigToolchainPanel() : ZigToolchainPanelBase() { private val pathToToolchain = textFieldWithBrowseButton( null, FileChooserDescriptorFactory.createSingleFolderDescriptor().withTitle(ZigBrainsBundle.message("dialog.title.zig-toolchain"))