ported core to new toolchain api
direnv and zls regressed for now
This commit is contained in:
parent
b485c1e48c
commit
a8f97172d6
35 changed files with 350 additions and 789 deletions
|
@ -83,7 +83,7 @@ allprojects {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
filter {
|
filter {
|
||||||
includeModule("com.redhat.devtools.intellij", "lsp4ij")
|
// includeModule("com.redhat.devtools.intellij", "lsp4ij")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -104,12 +104,12 @@ dependencies {
|
||||||
|
|
||||||
pluginVerifier()
|
pluginVerifier()
|
||||||
zipSigner()
|
zipSigner()
|
||||||
plugin(lsp4ijPluginString)
|
// plugin(lsp4ijPluginString)
|
||||||
}
|
}
|
||||||
|
|
||||||
runtimeOnly(project(":core"))
|
runtimeOnly(project(":core"))
|
||||||
runtimeOnly(project(":cidr"))
|
runtimeOnly(project(":cidr"))
|
||||||
runtimeOnly(project(":lsp"))
|
// runtimeOnly(project(":lsp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
intellijPlatform {
|
intellijPlatform {
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
package com.falsepattern.zigbrains
|
package com.falsepattern.zigbrains
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
||||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
|
||||||
import com.falsepattern.zigbrains.project.toolchain.local.LocalZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.local.LocalZigToolchain
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.suggestZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.base.suggestZigToolchain
|
||||||
import com.intellij.ide.BrowserUtil
|
import com.intellij.ide.BrowserUtil
|
||||||
|
@ -73,19 +72,6 @@ class ZBStartup: ProjectActivity {
|
||||||
notif.notify(null)
|
notif.notify(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Autodetection
|
|
||||||
val zigProjectState = project.zigProjectSettings.state
|
|
||||||
if (zigProjectState.toolchainPath.isNullOrBlank()) {
|
|
||||||
val data = UserDataHolderBase()
|
|
||||||
data.putUserData(LocalZigToolchain.DIRENV_KEY,
|
|
||||||
DirenvCmd.direnvInstalled() && !project.isDefault && zigProjectState.direnv
|
|
||||||
)
|
|
||||||
val tc = project.suggestZigToolchain(data) ?: return
|
|
||||||
if (tc is LocalZigToolchain) {
|
|
||||||
zigProjectState.toolchainPath = tc.location.pathString
|
|
||||||
project.zigProjectSettings.state = zigProjectState
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,15 +24,12 @@ package com.falsepattern.zigbrains.project.execution.base
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
import com.falsepattern.zigbrains.project.execution.base.ZigConfigurable.ZigConfigModule
|
import com.falsepattern.zigbrains.project.execution.base.ZigConfigurable.ZigConfigModule
|
||||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
|
||||||
import com.falsepattern.zigbrains.shared.cli.translateCommandline
|
import com.falsepattern.zigbrains.shared.cli.translateCommandline
|
||||||
import com.falsepattern.zigbrains.shared.element.*
|
import com.falsepattern.zigbrains.shared.element.*
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
||||||
import com.intellij.openapi.options.SettingsEditor
|
import com.intellij.openapi.options.SettingsEditor
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.openapi.ui.ComboBox
|
import com.intellij.openapi.ui.ComboBox
|
||||||
import com.intellij.openapi.ui.TextBrowseFolderListener
|
|
||||||
import com.intellij.openapi.util.Disposer
|
import com.intellij.openapi.util.Disposer
|
||||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||||
import com.intellij.ui.components.JBCheckBox
|
import com.intellij.ui.components.JBCheckBox
|
||||||
|
|
|
@ -22,9 +22,7 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.execution.base
|
package com.falsepattern.zigbrains.project.execution.base
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
|
||||||
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
||||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
|
||||||
import com.intellij.execution.ExecutionException
|
import com.intellij.execution.ExecutionException
|
||||||
import com.intellij.execution.Executor
|
import com.intellij.execution.Executor
|
||||||
import com.intellij.execution.configurations.ConfigurationFactory
|
import com.intellij.execution.configurations.ConfigurationFactory
|
||||||
|
@ -65,9 +63,10 @@ abstract class ZigExecConfig<T: ZigExecConfig<T>>(project: Project, factory: Con
|
||||||
|
|
||||||
|
|
||||||
suspend fun patchCommandLine(commandLine: GeneralCommandLine): GeneralCommandLine {
|
suspend fun patchCommandLine(commandLine: GeneralCommandLine): GeneralCommandLine {
|
||||||
if (project.zigProjectSettings.state.direnv) {
|
// TODO direnv
|
||||||
commandLine.withEnvironment(DirenvCmd.importDirenv(project).env)
|
// if (project.zigProjectSettings.state.direnv) {
|
||||||
}
|
// commandLine.withEnvironment(DirenvCmd.importDirenv(project).env)
|
||||||
|
// }
|
||||||
return commandLine
|
return commandLine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ package com.falsepattern.zigbrains.project.execution.base
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
import com.falsepattern.zigbrains.project.execution.ZigConsoleBuilder
|
import com.falsepattern.zigbrains.project.execution.ZigConsoleBuilder
|
||||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainService
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||||
import com.falsepattern.zigbrains.shared.cli.startIPCAwareProcess
|
import com.falsepattern.zigbrains.shared.cli.startIPCAwareProcess
|
||||||
import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking
|
import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking
|
||||||
|
@ -55,7 +55,7 @@ abstract class ZigProfileState<T: ZigExecConfig<T>> (
|
||||||
|
|
||||||
@Throws(ExecutionException::class)
|
@Throws(ExecutionException::class)
|
||||||
suspend fun startProcessSuspend(): ProcessHandler {
|
suspend fun startProcessSuspend(): ProcessHandler {
|
||||||
val toolchain = environment.project.zigProjectSettings.state.toolchain ?: throw ExecutionException(ZigBrainsBundle.message("exception.zig-profile-state.start-process.no-toolchain"))
|
val toolchain = ZigToolchainService.getInstance(environment.project).toolchain ?: throw ExecutionException(ZigBrainsBundle.message("exception.zig-profile-state.start-process.no-toolchain"))
|
||||||
return getCommandLine(toolchain, false).startIPCAwareProcess(environment.project, emulateTerminal = true)
|
return getCommandLine(toolchain, false).startIPCAwareProcess(environment.project, emulateTerminal = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ class ZigModuleBuilder: ModuleBuilder() {
|
||||||
|
|
||||||
override fun getCustomOptionsStep(context: WizardContext?, parentDisposable: Disposable?): ModuleWizardStep? {
|
override fun getCustomOptionsStep(context: WizardContext?, parentDisposable: Disposable?): ModuleWizardStep? {
|
||||||
val step = ZigModuleWizardStep(parentDisposable)
|
val step = ZigModuleWizardStep(parentDisposable)
|
||||||
parentDisposable?.let { Disposer.register(it, step.peer) }
|
parentDisposable?.let { Disposer.register(it) { step.peer.dispose() } }
|
||||||
return step
|
return step
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,14 +65,14 @@ class ZigModuleBuilder: ModuleBuilder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ZigModuleWizardStep(parent: Disposable?): ModuleWizardStep() {
|
inner class ZigModuleWizardStep(parent: Disposable?): ModuleWizardStep() {
|
||||||
internal val peer = ZigProjectGeneratorPeer(true).also { Disposer.register(parent ?: return@also, it) }
|
internal val peer = ZigProjectGeneratorPeer(true).also { Disposer.register(parent ?: return@also) {it.dispose()} }
|
||||||
|
|
||||||
override fun getComponent(): JComponent {
|
override fun getComponent(): JComponent {
|
||||||
return peer.myComponent.withBorder()
|
return peer.myComponent.withBorder()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun disposeUIResources() {
|
override fun disposeUIResources() {
|
||||||
Disposer.dispose(peer)
|
Disposer.dispose(peer.newProjectPanel)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateDataModel() {
|
override fun updateDataModel() {
|
||||||
|
|
|
@ -39,9 +39,9 @@ import com.intellij.util.ui.JBUI
|
||||||
import javax.swing.JList
|
import javax.swing.JList
|
||||||
import javax.swing.ListSelectionModel
|
import javax.swing.ListSelectionModel
|
||||||
|
|
||||||
class ZigNewProjectPanel(private var handleGit: Boolean): Disposable, ZigProjectConfigurationProvider.SettingsPanelHolder {
|
class ZigNewProjectPanel(private var handleGit: Boolean): Disposable {
|
||||||
private val git = JBCheckBox()
|
private val git = JBCheckBox()
|
||||||
override val panels = ZigProjectConfigurationProvider.createNewProjectSettingsPanels(this).onEach { Disposer.register(this, it) }
|
val panels = ZigProjectConfigurationProvider.createNewProjectSettingsPanels().onEach { Disposer.register(this, it) }
|
||||||
private val templateList = JBList(JBList.createDefaultListModel(defaultTemplates)).apply {
|
private val templateList = JBList(JBList.createDefaultListModel(defaultTemplates)).apply {
|
||||||
selectionMode = ListSelectionModel.SINGLE_SELECTION
|
selectionMode = ListSelectionModel.SINGLE_SELECTION
|
||||||
selectedIndex = 0
|
selectedIndex = 0
|
||||||
|
@ -64,7 +64,7 @@ class ZigNewProjectPanel(private var handleGit: Boolean): Disposable, ZigProject
|
||||||
|
|
||||||
fun getData(): ZigProjectConfigurationData {
|
fun getData(): ZigProjectConfigurationData {
|
||||||
val selectedTemplate = templateList.selectedValue
|
val selectedTemplate = templateList.selectedValue
|
||||||
return ZigProjectConfigurationData(handleGit && git.isSelected, panels.map { it.data }, selectedTemplate)
|
return ZigProjectConfigurationData(handleGit && git.isSelected, panels, selectedTemplate)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun attach(p: Panel): Unit = with(p) {
|
fun attach(p: Panel): Unit = with(p) {
|
||||||
|
@ -73,6 +73,7 @@ class ZigNewProjectPanel(private var handleGit: Boolean): Disposable, ZigProject
|
||||||
cell(git)
|
cell(git)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
panels.filter { it.newProjectBeforeInitSelector }.forEach { it.attach(p) }
|
||||||
group("Zig Project Template") {
|
group("Zig Project Template") {
|
||||||
row {
|
row {
|
||||||
resizableRow()
|
resizableRow()
|
||||||
|
@ -81,7 +82,7 @@ class ZigNewProjectPanel(private var handleGit: Boolean): Disposable, ZigProject
|
||||||
.align(AlignY.FILL)
|
.align(AlignY.FILL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panels.forEach { it.attach(p) }
|
panels.filter { !it.newProjectBeforeInitSelector }.forEach { it.attach(p) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
|
|
|
@ -22,9 +22,10 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.newproject
|
package com.falsepattern.zigbrains.project.newproject
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider
|
|
||||||
import com.falsepattern.zigbrains.project.template.ZigInitTemplate
|
import com.falsepattern.zigbrains.project.template.ZigInitTemplate
|
||||||
import com.falsepattern.zigbrains.project.template.ZigProjectTemplate
|
import com.falsepattern.zigbrains.project.template.ZigProjectTemplate
|
||||||
|
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainService
|
||||||
|
import com.falsepattern.zigbrains.shared.SubConfigurable
|
||||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
import com.intellij.notification.Notification
|
import com.intellij.notification.Notification
|
||||||
import com.intellij.notification.NotificationType
|
import com.intellij.notification.NotificationType
|
||||||
|
@ -42,7 +43,7 @@ import kotlinx.coroutines.launch
|
||||||
@JvmRecord
|
@JvmRecord
|
||||||
data class ZigProjectConfigurationData(
|
data class ZigProjectConfigurationData(
|
||||||
val git: Boolean,
|
val git: Boolean,
|
||||||
val conf: List<ZigProjectConfigurationProvider.Settings>,
|
val conf: List<SubConfigurable<Project>>,
|
||||||
val selectedTemplate: ZigProjectTemplate
|
val selectedTemplate: ZigProjectTemplate
|
||||||
) {
|
) {
|
||||||
@RequiresBackgroundThread
|
@RequiresBackgroundThread
|
||||||
|
@ -54,9 +55,7 @@ data class ZigProjectConfigurationData(
|
||||||
|
|
||||||
if (!reporter.indeterminateStep("Initializing project") {
|
if (!reporter.indeterminateStep("Initializing project") {
|
||||||
if (template is ZigInitTemplate) {
|
if (template is ZigInitTemplate) {
|
||||||
val toolchain = conf
|
val toolchain = ZigToolchainService.getInstance(project).toolchain ?: run {
|
||||||
.mapNotNull { it as? ZigProjectConfigurationProvider.ToolchainProvider }
|
|
||||||
.firstNotNullOfOrNull { it.toolchain } ?: run {
|
|
||||||
Notification(
|
Notification(
|
||||||
"zigbrains",
|
"zigbrains",
|
||||||
"Tried to generate project with zig init, but zig toolchain is invalid",
|
"Tried to generate project with zig init, but zig toolchain is invalid",
|
||||||
|
|
|
@ -31,9 +31,9 @@ import com.intellij.platform.ProjectGeneratorPeer
|
||||||
import com.intellij.ui.dsl.builder.panel
|
import com.intellij.ui.dsl.builder.panel
|
||||||
import javax.swing.JComponent
|
import javax.swing.JComponent
|
||||||
|
|
||||||
class ZigProjectGeneratorPeer(var handleGit: Boolean): ProjectGeneratorPeer<ZigProjectConfigurationData>, Disposable {
|
class ZigProjectGeneratorPeer(var handleGit: Boolean): ProjectGeneratorPeer<ZigProjectConfigurationData> {
|
||||||
private val newProjectPanel by lazy {
|
val newProjectPanel by lazy {
|
||||||
ZigNewProjectPanel(handleGit).also { Disposer.register(this, it) }
|
ZigNewProjectPanel(handleGit)
|
||||||
}
|
}
|
||||||
val myComponent: JComponent by lazy {
|
val myComponent: JComponent by lazy {
|
||||||
panel {
|
panel {
|
||||||
|
@ -61,6 +61,7 @@ class ZigProjectGeneratorPeer(var handleGit: Boolean): ProjectGeneratorPeer<ZigP
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
fun dispose() {
|
||||||
|
newProjectPanel.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,7 +23,7 @@
|
||||||
package com.falsepattern.zigbrains.project.run
|
package com.falsepattern.zigbrains.project.run
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainService
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
import com.intellij.execution.ExecutionException
|
import com.intellij.execution.ExecutionException
|
||||||
|
@ -61,7 +61,7 @@ abstract class ZigProgramRunner<ProfileState : ZigProfileState<*>>(protected val
|
||||||
|
|
||||||
val state = castProfileState(baseState) ?: return null
|
val state = castProfileState(baseState) ?: return null
|
||||||
|
|
||||||
val toolchain = environment.project.zigProjectSettings.state.toolchain ?: run {
|
val toolchain = ZigToolchainService.getInstance(environment.project).toolchain ?: run {
|
||||||
Notification(
|
Notification(
|
||||||
"zigbrains",
|
"zigbrains",
|
||||||
"Zig project toolchain not set, cannot execute program! Please configure it in [Settings | Languages & Frameworks | Zig]",
|
"Zig project toolchain not set, cannot execute program! Please configure it in [Settings | Languages & Frameworks | Zig]",
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.settings
|
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.shared.MultiConfigurable
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
|
|
||||||
class ZigConfigurable(project: Project): MultiConfigurable(ZigProjectConfigurationProvider.createConfigurables(project)) {
|
|
||||||
override fun getDisplayName(): String {
|
|
||||||
return "Zig"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,20 +22,21 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.settings
|
package com.falsepattern.zigbrains.project.settings
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.project.toolchain.ui.ZigToolchainEditor
|
||||||
import com.falsepattern.zigbrains.shared.SubConfigurable
|
import com.falsepattern.zigbrains.shared.SubConfigurable
|
||||||
|
import com.intellij.openapi.options.Configurable
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.project.ProjectManager
|
|
||||||
|
|
||||||
class ZigCoreProjectConfigurationProvider: ZigProjectConfigurationProvider {
|
class ZigCoreProjectConfigurationProvider: ZigProjectConfigurationProvider {
|
||||||
override fun handleMainConfigChanged(project: Project) {
|
override fun handleMainConfigChanged(project: Project) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createConfigurable(project: Project): SubConfigurable {
|
override fun createConfigurable(project: Project): Configurable {
|
||||||
return ZigProjectConfigurable(project)
|
return ZigToolchainEditor.Adapter(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createNewProjectSettingsPanel(holder: ZigProjectConfigurationProvider.SettingsPanelHolder): ZigProjectConfigurationProvider.SettingsPanel {
|
override fun createNewProjectSettingsPanel(): SubConfigurable<Project> {
|
||||||
return ZigProjectSettingsPanel(holder, ProjectManager.getInstance().defaultProject)
|
return ZigToolchainEditor().also { it.reset(null) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override val priority: Int
|
override val priority: Int
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.settings
|
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.shared.SubConfigurable
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.openapi.util.Disposer
|
|
||||||
import com.intellij.ui.dsl.builder.Panel
|
|
||||||
|
|
||||||
class ZigProjectConfigurable(private val project: Project): SubConfigurable {
|
|
||||||
private var settingsPanel: ZigProjectSettingsPanel? = null
|
|
||||||
override fun createComponent(holder: ZigProjectConfigurationProvider.SettingsPanelHolder, panel: Panel): ZigProjectConfigurationProvider.SettingsPanel {
|
|
||||||
settingsPanel?.let { Disposer.dispose(it) }
|
|
||||||
val sp = ZigProjectSettingsPanel(holder, project).apply { attach(panel) }.also { Disposer.register(this, it) }
|
|
||||||
settingsPanel = sp
|
|
||||||
return sp
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isModified(): Boolean {
|
|
||||||
return project.zigProjectSettings.isModified(settingsPanel?.data ?: return false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun apply() {
|
|
||||||
val service = project.zigProjectSettings
|
|
||||||
val data = settingsPanel?.data ?: return
|
|
||||||
val modified = service.isModified(data)
|
|
||||||
service.state = data
|
|
||||||
if (modified) {
|
|
||||||
ZigProjectConfigurationProvider.mainConfigChanged(project)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
settingsPanel?.data = project.zigProjectSettings.state
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dispose() {
|
|
||||||
settingsPanel = null
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,42 +22,26 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.settings
|
package com.falsepattern.zigbrains.project.settings
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
|
||||||
import com.falsepattern.zigbrains.shared.SubConfigurable
|
import com.falsepattern.zigbrains.shared.SubConfigurable
|
||||||
import com.intellij.openapi.Disposable
|
|
||||||
import com.intellij.openapi.extensions.ExtensionPointName
|
import com.intellij.openapi.extensions.ExtensionPointName
|
||||||
|
import com.intellij.openapi.options.Configurable
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.ui.dsl.builder.Panel
|
|
||||||
|
|
||||||
interface ZigProjectConfigurationProvider {
|
interface ZigProjectConfigurationProvider {
|
||||||
fun handleMainConfigChanged(project: Project)
|
fun handleMainConfigChanged(project: Project)
|
||||||
fun createConfigurable(project: Project): SubConfigurable
|
fun createConfigurable(project: Project): Configurable
|
||||||
fun createNewProjectSettingsPanel(holder: SettingsPanelHolder): SettingsPanel?
|
fun createNewProjectSettingsPanel(): SubConfigurable<Project>?
|
||||||
val priority: Int
|
val priority: Int
|
||||||
companion object {
|
companion object {
|
||||||
private val EXTENSION_POINT_NAME = ExtensionPointName.create<ZigProjectConfigurationProvider>("com.falsepattern.zigbrains.projectConfigProvider")
|
private val EXTENSION_POINT_NAME = ExtensionPointName.create<ZigProjectConfigurationProvider>("com.falsepattern.zigbrains.projectConfigProvider")
|
||||||
fun mainConfigChanged(project: Project) {
|
fun mainConfigChanged(project: Project) {
|
||||||
EXTENSION_POINT_NAME.extensionList.forEach { it.handleMainConfigChanged(project) }
|
EXTENSION_POINT_NAME.extensionList.forEach { it.handleMainConfigChanged(project) }
|
||||||
}
|
}
|
||||||
fun createConfigurables(project: Project): List<SubConfigurable> {
|
fun createConfigurables(project: Project): List<Configurable> {
|
||||||
return EXTENSION_POINT_NAME.extensionList.sortedBy { it.priority }.map { it.createConfigurable(project) }
|
return EXTENSION_POINT_NAME.extensionList.sortedBy { it.priority }.map { it.createConfigurable(project) }
|
||||||
}
|
}
|
||||||
fun createNewProjectSettingsPanels(holder: SettingsPanelHolder): List<SettingsPanel> {
|
fun createNewProjectSettingsPanels(): List<SubConfigurable<Project>> {
|
||||||
return EXTENSION_POINT_NAME.extensionList.sortedBy { it.priority }.mapNotNull { it.createNewProjectSettingsPanel(holder) }
|
return EXTENSION_POINT_NAME.extensionList.sortedBy { it.priority }.mapNotNull { it.createNewProjectSettingsPanel() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
interface SettingsPanel: Disposable {
|
|
||||||
val data: Settings
|
|
||||||
fun attach(p: Panel)
|
|
||||||
fun direnvChanged(state: Boolean)
|
|
||||||
}
|
|
||||||
interface SettingsPanelHolder {
|
|
||||||
val panels: List<SettingsPanel>
|
|
||||||
}
|
|
||||||
interface Settings {
|
|
||||||
fun apply(project: Project)
|
|
||||||
}
|
|
||||||
interface ToolchainProvider {
|
|
||||||
val toolchain: ZigToolchain?
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.settings
|
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.toolchain.local.LocalZigToolchain
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
|
||||||
import com.intellij.util.xmlb.annotations.Transient
|
|
||||||
import kotlin.io.path.isDirectory
|
|
||||||
import kotlin.io.path.pathString
|
|
||||||
|
|
||||||
data class ZigProjectSettings(
|
|
||||||
var direnv: Boolean = false,
|
|
||||||
var overrideStdPath: Boolean = false,
|
|
||||||
var explicitPathToStd: String? = null,
|
|
||||||
var toolchainPath: String? = null
|
|
||||||
): ZigProjectConfigurationProvider.Settings, ZigProjectConfigurationProvider.ToolchainProvider {
|
|
||||||
override fun apply(project: Project) {
|
|
||||||
project.zigProjectSettings.loadState(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
@get:Transient
|
|
||||||
@set:Transient
|
|
||||||
override var toolchain: LocalZigToolchain?
|
|
||||||
get() {
|
|
||||||
val nioPath = toolchainPath?.toNioPathOrNull() ?: return null
|
|
||||||
if (!nioPath.isDirectory()) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return LocalZigToolchain(nioPath)
|
|
||||||
}
|
|
||||||
set(value) {
|
|
||||||
toolchainPath = value?.location?.pathString
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,211 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.settings
|
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
|
||||||
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
|
||||||
import com.falsepattern.zigbrains.project.toolchain.local.LocalZigToolchain
|
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.suggestZigToolchain
|
|
||||||
import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT
|
|
||||||
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
|
||||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
|
||||||
import com.intellij.openapi.application.ModalityState
|
|
||||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.openapi.util.Disposer
|
|
||||||
import com.intellij.openapi.util.UserDataHolderBase
|
|
||||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
|
||||||
import com.intellij.platform.ide.progress.ModalTaskOwner
|
|
||||||
import com.intellij.platform.ide.progress.TaskCancellation
|
|
||||||
import com.intellij.platform.ide.progress.withModalProgress
|
|
||||||
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.textFieldWithBrowseButton
|
|
||||||
import com.intellij.ui.dsl.builder.AlignX
|
|
||||||
import com.intellij.ui.dsl.builder.Panel
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import javax.swing.event.DocumentEvent
|
|
||||||
import kotlin.io.path.pathString
|
|
||||||
|
|
||||||
class ZigProjectSettingsPanel(private val holder: ZigProjectConfigurationProvider.SettingsPanelHolder, private val project: Project) : ZigProjectConfigurationProvider.SettingsPanel {
|
|
||||||
private val direnv = JBCheckBox(ZigBrainsBundle.message("settings.project.label.direnv")).apply { addActionListener {
|
|
||||||
dispatchDirenvUpdate()
|
|
||||||
} }
|
|
||||||
private val pathToToolchain = textFieldWithBrowseButton(
|
|
||||||
project,
|
|
||||||
FileChooserDescriptorFactory.createSingleFolderDescriptor().withTitle(ZigBrainsBundle.message("dialog.title.zig-toolchain"))
|
|
||||||
).also {
|
|
||||||
it.textField.document.addDocumentListener(object : DocumentAdapter() {
|
|
||||||
override fun textChanged(e: DocumentEvent) {
|
|
||||||
dispatchUpdateUI()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Disposer.register(this, it)
|
|
||||||
}
|
|
||||||
private val toolchainVersion = JBTextArea().also { it.isEditable = false }
|
|
||||||
private val stdFieldOverride = JBCheckBox(ZigBrainsBundle.message("settings.project.label.override-std")).apply {
|
|
||||||
addChangeListener {
|
|
||||||
if (isSelected) {
|
|
||||||
pathToStd.isEnabled = true
|
|
||||||
} else {
|
|
||||||
pathToStd.isEnabled = false
|
|
||||||
updateUI()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private val pathToStd = textFieldWithBrowseButton(
|
|
||||||
project,
|
|
||||||
FileChooserDescriptorFactory.createSingleFolderDescriptor().withTitle(ZigBrainsBundle.message("dialog.title.zig-std"))
|
|
||||||
).also { Disposer.register(this, it) }
|
|
||||||
private var debounce: Job? = null
|
|
||||||
|
|
||||||
private fun dispatchDirenvUpdate() {
|
|
||||||
holder.panels.forEach {
|
|
||||||
it.direnvChanged(direnv.isSelected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun direnvChanged(state: Boolean) {
|
|
||||||
dispatchAutodetect(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun dispatchAutodetect(force: Boolean) {
|
|
||||||
project.zigCoroutineScope.launchWithEDT(ModalityState.defaultModalityState()) {
|
|
||||||
withModalProgress(ModalTaskOwner.component(pathToToolchain), "Detecting Zig...", TaskCancellation.cancellable()) {
|
|
||||||
autodetect(force)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun autodetect(force: Boolean) {
|
|
||||||
if (!force && pathToToolchain.text.isNotBlank())
|
|
||||||
return
|
|
||||||
val data = UserDataHolderBase()
|
|
||||||
data.putUserData(LocalZigToolchain.DIRENV_KEY, !project.isDefault && direnv.isSelected && DirenvCmd.direnvInstalled())
|
|
||||||
val tc = project.suggestZigToolchain(project) ?: return
|
|
||||||
if (tc !is LocalZigToolchain) {
|
|
||||||
TODO("Implement non-local zig toolchain in config")
|
|
||||||
}
|
|
||||||
if (force || pathToToolchain.text.isBlank()) {
|
|
||||||
pathToToolchain.text = tc.location.pathString
|
|
||||||
dispatchUpdateUI()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override var data
|
|
||||||
get() = ZigProjectSettings(
|
|
||||||
direnv.isSelected,
|
|
||||||
stdFieldOverride.isSelected,
|
|
||||||
pathToStd.text.ifBlank { null },
|
|
||||||
pathToToolchain.text.ifBlank { null }
|
|
||||||
)
|
|
||||||
set(value) {
|
|
||||||
direnv.isSelected = value.direnv
|
|
||||||
pathToToolchain.text = value.toolchainPath ?: ""
|
|
||||||
stdFieldOverride.isSelected = value.overrideStdPath
|
|
||||||
pathToStd.text = value.explicitPathToStd ?: ""
|
|
||||||
pathToStd.isEnabled = value.overrideStdPath
|
|
||||||
dispatchUpdateUI()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun attach(p: Panel): Unit = with(p) {
|
|
||||||
data = project.zigProjectSettings.state
|
|
||||||
if (project.isDefault) {
|
|
||||||
row(ZigBrainsBundle.message("settings.project.label.toolchain")) {
|
|
||||||
cell(pathToToolchain).resizableColumn().align(AlignX.FILL)
|
|
||||||
}
|
|
||||||
row(ZigBrainsBundle.message("settings.project.label.toolchain-version")) {
|
|
||||||
cell(toolchainVersion)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
group(ZigBrainsBundle.message("settings.project.group.title")) {
|
|
||||||
row(ZigBrainsBundle.message("settings.project.label.toolchain")) {
|
|
||||||
cell(pathToToolchain).resizableColumn().align(AlignX.FILL)
|
|
||||||
if (DirenvCmd.direnvInstalled()) {
|
|
||||||
cell(direnv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
row(ZigBrainsBundle.message("settings.project.label.toolchain-version")) {
|
|
||||||
cell(toolchainVersion)
|
|
||||||
}
|
|
||||||
row(ZigBrainsBundle.message("settings.project.label.std-location")) {
|
|
||||||
cell(pathToStd).resizableColumn().align(AlignX.FILL)
|
|
||||||
cell(stdFieldOverride)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dispatchAutodetect(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun dispatchUpdateUI() {
|
|
||||||
debounce?.cancel("New debounce")
|
|
||||||
debounce = project.zigCoroutineScope.launch {
|
|
||||||
updateUI()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun updateUI() {
|
|
||||||
delay(200)
|
|
||||||
val pathToToolchain = this.pathToToolchain.text.ifBlank { null }?.toNioPathOrNull()
|
|
||||||
if (pathToToolchain == null) {
|
|
||||||
withEDTContext(ModalityState.any()) {
|
|
||||||
toolchainVersion.text = "[toolchain path empty or invalid]"
|
|
||||||
if (!stdFieldOverride.isSelected) {
|
|
||||||
pathToStd.text = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val toolchain = LocalZigToolchain(pathToToolchain)
|
|
||||||
val zig = toolchain.zig
|
|
||||||
val env = zig.getEnv(project).getOrElse { throwable ->
|
|
||||||
throwable.printStackTrace()
|
|
||||||
withEDTContext(ModalityState.any()) {
|
|
||||||
toolchainVersion.text = "[failed to run \"zig env\"]\n${throwable.message}"
|
|
||||||
if (!stdFieldOverride.isSelected) {
|
|
||||||
pathToStd.text = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val version = env.version
|
|
||||||
val stdPath = env.stdPath(toolchain, project)
|
|
||||||
|
|
||||||
withEDTContext(ModalityState.any()) {
|
|
||||||
toolchainVersion.text = version
|
|
||||||
toolchainVersion.foreground = JBColor.foreground()
|
|
||||||
if (!stdFieldOverride.isSelected) {
|
|
||||||
pathToStd.text = stdPath?.pathString ?: ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dispose() {
|
|
||||||
debounce?.cancel("Disposed")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.settings
|
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.stdlib.ZigSyntheticLibrary
|
|
||||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
|
||||||
import com.intellij.openapi.components.*
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@Service(Service.Level.PROJECT)
|
|
||||||
@State(
|
|
||||||
name = "ZigProjectSettings",
|
|
||||||
storages = [Storage("zigbrains.xml")]
|
|
||||||
)
|
|
||||||
class ZigProjectSettingsService(val project: Project): PersistentStateComponent<ZigProjectSettings> {
|
|
||||||
@Volatile
|
|
||||||
private var state = ZigProjectSettings()
|
|
||||||
|
|
||||||
override fun getState(): ZigProjectSettings {
|
|
||||||
return state.copy()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setState(value: ZigProjectSettings) {
|
|
||||||
this.state = value
|
|
||||||
zigCoroutineScope.launch {
|
|
||||||
ZigSyntheticLibrary.reload(project, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun loadState(state: ZigProjectSettings) {
|
|
||||||
setState(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isModified(otherData: ZigProjectSettings): Boolean {
|
|
||||||
return state != otherData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val Project.zigProjectSettings get() = service<ZigProjectSettingsService>()
|
|
|
@ -23,13 +23,13 @@
|
||||||
package com.falsepattern.zigbrains.project.stdlib
|
package com.falsepattern.zigbrains.project.stdlib
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.Icons
|
import com.falsepattern.zigbrains.Icons
|
||||||
import com.falsepattern.zigbrains.project.settings.ZigProjectSettings
|
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainService
|
||||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||||
|
import com.falsepattern.zigbrains.project.toolchain.local.LocalZigToolchain
|
||||||
import com.intellij.navigation.ItemPresentation
|
import com.intellij.navigation.ItemPresentation
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.project.guessProjectDir
|
import com.intellij.openapi.project.guessProjectDir
|
||||||
import com.intellij.openapi.roots.SyntheticLibrary
|
import com.intellij.openapi.roots.SyntheticLibrary
|
||||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.openapi.vfs.refreshAndFindVirtualDirectory
|
import com.intellij.openapi.vfs.refreshAndFindVirtualDirectory
|
||||||
import com.intellij.platform.backend.workspace.WorkspaceModel
|
import com.intellij.platform.backend.workspace.WorkspaceModel
|
||||||
|
@ -41,20 +41,20 @@ import java.util.*
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
class ZigSyntheticLibrary(val project: Project) : SyntheticLibrary(), ItemPresentation {
|
class ZigSyntheticLibrary(val project: Project) : SyntheticLibrary(), ItemPresentation {
|
||||||
private var state: ZigProjectSettings = project.zigProjectSettings.state.copy()
|
private var toolchain: ZigToolchain? = ZigToolchainService.getInstance(project).toolchain
|
||||||
private val roots by lazy {
|
private val roots by lazy {
|
||||||
runBlocking {getRoot(state, project)}?.let { setOf(it) } ?: emptySet()
|
runBlocking {getRoot(toolchain, project)}?.let { setOf(it) } ?: emptySet()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val name by lazy {
|
private val name by lazy {
|
||||||
getName(state, project)
|
getName(toolchain, project)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other !is ZigSyntheticLibrary)
|
if (other !is ZigSyntheticLibrary)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
return state == other.state
|
return toolchain == other.toolchain
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
|
@ -76,10 +76,10 @@ class ZigSyntheticLibrary(val project: Project) : SyntheticLibrary(), ItemPresen
|
||||||
companion object {
|
companion object {
|
||||||
private const val ZIG_LIBRARY_ID = "Zig SDK"
|
private const val ZIG_LIBRARY_ID = "Zig SDK"
|
||||||
private const val ZIG_MODULE_ID = "Zig"
|
private const val ZIG_MODULE_ID = "Zig"
|
||||||
suspend fun reload(project: Project, state: ZigProjectSettings) {
|
suspend fun reload(project: Project, toolchain: ZigToolchain?) {
|
||||||
val moduleId = ModuleId(ZIG_MODULE_ID)
|
val moduleId = ModuleId(ZIG_MODULE_ID)
|
||||||
val workspaceModel = WorkspaceModel.getInstance(project)
|
val workspaceModel = WorkspaceModel.getInstance(project)
|
||||||
val root = getRoot(state, project) ?: return
|
val root = getRoot(toolchain, project) ?: return
|
||||||
val libRoot = LibraryRoot(root.toVirtualFileUrl(workspaceModel.getVirtualFileUrlManager()), LibraryRootTypeId.SOURCES)
|
val libRoot = LibraryRoot(root.toVirtualFileUrl(workspaceModel.getVirtualFileUrlManager()), LibraryRootTypeId.SOURCES)
|
||||||
val libraryTableId = LibraryTableId.ProjectLibraryTableId
|
val libraryTableId = LibraryTableId.ProjectLibraryTableId
|
||||||
val libraryId = LibraryId(ZIG_LIBRARY_ID, libraryTableId)
|
val libraryId = LibraryId(ZIG_LIBRARY_ID, libraryTableId)
|
||||||
|
@ -118,37 +118,39 @@ class ZigSyntheticLibrary(val project: Project) : SyntheticLibrary(), ItemPresen
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getName(
|
private fun getName(
|
||||||
state: ZigProjectSettings,
|
toolchain: ZigToolchain?,
|
||||||
project: Project
|
project: Project
|
||||||
): String {
|
): String {
|
||||||
val tc = state.toolchain ?: return "Zig"
|
val tc = toolchain ?: return "Zig"
|
||||||
val version = runBlocking { tc.zig.getEnv(project) }.mapCatching { it.version }.getOrElse { return "Zig" }
|
toolchain.name?.let { return it }
|
||||||
return "Zig $version"
|
runBlocking { tc.zig.getEnv(project) }
|
||||||
|
.mapCatching { it.version }
|
||||||
|
.getOrNull()
|
||||||
|
?.let { return "Zig $it" }
|
||||||
|
return "Zig"
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getRoot(
|
suspend fun getRoot(
|
||||||
state: ZigProjectSettings,
|
toolchain: ZigToolchain?,
|
||||||
project: Project
|
project: Project
|
||||||
): VirtualFile? {
|
): VirtualFile? {
|
||||||
val toolchain = state.toolchain
|
//TODO universal
|
||||||
if (state.overrideStdPath) run {
|
if (toolchain !is LocalZigToolchain) {
|
||||||
val ePathStr = state.explicitPathToStd ?: return@run
|
return null
|
||||||
val ePath = ePathStr.toNioPathOrNull() ?: return@run
|
}
|
||||||
|
if (toolchain.std != null) run {
|
||||||
|
val ePath = toolchain.std
|
||||||
if (ePath.isAbsolute) {
|
if (ePath.isAbsolute) {
|
||||||
val roots = ePath.refreshAndFindVirtualDirectory() ?: return@run
|
val roots = ePath.refreshAndFindVirtualDirectory() ?: return@run
|
||||||
return roots
|
return roots
|
||||||
} else if (toolchain != null) {
|
}
|
||||||
val stdPath = toolchain.location.resolve(ePath)
|
val stdPath = toolchain.location.resolve(ePath)
|
||||||
if (stdPath.isAbsolute) {
|
if (stdPath.isAbsolute) {
|
||||||
val roots = stdPath.refreshAndFindVirtualDirectory() ?: return@run
|
val roots = stdPath.refreshAndFindVirtualDirectory() ?: return@run
|
||||||
return roots
|
return roots
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (toolchain != null) {
|
|
||||||
val stdPath = toolchain.zig.getEnv(project).mapCatching { it.stdPath(toolchain, project) }.getOrNull() ?: return null
|
val stdPath = toolchain.zig.getEnv(project).mapCatching { it.stdPath(toolchain, project) }.getOrNull() ?: return null
|
||||||
val roots = stdPath.refreshAndFindVirtualDirectory() ?: return null
|
val roots = stdPath.refreshAndFindVirtualDirectory() ?: return null
|
||||||
return roots
|
return roots
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
}
|
|
@ -22,8 +22,8 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.steps.discovery
|
package com.falsepattern.zigbrains.project.steps.discovery
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
|
||||||
import com.falsepattern.zigbrains.project.steps.discovery.ZigStepDiscoveryListener.ErrorType
|
import com.falsepattern.zigbrains.project.steps.discovery.ZigStepDiscoveryListener.ErrorType
|
||||||
|
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainService
|
||||||
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
|
@ -76,7 +76,7 @@ class ZigStepDiscoveryService(private val project: Project) {
|
||||||
|
|
||||||
private tailrec suspend fun doReload() {
|
private tailrec suspend fun doReload() {
|
||||||
preReload()
|
preReload()
|
||||||
val toolchain = project.zigProjectSettings.state.toolchain ?: run {
|
val toolchain = ZigToolchainService.getInstance(project).toolchain ?: run {
|
||||||
errorReload(ErrorType.MissingToolchain)
|
errorReload(ErrorType.MissingToolchain)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,9 +36,19 @@ import java.util.UUID
|
||||||
name = "ZigToolchainList",
|
name = "ZigToolchainList",
|
||||||
storages = [Storage("zigbrains.xml")]
|
storages = [Storage("zigbrains.xml")]
|
||||||
)
|
)
|
||||||
class ZigToolchainListService: SerializablePersistentStateComponent<ZigToolchainListService.State>(State()) {
|
class ZigToolchainListService: SerializablePersistentStateComponent<ZigToolchainListService.State>(State()), ZigToolchainListService.IService {
|
||||||
private val changeListeners = ArrayList<WeakReference<ToolchainListChangeListener>>()
|
private val changeListeners = ArrayList<WeakReference<ToolchainListChangeListener>>()
|
||||||
fun setToolchain(uuid: UUID, toolchain: ZigToolchain) {
|
|
||||||
|
override val toolchains: Sequence<Pair<UUID, ZigToolchain>>
|
||||||
|
get() = state.toolchains
|
||||||
|
.asSequence()
|
||||||
|
.mapNotNull {
|
||||||
|
val uuid = UUID.fromString(it.key) ?: return@mapNotNull null
|
||||||
|
val tc = it.value.resolve() ?: return@mapNotNull null
|
||||||
|
uuid to tc
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setToolchain(uuid: UUID, toolchain: ZigToolchain) {
|
||||||
val str = uuid.toString()
|
val str = uuid.toString()
|
||||||
val ref = toolchain.toRef()
|
val ref = toolchain.toRef()
|
||||||
updateState {
|
updateState {
|
||||||
|
@ -50,7 +60,7 @@ class ZigToolchainListService: SerializablePersistentStateComponent<ZigToolchain
|
||||||
notifyChanged()
|
notifyChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun registerNewToolchain(toolchain: ZigToolchain): UUID {
|
override fun registerNewToolchain(toolchain: ZigToolchain): UUID {
|
||||||
val ref = toolchain.toRef()
|
val ref = toolchain.toRef()
|
||||||
var uuid = UUID.randomUUID()
|
var uuid = UUID.randomUUID()
|
||||||
updateState {
|
updateState {
|
||||||
|
@ -68,15 +78,15 @@ class ZigToolchainListService: SerializablePersistentStateComponent<ZigToolchain
|
||||||
return uuid
|
return uuid
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getToolchain(uuid: UUID): ZigToolchain? {
|
override fun getToolchain(uuid: UUID): ZigToolchain? {
|
||||||
return state.toolchains[uuid.toString()]?.resolve()
|
return state.toolchains[uuid.toString()]?.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasToolchain(uuid: UUID): Boolean {
|
override fun hasToolchain(uuid: UUID): Boolean {
|
||||||
return state.toolchains.containsKey(uuid.toString())
|
return state.toolchains.containsKey(uuid.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeToolchain(uuid: UUID) {
|
override fun removeToolchain(uuid: UUID) {
|
||||||
val str = uuid.toString()
|
val str = uuid.toString()
|
||||||
updateState {
|
updateState {
|
||||||
it.copy(toolchains = it.toolchains.filter { it.key != str })
|
it.copy(toolchains = it.toolchains.filter { it.key != str })
|
||||||
|
@ -84,6 +94,21 @@ class ZigToolchainListService: SerializablePersistentStateComponent<ZigToolchain
|
||||||
notifyChanged()
|
notifyChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun addChangeListener(listener: ToolchainListChangeListener) {
|
||||||
|
synchronized(changeListeners) {
|
||||||
|
changeListeners.add(WeakReference(listener))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeChangeListener(listener: ToolchainListChangeListener) {
|
||||||
|
synchronized(changeListeners) {
|
||||||
|
changeListeners.removeIf {
|
||||||
|
val v = it.get()
|
||||||
|
v == null || v === listener
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun notifyChanged() {
|
private fun notifyChanged() {
|
||||||
synchronized(changeListeners) {
|
synchronized(changeListeners) {
|
||||||
var i = 0
|
var i = 0
|
||||||
|
@ -101,31 +126,6 @@ class ZigToolchainListService: SerializablePersistentStateComponent<ZigToolchain
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addChangeListener(listener: ToolchainListChangeListener) {
|
|
||||||
synchronized(changeListeners) {
|
|
||||||
changeListeners.add(WeakReference(listener))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun removeChangeListener(listener: ToolchainListChangeListener) {
|
|
||||||
synchronized(changeListeners) {
|
|
||||||
changeListeners.removeIf {
|
|
||||||
val v = it.get()
|
|
||||||
v == null || v === listener
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val toolchains: Sequence<Pair<UUID, ZigToolchain>>
|
|
||||||
get() = state.toolchains
|
|
||||||
.asSequence()
|
|
||||||
.mapNotNull {
|
|
||||||
val uuid = UUID.fromString(it.key) ?: return@mapNotNull null
|
|
||||||
val tc = it.value.resolve() ?: return@mapNotNull null
|
|
||||||
uuid to tc
|
|
||||||
}
|
|
||||||
|
|
||||||
data class State(
|
data class State(
|
||||||
@JvmField
|
@JvmField
|
||||||
val toolchains: Map<String, ZigToolchain.Ref> = emptyMap(),
|
val toolchains: Map<String, ZigToolchain.Ref> = emptyMap(),
|
||||||
|
@ -133,7 +133,18 @@ class ZigToolchainListService: SerializablePersistentStateComponent<ZigToolchain
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getInstance(): ZigToolchainListService = service()
|
fun getInstance(): IService = service<ZigToolchainListService>()
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed interface IService {
|
||||||
|
val toolchains: Sequence<Pair<UUID, ZigToolchain>>
|
||||||
|
fun setToolchain(uuid: UUID, toolchain: ZigToolchain)
|
||||||
|
fun registerNewToolchain(toolchain: ZigToolchain): UUID
|
||||||
|
fun getToolchain(uuid: UUID): ZigToolchain?
|
||||||
|
fun hasToolchain(uuid: UUID): Boolean
|
||||||
|
fun removeToolchain(uuid: UUID)
|
||||||
|
fun addChangeListener(listener: ToolchainListChangeListener)
|
||||||
|
fun removeChangeListener(listener: ToolchainListChangeListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
|
|
|
@ -37,8 +37,8 @@ import java.util.UUID
|
||||||
name = "ZigToolchain",
|
name = "ZigToolchain",
|
||||||
storages = [Storage("zigbrains.xml")]
|
storages = [Storage("zigbrains.xml")]
|
||||||
)
|
)
|
||||||
class ZigToolchainService: SerializablePersistentStateComponent<ZigToolchainService.State>(State()) {
|
class ZigToolchainService: SerializablePersistentStateComponent<ZigToolchainService.State>(State()), ZigToolchainService.IService {
|
||||||
var toolchainUUID: UUID?
|
override var toolchainUUID: UUID?
|
||||||
get() = state.toolchain.ifBlank { null }?.let { UUID.fromString(it) }?.takeIf {
|
get() = state.toolchain.ifBlank { null }?.let { UUID.fromString(it) }?.takeIf {
|
||||||
if (ZigToolchainListService.getInstance().hasToolchain(it)) {
|
if (ZigToolchainListService.getInstance().hasToolchain(it)) {
|
||||||
true
|
true
|
||||||
|
@ -55,7 +55,7 @@ class ZigToolchainService: SerializablePersistentStateComponent<ZigToolchainServ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val toolchain: ZigToolchain?
|
override val toolchain: ZigToolchain?
|
||||||
get() = toolchainUUID?.let { ZigToolchainListService.getInstance().getToolchain(it) }
|
get() = toolchainUUID?.let { ZigToolchainListService.getInstance().getToolchain(it) }
|
||||||
|
|
||||||
data class State(
|
data class State(
|
||||||
|
@ -66,6 +66,11 @@ class ZigToolchainService: SerializablePersistentStateComponent<ZigToolchainServ
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getInstance(project: Project): ZigToolchainService = project.service()
|
fun getInstance(project: Project): IService = project.service<ZigToolchainService>()
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed interface IService {
|
||||||
|
var toolchainUUID: UUID?
|
||||||
|
val toolchain: ZigToolchain?
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,21 +25,23 @@ package com.falsepattern.zigbrains.project.toolchain.base
|
||||||
import com.falsepattern.zigbrains.project.toolchain.tools.ZigCompilerTool
|
import com.falsepattern.zigbrains.project.toolchain.tools.ZigCompilerTool
|
||||||
import com.intellij.execution.configurations.GeneralCommandLine
|
import com.intellij.execution.configurations.GeneralCommandLine
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.UserDataHolderBase
|
|
||||||
import com.intellij.util.xmlb.annotations.Attribute
|
import com.intellij.util.xmlb.annotations.Attribute
|
||||||
import com.intellij.util.xmlb.annotations.MapAnnotation
|
import com.intellij.util.xmlb.annotations.MapAnnotation
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
abstract class ZigToolchain: UserDataHolderBase() {
|
/**
|
||||||
val zig: ZigCompilerTool by lazy { ZigCompilerTool(this) }
|
* These MUST be stateless and interchangeable! (e.g., immutable data class)
|
||||||
|
*/
|
||||||
|
interface ZigToolchain {
|
||||||
|
val zig: ZigCompilerTool get() = ZigCompilerTool(this)
|
||||||
|
|
||||||
abstract val name: String?
|
val name: String?
|
||||||
|
|
||||||
abstract fun workingDirectory(project: Project? = null): Path?
|
fun workingDirectory(project: Project? = null): Path?
|
||||||
|
|
||||||
abstract suspend fun patchCommandLine(commandLine: GeneralCommandLine, project: Project? = null): GeneralCommandLine
|
suspend fun patchCommandLine(commandLine: GeneralCommandLine, project: Project? = null): GeneralCommandLine
|
||||||
|
|
||||||
abstract fun pathToExecutable(toolName: String, project: Project? = null): Path
|
fun pathToExecutable(toolName: String, project: Project? = null): Path
|
||||||
|
|
||||||
data class Ref(
|
data class Ref(
|
||||||
@JvmField
|
@JvmField
|
||||||
|
|
|
@ -26,6 +26,7 @@ import com.falsepattern.zigbrains.project.toolchain.ZigToolchainListService
|
||||||
import com.intellij.openapi.ui.NamedConfigurable
|
import com.intellij.openapi.ui.NamedConfigurable
|
||||||
import com.intellij.openapi.util.NlsContexts
|
import com.intellij.openapi.util.NlsContexts
|
||||||
import com.intellij.ui.dsl.builder.panel
|
import com.intellij.ui.dsl.builder.panel
|
||||||
|
import com.intellij.ui.util.minimumWidth
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import javax.swing.JComponent
|
import javax.swing.JComponent
|
||||||
|
|
||||||
|
@ -40,6 +41,8 @@ abstract class ZigToolchainConfigurable<T: ZigToolchain>(
|
||||||
}
|
}
|
||||||
private var myView: ZigToolchainPanel<T>? = null
|
private var myView: ZigToolchainPanel<T>? = null
|
||||||
|
|
||||||
|
var floating: Boolean = false
|
||||||
|
|
||||||
abstract fun createPanel(): ZigToolchainPanel<T>
|
abstract fun createPanel(): ZigToolchainPanel<T>
|
||||||
|
|
||||||
override fun createOptionsPanel(): JComponent? {
|
override fun createOptionsPanel(): JComponent? {
|
||||||
|
@ -51,7 +54,7 @@ abstract class ZigToolchainConfigurable<T: ZigToolchain>(
|
||||||
}
|
}
|
||||||
return panel {
|
return panel {
|
||||||
view.attach(this)
|
view.attach(this)
|
||||||
}
|
}.withMinimumWidth(20)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getEditableObject(): UUID? {
|
override fun getEditableObject(): UUID? {
|
||||||
|
|
|
@ -27,9 +27,11 @@ import com.intellij.openapi.Disposable
|
||||||
import com.intellij.ui.components.JBTextField
|
import com.intellij.ui.components.JBTextField
|
||||||
import com.intellij.ui.dsl.builder.AlignX
|
import com.intellij.ui.dsl.builder.AlignX
|
||||||
import com.intellij.ui.dsl.builder.Panel
|
import com.intellij.ui.dsl.builder.Panel
|
||||||
|
import com.intellij.ui.util.preferredHeight
|
||||||
|
import java.awt.Dimension
|
||||||
|
|
||||||
abstract class ZigToolchainPanel<T: ZigToolchain>: Disposable {
|
abstract class ZigToolchainPanel<T: ZigToolchain>: Disposable {
|
||||||
private val nameField = JBTextField()
|
private val nameField = JBTextField(25)
|
||||||
|
|
||||||
protected var nameFieldValue: String?
|
protected var nameFieldValue: String?
|
||||||
get() = nameField.text.ifBlank { null }
|
get() = nameField.text.ifBlank { null }
|
||||||
|
|
|
@ -25,6 +25,7 @@ package com.falsepattern.zigbrains.project.toolchain.downloader
|
||||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||||
import com.falsepattern.zigbrains.project.toolchain.local.LocalZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.local.LocalZigToolchain
|
||||||
|
import com.falsepattern.zigbrains.project.toolchain.local.getSuggestedLocalToolchainPath
|
||||||
import com.falsepattern.zigbrains.shared.coroutine.asContextElement
|
import com.falsepattern.zigbrains.shared.coroutine.asContextElement
|
||||||
import com.falsepattern.zigbrains.shared.coroutine.runInterruptibleEDT
|
import com.falsepattern.zigbrains.shared.coroutine.runInterruptibleEDT
|
||||||
import com.intellij.icons.AllIcons
|
import com.intellij.icons.AllIcons
|
||||||
|
@ -52,6 +53,7 @@ import java.util.*
|
||||||
import javax.swing.DefaultComboBoxModel
|
import javax.swing.DefaultComboBoxModel
|
||||||
import javax.swing.JList
|
import javax.swing.JList
|
||||||
import javax.swing.event.DocumentEvent
|
import javax.swing.event.DocumentEvent
|
||||||
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
object Downloader {
|
object Downloader {
|
||||||
suspend fun downloadToolchain(component: Component): ZigToolchain? {
|
suspend fun downloadToolchain(component: Component): ZigToolchain? {
|
||||||
|
@ -129,7 +131,7 @@ object Downloader {
|
||||||
})
|
})
|
||||||
var archiveSizeCell: Cell<*>? = null
|
var archiveSizeCell: Cell<*>? = null
|
||||||
fun detect(item: ZigVersionInfo) {
|
fun detect(item: ZigVersionInfo) {
|
||||||
outputPath.text = System.getProperty("user.home") + "/.zig/" + item.version
|
outputPath.text = getSuggestedLocalToolchainPath()?.resolve(item.version.rawVersion)?.pathString ?: ""
|
||||||
val size = item.dist.size
|
val size = item.dist.size
|
||||||
val sizeMb = size / (1024f * 1024f)
|
val sizeMb = size / (1024f * 1024f)
|
||||||
archiveSizeCell?.comment?.text = ZigBrainsBundle.message("settings.toolchain.downloader.archive-size.text", "%.2fMB".format(sizeMb))
|
archiveSizeCell?.comment?.text = ZigBrainsBundle.message("settings.toolchain.downloader.archive-size.text", "%.2fMB".format(sizeMb))
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
package com.falsepattern.zigbrains.project.toolchain.local
|
package com.falsepattern.zigbrains.project.toolchain.local
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
||||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||||
import com.intellij.execution.ExecutionException
|
import com.intellij.execution.ExecutionException
|
||||||
import com.intellij.execution.configurations.GeneralCommandLine
|
import com.intellij.execution.configurations.GeneralCommandLine
|
||||||
|
@ -35,15 +34,17 @@ import com.intellij.openapi.util.io.toNioPathOrNull
|
||||||
import com.intellij.openapi.vfs.toNioPathOrNull
|
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
data class LocalZigToolchain(val location: Path, val std: Path? = null, override val name: String? = null): ZigToolchain() {
|
@JvmRecord
|
||||||
|
data class LocalZigToolchain(val location: Path, val std: Path? = null, override val name: String? = null): ZigToolchain {
|
||||||
override fun workingDirectory(project: Project?): Path? {
|
override fun workingDirectory(project: Project?): Path? {
|
||||||
return project?.guessProjectDir()?.toNioPathOrNull()
|
return project?.guessProjectDir()?.toNioPathOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun patchCommandLine(commandLine: GeneralCommandLine, project: Project?): GeneralCommandLine {
|
override suspend fun patchCommandLine(commandLine: GeneralCommandLine, project: Project?): GeneralCommandLine {
|
||||||
if (project != null && (commandLine.getUserData(DIRENV_KEY) ?: project.zigProjectSettings.state.direnv)) {
|
//TODO direnv
|
||||||
commandLine.withEnvironment(DirenvCmd.importDirenv(project).env)
|
// if (project != null && (commandLine.getUserData(DIRENV_KEY) ?: project.zigProjectSettings.state.direnv)) {
|
||||||
}
|
// commandLine.withEnvironment(DirenvCmd.importDirenv(project).env)
|
||||||
|
// }
|
||||||
return commandLine
|
return commandLine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ class LocalZigToolchainPanel() : ZigToolchainPanel<LocalZigToolchain>() {
|
||||||
Disposer.register(this, it)
|
Disposer.register(this, it)
|
||||||
}
|
}
|
||||||
private val toolchainVersion = JBTextArea().also { it.isEditable = false }
|
private val toolchainVersion = JBTextArea().also { it.isEditable = false }
|
||||||
private val stdFieldOverride = JBCheckBox(ZigBrainsBundle.message("settings.project.label.override-std")).apply {
|
private val stdFieldOverride = JBCheckBox().apply {
|
||||||
addChangeListener {
|
addChangeListener {
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
pathToStd.isEnabled = true
|
pathToStd.isEnabled = true
|
||||||
|
@ -84,8 +84,8 @@ class LocalZigToolchainPanel() : ZigToolchainPanel<LocalZigToolchain>() {
|
||||||
cell(toolchainVersion)
|
cell(toolchainVersion)
|
||||||
}
|
}
|
||||||
row(ZigBrainsBundle.message("settings.toolchain.local.std.label")) {
|
row(ZigBrainsBundle.message("settings.toolchain.local.std.label")) {
|
||||||
cell(pathToStd).resizableColumn().align(AlignX.FILL)
|
|
||||||
cell(stdFieldOverride)
|
cell(stdFieldOverride)
|
||||||
|
cell(pathToStd).resizableColumn().align(AlignX.FILL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@ package com.falsepattern.zigbrains.project.toolchain.local
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
||||||
import com.falsepattern.zigbrains.direnv.emptyEnv
|
import com.falsepattern.zigbrains.direnv.emptyEnv
|
||||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchainConfigurable
|
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchainConfigurable
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchainProvider
|
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchainProvider
|
||||||
|
@ -37,17 +36,23 @@ import com.intellij.openapi.util.text.StringUtil
|
||||||
import com.intellij.ui.SimpleColoredComponent
|
import com.intellij.ui.SimpleColoredComponent
|
||||||
import com.intellij.ui.SimpleTextAttributes
|
import com.intellij.ui.SimpleTextAttributes
|
||||||
import com.intellij.util.EnvironmentUtil
|
import com.intellij.util.EnvironmentUtil
|
||||||
|
import com.intellij.util.system.OS
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
import kotlin.io.path.isDirectory
|
||||||
import kotlin.io.path.pathString
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
class LocalZigToolchainProvider: ZigToolchainProvider {
|
class LocalZigToolchainProvider: ZigToolchainProvider {
|
||||||
override suspend fun suggestToolchain(project: Project?, extraData: UserDataHolder): LocalZigToolchain? {
|
override suspend fun suggestToolchain(project: Project?, extraData: UserDataHolder): LocalZigToolchain? {
|
||||||
val env = if (project != null && (extraData.getUserData(LocalZigToolchain.DIRENV_KEY) ?: project.zigProjectSettings.state.direnv)) {
|
//TODO direnv
|
||||||
DirenvCmd.importDirenv(project)
|
// val env = if (project != null && (extraData.getUserData(LocalZigToolchain.DIRENV_KEY) ?: project.zigProjectSettings.state.direnv)) {
|
||||||
} else {
|
// DirenvCmd.importDirenv(project)
|
||||||
emptyEnv
|
// } else {
|
||||||
}
|
// emptyEnv
|
||||||
|
// }
|
||||||
|
val env = emptyEnv
|
||||||
val zigExePath = env.findExecutableOnPATH("zig") ?: return null
|
val zigExePath = env.findExecutableOnPATH("zig") ?: return null
|
||||||
return LocalZigToolchain(zigExePath.parent)
|
return LocalZigToolchain(zigExePath.parent)
|
||||||
}
|
}
|
||||||
|
@ -95,6 +100,18 @@ class LocalZigToolchainProvider: ZigToolchainProvider {
|
||||||
override fun suggestToolchains(): List<ZigToolchain> {
|
override fun suggestToolchains(): List<ZigToolchain> {
|
||||||
val res = HashSet<String>()
|
val res = HashSet<String>()
|
||||||
EnvironmentUtil.getValue("PATH")?.split(File.pathSeparatorChar)?.let { res.addAll(it.toList()) }
|
EnvironmentUtil.getValue("PATH")?.split(File.pathSeparatorChar)?.let { res.addAll(it.toList()) }
|
||||||
|
val wellKnown = getWellKnown()
|
||||||
|
wellKnown.forEach { dir ->
|
||||||
|
if (!dir.isDirectory())
|
||||||
|
return@forEach
|
||||||
|
runCatching {
|
||||||
|
Files.newDirectoryStream(dir).use { stream ->
|
||||||
|
stream.forEach { subDir ->
|
||||||
|
res.add(subDir.pathString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return res.mapNotNull { LocalZigToolchain.tryFromPathString(it) }
|
return res.mapNotNull { LocalZigToolchain.tryFromPathString(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +136,25 @@ class LocalZigToolchainProvider: ZigToolchainProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getSuggestedLocalToolchainPath(): Path? {
|
||||||
|
return getWellKnown().getOrNull(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getWellKnown(): List<Path> {
|
||||||
|
val home = System.getProperty("user.home")?.toNioPathOrNull() ?: return emptyList()
|
||||||
|
val xdgDataHome = when(OS.CURRENT) {
|
||||||
|
OS.macOS -> home.resolve("Library")
|
||||||
|
OS.Windows -> System.getenv("LOCALAPPDATA")?.toNioPathOrNull()
|
||||||
|
else -> System.getenv("XDG_DATA_HOME")?.toNioPathOrNull() ?: home.resolve(Path.of(".local", "share"))
|
||||||
|
}
|
||||||
|
val res = ArrayList<Path>()
|
||||||
|
if (xdgDataHome != null && xdgDataHome.isDirectory()) {
|
||||||
|
res.add(xdgDataHome.resolve("zig"))
|
||||||
|
res.add(xdgDataHome.resolve("zigup"))
|
||||||
|
}
|
||||||
|
res.add(home.resolve(".zig"))
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
private fun presentDetectedPath(home: String, maxLength: Int = 50, suffixLength: Int = 30): String {
|
private fun presentDetectedPath(home: String, maxLength: Int = 50, suffixLength: Int = 30): String {
|
||||||
//for macOS, let's try removing Bundle internals
|
//for macOS, let's try removing Bundle internals
|
||||||
|
|
|
@ -25,82 +25,39 @@ package com.falsepattern.zigbrains.project.toolchain.ui
|
||||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainListService
|
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainListService
|
||||||
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainService
|
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainService
|
||||||
|
import com.falsepattern.zigbrains.project.toolchain.base.createNamedConfigurable
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.suggestZigToolchains
|
import com.falsepattern.zigbrains.project.toolchain.base.suggestZigToolchains
|
||||||
|
import com.falsepattern.zigbrains.shared.SubConfigurable
|
||||||
import com.falsepattern.zigbrains.shared.coroutine.asContextElement
|
import com.falsepattern.zigbrains.shared.coroutine.asContextElement
|
||||||
import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT
|
import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT
|
||||||
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
import com.intellij.openapi.Disposable
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.intellij.openapi.application.EDT
|
import com.intellij.openapi.application.EDT
|
||||||
import com.intellij.openapi.options.Configurable
|
|
||||||
import com.intellij.openapi.options.ShowSettingsUtil
|
import com.intellij.openapi.options.ShowSettingsUtil
|
||||||
import com.intellij.openapi.options.newEditor.SettingsDialog
|
|
||||||
import com.intellij.openapi.options.newEditor.SettingsTreeView
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.project.ProjectManager
|
||||||
import com.intellij.openapi.ui.DialogWrapper
|
import com.intellij.openapi.ui.DialogWrapper
|
||||||
import com.intellij.openapi.util.Disposer
|
|
||||||
import com.intellij.openapi.util.NlsContexts
|
|
||||||
import com.intellij.ui.dsl.builder.AlignX
|
import com.intellij.ui.dsl.builder.AlignX
|
||||||
import com.intellij.ui.dsl.builder.Panel
|
import com.intellij.ui.dsl.builder.Panel
|
||||||
import com.intellij.ui.dsl.builder.panel
|
|
||||||
import com.intellij.util.concurrency.annotations.RequiresEdt
|
import com.intellij.util.concurrency.annotations.RequiresEdt
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.awt.event.ItemEvent
|
import java.awt.event.ItemEvent
|
||||||
import java.lang.reflect.Field
|
|
||||||
import java.lang.reflect.Method
|
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import javax.swing.JComponent
|
import javax.swing.JButton
|
||||||
import kotlin.collections.addAll
|
import kotlin.collections.addAll
|
||||||
|
|
||||||
class ZigToolchainEditor(private val project: Project): Configurable {
|
class ZigToolchainEditor(private val isForDefaultProject: Boolean = false): SubConfigurable<Project>, ZigToolchainListService.ToolchainListChangeListener {
|
||||||
private var myUi: UI? = null
|
|
||||||
override fun getDisplayName(): @NlsContexts.ConfigurableName String? {
|
|
||||||
return ZigBrainsBundle.message("settings.toolchain.editor.display-name")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createComponent(): JComponent? {
|
|
||||||
if (myUi != null) {
|
|
||||||
disposeUIResources()
|
|
||||||
}
|
|
||||||
val ui = UI()
|
|
||||||
myUi = ui
|
|
||||||
return panel {
|
|
||||||
ui.attach(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isModified(): Boolean {
|
|
||||||
return myUi?.isModified() == true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun apply() {
|
|
||||||
myUi?.apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
myUi?.reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun disposeUIResources() {
|
|
||||||
myUi?.let { Disposer.dispose(it) }
|
|
||||||
myUi = null
|
|
||||||
super.disposeUIResources()
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class UI(): Disposable, ZigToolchainListService.ToolchainListChangeListener {
|
|
||||||
private val toolchainBox: TCComboBox
|
private val toolchainBox: TCComboBox
|
||||||
private var selectOnNextReload: UUID? = null
|
private var selectOnNextReload: UUID? = null
|
||||||
private val model: TCModel
|
private val model: TCModel
|
||||||
|
private lateinit var editButton: JButton
|
||||||
init {
|
init {
|
||||||
model = TCModel(getModelList())
|
model = TCModel(getModelList())
|
||||||
toolchainBox = TCComboBox(model)
|
toolchainBox = TCComboBox(model)
|
||||||
toolchainBox.addItemListener(::itemStateChanged)
|
toolchainBox.addItemListener(::itemStateChanged)
|
||||||
ZigToolchainListService.getInstance().addChangeListener(this)
|
ZigToolchainListService.getInstance().addChangeListener(this)
|
||||||
reset()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun itemStateChanged(event: ItemEvent) {
|
private fun itemStateChanged(event: ItemEvent) {
|
||||||
|
@ -148,30 +105,31 @@ class ZigToolchainEditor(private val project: Project): Configurable {
|
||||||
}
|
}
|
||||||
model.selectedItem = TCListElem.None
|
model.selectedItem = TCListElem.None
|
||||||
}
|
}
|
||||||
|
withContext(Dispatchers.EDT + editButton.asContextElement()) {
|
||||||
|
editButton.isEnabled = model.selectedItem is TCListElem.Toolchain.Actual
|
||||||
|
editButton.repaint()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun attach(p: Panel): Unit = with(p) {
|
override fun attach(p: Panel): Unit = with(p) {
|
||||||
row(ZigBrainsBundle.message("settings.toolchain.editor.toolchain.label")) {
|
row(ZigBrainsBundle.message(
|
||||||
|
if (isForDefaultProject)
|
||||||
|
"settings.toolchain.editor.toolchain-default.label"
|
||||||
|
else
|
||||||
|
"settings.toolchain.editor.toolchain.label")
|
||||||
|
) {
|
||||||
cell(toolchainBox).resizableColumn().align(AlignX.FILL)
|
cell(toolchainBox).resizableColumn().align(AlignX.FILL)
|
||||||
button(ZigBrainsBundle.message("settings.toolchain.editor.toolchain.edit-button.name")) { e ->
|
button(ZigBrainsBundle.message("settings.toolchain.editor.toolchain.edit-button.name")) { e ->
|
||||||
zigCoroutineScope.launchWithEDT(toolchainBox.asContextElement()) {
|
zigCoroutineScope.launchWithEDT(toolchainBox.asContextElement()) {
|
||||||
val config = ZigToolchainListEditor()
|
var selectedUUID = toolchainBox.selectedToolchain ?: return@launchWithEDT
|
||||||
var inited = false
|
val toolchain = ZigToolchainListService.getInstance().getToolchain(selectedUUID) ?: return@launchWithEDT
|
||||||
var selectedUUID: UUID? = toolchainBox.selectedToolchain
|
val config = toolchain.createNamedConfigurable(selectedUUID)
|
||||||
config.addItemSelectedListener {
|
val apply = ShowSettingsUtil.getInstance().editConfigurable(DialogWrapper.findInstance(toolchainBox)?.contentPane, config)
|
||||||
if (inited) {
|
|
||||||
selectedUUID = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val apply = ShowSettingsUtil.getInstance().editConfigurable(DialogWrapper.findInstance(toolchainBox)?.contentPane, config) {
|
|
||||||
config.selectNodeInTree(selectedUUID)
|
|
||||||
inited = true
|
|
||||||
}
|
|
||||||
if (apply) {
|
if (apply) {
|
||||||
applyUUIDNowOrOnReload(selectedUUID)
|
applyUUIDNowOrOnReload(selectedUUID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}.component.let { editButton = it }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,23 +143,28 @@ class ZigToolchainEditor(private val project: Project): Configurable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isModified(): Boolean {
|
override fun isModified(context: Project): Boolean {
|
||||||
return ZigToolchainService.getInstance(project).toolchainUUID != toolchainBox.selectedToolchain
|
return ZigToolchainService.getInstance(context).toolchainUUID != toolchainBox.selectedToolchain
|
||||||
}
|
}
|
||||||
|
|
||||||
fun apply() {
|
override fun apply(context: Project) {
|
||||||
ZigToolchainService.getInstance(project).toolchainUUID = toolchainBox.selectedToolchain
|
ZigToolchainService.getInstance(context).toolchainUUID = toolchainBox.selectedToolchain
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reset() {
|
override fun reset(context: Project?) {
|
||||||
|
val project = context ?: ProjectManager.getInstance().defaultProject
|
||||||
toolchainBox.selectedToolchain = ZigToolchainService.getInstance(project).toolchainUUID
|
toolchainBox.selectedToolchain = ZigToolchainService.getInstance(project).toolchainUUID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
ZigToolchainListService.getInstance().removeChangeListener(this)
|
ZigToolchainListService.getInstance().removeChangeListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val newProjectBeforeInitSelector get() = true
|
||||||
|
|
||||||
|
class Adapter(override val context: Project): SubConfigurable.Adapter<Project>() {
|
||||||
|
override fun instantiate() = ZigToolchainEditor(context.isDefault)
|
||||||
|
override fun getDisplayName() = ZigBrainsBundle.message("settings.toolchain.editor.display-name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.shared
|
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider
|
|
||||||
import com.intellij.openapi.options.Configurable
|
|
||||||
import com.intellij.openapi.util.Disposer
|
|
||||||
import com.intellij.ui.dsl.builder.panel
|
|
||||||
import javax.swing.JComponent
|
|
||||||
|
|
||||||
abstract class MultiConfigurable(val configurables: List<SubConfigurable>): Configurable, ZigProjectConfigurationProvider.SettingsPanelHolder {
|
|
||||||
final override var panels: List<ZigProjectConfigurationProvider.SettingsPanel> = emptyList()
|
|
||||||
private set
|
|
||||||
|
|
||||||
override fun createComponent(): JComponent? {
|
|
||||||
return panel {
|
|
||||||
panels = configurables.map { it.createComponent(this@MultiConfigurable, this@panel) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isModified(): Boolean {
|
|
||||||
return configurables.any { it.isModified() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun apply() {
|
|
||||||
configurables.forEach { it.apply() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun reset() {
|
|
||||||
configurables.forEach { it.reset() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun disposeUIResources() {
|
|
||||||
configurables.forEach { Disposer.dispose(it) }
|
|
||||||
panels = emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,16 +22,56 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.shared
|
package com.falsepattern.zigbrains.shared
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider
|
|
||||||
import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider.SettingsPanelHolder
|
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
import com.intellij.openapi.options.ConfigurationException
|
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 com.intellij.ui.dsl.builder.panel
|
||||||
|
import javax.swing.JComponent
|
||||||
|
|
||||||
interface SubConfigurable: Disposable {
|
interface SubConfigurable<T>: Disposable {
|
||||||
fun createComponent(holder: SettingsPanelHolder, panel: Panel): ZigProjectConfigurationProvider.SettingsPanel
|
fun attach(panel: Panel)
|
||||||
fun isModified(): Boolean
|
fun isModified(context: T): Boolean
|
||||||
@Throws(ConfigurationException::class)
|
fun apply(context: T)
|
||||||
fun apply()
|
fun reset(context: T?)
|
||||||
fun reset()
|
|
||||||
|
val newProjectBeforeInitSelector: Boolean get() = false
|
||||||
|
|
||||||
|
abstract class Adapter<T>: Configurable {
|
||||||
|
private var myConfigurable: SubConfigurable<T>? = null
|
||||||
|
|
||||||
|
abstract fun instantiate(): SubConfigurable<T>
|
||||||
|
protected abstract val context: T
|
||||||
|
|
||||||
|
override fun createComponent(): JComponent? {
|
||||||
|
if (myConfigurable != null) {
|
||||||
|
disposeUIResources()
|
||||||
|
}
|
||||||
|
val configurable = instantiate()
|
||||||
|
configurable.reset(context)
|
||||||
|
myConfigurable = configurable
|
||||||
|
return panel {
|
||||||
|
configurable.attach(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isModified(): Boolean {
|
||||||
|
return myConfigurable?.isModified(context) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun apply() {
|
||||||
|
myConfigurable?.apply(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reset() {
|
||||||
|
myConfigurable?.reset(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun disposeUIResources() {
|
||||||
|
val configurable = myConfigurable
|
||||||
|
myConfigurable = null
|
||||||
|
configurable?.let { Disposer.dispose(it) }
|
||||||
|
super.disposeUIResources()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -140,7 +140,7 @@
|
||||||
/>
|
/>
|
||||||
<projectConfigurable
|
<projectConfigurable
|
||||||
parentId="language"
|
parentId="language"
|
||||||
instance="com.falsepattern.zigbrains.project.toolchain.ui.ZigToolchainEditor"
|
instance="com.falsepattern.zigbrains.project.toolchain.ui.ZigToolchainEditor$Adapter"
|
||||||
id="ZigConfigurable"
|
id="ZigConfigurable"
|
||||||
displayName="Zig"
|
displayName="Zig"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -116,6 +116,7 @@ settings.toolchain.local.version.label=Detected zig version
|
||||||
settings.toolchain.local.std.label=Override standard library
|
settings.toolchain.local.std.label=Override standard library
|
||||||
settings.toolchain.editor.display-name=Zig
|
settings.toolchain.editor.display-name=Zig
|
||||||
settings.toolchain.editor.toolchain.label=Toolchain
|
settings.toolchain.editor.toolchain.label=Toolchain
|
||||||
|
settings.toolchain.editor.toolchain-default.label=Default toolchain
|
||||||
settings.toolchain.editor.toolchain.edit-button.name=Edit
|
settings.toolchain.editor.toolchain.edit-button.name=Edit
|
||||||
settings.toolchain.model.detected.separator=Detected toolchains
|
settings.toolchain.model.detected.separator=Detected toolchains
|
||||||
settings.toolchain.model.none.text=<No Toolchain>
|
settings.toolchain.model.none.text=<No Toolchain>
|
||||||
|
|
|
@ -34,7 +34,7 @@ class ZLSProjectConfigurationProvider: ZigProjectConfigurationProvider {
|
||||||
startLSP(project, true)
|
startLSP(project, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createConfigurable(project: Project): SubConfigurable {
|
override fun createConfigurable(project: Project): SubConfigurable<Project> {
|
||||||
return ZLSSettingsConfigurable(project)
|
return ZLSSettingsConfigurable(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<vendor>FalsePattern</vendor>
|
<vendor>FalsePattern</vendor>
|
||||||
|
|
||||||
<depends config-file="zigbrains-core.xml">com.intellij.modules.platform</depends>
|
<depends config-file="zigbrains-core.xml">com.intellij.modules.platform</depends>
|
||||||
<depends config-file="zigbrains-lsp.xml">com.redhat.devtools.lsp4ij</depends>
|
<depends config-file="zigbrains-lsp.xml" optional="true">com.redhat.devtools.lsp4ij</depends>
|
||||||
<depends config-file="zigbrains-debugger.xml" optional="true">com.intellij.modules.cidr.debugger</depends>
|
<depends config-file="zigbrains-debugger.xml" optional="true">com.intellij.modules.cidr.debugger</depends>
|
||||||
<depends config-file="zigbrains-cidr.xml" optional="true">com.intellij.cidr.base</depends>
|
<depends config-file="zigbrains-cidr.xml" optional="true">com.intellij.cidr.base</depends>
|
||||||
<depends config-file="zigbrains-clion.xml" optional="true">com.intellij.clion</depends>
|
<depends config-file="zigbrains-clion.xml" optional="true">com.intellij.clion</depends>
|
||||||
|
|
Loading…
Add table
Reference in a new issue