Przeglądaj źródła

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

rari404 2 miesięcy temu
rodzic
commit
fab8ab2840

+ 9 - 0
packages/opencode/src/format/formatter.ts

@@ -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
+  },
+}

+ 3 - 0
packages/opencode/src/lsp/language.ts

@@ -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

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

@@ -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,
+          },
+        },
+      }
+    },
+  }
 }