Compare commits

..

13 commits

41 changed files with 351 additions and 144 deletions

View file

@ -17,6 +17,39 @@ Changelog structure reference:
## [Unreleased] ## [Unreleased]
## [25.2.0]
### Added
- Debugger
- Notify the user if zig run / zig test debugging starts, but a build.zig is present
### Changed
- Project
- Line marker task suggestions for main/test now defer to Zig Build if build.zig file is detected.
### Fixed
- Debugger
- Compilation failures did not open the terminal properly and suppressed the error message
## [25.1.0]
### Added
- IDEA 2025.1 support
- LSP
- Configurable inlay hints file size limit to reduce IDE lag
## [25.0.2]
### Fixed
- Project
- ZLS settings not scrollable in the language server list
## [25.0.1] ## [25.0.1]
### Fixed ### Fixed

View file

@ -15,6 +15,7 @@ through the built-in plugin browser:
1. Go to `Settings -> Plugins` 1. Go to `Settings -> Plugins`
2. To the right of the `Installed` button at the top, click on the `...` dropdown menu, then select `Manage Plugin Repositories...` 2. To the right of the `Installed` button at the top, click on the `...` dropdown menu, then select `Manage Plugin Repositories...`
3. Click the add button, and then enter the ZigBrains updater URL, based on your IDE version: 3. Click the add button, and then enter the ZigBrains updater URL, based on your IDE version:
- `2025.1.*` or newer: https://falsepattern.com/zigbrains/updatePlugins-251.xml
- `2024.3.*`: https://falsepattern.com/zigbrains/updatePlugins-243.xml - `2024.3.*`: https://falsepattern.com/zigbrains/updatePlugins-243.xml
- `2024.2.*`: https://falsepattern.com/zigbrains/updatePlugins-242.xml - `2024.2.*`: https://falsepattern.com/zigbrains/updatePlugins-242.xml
- `2024.1.*`: https://falsepattern.com/zigbrains/updatePlugins-241.xml - `2024.1.*`: https://falsepattern.com/zigbrains/updatePlugins-241.xml

View file

@ -6,15 +6,15 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
plugins { plugins {
kotlin("jvm") version "2.0.21" apply false kotlin("jvm") version "2.1.10" apply false
kotlin("plugin.serialization") version "2.0.21" apply false kotlin("plugin.serialization") version "2.1.10" apply false
id("org.jetbrains.intellij.platform") version "2.5.0" id("org.jetbrains.intellij.platform") version "2.5.0"
id("org.jetbrains.changelog") version "2.2.1" id("org.jetbrains.changelog") version "2.2.1"
id("org.jetbrains.grammarkit") version "2022.3.2.2" apply false id("org.jetbrains.grammarkit") version "2022.3.2.2" apply false
idea idea
`maven-publish` `maven-publish`
} }
val publishVersions = listOf("241", "242", "243") val publishVersions = listOf("241", "242", "243", "251")
val pluginVersionFull get() = "$pluginVersion-$pluginSinceBuild" val pluginVersionFull get() = "$pluginVersion-$pluginSinceBuild"
val pluginVersion: String by project val pluginVersion: String by project
val pluginSinceBuild: String by project val pluginSinceBuild: String by project

View file

@ -23,7 +23,7 @@
set -e set -e
declare -a branches=("master" "242" "241") declare -a branches=("master" "243" "242" "241")
DEFAULT_BRANCH="${branches[0]}" DEFAULT_BRANCH="${branches[0]}"

View file

@ -58,7 +58,8 @@ class ZigClionDebuggerDriverConfigurationProvider: ZigDebuggerDriverConfiguratio
return when(toolchain.debuggerKind) { return when(toolchain.debuggerKind) {
CPPDebugger.Kind.BUNDLED_GDB, CPPDebugger.Kind.BUNDLED_GDB,
CPPDebugger.Kind.CUSTOM_GDB -> CLionGDBDriverConfiguration(project, toolchain, isEmulateTerminal = emulateTerminal) CPPDebugger.Kind.CUSTOM_GDB -> CLionGDBDriverConfiguration(project, toolchain, isEmulateTerminal = emulateTerminal)
CPPDebugger.Kind.BUNDLED_LLDB -> CLionLLDBDriverConfiguration(project, toolchain, isEmulateTerminal = emulateTerminal) CPPDebugger.Kind.BUNDLED_LLDB,
CPPDebugger.Kind.CUSTOM_LLDB -> CLionLLDBDriverConfiguration(project, toolchain, isEmulateTerminal = emulateTerminal)
} }
} }
} }

View file

@ -22,6 +22,7 @@
package com.falsepattern.zigbrains.debugger.runner.base package com.falsepattern.zigbrains.debugger.runner.base
import com.falsepattern.zigbrains.project.run.ZigProcessHandler
import com.falsepattern.zigbrains.shared.cli.startIPCAwareProcess import com.falsepattern.zigbrains.shared.cli.startIPCAwareProcess
import com.intellij.execution.ExecutionException import com.intellij.execution.ExecutionException
import com.intellij.execution.configurations.GeneralCommandLine import com.intellij.execution.configurations.GeneralCommandLine
@ -40,7 +41,7 @@ import kotlinx.coroutines.withContext
class PreLaunchProcessListener(val console: ConsoleView) : ProcessListener { class PreLaunchProcessListener(val console: ConsoleView) : ProcessListener {
var isBuildFailed: Boolean = false var isBuildFailed: Boolean = false
private set private set
lateinit var processHandler: ProcessHandler lateinit var processHandler: ZigProcessHandler.IPCAware
private set private set
@Throws(ExecutionException::class) @Throws(ExecutionException::class)
@ -50,7 +51,7 @@ class PreLaunchProcessListener(val console: ConsoleView) : ProcessListener {
this@PreLaunchProcessListener.processHandler = processHandler this@PreLaunchProcessListener.processHandler = processHandler
hook(processHandler) hook(processHandler)
processHandler.startNotify() processHandler.startNotify()
withContext(Dispatchers.Default) { withContext(Dispatchers.IO) {
processHandler.process.awaitExit() processHandler.process.awaitExit()
} }
runInterruptible { runInterruptible {

View file

@ -27,6 +27,7 @@ import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
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.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.io.toNioPathOrNull
import com.intellij.platform.util.progress.withProgressText import com.intellij.platform.util.progress.withProgressText
import com.intellij.util.containers.orNull import com.intellij.util.containers.orNull
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
@ -36,6 +37,7 @@ import java.io.File
import java.nio.file.Files import java.nio.file.Files
import kotlin.io.path.absolutePathString import kotlin.io.path.absolutePathString
import kotlin.io.path.isExecutable import kotlin.io.path.isExecutable
import kotlin.io.path.pathString
abstract class ZigDebugParametersEmitBinaryBase<ProfileState: ZigProfileState<*>>( abstract class ZigDebugParametersEmitBinaryBase<ProfileState: ZigProfileState<*>>(
driverConfiguration: DebuggerDriverConfiguration, driverConfiguration: DebuggerDriverConfiguration,
@ -49,13 +51,14 @@ abstract class ZigDebugParametersEmitBinaryBase<ProfileState: ZigProfileState<*>
@Throws(ExecutionException::class) @Throws(ExecutionException::class)
private suspend fun compileExe(listener: PreLaunchProcessListener): File { private suspend fun compileExe(listener: PreLaunchProcessListener): File {
val commandLine = profileState.getCommandLine(toolchain, true) val commandLine = profileState.getCommandLine(toolchain, true)
val cliString = commandLine.getCommandLineString(commandLine.exePath.toNioPathOrNull()?.fileName?.pathString)
val tmpDir = FileUtil.createTempDirectory("zigbrains_debug", "", true).toPath() val tmpDir = FileUtil.createTempDirectory("zigbrains_debug", "", true).toPath()
val exe = tmpDir.resolve("executable") val exe = tmpDir.resolve("executable")
commandLine.addParameters("-femit-bin=${exe.absolutePathString()}") commandLine.addParameters("-femit-bin=${exe.absolutePathString()}")
if (listener.executeCommandLineWithHook(profileState.environment.project, commandLine)) if (listener.executeCommandLineWithHook(profileState.environment.project, commandLine))
throw ExecutionException(ZigDebugBundle.message("debug.base.compile.failed.generic")) throw ExecutionException(ZigDebugBundle.message("debug.base.compile.failed.generic", cliString))
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
Files.list(tmpDir).use { stream -> Files.list(tmpDir).use { stream ->

View file

@ -24,6 +24,7 @@ package com.falsepattern.zigbrains.debugger.runner.base
import com.falsepattern.zigbrains.debugbridge.ZigDebuggerDriverConfigurationProviderBase import com.falsepattern.zigbrains.debugbridge.ZigDebuggerDriverConfigurationProviderBase
import com.falsepattern.zigbrains.debugger.ZigLocalDebugProcess import com.falsepattern.zigbrains.debugger.ZigLocalDebugProcess
import com.falsepattern.zigbrains.debugger.runner.build.ZigDebugRunnerBuild
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
import com.falsepattern.zigbrains.project.run.ZigProgramRunner import com.falsepattern.zigbrains.project.run.ZigProgramRunner
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
@ -41,6 +42,7 @@ import com.intellij.execution.ui.ConsoleView
import com.intellij.execution.ui.ConsoleViewContentType import com.intellij.execution.ui.ConsoleViewContentType
import com.intellij.execution.ui.RunContentDescriptor import com.intellij.execution.ui.RunContentDescriptor
import com.intellij.openapi.application.ModalityState import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.project.guessProjectDir
import com.intellij.platform.util.progress.reportProgress import com.intellij.platform.util.progress.reportProgress
import com.intellij.xdebugger.XDebugProcess import com.intellij.xdebugger.XDebugProcess
import com.intellij.xdebugger.XDebugProcessStarter import com.intellij.xdebugger.XDebugProcessStarter
@ -82,11 +84,13 @@ abstract class ZigDebugRunnerBase<ProfileState : ZigProfileState<*>> : ZigProgra
} }
} catch (e: ExecutionException) { } catch (e: ExecutionException) {
console.print("\n", ConsoleViewContentType.ERROR_OUTPUT) console.print("\n", ConsoleViewContentType.ERROR_OUTPUT)
e.message?.let { listener.console.print(it, ConsoleViewContentType.SYSTEM_OUTPUT) } e.message?.let { listener.console.print(it, ConsoleViewContentType.ERROR_OUTPUT) }
throw e; if (this !is ZigDebugRunnerBuild && environment.project.guessProjectDir()?.children?.any { it.name == "build.zig" } == true) {
console.print("\n Warning: build.zig file detected in project.\n Did you want to use a Zig Build task instead?", ConsoleViewContentType.ERROR_OUTPUT)
}
} }
if (listener.isBuildFailed) { if (listener.isBuildFailed) {
val executionResult = DefaultExecutionResult(console, listener.processHandler) val executionResult = DefaultExecutionResult(console, listener.processHandler.unwrap())
return@reportProgress withEDTContext(ModalityState.any()) { return@reportProgress withEDTContext(ModalityState.any()) {
val runContentBuilder = RunContentBuilder(executionResult, environment) val runContentBuilder = RunContentBuilder(executionResult, environment)
runContentBuilder.showRunContent(null) runContentBuilder.showRunContent(null)

View file

@ -15,7 +15,7 @@ debugger.run.unavailable.reason.download.button=Download
debugger.run.unavailable.reason.update=Debugger is outdated debugger.run.unavailable.reason.update=Debugger is outdated
debugger.run.unavailable.reason.update.button=Update debugger.run.unavailable.reason.update.button=Update
debug.build.compile.failed.boilerplate={0}\nPlease edit this intellij build configuration and specify the path of the executable created by "zig build" directly! debug.build.compile.failed.boilerplate={0}\nPlease edit this intellij build configuration and specify the path of the executable created by "zig build" directly!
debug.base.compile.failed.generic=Failed to compile executable debug.base.compile.failed.generic=Failed to compile executable with command: {0}
debug.base.compile.failed.no-exe=Failed to find compiled binary debug.base.compile.failed.no-exe=Failed to find compiled binary
debug.build.compile.failed.multiple-exe=Multiple compiled binaries found debug.build.compile.failed.multiple-exe=Multiple compiled binaries found
debug.build.compile.failed.no-workdir=Cannot find working directory to run debugged executable debug.build.compile.failed.no-workdir=Cannot find working directory to run debugged executable

View file

@ -9,12 +9,15 @@ plugins {
val ideaCommunityVersion: String by project val ideaCommunityVersion: String by project
val useInstaller = property("useInstaller").toString().toBoolean() val useInstaller = property("useInstaller").toString().toBoolean()
val serializationVersion: String by project
dependencies { dependencies {
intellijPlatform { intellijPlatform {
create(IntelliJPlatformType.IntellijIdeaCommunity, ideaCommunityVersion, useInstaller = useInstaller) create(IntelliJPlatformType.IntellijIdeaCommunity, ideaCommunityVersion, useInstaller = useInstaller)
} }
compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.3") compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:$serializationVersion") {
isTransitive = false
}
} }
//region grammars //region grammars

View file

@ -0,0 +1,56 @@
/*
* 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.execution.base
import com.falsepattern.zigbrains.zig.psi.ZigContainerMembers
import com.falsepattern.zigbrains.zig.psi.ZigFile
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.isFile
import com.intellij.psi.util.childrenOfType
fun ZigFile.hasMainFunction(): Boolean {
val members = childrenOfType<ZigContainerMembers>().firstOrNull() ?: return false
return members.containerDeclarationList.any { it.decl?.fnProto?.identifier?.textMatches("main") == true }
}
fun ZigFile.hasTests(): Boolean {
val members = childrenOfType<ZigContainerMembers>().firstOrNull() ?: return false
return members.containerDeclarationList.any { it.testDecl != null }
}
fun VirtualFile.findBuildZig(): VirtualFile? {
var parent = this.parent
while (parent != null) {
parent.children.forEach {
if (it.isFile && it.name == "build.zig") {
return it
}
}
parent = parent.parent
}
return null
}
fun VirtualFile.isBuildZig(): Boolean {
return name == "build.zig"
}

View file

@ -24,12 +24,16 @@ package com.falsepattern.zigbrains.project.execution.build
import com.falsepattern.zigbrains.ZigBrainsBundle import com.falsepattern.zigbrains.ZigBrainsBundle
import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer
import com.falsepattern.zigbrains.project.execution.base.findBuildZig
import com.falsepattern.zigbrains.project.execution.base.isBuildZig
import com.falsepattern.zigbrains.project.execution.firstConfigFactory import com.falsepattern.zigbrains.project.execution.firstConfigFactory
import com.falsepattern.zigbrains.zig.psi.ZigFile import com.falsepattern.zigbrains.zig.psi.ZigFile
import com.falsepattern.zigbrains.zig.psi.ZigTypes
import com.intellij.execution.actions.ConfigurationFromContext import com.intellij.execution.actions.ConfigurationFromContext
import com.intellij.execution.configurations.ConfigurationFactory import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.util.elementType
import java.nio.file.Path import java.nio.file.Path
class ZigConfigProducerBuild: ZigConfigProducer<ZigExecConfigBuild>() { class ZigConfigProducerBuild: ZigConfigProducer<ZigExecConfigBuild>() {
@ -38,17 +42,42 @@ class ZigConfigProducerBuild: ZigConfigProducer<ZigExecConfigBuild>() {
} }
override fun setupConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean { override fun setupConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean {
if (theFile.name != "build.zig") if (theFile.isBuildZig()) {
return false configuration.name = ZigBrainsBundle.message("configuration.build.marker-run")
configuration.name = ZigBrainsBundle.message("configuration.build.marker-name") configuration.buildSteps.args = "run"
return true configuration.debugBuildSteps.args = "install"
return true
}
val buildZig = theFile.findBuildZig() ?: return false
configuration.workingDirectory.path = buildZig.parent.toNioPath()
if (element.elementType == ZigTypes.KEYWORD_TEST) {
configuration.name = ZigBrainsBundle.message("configuration.build.marker-test")
configuration.buildSteps.args = "test"
configuration.debugBuildSteps.args = "install_test"
return true
} else {
configuration.name = ZigBrainsBundle.message("configuration.build.marker-run")
configuration.buildSteps.args = "run"
configuration.debugBuildSteps.args = "install"
return true
}
} }
override fun isConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, psiFile: ZigFile, 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) val dir = configuration.workingDirectory.path ?: return false
if (theFile.isBuildZig()) {
return filePath.parent == dir
} else {
if (element.elementType == ZigTypes.KEYWORD_TEST) {
if (configuration.buildSteps.args != "test")
return false
}
val buildZig = theFile.findBuildZig() ?: return false
return buildZig.parent.toNioPath() == dir
}
} }
override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean { override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean {
return self.configurationType is ZigConfigTypeBuild return self.configurationType is ZigConfigTypeBuild
} }
} }

View file

@ -23,14 +23,14 @@
package com.falsepattern.zigbrains.project.execution.run package com.falsepattern.zigbrains.project.execution.run
import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer
import com.falsepattern.zigbrains.project.execution.base.findBuildZig
import com.falsepattern.zigbrains.project.execution.base.hasMainFunction
import com.falsepattern.zigbrains.project.execution.firstConfigFactory import com.falsepattern.zigbrains.project.execution.firstConfigFactory
import com.falsepattern.zigbrains.zig.psi.ZigContainerMembers
import com.falsepattern.zigbrains.zig.psi.ZigFile import com.falsepattern.zigbrains.zig.psi.ZigFile
import com.intellij.execution.actions.ConfigurationFromContext import com.intellij.execution.actions.ConfigurationFromContext
import com.intellij.execution.configurations.ConfigurationFactory import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.util.childrenOfType
import java.nio.file.Path import java.nio.file.Path
class ZigConfigProducerRun: ZigConfigProducer<ZigExecConfigRun>() { class ZigConfigProducerRun: ZigConfigProducer<ZigExecConfigRun>() {
@ -39,8 +39,10 @@ class ZigConfigProducerRun: ZigConfigProducer<ZigExecConfigRun>() {
} }
override fun setupConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean { override fun setupConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean {
val members = psiFile.childrenOfType<ZigContainerMembers>().firstOrNull() ?: return false if (!psiFile.hasMainFunction()) {
if (members.containerDeclarationList.none { it.decl?.fnProto?.identifier?.textMatches("main") == true }) { return false
}
if (theFile.findBuildZig() != null) {
return false return false
} }
configuration.filePath.path = filePath configuration.filePath.path = filePath
@ -56,5 +58,3 @@ class ZigConfigProducerRun: ZigConfigProducer<ZigExecConfigRun>() {
return self.configurationType is ZigConfigTypeRun return self.configurationType is ZigConfigTypeRun
} }
} }
private val LINE_MARKER = ZigLineMarkerRun()

View file

@ -24,14 +24,14 @@ package com.falsepattern.zigbrains.project.execution.test
import com.falsepattern.zigbrains.ZigBrainsBundle import com.falsepattern.zigbrains.ZigBrainsBundle
import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer
import com.falsepattern.zigbrains.project.execution.base.findBuildZig
import com.falsepattern.zigbrains.project.execution.base.hasTests
import com.falsepattern.zigbrains.project.execution.firstConfigFactory import com.falsepattern.zigbrains.project.execution.firstConfigFactory
import com.falsepattern.zigbrains.zig.psi.ZigContainerMembers
import com.falsepattern.zigbrains.zig.psi.ZigFile import com.falsepattern.zigbrains.zig.psi.ZigFile
import com.intellij.execution.actions.ConfigurationFromContext import com.intellij.execution.actions.ConfigurationFromContext
import com.intellij.execution.configurations.ConfigurationFactory import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.util.childrenOfType
import java.nio.file.Path import java.nio.file.Path
class ZigConfigProducerTest: ZigConfigProducer<ZigExecConfigTest>() { class ZigConfigProducerTest: ZigConfigProducer<ZigExecConfigTest>() {
@ -40,8 +40,10 @@ class ZigConfigProducerTest: ZigConfigProducer<ZigExecConfigTest>() {
} }
override fun setupConfigurationFromContext(configuration: ZigExecConfigTest, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean { override fun setupConfigurationFromContext(configuration: ZigExecConfigTest, element: PsiElement, psiFile: ZigFile, filePath: Path, theFile: VirtualFile): Boolean {
val members = psiFile.childrenOfType<ZigContainerMembers>().firstOrNull() ?: return false if (!psiFile.hasTests()) {
if (members.containerDeclarationList.none { it.testDecl != null }) { return false
}
if (theFile.findBuildZig() != null) {
return false return false
} }
configuration.filePath.path = filePath configuration.filePath.path = filePath

View file

@ -28,14 +28,25 @@ import com.intellij.execution.process.KillableProcessHandler
import com.pty4j.PtyProcess import com.pty4j.PtyProcess
import java.nio.charset.Charset import java.nio.charset.Charset
class ZigProcessHandler : KillableProcessHandler { open class ZigProcessHandler : KillableProcessHandler {
constructor(commandLine: GeneralCommandLine) : super(commandLine) { constructor(commandLine: GeneralCommandLine) : super(commandLine) {
setHasPty(commandLine is PtyCommandLine) setHasPty(commandLine is PtyCommandLine)
setShouldDestroyProcessRecursively(!hasPty()) setShouldDestroyProcessRecursively(!hasPty())
} }
constructor (process: Process, commandLine: String, charset: Charset) : super(process, commandLine, charset) { protected constructor (process: Process, commandLine: String, charset: Charset) : super(process, commandLine, charset) {
setHasPty(process is PtyProcess) setHasPty(process is PtyProcess)
setShouldDestroyProcessRecursively(!hasPty()) setShouldDestroyProcessRecursively(!hasPty())
} }
class IPCAware : ZigProcessHandler {
val originalCommandLine: String
constructor(originalCommandLine: String, commandLine: GeneralCommandLine) : super(commandLine) {
this.originalCommandLine = originalCommandLine
}
fun unwrap(): ZigProcessHandler {
return ZigProcessHandler(this.process, this.originalCommandLine, this.charset ?: Charsets.UTF_8)
}
}
} }

View file

@ -25,6 +25,7 @@ package com.falsepattern.zigbrains.project.toolchain.base
import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider
import com.falsepattern.zigbrains.project.toolchain.ui.ImmutableElementPanel import com.falsepattern.zigbrains.project.toolchain.ui.ImmutableElementPanel
import com.falsepattern.zigbrains.project.toolchain.zigToolchainList import com.falsepattern.zigbrains.project.toolchain.zigToolchainList
import com.falsepattern.zigbrains.shared.ui.UUIDComboBoxDriver.Companion.wrapModal
import com.intellij.openapi.ui.NamedConfigurable import com.intellij.openapi.ui.NamedConfigurable
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.openapi.util.NlsContexts import com.intellij.openapi.util.NlsContexts
@ -37,7 +38,7 @@ abstract class ZigToolchainConfigurable<T: ZigToolchain>(
val uuid: UUID, val uuid: UUID,
tc: T, tc: T,
val data: ZigProjectConfigurationProvider.IUserDataBridge?, val data: ZigProjectConfigurationProvider.IUserDataBridge?,
val modal: Boolean private val modal: Boolean
): NamedConfigurable<UUID>() { ): NamedConfigurable<UUID>() {
var toolchain: T = tc var toolchain: T = tc
set(value) { set(value) {
@ -64,7 +65,7 @@ abstract class ZigToolchainConfigurable<T: ZigToolchain>(
views.forEach { it.attach(this@panel) } views.forEach { it.attach(this@panel) }
}.withMinimumWidth(20) }.withMinimumWidth(20)
views.forEach { it.reset(toolchain) } views.forEach { it.reset(toolchain) }
return p return wrapModal(p, modal)
} }
override fun getEditableObject(): UUID? { override fun getEditableObject(): UUID? {

View file

@ -24,15 +24,15 @@ package com.falsepattern.zigbrains.project.toolchain.downloader
import com.falsepattern.zigbrains.ZigBrainsBundle import com.falsepattern.zigbrains.ZigBrainsBundle
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.project.toolchain.local.suggestedLocalToolchainPath
import com.falsepattern.zigbrains.shared.downloader.Downloader import com.falsepattern.zigbrains.shared.downloader.Downloader
import java.awt.Component import java.awt.Component
class LocalToolchainDownloader(component: Component) : Downloader<LocalZigToolchain, ZigVersionInfo>(component) { class LocalToolchainDownloader(component: Component) : Downloader<LocalZigToolchain, ZigVersionInfo>(component) {
override val windowTitle get() = ZigBrainsBundle.message("settings.toolchain.downloader.title") override val windowTitle get() = ZigBrainsBundle.message("settings.toolchain.downloader.title")
override val versionInfoFetchTitle get() = ZigBrainsBundle.message("settings.toolchain.downloader.progress.fetch") override val versionInfoFetchTitle get() = ZigBrainsBundle.message("settings.toolchain.downloader.progress.fetch")
override val suggestedPath get() = suggestedLocalToolchainPath
override fun downloadProgressTitle(version: ZigVersionInfo) = ZigBrainsBundle.message("settings.toolchain.downloader.progress.install", version.version.rawVersion) override fun downloadProgressTitle(version: ZigVersionInfo) = ZigBrainsBundle.message("settings.toolchain.downloader.progress.install", version.version.rawVersion)
override fun localSelector() = LocalToolchainSelector(component) override fun localSelector() = LocalToolchainSelector(component)
override suspend fun downloadVersionList() = ZigVersionInfo.downloadVersionList() override suspend fun downloadVersionList() = ZigVersionInfo.downloadVersionList()
override fun getSuggestedPath() = getSuggestedLocalToolchainPath()
} }

View file

@ -73,8 +73,8 @@ class LocalZigToolchainPanel() : ImmutableNamedElementPanelBase<LocalZigToolchai
).also { Disposer.register(this, it) } ).also { Disposer.register(this, it) }
private var debounce: Job? = null private var debounce: Job? = null
override fun attach(p: Panel): Unit = with(p) { override fun attach(panel: Panel): Unit = with(panel) {
super.attach(p) super.attach(panel)
row(ZigBrainsBundle.message("settings.toolchain.local.path.label")) { row(ZigBrainsBundle.message("settings.toolchain.local.path.label")) {
cell(pathToToolchain).resizableColumn().align(AlignX.FILL) cell(pathToToolchain).resizableColumn().align(AlignX.FILL)
} }
@ -87,23 +87,23 @@ class LocalZigToolchainPanel() : ImmutableNamedElementPanelBase<LocalZigToolchai
} }
} }
override fun isModified(toolchain: LocalZigToolchain): Boolean { override fun isModified(elem: LocalZigToolchain): Boolean {
val name = nameFieldValue ?: return false val name = nameFieldValue ?: return false
val location = this.pathToToolchain.text.ifBlank { null }?.toNioPathOrNull() ?: return false val location = this.pathToToolchain.text.ifBlank { null }?.toNioPathOrNull() ?: return false
val std = if (stdFieldOverride.isSelected) pathToStd.text.ifBlank { null }?.toNioPathOrNull() else null val std = if (stdFieldOverride.isSelected) pathToStd.text.ifBlank { null }?.toNioPathOrNull() else null
return name != toolchain.name || toolchain.location != location || toolchain.std != std return name != elem.name || elem.location != location || elem.std != std
} }
override fun apply(toolchain: LocalZigToolchain): LocalZigToolchain? { override fun apply(elem: LocalZigToolchain): LocalZigToolchain? {
val location = this.pathToToolchain.text.ifBlank { null }?.toNioPathOrNull() ?: return null val location = this.pathToToolchain.text.ifBlank { null }?.toNioPathOrNull() ?: return null
val std = if (stdFieldOverride.isSelected) pathToStd.text.ifBlank { null }?.toNioPathOrNull() else null val std = if (stdFieldOverride.isSelected) pathToStd.text.ifBlank { null }?.toNioPathOrNull() else null
return toolchain.copy(location = location, std = std, name = nameFieldValue ?: "") return elem.copy(location = location, std = std, name = nameFieldValue ?: "")
} }
override fun reset(toolchain: LocalZigToolchain?) { override fun reset(elem: LocalZigToolchain?) {
nameFieldValue = toolchain?.name ?: "" nameFieldValue = elem?.name ?: ""
this.pathToToolchain.text = toolchain?.location?.pathString ?: "" this.pathToToolchain.text = elem?.location?.pathString ?: ""
val std = toolchain?.std val std = elem?.std
if (std != null) { if (std != null) {
stdFieldOverride.isSelected = true stdFieldOverride.isSelected = true
pathToStd.text = std.pathString pathToStd.text = std.pathString

View file

@ -28,18 +28,18 @@ import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvid
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
import com.falsepattern.zigbrains.shared.downloader.homePath
import com.falsepattern.zigbrains.shared.downloader.xdgDataHome
import com.falsepattern.zigbrains.shared.ui.renderPathNameComponent import com.falsepattern.zigbrains.shared.ui.renderPathNameComponent
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.UserDataHolder import com.intellij.openapi.util.UserDataHolder
import com.intellij.openapi.util.io.toNioPathOrNull import com.intellij.openapi.util.io.toNioPathOrNull
import com.intellij.ui.SimpleColoredComponent import com.intellij.ui.SimpleColoredComponent
import com.intellij.util.system.OS
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.util.* import java.util.*
import kotlin.io.path.isDirectory
import kotlin.io.path.pathString import kotlin.io.path.pathString
class LocalZigToolchainProvider: ZigToolchainProvider { class LocalZigToolchainProvider: ZigToolchainProvider {
@ -93,7 +93,7 @@ class LocalZigToolchainProvider: ZigToolchainProvider {
Env.empty Env.empty
} }
val pathToolchains = env.findAllExecutablesOnPATH("zig").mapNotNull { it.parent } val pathToolchains = env.findAllExecutablesOnPATH("zig").mapNotNull { it.parent }
val wellKnown = getWellKnown().asFlow().flatMapConcat { dir -> val wellKnown = wellKnown.asFlow().flatMapConcat { dir ->
runCatching { runCatching {
Files.newDirectoryStream(dir).use { stream -> Files.newDirectoryStream(dir).use { stream ->
stream.toList().filterNotNull().asFlow() stream.toList().filterNotNull().asFlow()
@ -112,8 +112,8 @@ class LocalZigToolchainProvider: ZigToolchainProvider {
} }
} }
fun getSuggestedLocalToolchainPath(): Path? { val suggestedLocalToolchainPath: Path? by lazy {
return getWellKnown().getOrNull(0) wellKnown.getOrNull(0)
} }
/** /**
@ -130,18 +130,12 @@ fun getSuggestedLocalToolchainPath(): Path? {
* *
* and HOME is the user home path * and HOME is the user home path
*/ */
private fun getWellKnown(): List<Path> { private val wellKnown: List<Path> by lazy {
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>() val res = ArrayList<Path>()
if (xdgDataHome != null && xdgDataHome.isDirectory()) { xdgDataHome?.let {
res.add(xdgDataHome.resolve("zig")) res.add(it.resolve("zig"))
res.add(xdgDataHome.resolve("zigup")) res.add(it.resolve("zigup"))
} }
res.add(home.resolve(".zig")) homePath?.let { res.add(it.resolve(".zig")) }
return res res
} }

View file

@ -26,7 +26,7 @@ import com.intellij.openapi.Disposable
import com.intellij.ui.dsl.builder.Panel import com.intellij.ui.dsl.builder.Panel
interface ImmutableElementPanel<T>: Disposable { interface ImmutableElementPanel<T>: Disposable {
fun attach(p: Panel) fun attach(panel: Panel)
fun isModified(elem: T): Boolean fun isModified(elem: T): Boolean
/** /**
* Returned object must be the exact same class as the provided one. * Returned object must be the exact same class as the provided one.

View file

@ -34,7 +34,7 @@ abstract class ImmutableNamedElementPanelBase<T>: ImmutableElementPanel<T> {
get() = nameField.text.ifBlank { null } get() = nameField.text.ifBlank { null }
set(value) {nameField.text = value ?: ""} set(value) {nameField.text = value ?: ""}
override fun attach(p: Panel): Unit = with(p) { override fun attach(panel: Panel): Unit = with(panel) {
row(ZigBrainsBundle.message("settings.toolchain.base.name.label")) { row(ZigBrainsBundle.message("settings.toolchain.base.name.label")) {
cell(nameField).resizableColumn().align(AlignX.FILL) cell(nameField).resizableColumn().align(AlignX.FILL)
} }

View file

@ -60,7 +60,7 @@ class ZigToolchainEditor(private val sharedState: ZigProjectConfigurationProvide
} }
override fun attach(p: Panel): Unit = with(p) { override fun attach(panel: Panel): Unit = with(panel) {
row(ZigBrainsBundle.message( row(ZigBrainsBundle.message(
if (sharedState.getUserData(PROJECT_KEY)?.isDefault == true) if (sharedState.getUserData(PROJECT_KEY)?.isDefault == true)
"settings.toolchain.editor.toolchain-default.label" "settings.toolchain.editor.toolchain-default.label"
@ -75,7 +75,7 @@ class ZigToolchainEditor(private val sharedState: ZigProjectConfigurationProvide
views.addAll(createZigToolchainExtensionPanels(sharedState, PanelState.ProjectEditor)) views.addAll(createZigToolchainExtensionPanels(sharedState, PanelState.ProjectEditor))
myViews = views myViews = views
} }
views.forEach { it.attach(p) } views.forEach { it.attach(panel) }
} }
override fun onSelection(uuid: UUID?) { override fun onSelection(uuid: UUID?) {

View file

@ -130,13 +130,14 @@ fun createCommandLineSafe(
} }
@Throws(ExecutionException::class) @Throws(ExecutionException::class)
suspend fun GeneralCommandLine.startIPCAwareProcess(project: Project?, emulateTerminal: Boolean = false): ZigProcessHandler { suspend fun GeneralCommandLine.startIPCAwareProcess(project: Project?, emulateTerminal: Boolean = false): ZigProcessHandler.IPCAware {
val original = this.commandLineString
val ipc = if (project != null && !emulateTerminal) IPCUtil.wrapWithIPC(this) else null val ipc = if (project != null && !emulateTerminal) IPCUtil.wrapWithIPC(this) else null
val cli = ipc?.cli ?: this val cli = ipc?.cli ?: this
if (emulateTerminal && OS.CURRENT != OS.Windows && !cli.environment.contains("TERM")) { if (emulateTerminal && OS.CURRENT != OS.Windows && !cli.environment.contains("TERM")) {
cli.withEnvironment("TERM", "xterm-256color") cli.withEnvironment("TERM", "xterm-256color")
} }
val handler = ZigProcessHandler(cli) val handler = ZigProcessHandler.IPCAware(original, cli)
ProcessTerminatedListener.attach(handler) ProcessTerminatedListener.attach(handler)
if (ipc != null) { if (ipc != null) {

View file

@ -76,10 +76,10 @@ abstract class Downloader<T, V: VersionInfo>(val component: Component) {
protected abstract val windowTitle: String protected abstract val windowTitle: String
protected abstract val versionInfoFetchTitle: @NlsContexts.ProgressTitle String protected abstract val versionInfoFetchTitle: @NlsContexts.ProgressTitle String
protected abstract val suggestedPath: Path?
protected abstract fun downloadProgressTitle(version: V): @NlsContexts.ProgressTitle String protected abstract fun downloadProgressTitle(version: V): @NlsContexts.ProgressTitle String
protected abstract fun localSelector(): LocalSelector<T> protected abstract fun localSelector(): LocalSelector<T>
protected abstract suspend fun downloadVersionList(): List<V> protected abstract suspend fun downloadVersionList(): List<V>
protected abstract fun getSuggestedPath(): Path?
@RequiresEdt @RequiresEdt
private fun selectVersion(info: List<V>, selector: LocalSelector<T>): Pair<Path, V>? { private fun selectVersion(info: List<V>, selector: LocalSelector<T>): Pair<Path, V>? {
@ -131,7 +131,7 @@ abstract class Downloader<T, V: VersionInfo>(val component: Component) {
}) })
var archiveSizeCell: Cell<*>? = null var archiveSizeCell: Cell<*>? = null
fun detect(item: V) { fun detect(item: V) {
outputPath.text = getSuggestedPath()?.resolve(item.version.rawVersion)?.pathString ?: "" outputPath.text = suggestedPath?.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.shared.downloader.archive-size.text", "%.2fMB".format(sizeMb)) archiveSizeCell?.comment?.text = ZigBrainsBundle.message("settings.shared.downloader.archive-size.text", "%.2fMB".format(sizeMb))

View file

@ -41,11 +41,13 @@ import com.intellij.ui.components.textFieldWithBrowseButton
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.util.concurrency.annotations.RequiresEdt import com.intellij.util.concurrency.annotations.RequiresEdt
import com.intellij.util.system.OS
import java.awt.Component import java.awt.Component
import java.nio.file.Path import java.nio.file.Path
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import javax.swing.Icon import javax.swing.Icon
import javax.swing.event.DocumentEvent import javax.swing.event.DocumentEvent
import kotlin.io.path.isDirectory
import kotlin.io.path.pathString import kotlin.io.path.pathString
abstract class LocalSelector<T>(val component: Component) { abstract class LocalSelector<T>(val component: Component) {
@ -135,4 +137,16 @@ abstract class LocalSelector<T>(val component: Component) {
val errorIcon: Icon, val errorIcon: Icon,
val errorText: String, val errorText: String,
) )
}
val homePath: Path? by lazy {
System.getProperty("user.home")?.toNioPathOrNull()?.takeIf { it.isDirectory() }
}
val xdgDataHome: Path? by lazy {
when(OS.CURRENT) {
OS.macOS -> homePath?.resolve("Library")
OS.Windows -> System.getenv("LOCALAPPDATA")?.toNioPathOrNull()
else -> System.getenv("XDG_DATA_HOME")?.toNioPathOrNull() ?: homePath?.resolve(Path.of(".local", "share"))
}?.takeIf { it.isDirectory() }
} }

View file

@ -24,8 +24,11 @@ package com.falsepattern.zigbrains.shared.ui
import com.falsepattern.zigbrains.shared.UUIDMapSerializable import com.falsepattern.zigbrains.shared.UUIDMapSerializable
import com.intellij.openapi.ui.NamedConfigurable import com.intellij.openapi.ui.NamedConfigurable
import com.intellij.ui.components.JBScrollPane
import java.awt.Component import java.awt.Component
import java.awt.Dimension
import java.util.* import java.util.*
import javax.swing.JComponent
interface UUIDComboBoxDriver<T> { interface UUIDComboBoxDriver<T> {
val theMap: UUIDMapSerializable.Converting<T, *, *> val theMap: UUIDMapSerializable.Converting<T, *, *>
@ -34,4 +37,15 @@ interface UUIDComboBoxDriver<T> {
fun createComboBox(model: ZBModel<T>): ZBComboBox<T> fun createComboBox(model: ZBModel<T>): ZBComboBox<T>
suspend fun resolvePseudo(context: Component, elem: ListElem.Pseudo<T>): UUID? suspend fun resolvePseudo(context: Component, elem: ListElem.Pseudo<T>): UUID?
fun createNamedConfigurable(uuid: UUID, elem: T): NamedConfigurable<UUID> fun createNamedConfigurable(uuid: UUID, elem: T): NamedConfigurable<UUID>
companion object {
fun wrapModal(component: JComponent, modal: Boolean): JComponent {
if (modal) {
component.preferredSize = Dimension(640, 480)
return component
} else {
return JBScrollPane(component)
}
}
}
} }

View file

@ -161,7 +161,7 @@ abstract class UUIDMapSelector<T>(val driver: UUIDComboBoxDriver<T>): Disposable
protected fun attachComboBoxRow(row: Row): Unit = with(row) { protected fun attachComboBoxRow(row: Row): Unit = with(row) {
cell(comboBox).resizableColumn().align(AlignX.FILL) cell(comboBox).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")) {
zigCoroutineScope.launchWithEDT(comboBox.asContextElement()) { zigCoroutineScope.launchWithEDT(comboBox.asContextElement()) {
var selectedUUID = comboBox.selectedUUID ?: return@launchWithEDT var selectedUUID = comboBox.selectedUUID ?: return@launchWithEDT
val elem = driver.theMap[selectedUUID] ?: return@launchWithEDT val elem = driver.theMap[selectedUUID] ?: return@launchWithEDT

View file

@ -250,16 +250,16 @@ abstract class ZBCellRenderer<T>(val getModel: () -> ZBModel<T>) : ColoredListCe
} }
fun renderPathNameComponent(path: String, name: String?, nameFallback: String, component: SimpleColoredComponent, isSuggestion: Boolean, isSelected: Boolean) { fun renderPathNameComponent(path: String, name: String?, nameFallback: String, component: SimpleColoredComponent, isSuggestion: Boolean, isSelected: Boolean) {
val path = presentDetectedPath(path) val thePath = presentDetectedPath(path)
val primary: String val primary: String
var secondary: String? var secondary: String?
val tooltip: String? val tooltip: String?
if (isSuggestion) { if (isSuggestion) {
primary = path primary = thePath
secondary = name secondary = name
} else { } else {
primary = name ?: nameFallback primary = name ?: nameFallback
secondary = path secondary = thePath
} }
if (isSelected) { if (isSelected) {
tooltip = secondary tooltip = secondary
@ -277,12 +277,12 @@ fun renderPathNameComponent(path: String, name: String?, nameFallback: String, c
fun presentDetectedPath(home: String, maxLength: Int = 50, suffixLength: Int = 30): String { 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
var home = home var theHome = home
home = StringUtil.trimEnd(home, "/Contents/Home") //NON-NLS theHome = StringUtil.trimEnd(theHome, "/Contents/Home") //NON-NLS
home = StringUtil.trimEnd(home, "/Contents/MacOS") //NON-NLS theHome = StringUtil.trimEnd(theHome, "/Contents/MacOS") //NON-NLS
home = FileUtil.getLocationRelativeToUserHome(home, false) theHome = FileUtil.getLocationRelativeToUserHome(theHome, false)
home = StringUtil.shortenTextWithEllipsis(home, maxLength, suffixLength) theHome = StringUtil.shortenTextWithEllipsis(theHome, maxLength, suffixLength)
return home return theHome
} }
private val EMPTY_ICON = EmptyIcon.create(1, 16) private val EMPTY_ICON = EmptyIcon.create(1, 16)

View file

@ -91,7 +91,8 @@ configuration.test.marker-name=all tests in {0}
configuration.build.name=Zig build configuration.build.name=Zig build
configuration.build.suggested-name=Build configuration.build.suggested-name=Build
configuration.build.description=Execute "zig build" with custom steps configuration.build.description=Execute "zig build" with custom steps
configuration.build.marker-name=Build and Run configuration.build.marker-run=Build and Run
configuration.build.marker-test=Build and Test
settings.project.group.title=Zig Settings settings.project.group.title=Zig Settings
settings.project.label.direnv=Use direnv settings.project.label.direnv=Use direnv
settings.project.label.toolchain=Toolchain location settings.project.label.toolchain=Toolchain location

View file

@ -1,13 +1,13 @@
pluginName=ZigBrains pluginName=ZigBrains
pluginRepositoryUrl=https://github.com/FalsePattern/ZigBrains pluginRepositoryUrl=https://github.com/FalsePattern/ZigBrains
pluginVersion=25.0.1 pluginVersion=25.2.0
pluginSinceBuild=243 pluginSinceBuild=251
pluginUntilBuild= pluginUntilBuild=
ideaCommunityVersion=2024.3 ideaCommunityVersion=2025.1
clionVersion=2024.3 clionVersion=2025.1
useInstaller=true useInstaller=true
javaVersion=21 javaVersion=21
# ideaCommunity / clion # ideaCommunity / clion
@ -17,6 +17,8 @@ lsp4jVersion=0.21.1
lsp4ijVersion=0.12.0 lsp4ijVersion=0.12.0
lsp4ijNightly=false lsp4ijNightly=false
serializationVersion=1.7.3
kotlin.stdlib.default.dependency=false kotlin.stdlib.default.dependency=false
kotlin.code.style=official kotlin.code.style=official
org.gradle.configuration-cache=true org.gradle.configuration-cache=true

View file

@ -8,12 +8,15 @@ val lsp4ijVersion: String by project
val lsp4jVersion: String by project val lsp4jVersion: String by project
val ideaCommunityVersion: String by project val ideaCommunityVersion: String by project
val useInstaller = property("useInstaller").toString().toBoolean() val useInstaller = property("useInstaller").toString().toBoolean()
val serializationVersion: String by project
dependencies { dependencies {
intellijPlatform { intellijPlatform {
create(IntelliJPlatformType.IntellijIdeaCommunity, ideaCommunityVersion, useInstaller = useInstaller) create(IntelliJPlatformType.IntellijIdeaCommunity, ideaCommunityVersion, useInstaller = useInstaller)
} }
compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.3") compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:$serializationVersion") {
isTransitive = false
}
compileOnly("com.redhat.devtools.intellij:lsp4ij:$lsp4ijVersion") compileOnly("com.redhat.devtools.intellij:lsp4ij:$lsp4ijVersion")
compileOnly("org.eclipse.lsp4j:org.eclipse.lsp4j:$lsp4jVersion") compileOnly("org.eclipse.lsp4j:org.eclipse.lsp4j:$lsp4jVersion")
implementation(project(":core")) { implementation(project(":core")) {

View file

@ -68,7 +68,14 @@ class ZigLanguageServerFactory: LanguageServerFactory, LanguageServerEnablementS
} }
features.inlayHintFeature = object: LSPInlayHintFeature() { features.inlayHintFeature = object: LSPInlayHintFeature() {
override fun isEnabled(file: PsiFile): Boolean { override fun isEnabled(file: PsiFile): Boolean {
return project.zls?.settings?.inlayHints == true val settings = project.zls?.settings ?: return false
if (!settings.inlayHints)
return false
val maxFileSizeKb = settings.inlayHintsMaxFileSizeKb
if (maxFileSizeKb == 0)
return true
val fileSizeKb = file.fileDocument.textLength / 1024
return fileSizeKb <= maxFileSizeKb
} }
} }
return features return features

View file

@ -30,6 +30,7 @@ import org.jetbrains.annotations.NonNls
data class ZLSSettings( data class ZLSSettings(
@JvmField @Attribute val zlsConfigPath: @NonNls String = "", @JvmField @Attribute val zlsConfigPath: @NonNls String = "",
@JvmField @Attribute val inlayHints: Boolean = true, @JvmField @Attribute val inlayHints: Boolean = true,
@JvmField @Attribute val inlayHintsMaxFileSizeKb: Int = 128,
@JvmField @Attribute val enable_snippets: Boolean = true, @JvmField @Attribute val enable_snippets: Boolean = true,
@JvmField @Attribute val enable_argument_placeholders: Boolean = true, @JvmField @Attribute val enable_argument_placeholders: Boolean = true,
@JvmField @Attribute val completion_label_details: Boolean = true, @JvmField @Attribute val completion_label_details: Boolean = true,

View file

@ -35,6 +35,9 @@ 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.Row import com.intellij.ui.dsl.builder.Row
import org.jetbrains.annotations.PropertyKey import org.jetbrains.annotations.PropertyKey
import javax.swing.text.AttributeSet
import javax.swing.text.DocumentFilter
import javax.swing.text.PlainDocument
@Suppress("PrivatePropertyName") @Suppress("PrivatePropertyName")
class ZLSSettingsPanel() : ImmutableElementPanel<ZLSSettings> { class ZLSSettingsPanel() : ImmutableElementPanel<ZLSSettings> {
@ -44,6 +47,27 @@ class ZLSSettingsPanel() : ImmutableElementPanel<ZLSSettings> {
.withTitle(ZLSBundle.message("settings.zls-config-path.browse.title")) .withTitle(ZLSBundle.message("settings.zls-config-path.browse.title"))
).also { Disposer.register(this, it) } ).also { Disposer.register(this, it) }
private val inlayHints = JBCheckBox() private val inlayHints = JBCheckBox()
private val inlayHintsMaxFileSize = ExtendableTextField(5).also { (it.document as PlainDocument).documentFilter = object: DocumentFilter() {
override fun insertString(fb: FilterBypass?, offset: Int, string: String?, attr: AttributeSet?) {
if (string != null && !string.isEmpty() && string.toIntOrNull() == null) {
return
}
super.insertString(fb, offset, string, attr)
}
override fun replace(
fb: FilterBypass?,
offset: Int,
length: Int,
text: String?,
attrs: AttributeSet?
) {
if (text != null && !text.isEmpty() && text.toIntOrNull() == null) {
return
}
super.replace(fb, offset, length, text, attrs)
}
} }
private val enable_snippets = JBCheckBox() private val enable_snippets = JBCheckBox()
private val enable_argument_placeholders = JBCheckBox() private val enable_argument_placeholders = JBCheckBox()
private val completion_label_details = JBCheckBox() private val completion_label_details = JBCheckBox()
@ -65,7 +89,7 @@ class ZLSSettingsPanel() : ImmutableElementPanel<ZLSSettings> {
private val build_runner_path = ExtendableTextField() private val build_runner_path = ExtendableTextField()
private val global_cache_path = ExtendableTextField() private val global_cache_path = ExtendableTextField()
override fun attach(p: Panel): Unit = with(p) { override fun attach(panel: Panel): Unit = with(panel) {
fancyRow( fancyRow(
"settings.zls-config-path.label", "settings.zls-config-path.label",
"settings.zls-config-path.tooltip" "settings.zls-config-path.tooltip"
@ -99,6 +123,13 @@ class ZLSSettingsPanel() : ImmutableElementPanel<ZLSSettings> {
"settings.inlay-hints-enable.label", "settings.inlay-hints-enable.label",
"settings.inlay-hints-enable.tooltip" "settings.inlay-hints-enable.tooltip"
) { cell(inlayHints) } ) { cell(inlayHints) }
fancyRow(
"settings.inlay-hints-max-size.label",
"settings.inlay-hints-max-size.tooltip",
) {
cell(inlayHintsMaxFileSize)
text(ZLSBundle.message("settings.inlay-hints-max-size.unit"))
}
fancyRow( fancyRow(
"settings.inlay_hints_show_variable_type_hints.label", "settings.inlay_hints_show_variable_type_hints.label",
"settings.inlay_hints_show_variable_type_hints.tooltip" "settings.inlay_hints_show_variable_type_hints.tooltip"
@ -174,6 +205,7 @@ class ZLSSettingsPanel() : ImmutableElementPanel<ZLSSettings> {
get() = ZLSSettings( get() = ZLSSettings(
zlsConfigPath.text, zlsConfigPath.text,
inlayHints.isSelected, inlayHints.isSelected,
inlayHintsMaxFileSize.text.toIntOrNull() ?: 128,
enable_snippets.isSelected, enable_snippets.isSelected,
enable_argument_placeholders.isSelected, enable_argument_placeholders.isSelected,
completion_label_details.isSelected, completion_label_details.isSelected,
@ -198,6 +230,7 @@ class ZLSSettingsPanel() : ImmutableElementPanel<ZLSSettings> {
set(value) { set(value) {
zlsConfigPath.text = value.zlsConfigPath zlsConfigPath.text = value.zlsConfigPath
inlayHints.isSelected = value.inlayHints inlayHints.isSelected = value.inlayHints
inlayHintsMaxFileSize.text = value.inlayHintsMaxFileSizeKb.toString()
enable_snippets.isSelected = value.enable_snippets enable_snippets.isSelected = value.enable_snippets
enable_argument_placeholders.isSelected = value.enable_argument_placeholders enable_argument_placeholders.isSelected = value.enable_argument_placeholders
completion_label_details.isSelected = value.completion_label_details completion_label_details.isSelected = value.completion_label_details

View file

@ -22,14 +22,14 @@
package com.falsepattern.zigbrains.lsp.zls package com.falsepattern.zigbrains.lsp.zls
import com.falsepattern.zigbrains.shared.ui.UUIDComboBoxDriver.Companion.wrapModal
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 java.awt.Dimension
import java.util.* import java.util.*
import javax.swing.JComponent import javax.swing.JComponent
class ZLSConfigurable(val uuid: UUID, zls: ZLSVersion): NamedConfigurable<UUID>() { class ZLSConfigurable(val uuid: UUID, zls: ZLSVersion, private val modal: Boolean): NamedConfigurable<UUID>() {
var zls: ZLSVersion = zls var zls: ZLSVersion = zls
set(value) { set(value) {
zlsInstallations[uuid] = value zlsInstallations[uuid] = value
@ -59,8 +59,7 @@ class ZLSConfigurable(val uuid: UUID, zls: ZLSVersion): NamedConfigurable<UUID>(
val p = panel { val p = panel {
view.attach(this@panel) view.attach(this@panel)
} }
p.preferredSize = Dimension(640, 480) return wrapModal(p, modal)
return p
} }
override fun getDisplayName(): @NlsContexts.ConfigurableName String? { override fun getDisplayName(): @NlsContexts.ConfigurableName String? {

View file

@ -62,8 +62,8 @@ class ZLSPanel() : ImmutableNamedElementPanelBase<ZLSVersion>() {
private var settingsPanel: ZLSSettingsPanel? = null private var settingsPanel: ZLSSettingsPanel? = null
private var debounce: Job? = null private var debounce: Job? = null
override fun attach(p: Panel): Unit = with(p) { override fun attach(panel: Panel): Unit = with(panel) {
super.attach(p) super.attach(panel)
row(ZLSBundle.message("settings.panel.path.label")) { row(ZLSBundle.message("settings.panel.path.label")) {
cell(pathToZLS).resizableColumn().align(AlignX.FILL) cell(pathToZLS).resizableColumn().align(AlignX.FILL)
} }
@ -71,27 +71,27 @@ class ZLSPanel() : ImmutableNamedElementPanelBase<ZLSVersion>() {
cell(zlsVersion) cell(zlsVersion)
} }
val sp = ZLSSettingsPanel() val sp = ZLSSettingsPanel()
p.collapsibleGroup(ZLSBundle.message("settings.panel.settings.group.label"), indent = false) { panel.collapsibleGroup(ZLSBundle.message("settings.panel.settings.group.label"), indent = false) {
sp.attach(this@collapsibleGroup) sp.attach(this@collapsibleGroup)
} }
settingsPanel = sp settingsPanel = sp
} }
override fun isModified(version: ZLSVersion): Boolean { override fun isModified(elem: ZLSVersion): Boolean {
val name = nameFieldValue ?: return false val name = nameFieldValue ?: return false
val path = this.pathToZLS.text.ifBlank { null }?.toNioPathOrNull() ?: return false val path = this.pathToZLS.text.ifBlank { null }?.toNioPathOrNull() ?: return false
return name != version.name || version.path != path || settingsPanel?.isModified(version.settings) == true return name != elem.name || elem.path != path || settingsPanel?.isModified(elem.settings) == true
} }
override fun apply(version: ZLSVersion): ZLSVersion? { override fun apply(elem: ZLSVersion): ZLSVersion? {
val path = this.pathToZLS.text.ifBlank { null }?.toNioPathOrNull() ?: return null val path = this.pathToZLS.text.ifBlank { null }?.toNioPathOrNull() ?: return null
return version.copy(path = path, name = nameFieldValue ?: "", settings = settingsPanel?.apply(version.settings) ?: version.settings) return elem.copy(path = path, name = nameFieldValue ?: "", settings = settingsPanel?.apply(elem.settings) ?: elem.settings)
} }
override fun reset(version: ZLSVersion?) { override fun reset(elem: ZLSVersion?) {
nameFieldValue = version?.name ?: "" nameFieldValue = elem?.name ?: ""
this.pathToZLS.text = version?.path?.pathString ?: "" this.pathToZLS.text = elem?.path?.pathString ?: ""
settingsPanel?.reset(version?.settings) settingsPanel?.reset(elem?.settings)
dispatchUpdateUI() dispatchUpdateUI()
} }

View file

@ -24,7 +24,7 @@ package com.falsepattern.zigbrains.lsp.zls.downloader
import com.falsepattern.zigbrains.lsp.ZLSBundle import com.falsepattern.zigbrains.lsp.ZLSBundle
import com.falsepattern.zigbrains.lsp.zls.ZLSVersion import com.falsepattern.zigbrains.lsp.zls.ZLSVersion
import com.falsepattern.zigbrains.lsp.zls.ui.getSuggestedZLSPath import com.falsepattern.zigbrains.lsp.zls.ui.suggestedZLSPath
import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider
import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider.IUserDataBridge import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider.IUserDataBridge
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchainConfigurable import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchainConfigurable
@ -34,6 +34,7 @@ import java.awt.Component
class ZLSDownloader(component: Component, private val data: IUserDataBridge?) : Downloader<ZLSVersion, ZLSVersionInfo>(component) { class ZLSDownloader(component: Component, private val data: IUserDataBridge?) : Downloader<ZLSVersion, ZLSVersionInfo>(component) {
override val windowTitle get() = ZLSBundle.message("settings.downloader.title") override val windowTitle get() = ZLSBundle.message("settings.downloader.title")
override val versionInfoFetchTitle get() = ZLSBundle.message("settings.downloader.progress.fetch") override val versionInfoFetchTitle get() = ZLSBundle.message("settings.downloader.progress.fetch")
override val suggestedPath get() = suggestedZLSPath
override fun downloadProgressTitle(version: ZLSVersionInfo) = ZLSBundle.message("settings.downloader.progress.install", version.version.rawVersion) override fun downloadProgressTitle(version: ZLSVersionInfo) = ZLSBundle.message("settings.downloader.progress.install", version.version.rawVersion)
override fun localSelector() = ZLSLocalSelector(component) override fun localSelector() = ZLSLocalSelector(component)
override suspend fun downloadVersionList(): List<ZLSVersionInfo> { override suspend fun downloadVersionList(): List<ZLSVersionInfo> {
@ -41,5 +42,4 @@ class ZLSDownloader(component: Component, private val data: IUserDataBridge?) :
val project = data?.getUserData(ZigProjectConfigurationProvider.PROJECT_KEY) val project = data?.getUserData(ZigProjectConfigurationProvider.PROJECT_KEY)
return ZLSVersionInfo.downloadVersionInfoFor(toolchain, project) return ZLSVersionInfo.downloadVersionInfoFor(toolchain, project)
} }
override fun getSuggestedPath() = getSuggestedZLSPath()
} }

View file

@ -33,14 +33,14 @@ import com.falsepattern.zigbrains.lsp.zls.zlsInstallations
import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider import com.falsepattern.zigbrains.project.settings.ZigProjectConfigurationProvider
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchainConfigurable.Companion.TOOLCHAIN_KEY import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchainConfigurable.Companion.TOOLCHAIN_KEY
import com.falsepattern.zigbrains.shared.UUIDMapSerializable import com.falsepattern.zigbrains.shared.UUIDMapSerializable
import com.falsepattern.zigbrains.shared.downloader.homePath
import com.falsepattern.zigbrains.shared.downloader.xdgDataHome
import com.falsepattern.zigbrains.shared.ui.* import com.falsepattern.zigbrains.shared.ui.*
import com.falsepattern.zigbrains.shared.ui.ListElem.One.Actual import com.falsepattern.zigbrains.shared.ui.ListElem.One.Actual
import com.falsepattern.zigbrains.shared.withUniqueName import com.falsepattern.zigbrains.shared.withUniqueName
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.NamedConfigurable import com.intellij.openapi.ui.NamedConfigurable
import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.io.toNioPathOrNull
import com.intellij.util.system.OS
import com.intellij.util.text.SemVer import com.intellij.util.text.SemVer
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -67,10 +67,6 @@ sealed interface ZLSDriver: UUIDComboBoxDriver<ZLSVersion> {
return ZLSComboBox(model) return ZLSComboBox(model)
} }
override fun createNamedConfigurable(uuid: UUID, elem: ZLSVersion): NamedConfigurable<UUID> {
return ZLSConfigurable(uuid, elem)
}
override suspend fun resolvePseudo( override suspend fun resolvePseudo(
context: Component, context: Component,
elem: ListElem.Pseudo<ZLSVersion> elem: ListElem.Pseudo<ZLSVersion>
@ -93,6 +89,10 @@ sealed interface ZLSDriver: UUIDComboBoxDriver<ZLSVersion> {
return res return res
} }
override fun createNamedConfigurable(uuid: UUID, elem: ZLSVersion): NamedConfigurable<UUID> {
return ZLSConfigurable(uuid, elem, false)
}
override val data: ZigProjectConfigurationProvider.IUserDataBridge? override val data: ZigProjectConfigurationProvider.IUserDataBridge?
get() = null get() = null
} }
@ -113,6 +113,10 @@ sealed interface ZLSDriver: UUIDComboBoxDriver<ZLSVersion> {
res.add(suggestZLSVersions(project, data, toolchainVersion).asPending()) res.add(suggestZLSVersions(project, data, toolchainVersion).asPending())
return res return res
} }
override fun createNamedConfigurable(uuid: UUID, elem: ZLSVersion): NamedConfigurable<UUID> {
return ZLSConfigurable(uuid, elem, true)
}
} }
} }
@ -142,16 +146,16 @@ private fun suggestZLSVersions(project: Project? = null, data: ZigProjectConfigu
emitIfCompatible(path, toolchainVersion) emitIfCompatible(path, toolchainVersion)
} }
val exe = if (SystemInfo.isWindows) "zls.exe" else "zls" val exe = if (SystemInfo.isWindows) "zls.exe" else "zls"
getWellKnownZLS().forEach { wellKnown -> wellKnownZLS.forEach { wellKnown ->
runCatching { runCatching {
Files.newDirectoryStream(wellKnown).use { stream -> Files.newDirectoryStream(wellKnown).use { stream ->
stream.asSequence().filterNotNull().forEach { dir -> stream.asSequence().filterNotNull().forEach streamForEach@{ dir ->
val path = dir.resolve(exe) val path = dir.resolve(exe)
if (!path.isRegularFile() || !path.isExecutable()) { if (!path.isRegularFile() || !path.isExecutable()) {
return@forEach return@streamForEach
} }
if (existing.any { it.path == path }) { if (existing.any { it.path == path }) {
return@forEach return@streamForEach
} }
emitIfCompatible(path, toolchainVersion) emitIfCompatible(path, toolchainVersion)
} }
@ -188,8 +192,8 @@ private fun numericVersionEquals(a: SemVer, b: SemVer): Boolean {
} }
fun getSuggestedZLSPath(): Path? { val suggestedZLSPath: Path? by lazy {
return getWellKnownZLS().getOrNull(0) wellKnownZLS.getOrNull(0)
} }
/** /**
@ -205,17 +209,9 @@ fun getSuggestedZLSPath(): Path? {
* *
* and HOME is the user home path * and HOME is the user home path
*/ */
private fun getWellKnownZLS(): List<Path> { private val wellKnownZLS: List<Path> by lazy {
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>() val res = ArrayList<Path>()
if (xdgDataHome != null && xdgDataHome.isDirectory()) { xdgDataHome?.let { res.add(it.resolve("zls")) }
res.add(xdgDataHome.resolve("zls")) homePath?.let { res.add(it.resolve(".zls")) }
} res
res.add(home.resolve(".zls"))
return res
} }

View file

@ -55,21 +55,21 @@ class ZLSEditor<T: ZigToolchain>(private val sharedState: ZigProjectConfiguratio
} }
} }
override fun isModified(toolchain: T): Boolean { override fun isModified(elem: T): Boolean {
if (isEmpty) if (isEmpty)
return false return false
return toolchain.zlsUUID != selectedUUID return elem.zlsUUID != selectedUUID
} }
override fun apply(toolchain: T): T { override fun apply(elem: T): T {
return toolchain.withZLS(selectedUUID) return elem.withZLS(selectedUUID)
} }
override fun reset(toolchain: T?) { override fun reset(elem: T?) {
selectedUUID = toolchain?.zlsUUID selectedUUID = elem?.zlsUUID
zigCoroutineScope.launch { zigCoroutineScope.launch {
listChanged() listChanged()
selectedUUID = toolchain?.zlsUUID selectedUUID = elem?.zlsUUID
} }
} }

View file

@ -4,6 +4,9 @@ settings.zls-config-path.browse.title=Path to the Custom ZLS Config File (Option
settings.inlay-hints-group.label=Inlay Hints settings.inlay-hints-group.label=Inlay Hints
settings.inlay-hints-enable.label=Enable settings.inlay-hints-enable.label=Enable
settings.inlay-hints-enable.tooltip=Toggle this to enable/disable all inlay hints settings.inlay-hints-enable.tooltip=Toggle this to enable/disable all inlay hints
settings.inlay-hints-max-size.label=Maximum Size
settings.inlay-hints-max-size.tooltip=The maximum size of a zig file to show inlay hints for.\nInlay hints in very large files make the IDE lag.\nSet to 0 to disable.
settings.inlay-hints-max-size.unit=KB
settings.enable_snippets.label=Enable snippets settings.enable_snippets.label=Enable snippets
settings.enable_snippets.tooltip=Enables snippet completions when the client also supports them settings.enable_snippets.tooltip=Enables snippet completions when the client also supports them
settings.enable_argument_placeholders.label=Enable argument placeholders settings.enable_argument_placeholders.label=Enable argument placeholders

View file

@ -23,8 +23,6 @@
set -e set -e
declare -a branches=("dev" "master" "242" "241")
die () { die () {
echo >&2 "$@" echo >&2 "$@"
exit 1 exit 1
@ -32,8 +30,4 @@ die () {
[ "$#" -eq 1 ] || die "1 argument required, $# provided" [ "$#" -eq 1 ] || die "1 argument required, $# provided"
for i in "${branches[@]}" git push --atomic "$1" "dev" "master" "243" "242" "241"
do
echo "Pushing branch $i"
git push "$1" "$i"
done