modular toolchain config

This commit is contained in:
FalsePattern 2025-04-10 17:28:56 +02:00
parent ab20a57e9e
commit 137977f691
Signed by: falsepattern
GPG key ID: E930CDEC50C50E23
6 changed files with 112 additions and 51 deletions

View file

@ -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<ZigToolchain, ZigToolchain.Ref, MyState>(MyState()), IZigToolchainListService {
class ZigToolchainListService: UUIDMapSerializable.Converting<ZigToolchain, ZigToolchain.Ref, MyState>(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<ZigToolchainListService>()
fun getInstance(): ZigToolchainListService = service<ZigToolchainListService>()
}
}
inline val zigToolchainList: IZigToolchainListService get() = ZigToolchainListService.getInstance()
sealed interface IZigToolchainListService: ChangeTrackingStorage, AccessibleStorage<ZigToolchain>, IterableStorage<ZigToolchain>
inline val zigToolchainList: ZigToolchainListService get() = ZigToolchainListService.getInstance()
private typealias ToolchainStorage = UUIDStorage<ZigToolchain.Ref>

View file

@ -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<T: ZigToolchain>(
zigToolchainList[uuid] = value
field = value
}
private var myView: ZigToolchainPanel<T>? = null
private var myViews: List<ZigToolchainPanel<T>> = emptyList()
abstract fun createPanel(): ZigToolchainPanel<T>
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<ZigToolchainPanel<T>>()
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<T: ZigToolchain>(
}
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()
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
package com.falsepattern.zigbrains.project.toolchain.base
import com.intellij.openapi.extensions.ExtensionPointName
private val EXTENSION_POINT_NAME = ExtensionPointName.create<ZigToolchainExtensionsProvider>("com.falsepattern.zigbrains.toolchainExtensionsProvider")
internal interface ZigToolchainExtensionsProvider {
fun <T : ZigToolchain> createExtensionPanel(): ZigToolchainPanel<T>?
val index: Int
}
fun <T: ZigToolchain> createZigToolchainExtensionPanels(): List<ZigToolchainPanel<T>> {
return EXTENSION_POINT_NAME.extensionList.sortedBy{ it.index }.mapNotNull {
it.createExtensionPanel()
}
}

View file

@ -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<T: ZigToolchain>: 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<T: ZigToolchain>: 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)
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
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<T: ZigToolchain>: ZigToolchainPanel<T> {
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()
}
}

View file

@ -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<LocalZigToolchain>() {
class LocalZigToolchainPanel() : ZigToolchainPanelBase<LocalZigToolchain>() {
private val pathToToolchain = textFieldWithBrowseButton(
null,
FileChooserDescriptorFactory.createSingleFolderDescriptor().withTitle(ZigBrainsBundle.message("dialog.title.zig-toolchain"))