summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorFrank Denis <[email protected]>2025-07-08 22:31:11 +0200
committerGitHub <[email protected]>2025-07-08 15:31:11 -0500
commitf7d6175283e9296e17ea466d596d38c029e33f25 (patch)
treebc376d33e7e9f7ec00ecc4034cdea0b85b7b76c2
parent9ed187ee52fc74bceed3b6cbd18029dc06a4695c (diff)
downloadopencode-f7d6175283e9296e17ea466d596d38c029e33f25.tar.gz
opencode-f7d6175283e9296e17ea466d596d38c029e33f25.zip
Add support for the Zig Language Server (ZLS) (#756)
-rw-r--r--packages/opencode/src/lsp/language.ts2
-rw-r--r--packages/opencode/src/lsp/server.ts102
2 files changed, 104 insertions, 0 deletions
diff --git a/packages/opencode/src/lsp/language.ts b/packages/opencode/src/lsp/language.ts
index 6c0da51b0..61686bd97 100644
--- a/packages/opencode/src/lsp/language.ts
+++ b/packages/opencode/src/lsp/language.ts
@@ -94,4 +94,6 @@ export const LANGUAGE_EXTENSIONS: Record<string, string> = {
".yml": "yaml",
".mjs": "javascript",
".cjs": "javascript",
+ ".zig": "zig",
+ ".zon": "zig",
} as const
diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts
index 3d965acbb..5546294be 100644
--- a/packages/opencode/src/lsp/server.ts
+++ b/packages/opencode/src/lsp/server.ts
@@ -181,4 +181,106 @@ export namespace LSPServer {
}
},
}
+
+ export const Zls: Info = {
+ id: "zls",
+ extensions: [".zig", ".zon"],
+ async spawn() {
+ let bin = Bun.which("zls", {
+ PATH: process.env["PATH"] + ":" + Global.Path.bin,
+ })
+
+ if (!bin) {
+ const zig = Bun.which("zig")
+ if (!zig) {
+ log.error("Zig is required to use zls. Please install Zig first.")
+ return
+ }
+
+ log.info("downloading zls from GitHub releases")
+
+ const releaseResponse = await fetch("https://api.github.com/repos/zigtools/zls/releases/latest")
+ if (!releaseResponse.ok) {
+ log.error("Failed to fetch zls release info")
+ return
+ }
+
+ const release = await releaseResponse.json()
+
+ const platform = process.platform
+ const arch = process.arch
+ let assetName = ""
+
+ let zlsArch: string = arch
+ if (arch === "arm64") zlsArch = "aarch64"
+ else if (arch === "x64") zlsArch = "x86_64"
+ else if (arch === "ia32") zlsArch = "x86"
+
+ let zlsPlatform: string = platform
+ if (platform === "darwin") zlsPlatform = "macos"
+ else if (platform === "win32") zlsPlatform = "windows"
+
+ const ext = platform === "win32" ? "zip" : "tar.xz"
+
+ assetName = `zls-${zlsArch}-${zlsPlatform}.${ext}`
+
+ const supportedCombos = [
+ "zls-x86_64-linux.tar.xz",
+ "zls-x86_64-macos.tar.xz",
+ "zls-x86_64-windows.zip",
+ "zls-aarch64-linux.tar.xz",
+ "zls-aarch64-macos.tar.xz",
+ "zls-aarch64-windows.zip",
+ "zls-x86-linux.tar.xz",
+ "zls-x86-windows.zip",
+ ]
+
+ if (!supportedCombos.includes(assetName)) {
+ log.error("Unsupported platform/architecture for zls", { platform, arch, assetName })
+ return
+ }
+
+ const asset = release.assets?.find((a: any) => a.name === assetName)
+
+ if (!asset) {
+ log.error("Could not find zls download for platform", { platform, arch, assetName })
+ return
+ }
+
+ const downloadUrl = asset.browser_download_url
+ log.info("downloading zls", { url: downloadUrl })
+
+ const response = await fetch(downloadUrl)
+ if (!response.ok) {
+ log.error("Failed to download zls")
+ return
+ }
+
+ const isZip = assetName.endsWith(".zip")
+ const archivePath = path.join(Global.Path.bin, isZip ? "zls.zip" : "zls.tar.xz")
+ await Bun.file(archivePath).write(response)
+
+ if (isZip) {
+ await $`unzip -o -q ${archivePath} -d ${Global.Path.bin}`.nothrow()
+ } else {
+ await $`tar -xf ${archivePath} -C ${Global.Path.bin}`.quiet()
+ }
+
+ await fs.rm(archivePath, { force: true })
+
+ if (platform !== "win32") {
+ bin = path.join(Global.Path.bin, "zls")
+ await $`chmod +x ${bin}`.quiet()
+ } else {
+ bin = path.join(Global.Path.bin, "zls.exe")
+ }
+
+ log.info("installed zls", { bin })
+ }
+
+ return {
+ process: spawn(bin!),
+ }
+ },
+ }
}