From dd9c6daae760d7b08450da23f93c33e20b5b1144 Mon Sep 17 00:00:00 2001 From: FalsePattern Date: Sun, 23 Mar 2025 13:59:05 +0100 Subject: [PATCH] backport: 23.1.0 --- CHANGELOG.md | 12 +++ build.gradle.kts | 1 + .../project/actions/ZigRunFileAction.kt | 90 +++++++++++++++++++ .../project/execution/base/Configuration.kt | 6 -- .../execution/base/ZigConfigProducer.kt | 8 +- .../project/execution/base/ZigExecConfig.kt | 8 +- .../execution/build/ZigConfigProducerBuild.kt | 18 ++-- .../execution/run/ZigConfigProducerRun.kt | 18 ++-- .../execution/test/ZigConfigProducerTest.kt | 22 ++--- .../project/newproject/ZigNewProjectPanel.kt | 4 +- .../ZigCoreProjectConfigurationProvider.kt | 4 +- .../settings/ZigProjectConfigurable.kt | 6 +- .../ZigProjectConfigurationProvider.kt | 10 ++- .../settings/ZigProjectSettingsPanel.kt | 14 ++- .../zigbrains/shared/MultiConfigurable.kt | 11 ++- .../zigbrains/shared/SubConfigurable.kt | 4 +- .../resources/META-INF/zigbrains-core.xml | 8 +- .../resources/zigbrains/Bundle.properties | 10 --- gradle.properties | 2 +- .../lsp/ZLSProjectConfigurationProvider.kt | 2 +- .../falsepattern/zigbrains/lsp/ZLSStartup.kt | 3 +- .../lsp/ZLSStreamConnectionProvider.kt | 3 +- .../lsp/settings/ZLSProjectSettingsService.kt | 3 +- .../zigbrains/lsp/settings/ZLSSettings.kt | 1 - .../lsp/settings/ZLSSettingsConfigurable.kt | 7 +- .../lsp/settings/ZLSSettingsPanel.kt | 21 ++--- 26 files changed, 206 insertions(+), 90 deletions(-) create mode 100644 core/src/main/kotlin/com/falsepattern/zigbrains/project/actions/ZigRunFileAction.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ce3e680..4a816f7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,18 @@ Changelog structure reference: ## [Unreleased] +## [23.1.0] + +### Added + +- Project + - Support running file main/tests with hotkey (default: ctrl+shift+f10) + +### Changed + +- Direnv + - Centralized all direnv toggling into a single project-level option + ## [23.0.2] ### Fixed diff --git a/build.gradle.kts b/build.gradle.kts index 3e1a2f38..e6e9f163 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -205,6 +205,7 @@ publishVersions.forEach { archiveFile = distFile(it) token = providers.environmentVariable("IJ_PUBLISH_TOKEN") channels = if (pluginVersion.contains("-")) listOf("nightly") else listOf("default") + setDependsOn(dependsOn.filter { if (it is TaskProvider<*>) it.name != "signPlugin" && it.name != "buildPlugin" else true }) } tasks.named("publish").configure { dependsOn("jbpublish-$it") diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/actions/ZigRunFileAction.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/actions/ZigRunFileAction.kt new file mode 100644 index 00000000..27aaa33b --- /dev/null +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/actions/ZigRunFileAction.kt @@ -0,0 +1,90 @@ +/* + * This file is part of ZigBrains. + * + * Copyright (C) 2023-2025 FalsePattern + * All Rights Reserved + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * ZigBrains is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, only version 3 of the License. + * + * ZigBrains is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with ZigBrains. If not, see . + */ + +package com.falsepattern.zigbrains.project.actions + +import com.falsepattern.zigbrains.project.execution.base.ZigExecConfig +import com.falsepattern.zigbrains.project.execution.run.ZigConfigProducerRun +import com.falsepattern.zigbrains.project.execution.run.ZigExecConfigRun +import com.falsepattern.zigbrains.project.execution.test.ZigConfigProducerTest +import com.falsepattern.zigbrains.project.execution.test.ZigExecConfigTest +import com.intellij.execution.ExecutionManager +import com.intellij.execution.actions.ConfigurationContext +import com.intellij.execution.actions.RunConfigurationProducer +import com.intellij.execution.executors.DefaultRunExecutor +import com.intellij.execution.runners.ExecutionEnvironmentBuilder +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.CommonDataKeys +import com.intellij.openapi.project.DumbAwareAction + +class ZigRunFileAction: DumbAwareAction() { + override fun actionPerformed(e: AnActionEvent) { + val file = e.getData(CommonDataKeys.PSI_FILE) ?: return + val config = getConfig(e) ?: return + val project = file.project + val builder = ExecutionEnvironmentBuilder.createOrNull(DefaultRunExecutor.getRunExecutorInstance(), config) ?: return + ExecutionManager.getInstance(project).restartRunProfile(builder.build()) + } + + private fun getConfig(e: AnActionEvent): ZigExecConfig<*>? { + val context = ConfigurationContext.getFromContext(e.dataContext, e.place) + return getRunConfiguration(context) ?: getTestConfiguration(context) + } + + override fun update(e: AnActionEvent) { + e.presentation.isEnabledAndVisible = getConfig(e) != null + } + + private fun getRunConfiguration(context: ConfigurationContext): ZigExecConfigRun? { + try { + val configProducer = RunConfigurationProducer.getInstance(ZigConfigProducerRun::class.java) + val settings = configProducer.findExistingConfiguration(context) + if (settings != null) { + return settings.configuration as? ZigExecConfigRun + } + val fromContext = configProducer.createConfigurationFromContext(context) + if (fromContext != null) { + return fromContext.configuration as? ZigExecConfigRun + } + } catch (_: NullPointerException) {} + return null + } + private fun getTestConfiguration(context: ConfigurationContext): ZigExecConfigTest? { + try { + val configProducer = RunConfigurationProducer.getInstance(ZigConfigProducerTest::class.java) + val settings = configProducer.findExistingConfiguration(context) + if (settings != null) { + return settings.configuration as? ZigExecConfigTest + } + val fromContext = configProducer.createConfigurationFromContext(context) + if (fromContext != null) { + return fromContext.configuration as? ZigExecConfigTest + } + } catch (_: NullPointerException) {} + return null + } + + override fun getActionUpdateThread(): ActionUpdateThread { + return ActionUpdateThread.BGT + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/Configuration.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/Configuration.kt index 62e524f5..913fe604 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/Configuration.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/Configuration.kt @@ -280,12 +280,6 @@ class ColoredConfigurable(serializedName: String): CheckboxConfigurable(serializ } } -class DirenvConfigurable(serializedName: String, project: Project): CheckboxConfigurable(serializedName, ZigBrainsBundle.message("exec.option.label.direnv"), project.zigProjectSettings.state.direnv) { - override fun clone(): DirenvConfigurable { - return super.clone() as DirenvConfigurable - } -} - class OptimizationConfigurable( @Transient private val serializedName: String, var level: OptimizationLevel = OptimizationLevel.Debug, diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigConfigProducer.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigConfigProducer.kt index 8f9c50df..8d4c1ab6 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigConfigProducer.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigConfigProducer.kt @@ -41,7 +41,7 @@ abstract class ZigConfigProducer>: LazyRunConfigurationProdu val psiFile = element.containingFile as? ZigFile ?: return false val theFile = psiFile.virtualFile ?: return false val filePath = theFile.toNioPathOrNull() ?: return false - return setupConfigurationFromContext(configuration, element, filePath, theFile) + return setupConfigurationFromContext(configuration, element, psiFile, filePath, theFile) } override fun isConfigurationFromContext(configuration: T, context: ConfigurationContext): Boolean { @@ -49,7 +49,7 @@ abstract class ZigConfigProducer>: LazyRunConfigurationProdu val psiFile = element.containingFile as? ZigFile ?: return false val theFile = psiFile.virtualFile ?: return false val filePath = theFile.toNioPathOrNull() ?: return false - return isConfigurationFromContext(configuration, element, filePath, theFile) + return isConfigurationFromContext(configuration, element, psiFile, filePath, theFile) } /* @@ -78,7 +78,7 @@ abstract class ZigConfigProducer>: LazyRunConfigurationProdu } */ - protected abstract fun setupConfigurationFromContext(configuration: T, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean - protected abstract fun isConfigurationFromContext(configuration: T, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean + protected abstract fun setupConfigurationFromContext(configuration: T, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean + protected abstract fun isConfigurationFromContext(configuration: T, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean abstract override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean } \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigExecConfig.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigExecConfig.kt index ab1ab23b..b03b16ad 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigExecConfig.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigExecConfig.kt @@ -24,6 +24,7 @@ package com.falsepattern.zigbrains.project.execution.base import com.falsepattern.zigbrains.ZigBrainsBundle import com.falsepattern.zigbrains.direnv.DirenvCmd +import com.falsepattern.zigbrains.project.settings.zigProjectSettings import com.intellij.execution.ExecutionException import com.intellij.execution.Executor import com.intellij.execution.configurations.ConfigurationFactory @@ -44,8 +45,6 @@ abstract class ZigExecConfig>(project: Project, factory: Con private set var pty = CheckboxConfigurable("pty", ZigBrainsBundle.message("exec.option.label.emulate-terminal"), false) private set - var direnv = DirenvConfigurable("direnv", project) - private set abstract val suggestedName: @ActionText String @Throws(ExecutionException::class) @@ -68,7 +67,7 @@ abstract class ZigExecConfig>(project: Project, factory: Con suspend fun patchCommandLine(commandLine: GeneralCommandLine): GeneralCommandLine { - if (direnv.value) { + if (project.zigProjectSettings.state.direnv) { commandLine.withEnvironment(DirenvCmd.importDirenv(project).env) } return commandLine @@ -82,10 +81,9 @@ abstract class ZigExecConfig>(project: Project, factory: Con val myClone = super.clone() as ZigExecConfig<*> myClone.workingDirectory = workingDirectory.clone() myClone.pty = pty.clone() - myClone.direnv = direnv.clone() @Suppress("UNCHECKED_CAST") return myClone as T } - open fun getConfigurables(): List> = listOf(workingDirectory, pty, direnv) + open fun getConfigurables(): List> = listOf(workingDirectory, pty) } \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigConfigProducerBuild.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigConfigProducerBuild.kt index 2d027c88..db3675f3 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigConfigProducerBuild.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigConfigProducerBuild.kt @@ -25,6 +25,7 @@ package com.falsepattern.zigbrains.project.execution.build import com.falsepattern.zigbrains.ZigBrainsBundle import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer import com.falsepattern.zigbrains.project.execution.firstConfigFactory +import com.falsepattern.zigbrains.zig.psi.ZigFile import com.intellij.execution.actions.ConfigurationFromContext import com.intellij.execution.configurations.ConfigurationFactory import com.intellij.openapi.vfs.VirtualFile @@ -36,21 +37,18 @@ class ZigConfigProducerBuild: ZigConfigProducer() { return firstConfigFactory() } - override fun setupConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean { - if (LINE_MARKER.elementMatches(element)) { - configuration.name = ZigBrainsBundle.message("configuration.build.marker-name") - return true - } - return false + override fun setupConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean { + if (theFile.name != "build.zig") + return false + configuration.name = ZigBrainsBundle.message("configuration.build.marker-name") + return true } - override fun isConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean { + override fun isConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean { return filePath.parent == (configuration.workingDirectory.path ?: return false) } override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { return self.configurationType is ZigConfigTypeBuild } -} - -private val LINE_MARKER = ZigLineMarkerBuild() \ No newline at end of file +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigConfigProducerRun.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigConfigProducerRun.kt index 65c98081..684058d4 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigConfigProducerRun.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigConfigProducerRun.kt @@ -24,10 +24,13 @@ package com.falsepattern.zigbrains.project.execution.run import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer import com.falsepattern.zigbrains.project.execution.firstConfigFactory +import com.falsepattern.zigbrains.zig.psi.ZigContainerMembers +import com.falsepattern.zigbrains.zig.psi.ZigFile import com.intellij.execution.actions.ConfigurationFromContext import com.intellij.execution.configurations.ConfigurationFactory import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiElement +import com.intellij.psi.util.childrenOfType import java.nio.file.Path class ZigConfigProducerRun: ZigConfigProducer() { @@ -35,16 +38,17 @@ class ZigConfigProducerRun: ZigConfigProducer() { return firstConfigFactory() } - override fun setupConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean { - if (LINE_MARKER.elementMatches(element)) { - configuration.filePath.path = filePath - configuration.name = theFile.presentableName - return true + override fun setupConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean { + val members = psiFile.childrenOfType().firstOrNull() ?: return false + if (members.containerDeclarationList.none { it.decl?.fnProto?.identifier?.textMatches("main") == true }) { + return false } - return false + configuration.filePath.path = filePath + configuration.name = theFile.presentableName + return true } - override fun isConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean { + override fun isConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean { return filePath == configuration.filePath.path } diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigConfigProducerTest.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigConfigProducerTest.kt index 73d01aad..e215785e 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigConfigProducerTest.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigConfigProducerTest.kt @@ -25,10 +25,13 @@ package com.falsepattern.zigbrains.project.execution.test import com.falsepattern.zigbrains.ZigBrainsBundle import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer import com.falsepattern.zigbrains.project.execution.firstConfigFactory +import com.falsepattern.zigbrains.zig.psi.ZigContainerMembers +import com.falsepattern.zigbrains.zig.psi.ZigFile import com.intellij.execution.actions.ConfigurationFromContext import com.intellij.execution.configurations.ConfigurationFactory import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiElement +import com.intellij.psi.util.childrenOfType import java.nio.file.Path class ZigConfigProducerTest: ZigConfigProducer() { @@ -36,22 +39,21 @@ class ZigConfigProducerTest: ZigConfigProducer() { return firstConfigFactory() } - override fun setupConfigurationFromContext(configuration: ZigExecConfigTest, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean { - if (LINE_MARKER.elementMatches(element)) { - configuration.filePath.path = filePath - configuration.name = ZigBrainsBundle.message("configuration.test.marker-name", theFile.presentableName) - return true + override fun setupConfigurationFromContext(configuration: ZigExecConfigTest, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean { + val members = psiFile.childrenOfType().firstOrNull() ?: return false + if (members.containerDeclarationList.none { it.testDecl != null }) { + return false } - return false + configuration.filePath.path = filePath + configuration.name = ZigBrainsBundle.message("configuration.test.marker-name", theFile.presentableName) + return true } - override fun isConfigurationFromContext(configuration: ZigExecConfigTest, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean { + override fun isConfigurationFromContext(configuration: ZigExecConfigTest, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean { return filePath == configuration.filePath.path } override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { return self.configurationType is ZigConfigTypeTest } -} - -private val LINE_MARKER = ZigLineMarkerTest() \ No newline at end of file +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigNewProjectPanel.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigNewProjectPanel.kt index 6418285b..ac1abd24 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigNewProjectPanel.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigNewProjectPanel.kt @@ -39,9 +39,9 @@ import com.intellij.util.ui.JBUI import javax.swing.JList import javax.swing.ListSelectionModel -class ZigNewProjectPanel(private var handleGit: Boolean): Disposable { +class ZigNewProjectPanel(private var handleGit: Boolean): Disposable, ZigProjectConfigurationProvider.SettingsPanelHolder { private val git = JBCheckBox() - private val panels = ZigProjectConfigurationProvider.createNewProjectSettingsPanels().onEach { Disposer.register(this, it) } + override val panels = ZigProjectConfigurationProvider.createNewProjectSettingsPanels(this).onEach { Disposer.register(this, it) } private val templateList = JBList(JBList.createDefaultListModel(defaultTemplates)).apply { selectionMode = ListSelectionModel.SINGLE_SELECTION selectedIndex = 0 diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigCoreProjectConfigurationProvider.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigCoreProjectConfigurationProvider.kt index d8a76a88..207da863 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigCoreProjectConfigurationProvider.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigCoreProjectConfigurationProvider.kt @@ -34,8 +34,8 @@ class ZigCoreProjectConfigurationProvider: ZigProjectConfigurationProvider { return ZigProjectConfigurable(project) } - override fun createNewProjectSettingsPanel(): ZigProjectConfigurationProvider.SettingsPanel { - return ZigProjectSettingsPanel(ProjectManager.getInstance().defaultProject) + override fun createNewProjectSettingsPanel(holder: ZigProjectConfigurationProvider.SettingsPanelHolder): ZigProjectConfigurationProvider.SettingsPanel { + return ZigProjectSettingsPanel(holder, ProjectManager.getInstance().defaultProject) } override val priority: Int diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectConfigurable.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectConfigurable.kt index c45adba7..ff333f79 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectConfigurable.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectConfigurable.kt @@ -29,9 +29,11 @@ import com.intellij.ui.dsl.builder.Panel class ZigProjectConfigurable(private val project: Project): SubConfigurable { private var settingsPanel: ZigProjectSettingsPanel? = null - override fun createComponent(panel: Panel) { + override fun createComponent(holder: ZigProjectConfigurationProvider.SettingsPanelHolder, panel: Panel): ZigProjectConfigurationProvider.SettingsPanel { settingsPanel?.let { Disposer.dispose(it) } - settingsPanel = ZigProjectSettingsPanel(project).apply { attach(panel) }.also { Disposer.register(this, it) } + val sp = ZigProjectSettingsPanel(holder, project).apply { attach(panel) }.also { Disposer.register(this, it) } + settingsPanel = sp + return sp } override fun isModified(): Boolean { diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectConfigurationProvider.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectConfigurationProvider.kt index 058e18b6..a609a3ee 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectConfigurationProvider.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectConfigurationProvider.kt @@ -32,7 +32,7 @@ import com.intellij.ui.dsl.builder.Panel interface ZigProjectConfigurationProvider { fun handleMainConfigChanged(project: Project) fun createConfigurable(project: Project): SubConfigurable - fun createNewProjectSettingsPanel(): SettingsPanel? + fun createNewProjectSettingsPanel(holder: SettingsPanelHolder): SettingsPanel? val priority: Int companion object { private val EXTENSION_POINT_NAME = ExtensionPointName.create("com.falsepattern.zigbrains.projectConfigProvider") @@ -42,13 +42,17 @@ interface ZigProjectConfigurationProvider { fun createConfigurables(project: Project): List { return EXTENSION_POINT_NAME.extensionList.sortedBy { it.priority }.map { it.createConfigurable(project) } } - fun createNewProjectSettingsPanels(): List { - return EXTENSION_POINT_NAME.extensionList.sortedBy { it.priority }.mapNotNull { it.createNewProjectSettingsPanel() } + fun createNewProjectSettingsPanels(holder: SettingsPanelHolder): List { + return EXTENSION_POINT_NAME.extensionList.sortedBy { it.priority }.mapNotNull { it.createNewProjectSettingsPanel(holder) } } } interface SettingsPanel: Disposable { val data: Settings fun attach(p: Panel) + fun direnvChanged(state: Boolean) + } + interface SettingsPanelHolder { + val panels: List } interface Settings { fun apply(project: Project) diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettingsPanel.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettingsPanel.kt index b248e9ae..7a8fa6cc 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettingsPanel.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettingsPanel.kt @@ -52,9 +52,9 @@ import kotlinx.coroutines.launch import javax.swing.event.DocumentEvent import kotlin.io.path.pathString -class ZigProjectSettingsPanel(private val project: Project) : ZigProjectConfigurationProvider.SettingsPanel { +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 { - dispatchAutodetect(true) + dispatchDirenvUpdate() } } private val pathToToolchain = textFieldWithBrowseButton( project, @@ -86,6 +86,16 @@ class ZigProjectSettingsPanel(private val project: Project) : ZigProjectConfigur ).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 { withModalProgress(ModalTaskOwner.component(pathToToolchain), "Detecting Zig...", TaskCancellation.cancellable()) { diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/shared/MultiConfigurable.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/shared/MultiConfigurable.kt index 97c22e0a..36c30c13 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/shared/MultiConfigurable.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/shared/MultiConfigurable.kt @@ -22,17 +22,19 @@ 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(private val configurables: List): Configurable { +abstract class MultiConfigurable(val configurables: List): Configurable, ZigProjectConfigurationProvider.SettingsPanelHolder { + final override var panels: List = emptyList() + private set + override fun createComponent(): JComponent? { return panel { - for (configurable in configurables) { - configurable.createComponent(this) - } + panels = configurables.map { it.createComponent(this@MultiConfigurable, this@panel) } } } @@ -50,5 +52,6 @@ abstract class MultiConfigurable(private val configurables: List + icon="com.falsepattern.zigbrains.Icons.Zig"> + + diff --git a/core/src/main/resources/zigbrains/Bundle.properties b/core/src/main/resources/zigbrains/Bundle.properties index 68fc69a0..62f99988 100644 --- a/core/src/main/resources/zigbrains/Bundle.properties +++ b/core/src/main/resources/zigbrains/Bundle.properties @@ -53,16 +53,6 @@ zig.color-settings.variable-decl-depr=Variable//Declaration//Deprecated zig.color-settings.variable-ref=Variable//Reference zig.color-settings.variable-ref-depr=Variable//Reference//Deprecated zon.file.description=Zig object notation file -configurable.name.zon-color-settings-page=Zon -zon.color-settings.eq=Equals -zon.color-settings.id=Identifier -zon.color-settings.comment=Comment -zon.color-settings.bad_char=Bad value -zon.color-settings.string=String -zon.color-settings.comma=Comma -zon.color-settings.dot=Dot -zon.color-settings.boolean=Boolean -zon.color-settings.brace=Braces notification.group.zigbrains=ZigBrains notification.title.native-debug=Zig native debugger notification.content.native-debug=You need to install the "Native Debugging Support" plugin for Zig debugging in this IDE! diff --git a/gradle.properties b/gradle.properties index 0bc80027..9191f833 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ pluginName=ZigBrains pluginRepositoryUrl=https://github.com/FalsePattern/ZigBrains -pluginVersion=23.0.2 +pluginVersion=23.1.0 pluginSinceBuild=241 pluginUntilBuild=241.* diff --git a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSProjectConfigurationProvider.kt b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSProjectConfigurationProvider.kt index 5ce04806..5a1b423a 100644 --- a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSProjectConfigurationProvider.kt +++ b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSProjectConfigurationProvider.kt @@ -38,7 +38,7 @@ class ZLSProjectConfigurationProvider: ZigProjectConfigurationProvider { return ZLSSettingsConfigurable(project) } - override fun createNewProjectSettingsPanel(): ZigProjectConfigurationProvider.SettingsPanel { + override fun createNewProjectSettingsPanel(holder: ZigProjectConfigurationProvider.SettingsPanelHolder): ZigProjectConfigurationProvider.SettingsPanel { return ZLSSettingsPanel(ProjectManager.getInstance().defaultProject) } diff --git a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSStartup.kt b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSStartup.kt index 370a2408..d197dd30 100644 --- a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSStartup.kt +++ b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSStartup.kt @@ -26,6 +26,7 @@ import com.falsepattern.zigbrains.direnv.DirenvCmd import com.falsepattern.zigbrains.direnv.emptyEnv import com.falsepattern.zigbrains.direnv.getDirenv import com.falsepattern.zigbrains.lsp.settings.zlsSettings +import com.falsepattern.zigbrains.project.settings.zigProjectSettings import com.falsepattern.zigbrains.shared.zigCoroutineScope import com.intellij.openapi.project.Project import com.intellij.openapi.startup.ProjectActivity @@ -38,7 +39,7 @@ class ZLSStartup: ProjectActivity { override suspend fun execute(project: Project) { val zlsState = project.zlsSettings.state if (zlsState.zlsPath.isBlank()) { - val env = if (DirenvCmd.direnvInstalled() && !project.isDefault && zlsState.direnv) + val env = if (DirenvCmd.direnvInstalled() && !project.isDefault && project.zigProjectSettings.state.direnv) project.getDirenv() else emptyEnv diff --git a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSStreamConnectionProvider.kt b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSStreamConnectionProvider.kt index b1692051..75676e1a 100644 --- a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSStreamConnectionProvider.kt +++ b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSStreamConnectionProvider.kt @@ -26,6 +26,7 @@ import com.falsepattern.zigbrains.direnv.emptyEnv import com.falsepattern.zigbrains.direnv.getDirenv import com.falsepattern.zigbrains.lsp.config.ZLSConfigProviderBase import com.falsepattern.zigbrains.lsp.settings.zlsSettings +import com.falsepattern.zigbrains.project.settings.zigProjectSettings import com.intellij.execution.configurations.GeneralCommandLine import com.intellij.notification.Notification import com.intellij.notification.NotificationType @@ -58,7 +59,7 @@ class ZLSStreamConnectionProvider private constructor(private val project: Proje val state = svc.state val zlsPath: Path = state.zlsPath.let { zlsPath -> if (zlsPath.isEmpty()) { - val env = if (state.direnv) project.getDirenv() else emptyEnv + val env = if (project.zigProjectSettings.state.direnv) project.getDirenv() else emptyEnv env.findExecutableOnPATH("zls") ?: run { Notification( "zigbrains-lsp", diff --git a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSProjectSettingsService.kt b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSProjectSettingsService.kt index 5536bf4a..18039240 100644 --- a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSProjectSettingsService.kt +++ b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSProjectSettingsService.kt @@ -26,6 +26,7 @@ import com.falsepattern.zigbrains.direnv.emptyEnv import com.falsepattern.zigbrains.direnv.getDirenv import com.falsepattern.zigbrains.lsp.ZLSBundle import com.falsepattern.zigbrains.lsp.startLSP +import com.falsepattern.zigbrains.project.settings.zigProjectSettings import com.intellij.openapi.components.* import com.intellij.openapi.project.Project import com.intellij.openapi.util.io.toNioPathOrNull @@ -96,7 +97,7 @@ class ZLSProjectSettingsService(val project: Project): PersistentStateComponent< private suspend fun doValidate(project: Project, state: ZLSSettings): Boolean { val zlsPath: Path = state.zlsPath.let { zlsPath -> if (zlsPath.isEmpty()) { - val env = if (state.direnv) project.getDirenv() else emptyEnv + val env = if (project.zigProjectSettings.state.direnv) project.getDirenv() else emptyEnv env.findExecutableOnPATH("zls") ?: run { return false } diff --git a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettings.kt b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettings.kt index 388e2007..d7f2f26e 100644 --- a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettings.kt +++ b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettings.kt @@ -29,7 +29,6 @@ import org.jetbrains.annotations.NonNls @Suppress("PropertyName") data class ZLSSettings( - var direnv: Boolean = false, var zlsPath: @NonNls String = "", var zlsConfigPath: @NonNls String = "", val inlayHints: Boolean = true, diff --git a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsConfigurable.kt b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsConfigurable.kt index 85363a92..fad06b27 100644 --- a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsConfigurable.kt +++ b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsConfigurable.kt @@ -22,6 +22,7 @@ package com.falsepattern.zigbrains.lsp.settings +import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider import com.falsepattern.zigbrains.shared.SubConfigurable import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer @@ -29,8 +30,10 @@ import com.intellij.ui.dsl.builder.Panel class ZLSSettingsConfigurable(private val project: Project): SubConfigurable { private var appSettingsComponent: ZLSSettingsPanel? = null - override fun createComponent(panel: Panel) { - appSettingsComponent = ZLSSettingsPanel(project).apply { attach(panel) }.also { Disposer.register(this, it) } + override fun createComponent(holder: ZigProjectConfigurationProvider.SettingsPanelHolder, panel: Panel): ZigProjectConfigurationProvider.SettingsPanel { + val settingsPanel = ZLSSettingsPanel(project).apply { attach(panel) }.also { Disposer.register(this, it) } + appSettingsComponent = settingsPanel + return settingsPanel } override fun isModified(): Boolean { diff --git a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt index e96a0f29..06def51b 100644 --- a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt +++ b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt @@ -29,6 +29,7 @@ import com.falsepattern.zigbrains.direnv.getDirenv import com.falsepattern.zigbrains.lsp.ZLSBundle import com.falsepattern.zigbrains.lsp.config.SemanticTokens import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider +import com.falsepattern.zigbrains.project.settings.zigProjectSettings import com.falsepattern.zigbrains.shared.cli.call import com.falsepattern.zigbrains.shared.cli.createCommandLineSafe import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT @@ -87,6 +88,8 @@ class ZLSSettingsPanel(private val project: Project) : ZigProjectConfigurationPr private var debounce: Job? = null + private var direnv: Boolean = project.zigProjectSettings.state.direnv + private val inlayHints = JBCheckBox() private val enable_snippets = JBCheckBox() private val enable_argument_placeholders = JBCheckBox() @@ -109,12 +112,6 @@ class ZLSSettingsPanel(private val project: Project) : ZigProjectConfigurationPr private val build_runner_path = ExtendableTextField() private val global_cache_path = ExtendableTextField() - private val direnv = JBCheckBox(ZLSBundle.message("settings.zls-path.use-direnv.label")).apply { - addActionListener { - dispatchAutodetect(true) - } - } - override fun attach(p: Panel) = with(p) { if (!project.isDefault) { group(ZLSBundle.message("settings.group.title")) { @@ -123,9 +120,6 @@ class ZLSSettingsPanel(private val project: Project) : ZigProjectConfigurationPr "settings.zls-path.tooltip" ) { cell(zlsPath).resizableColumn().align(AlignX.FILL) - if (DirenvCmd.direnvInstalled()) { - cell(direnv) - } } row(ZLSBundle.message("settings.zls-version.label")) { cell(zlsVersion) @@ -225,9 +219,13 @@ class ZLSSettingsPanel(private val project: Project) : ZigProjectConfigurationPr dispatchAutodetect(false) } + override fun direnvChanged(state: Boolean) { + direnv = state + dispatchAutodetect(true) + } + override var data get() = ZLSSettings( - direnv.isSelected, zlsPath.text, zlsConfigPath.text, inlayHints.isSelected, @@ -253,7 +251,6 @@ class ZLSSettingsPanel(private val project: Project) : ZigProjectConfigurationPr global_cache_path.text?.ifBlank { null }, ) set(value) { - direnv.isSelected = value.direnv zlsPath.text = value.zlsPath zlsConfigPath.text = value.zlsConfigPath inlayHints.isSelected = value.inlayHints @@ -305,7 +302,7 @@ class ZLSSettingsPanel(private val project: Project) : ZigProjectConfigurationPr } private suspend fun getDirenv(): Env { - if (!project.isDefault && DirenvCmd.direnvInstalled() && direnv.isSelected) + if (!project.isDefault && DirenvCmd.direnvInstalled() && direnv) return project.getDirenv() return emptyEnv }