From 27160d677853d3078eb05279b7131c1a43479ff4 Mon Sep 17 00:00:00 2001 From: FalsePattern Date: Mon, 11 Nov 2024 12:15:28 +0100 Subject: [PATCH] feat: Background toolchain autodetection --- CHANGELOG.md | 1 + .../com/falsepattern/zigbrains/ZBStartup.kt | 33 ++++++++++++++++ .../zigbrains/lsp/settings/ZLSSettings.kt | 2 +- .../lsp/settings/ZLSSettingsPanel.kt | 38 ++++++++++++------- .../project/newproject/ZigNewProjectPanel.kt | 5 --- .../project/settings/ZigProjectSettings.kt | 2 +- .../settings/ZigProjectSettingsPanel.kt | 32 ++++++++++------ .../resources/zigbrains/Bundle.properties | 1 - .../resources/zigbrains/lsp/Bundle.properties | 1 - 9 files changed, 80 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1f60479..274cc89c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Changelog structure reference: - Project - Direnv now only runs automatically in trusted projects + - Toolchain autodetection is now done in the background on project load ### Fixed diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/ZBStartup.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/ZBStartup.kt index dcc98ba3..6e76a5f5 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/ZBStartup.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/ZBStartup.kt @@ -22,6 +22,13 @@ package com.falsepattern.zigbrains +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.project.toolchain.LocalZigToolchain +import com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider import com.intellij.ide.BrowserUtil import com.intellij.ide.plugins.PluginManager import com.intellij.notification.Notification @@ -33,8 +40,10 @@ import com.intellij.openapi.options.Configurable import com.intellij.openapi.options.ShowSettingsUtil import com.intellij.openapi.project.Project import com.intellij.openapi.startup.ProjectActivity +import com.intellij.openapi.util.UserDataHolderBase import java.lang.reflect.Constructor import java.lang.reflect.Method +import kotlin.io.path.pathString class ZBStartup: ProjectActivity { var firstInit = true @@ -67,6 +76,30 @@ class ZBStartup: ProjectActivity { 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 = ZigToolchainProvider.suggestToolchain(project, data) ?: return + if (tc is LocalZigToolchain) { + zigProjectState.toolchainPath = tc.location.pathString + project.zigProjectSettings.state = zigProjectState + } + } + val zlsState = project.zlsSettings.state + if (zlsState.zlsPath.isBlank()) { + val env = if (DirenvCmd.direnvInstalled() && !project.isDefault && zlsState.direnv) + project.getDirenv() + else + emptyEnv + env.findExecutableOnPATH("zls")?.let { + zlsState.zlsPath = it.pathString + project.zlsSettings.state = zlsState + } + } } } diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettings.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettings.kt index dd22faa1..89a8452c 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettings.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettings.kt @@ -25,7 +25,7 @@ package com.falsepattern.zigbrains.lsp.settings import org.jetbrains.annotations.NonNls data class ZLSSettings( - var direnv: Boolean = true, + var direnv: Boolean = false, var zlsPath: @NonNls String = "", var zlsConfigPath: @NonNls String = "", var debug: Boolean = false, diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt index b22845ec..8d069bfe 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt @@ -62,22 +62,17 @@ class ZLSSettingsPanel(private val project: Project?) : Disposable { private val messageTrace = JBCheckBox() private val debug = JBCheckBox() - private val direnv = JBCheckBox(ZLSBundle.message("settings.zls-path.use-direnv.label")) + private val direnv = JBCheckBox(ZLSBundle.message("settings.zls-path.use-direnv.label")).apply { addActionListener { + dispatchAutodetect(true) + } } fun attach(panel: Panel) = with(panel) { group(ZLSBundle.message("settings.group.title")) { row(ZLSBundle.message("settings.zls-path.label")) { cell(zlsPath).resizableColumn().align(AlignX.FILL) - if (DirenvCmd.direnvInstalled() && project != null && !project.isDefault) { + if (DirenvCmd.direnvInstalled() && project?.isDefault == false) { cell(direnv) } - button(ZLSBundle.message("settings.zls-path.autodetect.label")) { - project.zigCoroutineScope.launchWithEDT { - withModalProgress(ModalTaskOwner.component(zlsPath), "Detecting ZLS...", TaskCancellation.cancellable()) { - autodetect() - } - } - } } row(ZLSBundle.message("settings.zls-config-path.label")) { cell(zlsConfigPath).align(AlignX.FILL) } row(ZLSBundle.message("settings.inlay-hints.label")) { cell(inlayHints) } @@ -91,6 +86,7 @@ class ZLSSettingsPanel(private val project: Project?) : Disposable { row(ZLSBundle.message("dev-settings.debug.label")) { cell(debug) } row(ZLSBundle.message("dev-settings.message-trace.label")) { cell(messageTrace) } } + dispatchAutodetect(false) } var data @@ -121,16 +117,30 @@ class ZLSSettingsPanel(private val project: Project?) : Disposable { inlayHintsCompact.isSelected = value.inlayHintsCompact } - suspend fun autodetect() { - getDirenv().findExecutableOnPATH("zls")?.let { zlsPath.text = it.pathString } + private fun dispatchAutodetect(force: Boolean) { + project.zigCoroutineScope.launchWithEDT { + withModalProgress(ModalTaskOwner.component(zlsPath), "Detecting ZLS...", TaskCancellation.cancellable()) { + autodetect(force) + } + } + } + + suspend fun autodetect(force: Boolean) { + if (force || zlsPath.text.isBlank()) { + getDirenv().findExecutableOnPATH("zls")?.let { + if (force || zlsPath.text.isBlank()) { + zlsPath.text = it.pathString + } + } + } } override fun dispose() { } private suspend fun getDirenv(): Env { - if (!direnv.isSelected) - return emptyEnv - return project.getDirenv() + if (DirenvCmd.direnvInstalled() && project?.isDefault == false && direnv.isSelected) + return project.getDirenv() + return emptyEnv } } \ 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 35120f3a..f1a6ecfc 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 @@ -89,11 +89,6 @@ class ZigNewProjectPanel(private var handleGit: Boolean): Disposable { zlsConf.attach(p) } - suspend fun autodetect() { - projConf.autodetect() - zlsConf.autodetect() - } - override fun dispose() { } } diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettings.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettings.kt index 6c928d85..9763fe24 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettings.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettings.kt @@ -28,7 +28,7 @@ import com.intellij.util.xmlb.annotations.Transient import kotlin.io.path.pathString data class ZigProjectSettings( - var direnv: Boolean = true, + var direnv: Boolean = false, var overrideStdPath: Boolean = false, var explicitPathToStd: String? = null, var toolchainPath: String? = null 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 490ec4c4..820c6611 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 @@ -56,7 +56,9 @@ import kotlin.io.path.notExists import kotlin.io.path.pathString class ZigProjectSettingsPanel(private val project: Project?) : Disposable { - private val direnv = JBCheckBox(ZigBrainsBundle.message("settings.project.label.direnv")) + private val direnv = JBCheckBox(ZigBrainsBundle.message("settings.project.label.direnv")).apply { addActionListener { + dispatchAutodetect(true) + } } private val pathToToolchain = textFieldWithBrowseButton( project, FileChooserDescriptorFactory.createSingleFolderDescriptor().withTitle(ZigBrainsBundle.message("dialog.title.zig-toolchain")) @@ -85,15 +87,27 @@ class ZigProjectSettingsPanel(private val project: Project?) : Disposable { ).also { Disposer.register(this, it) } private var debounce: Job? = null - suspend fun autodetect() { + private fun dispatchAutodetect(force: Boolean) { + project.zigCoroutineScope.launchWithEDT { + 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, direnv.isSelected) + data.putUserData(LocalZigToolchain.DIRENV_KEY, DirenvCmd.direnvInstalled() && project?.isDefault == false && direnv.isSelected) val tc = ZigToolchainProvider.suggestToolchain(project, data) ?: return if (tc !is LocalZigToolchain) { TODO("Implement non-local zig toolchain in config") } - pathToToolchain.text = tc.location.pathString - dispatchUpdateUI() + if (force || pathToToolchain.text.isBlank()) { + pathToToolchain.text = tc.location.pathString + dispatchUpdateUI() + } } var data @@ -121,13 +135,6 @@ class ZigProjectSettingsPanel(private val project: Project?) : Disposable { if (DirenvCmd.direnvInstalled() && !project.isDefault) { cell(direnv) } - button(ZigBrainsBundle.message("settings.project.label.toolchain-autodetect")) { - project.zigCoroutineScope.launchWithEDT { - withModalProgress(ModalTaskOwner.component(pathToToolchain), "Detecting Zig...", TaskCancellation.cancellable()) { - autodetect() - } - } - } } row(ZigBrainsBundle.message("settings.project.label.toolchain-version")) { cell(toolchainVersion) @@ -137,6 +144,7 @@ class ZigProjectSettingsPanel(private val project: Project?) : Disposable { cell(stdFieldOverride) } } + dispatchAutodetect(false) } private fun dispatchUpdateUI() { diff --git a/core/src/main/resources/zigbrains/Bundle.properties b/core/src/main/resources/zigbrains/Bundle.properties index 0faa0150..9952d628 100644 --- a/core/src/main/resources/zigbrains/Bundle.properties +++ b/core/src/main/resources/zigbrains/Bundle.properties @@ -105,7 +105,6 @@ configuration.build.marker-name=Build and Run settings.project.group.title=Zig Settings settings.project.label.direnv=Use direnv settings.project.label.toolchain=Toolchain location -settings.project.label.toolchain-autodetect=Autodetect settings.project.label.toolchain-version=Toolchain version settings.project.label.override-std=Override standard library settings.project.label.std-location=Standard library location diff --git a/core/src/main/resources/zigbrains/lsp/Bundle.properties b/core/src/main/resources/zigbrains/lsp/Bundle.properties index 5e007a9d..0627339c 100644 --- a/core/src/main/resources/zigbrains/lsp/Bundle.properties +++ b/core/src/main/resources/zigbrains/lsp/Bundle.properties @@ -13,7 +13,6 @@ settings.build-on-save-step.tooltip=Which step should be executed on build-on-sa settings.global-var-declarations.label=Highlight global variable declarations settings.comptime-interpreter.label=Use the ZLS comptime interpreter (dangerous) settings.zls-path.use-direnv.label=Use direnv -settings.zls-path.autodetect.label=Autodetect dev-settings.group.title=ZLS Developer Settings dev-settings.debug.label=Debug log dev-settings.message-trace.label=Message trace