From ee0519aacc22db40f99365c6759d2f1715931a5c Mon Sep 17 00:00:00 2001 From: adamdotdevin <2363879+adamdottv@users.noreply.github.com> Date: Mon, 11 Aug 2025 19:21:59 -0500 Subject: [PATCH] feat: add clangd for cpp --- packages/opencode/src/lsp/server.ts | 77 +++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index cf78fe7b..3da5a7e2 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -421,4 +421,81 @@ export namespace LSPServer { } }, } + + export const Clangd: Info = { + id: "clangd", + root: NearestRoot(["compile_commands.json", "compile_flags.txt", ".clangd", "CMakeLists.txt", "Makefile"]), + extensions: [".c", ".cpp", ".cc", ".cxx", ".c++", ".h", ".hpp", ".hh", ".hxx", ".h++"], + async spawn(_, root) { + let bin = Bun.which("clangd", { + PATH: process.env["PATH"] + ":" + Global.Path.bin, + }) + if (!bin) { + log.info("downloading clangd from GitHub releases") + + const releaseResponse = await fetch("https://api.github.com/repos/clangd/clangd/releases/latest") + if (!releaseResponse.ok) { + log.error("Failed to fetch clangd release info") + return + } + + const release = await releaseResponse.json() + + const platform = process.platform + let assetName = "" + + if (platform === "darwin") { + assetName = "clangd-mac-" + } else if (platform === "linux") { + assetName = "clangd-linux-" + } else if (platform === "win32") { + assetName = "clangd-windows-" + } else { + log.error(`Platform ${platform} is not supported by clangd auto-download`) + return + } + + assetName += release.tag_name + ".zip" + + const asset = release.assets.find((a: any) => a.name === assetName) + if (!asset) { + log.error(`Could not find asset ${assetName} in latest clangd release`) + return + } + + const downloadUrl = asset.browser_download_url + const downloadResponse = await fetch(downloadUrl) + if (!downloadResponse.ok) { + log.error("Failed to download clangd") + return + } + + const zipPath = path.join(Global.Path.bin, "clangd.zip") + await Bun.file(zipPath).write(downloadResponse) + + await $`unzip -o -q ${zipPath}`.cwd(Global.Path.bin).nothrow() + await fs.rm(zipPath, { force: true }) + + const extractedDir = path.join(Global.Path.bin, assetName.replace(".zip", "")) + bin = path.join(extractedDir, "bin", "clangd" + (platform === "win32" ? ".exe" : "")) + + if (!(await Bun.file(bin).exists())) { + log.error("Failed to extract clangd binary") + return + } + + if (platform !== "win32") { + await $`chmod +x ${bin}`.nothrow() + } + + log.info(`installed clangd`, { bin }) + } + + return { + process: spawn(bin, ["--background-index", "--clang-tidy"], { + cwd: root, + }), + } + }, + } }