Răsfoiți Sursa

feat: support lua lsp (#3402)

Hieu Nguyen 4 luni în urmă
părinte
comite
483fcdaddb
2 a modificat fișierele cu 123 adăugiri și 0 ștergeri
  1. 122 0
      packages/opencode/src/lsp/server.ts
  2. 1 0
      packages/web/src/content/docs/lsp.mdx

+ 122 - 0
packages/opencode/src/lsp/server.ts

@@ -838,4 +838,126 @@ export namespace LSPServer {
       }
       }
     },
     },
   }
   }
+
+  export const LuaLS: Info = {
+    id: "lua-ls",
+    root: NearestRoot([
+      ".luarc.json",
+      ".luarc.jsonc",
+      ".luacheckrc",
+      ".stylua.toml",
+      "stylua.toml",
+      "selene.toml",
+      "selene.yml",
+    ]),
+    extensions: [".lua"],
+    async spawn(root) {
+      let bin = Bun.which("lua-language-server", {
+        PATH: process.env["PATH"] + ":" + Global.Path.bin,
+      })
+
+      if (!bin) {
+        if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return
+        log.info("downloading lua-language-server from GitHub releases")
+
+        const releaseResponse = await fetch("https://api.github.com/repos/LuaLS/lua-language-server/releases/latest")
+        if (!releaseResponse.ok) {
+          log.error("Failed to fetch lua-language-server release info")
+          return
+        }
+
+        const release = await releaseResponse.json()
+
+        const platform = process.platform
+        const arch = process.arch
+        let assetName = ""
+
+        let lualsArch: string = arch
+        if (arch === "arm64") lualsArch = "arm64"
+        else if (arch === "x64") lualsArch = "x64"
+        else if (arch === "ia32") lualsArch = "ia32"
+
+        let lualsPlatform: string = platform
+        if (platform === "darwin") lualsPlatform = "darwin"
+        else if (platform === "linux") lualsPlatform = "linux"
+        else if (platform === "win32") lualsPlatform = "win32"
+
+        const ext = platform === "win32" ? "zip" : "tar.gz"
+
+        assetName = `lua-language-server-${release.tag_name}-${lualsPlatform}-${lualsArch}.${ext}`
+
+        const supportedCombos = [
+          "darwin-arm64.tar.gz",
+          "darwin-x64.tar.gz",
+          "linux-x64.tar.gz",
+          "linux-arm64.tar.gz",
+          "win32-x64.zip",
+          "win32-ia32.zip",
+        ]
+
+        const assetSuffix = `${lualsPlatform}-${lualsArch}.${ext}`
+        if (!supportedCombos.includes(assetSuffix)) {
+          log.error(`Platform ${platform} and architecture ${arch} is not supported by lua-language-server`)
+          return
+        }
+
+        const asset = release.assets.find((a: any) => a.name === assetName)
+        if (!asset) {
+          log.error(`Could not find asset ${assetName} in latest lua-language-server release`)
+          return
+        }
+
+        const downloadUrl = asset.browser_download_url
+        const downloadResponse = await fetch(downloadUrl)
+        if (!downloadResponse.ok) {
+          log.error("Failed to download lua-language-server")
+          return
+        }
+
+        const tempPath = path.join(Global.Path.bin, assetName)
+        await Bun.file(tempPath).write(downloadResponse)
+
+        // Unlike zls which is a single self-contained binary,
+        // lua-language-server needs supporting files (meta/, locale/, etc.)
+        // Extract entire archive to dedicated directory to preserve all files
+        const installDir = path.join(Global.Path.bin, `lua-language-server-${lualsArch}-${lualsPlatform}`)
+
+        // Remove old installation if exists
+        const stats = await fs.stat(installDir).catch(() => undefined)
+        if (stats) {
+          await fs.rm(installDir, { force: true, recursive: true })
+        }
+
+        await fs.mkdir(installDir, { recursive: true })
+
+        if (ext === "zip") {
+          await $`unzip -o -q ${tempPath} -d ${installDir}`.quiet().nothrow()
+        } else {
+          await $`tar -xzf ${tempPath} -C ${installDir}`.nothrow()
+        }
+
+        await fs.rm(tempPath, { force: true })
+
+        // Binary is located in bin/ subdirectory within the extracted archive
+        bin = path.join(installDir, "bin", "lua-language-server" + (platform === "win32" ? ".exe" : ""))
+
+        if (!(await Bun.file(bin).exists())) {
+          log.error("Failed to extract lua-language-server binary")
+          return
+        }
+
+        if (platform !== "win32") {
+          await $`chmod +x ${bin}`.nothrow()
+        }
+
+        log.info(`installed lua-language-server`, { bin })
+      }
+
+      return {
+        process: spawn(bin, {
+          cwd: root,
+        }),
+      }
+    },
+  }
 }
 }

+ 1 - 0
packages/web/src/content/docs/lsp.mdx

@@ -28,6 +28,7 @@ OpenCode comes with several built-in LSP servers for popular languages:
 | svelte     | .svelte                                              | Auto-installs for Svelte projects                            |
 | svelte     | .svelte                                              | Auto-installs for Svelte projects                            |
 | astro      | .astro                                               | Auto-installs for Astro projects                             |
 | astro      | .astro                                               | Auto-installs for Astro projects                             |
 | jdtls      | .java                                                | `Java SDK (version 21+)` installed                           |
 | jdtls      | .java                                                | `Java SDK (version 21+)` installed                           |
+| lua-ls     | .lua                                                 | Auto-installs for Lua projects                               |
 
 
 LSP servers are automatically enabled when one of the above file extensions are detected and the requirements are met.
 LSP servers are automatically enabled when one of the above file extensions are detected and the requirements are met.