feat: add terraform-ls language server and formatter (#5243)

This commit is contained in:
rari404 2025-12-08 13:02:25 -05:00 committed by GitHub
parent 09ff8eba00
commit fab8ab2840
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 93 additions and 0 deletions

View file

@ -266,3 +266,12 @@ export const ocamlformat: Info = {
return items.length > 0
},
}
export const terraform: Info = {
name: "terraform",
command: ["terraform", "fmt", "$FILE"],
extensions: [".tf", ".tfvars"],
async enabled() {
return Bun.which("terraform") !== null
},
}

View file

@ -103,4 +103,7 @@ export const LANGUAGE_EXTENSIONS: Record<string, string> = {
".zig": "zig",
".zon": "zig",
".astro": "astro",
".tf": "terraform",
".tfvars": "terraform-vars",
".hcl": "hcl",
} as const

View file

@ -1223,4 +1223,85 @@ export namespace LSPServer {
}
},
}
export const TerraformLS: Info = {
id: "terraform",
extensions: [".tf", ".tfvars"],
root: NearestRoot([".terraform.lock.hcl", "terraform.tfstate", "*.tf"]),
async spawn(root) {
let bin = Bun.which("terraform-ls", {
PATH: process.env["PATH"] + ":" + Global.Path.bin,
})
if (!bin) {
if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return
log.info("downloading terraform-ls from GitHub releases")
const releaseResponse = await fetch("https://api.github.com/repos/hashicorp/terraform-ls/releases/latest")
if (!releaseResponse.ok) {
log.error("Failed to fetch terraform-ls release info")
return
}
const release = (await releaseResponse.json()) as { tag_name?: string; assets?: { name?: string; browser_download_url?: string }[] }
const version = release.tag_name?.replace("v", "")
if (!version) {
log.error("terraform-ls release did not include a version tag")
return
}
const platform = process.platform
const arch = process.arch
const tfArch = arch === "arm64" ? "arm64" : "amd64"
const tfPlatform = platform === "win32" ? "windows" : platform
const assetName = `terraform-ls_${version}_${tfPlatform}_${tfArch}.zip`
const assets = release.assets ?? []
const asset = assets.find((a) => a.name === assetName)
if (!asset?.browser_download_url) {
log.error(`Could not find asset ${assetName} in terraform-ls release`)
return
}
const downloadResponse = await fetch(asset.browser_download_url)
if (!downloadResponse.ok) {
log.error("Failed to download terraform-ls")
return
}
const tempPath = path.join(Global.Path.bin, assetName)
await Bun.file(tempPath).write(downloadResponse)
await $`unzip -o -q ${tempPath}`.cwd(Global.Path.bin).nothrow()
await fs.rm(tempPath, { force: true })
bin = path.join(Global.Path.bin, "terraform-ls" + (platform === "win32" ? ".exe" : ""))
if (!(await Bun.file(bin).exists())) {
log.error("Failed to extract terraform-ls binary")
return
}
if (platform !== "win32") {
await $`chmod +x ${bin}`.nothrow()
}
log.info(`installed terraform-ls`, { bin })
}
return {
process: spawn(bin, ["serve"], {
cwd: root,
}),
initialization: {
experimentalFeatures: {
prefillRequiredFields: true,
validateOnSave: true,
},
},
}
},
}
}