more work on the LSP

This commit is contained in:
FalsePattern 2024-10-31 01:16:06 +01:00
parent c22c77df7d
commit 277acce0f9
Signed by: falsepattern
GPG key ID: E930CDEC50C50E23
10 changed files with 475 additions and 0 deletions

View file

@ -1,3 +1,25 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 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/>.
*/
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
val lsp4ijVersion: String by project
@ -11,4 +33,5 @@ dependencies {
}
intellijPlatformPluginDependency(lsp4ijDepString)
compileOnly("org.eclipse.lsp4j:org.eclipse.lsp4j:$lsp4jVersion")
implementation(project(":core"))
}

View file

@ -0,0 +1,50 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 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.lsp
import com.intellij.DynamicBundle
import org.jetbrains.annotations.Nls
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.PropertyKey
import java.util.function.Supplier
@NonNls
private const val BUNDLE = "zigbrains.lsp.Bundle"
internal object ZLSBundle {
private val INSTANCE = DynamicBundle(ZLSBundle::class.java, BUNDLE)
fun message(
key: @PropertyKey(resourceBundle = BUNDLE) String,
vararg params: Any
): @Nls String {
return INSTANCE.getMessage(key, *params)
}
fun lazyMessage(
key: @PropertyKey(resourceBundle = BUNDLE) String,
vararg params: Any
): Supplier<@Nls String> {
return INSTANCE.getLazyMessage(key, *params)
}
}

View file

@ -0,0 +1,48 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 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/>.
*/
@file:Suppress("HardCodedStringLiteral")
package com.falsepattern.zigbrains.lsp.config
import kotlinx.serialization.SerialName
import org.jetbrains.annotations.NonNls
data class ZLSConfig(
@SerialName("zig_exe_path") val zigExePath: @NonNls String? = null,
@SerialName("zig_lib_path") val zigLibPath: @NonNls String? = null,
@SerialName("enable_build_on_save") val buildOnSave: Boolean? = null,
@SerialName("build_on_save_step") val buildOnSaveStep: @NonNls String? = null,
@SerialName("dangerous_comptime_experiments_do_not_enable") val comptimeInterpreter: Boolean? = null,
@SerialName("highlight_global_var_declarations") val globalVarDeclarations: Boolean? = null
) {
infix fun merge(other: ZLSConfig): ZLSConfig {
return ZLSConfig(
zigExePath ?: other.zigExePath,
zigLibPath ?: other.zigLibPath,
buildOnSave ?: other.buildOnSave,
buildOnSaveStep ?: other.buildOnSaveStep,
comptimeInterpreter ?: other.comptimeInterpreter,
globalVarDeclarations ?: other.globalVarDeclarations
)
}
}

View file

@ -0,0 +1,42 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 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.lsp.config
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.project.Project
interface ZLSConfigProvider {
fun getEnvironment(project: Project): ZLSConfig
companion object {
private val EXTENSION_POINT_NAME = ExtensionPointName.create<ZLSConfigProvider>("com.falsepattern.zigbrains.zlsConfigProvider")
fun findEnvironment(project: Project): ZLSConfig {
val extensions = EXTENSION_POINT_NAME.extensionList
var result = ZLSConfig()
for (extension in extensions) {
result = result merge extension.getEnvironment(project)
}
return result
}
}
}

View file

@ -0,0 +1,53 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 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.lsp.settings
import com.intellij.openapi.components.*
import com.intellij.openapi.project.Project
@Service(Service.Level.PROJECT)
@State(
name = "ZLSSettings",
storages = [Storage(value = "zigbrains.xml")]
)
class ZLSProjectSettingsService: PersistentStateComponent<ZLSSettings> {
@Volatile
private var state = ZLSSettings()
override fun getState(): ZLSSettings {
return state.copy()
}
fun setState(value: ZLSSettings) {
this.state = value
}
override fun loadState(state: ZLSSettings) {
this.state = state
}
fun isModified(otherData: ZLSSettings): Boolean {
return state != otherData
}
}
val Project.zlsSettings get() = service<ZLSProjectSettingsService>()

View file

@ -0,0 +1,39 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 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.lsp.settings
import org.jetbrains.annotations.NonNls
data class ZLSSettings(
val direnv: Boolean = true,
val zlsPath: @NonNls String = "",
val zlsConfigPath: @NonNls String = "",
val debug: Boolean = false,
val messageTrace: Boolean = false,
val buildOnSave: Boolean = false,
val buildOnSaveStep: @NonNls String = "install",
val globalVarDeclarations: Boolean = false,
val comptimeInterpreter: Boolean = false,
val inlayHints: Boolean = true,
val inlayHintsCompact: Boolean = true
)

View file

@ -0,0 +1,66 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 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.lsp.settings
import com.falsepattern.zigbrains.lsp.ZLSBundle
import com.falsepattern.zigbrains.shared.NestedConfigurable
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.ui.dsl.builder.Panel
import com.intellij.ui.dsl.builder.panel
import javax.swing.JComponent
class ZLSSettingsConfigurable(private val project: Project): NestedConfigurable {
private var appSettingsComponent: ZLSSettingsPanel? = null
override fun createComponent(panel: Panel) {
appSettingsComponent = ZLSSettingsPanel(project).apply { attach(panel) }
}
override fun isModified(): Boolean {
val data = appSettingsComponent?.data ?: return false
return project.zlsSettings.state != data
}
override fun apply() {
val data = appSettingsComponent?.data ?: return
val settings = project.zlsSettings
val reloadZLS = settings.isModified(data)
settings.state = data
if (reloadZLS) {
TODO("Not yet implemented")
}
}
override fun reset() {
appSettingsComponent?.data = project.zlsSettings.state
}
override fun disposeUIResources() {
appSettingsComponent?.dispose()
appSettingsComponent = null
}
override fun getDisplayName(): String {
return ZLSBundle.message("configurable.name.zls.settings")
}
}

View file

@ -0,0 +1,128 @@
/*
* This file is part of ZigBrains.
*
* Copyright (C) 2023-2024 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.lsp.settings
import com.falsepattern.zigbrains.direnv.*
import com.falsepattern.zigbrains.lsp.ZLSBundle
import com.intellij.openapi.Disposable
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
import com.intellij.openapi.project.Project
import com.intellij.ui.components.JBCheckBox
import com.intellij.ui.components.fields.ExtendableTextField
import com.intellij.ui.components.textFieldWithBrowseButton
import com.intellij.ui.dsl.builder.AlignX
import com.intellij.ui.dsl.builder.Panel
import kotlinx.coroutines.launch
import kotlin.io.path.pathString
class ZLSSettingsPanel(private val project: Project?) : Disposable {
private val zlsPath = textFieldWithBrowseButton(
project,
ZLSBundle.message("settings.zls-path.browse.title"),
FileChooserDescriptorFactory.createSingleFileDescriptor(),
)
private val zlsConfigPath = textFieldWithBrowseButton(
project,
ZLSBundle.message("settings.zls-config-path.browse.title"),
FileChooserDescriptorFactory.createSingleFileDescriptor()
)
private val buildOnSave = JBCheckBox().apply { toolTipText = ZLSBundle.message("settings.build-on-save.tooltip") }
private val buildOnSaveStep = ExtendableTextField().apply { toolTipText = ZLSBundle.message("settings.build-on-save-step.tooltip") }
private val globalVarDeclarations = JBCheckBox()
private val comptimeInterpreter = JBCheckBox()
private val inlayHints = JBCheckBox()
private val inlayHintsCompact = JBCheckBox().apply { toolTipText = ZLSBundle.message("settings.inlay-hints-compact.tooltip") }
private val messageTrace = JBCheckBox()
private val debug = JBCheckBox()
private val direnv = JBCheckBox(ZLSBundle.message("settings.zls-path.use-direnv.label"))
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) {
cell(direnv)
}
button(ZLSBundle.message("settings.zls-path.autodetect.label")) { autodetect() }
}
row(ZLSBundle.message("settings.zls-config-path.label")) { cell(zlsConfigPath).align(AlignX.FILL) }
row(ZLSBundle.message("settings.inlay-hints.label")) { cell(inlayHints) }
row(ZLSBundle.message("settings.inlay-hints-compact.label")) { cell(inlayHintsCompact) }
row(ZLSBundle.message("settings.build-on-save.label")) { cell(buildOnSave) }
row(ZLSBundle.message("settings.build-on-save-step.label")) { cell(buildOnSaveStep).resizableColumn().align(AlignX.FILL) }
row(ZLSBundle.message("settings.global-var-declarations.label")) { cell(globalVarDeclarations) }
row(ZLSBundle.message("settings.comptime-interpreter.label")) { cell(comptimeInterpreter) }
}
group(ZLSBundle.message("dev-settings.group.title")) {
row(ZLSBundle.message("dev-settings.debug.label")) { cell(debug) }
row(ZLSBundle.message("dev-settings.message-trace.label")) { cell(messageTrace) }
}
}
var data
get() = ZLSSettings(
direnv.isSelected,
zlsPath.text,
zlsConfigPath.text,
debug.isSelected,
messageTrace.isSelected,
buildOnSave.isSelected,
buildOnSaveStep.text,
globalVarDeclarations.isSelected,
comptimeInterpreter.isSelected,
inlayHints.isSelected,
inlayHintsCompact.isSelected
)
set(value) {
direnv.isSelected = value.direnv
zlsPath.text = value.zlsPath
zlsConfigPath.text = value.zlsConfigPath
debug.isSelected = value.debug
messageTrace.isSelected = value.messageTrace
buildOnSave.isSelected = value.buildOnSave
buildOnSaveStep.text = value.buildOnSaveStep
globalVarDeclarations.isSelected = value.globalVarDeclarations
comptimeInterpreter.isSelected = value.comptimeInterpreter
inlayHints.isSelected = value.inlayHints
inlayHintsCompact.isSelected = value.inlayHintsCompact
}
fun autodetect() {
direnvScope.launch {
getDirenv().findExecutableOnPATH("zls")?.let { zlsPath.text = it.pathString }
}
}
override fun dispose() {
zlsPath.dispose()
zlsConfigPath.dispose()
}
private suspend fun getDirenv(): Env {
if (!direnv.isSelected)
return emptyEnv
return project.getDirenv()
}
}

View file

@ -0,0 +1,20 @@
settings.group.title=ZLS Settings
settings.zls-path.label=Executable path
settings.zls-path.browse.title=Path to the ZLS Binary
settings.zls-config-path.label=Config path (leave empty to use built-in config)
settings.zls-config-path.browse.title=Path to the Custom ZLS Config File (Optional)
settings.inlay-hints.label=Inlay hints
settings.inlay-hints-compact.label=Compact errors in inlay hint
settings.inlay-hints-compact.tooltip=Replace extremely long error{...} snippets in inlay hints with a placeholder
settings.build-on-save.label=Build on save
settings.build-on-save.tooltip=Enable build-on-save diagnostics
settings.build-on-save-step.label=Build on save step
settings.build-on-save-step.tooltip=Which step should be executed on build-on-save
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
configurable.name.zls.settings=ZLS Settings

View file

@ -105,4 +105,10 @@
</extensions>
<!-- endregion direnv -->
<extensionPoints>
<extensionPoint
interface="com.falsepattern.zigbrains.lsp.config.ZLSConfigProvider"
dynamic="true"
name="zlsConfigProvider"/>
</extensionPoints>
</idea-plugin>