diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index 939a31a2df0..919e0c64e9a 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -4,7 +4,7 @@ import os from "os" import { Global } from "../global" import { Log } from "../util/log" import { BunProc } from "../bun" -import { $ } from "bun" +import { $, readableStreamToText } from "bun" import fs from "fs/promises" import { Filesystem } from "../util/filesystem" import { Instance } from "../project/instance" @@ -216,6 +216,77 @@ export namespace LSPServer { }, } + export const Oxlint: Info = { + id: "oxlint", + root: NearestRoot([ + ".oxlintrc.json", + "package-lock.json", + "bun.lockb", + "bun.lock", + "pnpm-lock.yaml", + "yarn.lock", + "package.json", + ]), + extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue", ".astro", ".svelte"], + async spawn(root) { + const ext = process.platform === "win32" ? ".cmd" : "" + + const serverTarget = path.join("node_modules", ".bin", "oxc_language_server" + ext) + const lintTarget = path.join("node_modules", ".bin", "oxlint" + ext) + + const resolveBin = async (target: string) => { + const localBin = path.join(root, target) + if (await Bun.file(localBin).exists()) return localBin + + const candidates = Filesystem.up({ + targets: [target], + start: root, + stop: Instance.worktree, + }) + const first = await candidates.next() + await candidates.return() + if (first.value) return first.value + + return undefined + } + + let lintBin = await resolveBin(lintTarget) + if (!lintBin) { + const found = Bun.which("oxlint") + if (found) lintBin = found + } + + if (lintBin) { + const proc = Bun.spawn([lintBin, "--help"], { stdout: "pipe" }) + await proc.exited + const help = await readableStreamToText(proc.stdout) + if (help.includes("--lsp")) { + return { + process: spawn(lintBin, ["--lsp"], { + cwd: root, + }), + } + } + } + + let serverBin = await resolveBin(serverTarget) + if (!serverBin) { + const found = Bun.which("oxc_language_server") + if (found) serverBin = found + } + if (serverBin) { + return { + process: spawn(serverBin, [], { + cwd: root, + }), + } + } + + log.info("oxlint not found, please install oxlint") + return + }, + } + export const Biome: Info = { id: "biome", root: NearestRoot([ diff --git a/packages/web/src/content/docs/lsp.mdx b/packages/web/src/content/docs/lsp.mdx index a96cf5324da..6572574f2eb 100644 --- a/packages/web/src/content/docs/lsp.mdx +++ b/packages/web/src/content/docs/lsp.mdx @@ -11,33 +11,34 @@ OpenCode integrates with your Language Server Protocol (LSP) to help the LLM int OpenCode comes with several built-in LSP servers for popular languages: -| LSP Server | Extensions | Requirements | -| ------------------ | ---------------------------------------------------- | ------------------------------------------------------------ | -| astro | .astro | Auto-installs for Astro projects | -| bash | .sh, .bash, .zsh, .ksh | Auto-installs bash-language-server | -| clangd | .c, .cpp, .cc, .cxx, .c++, .h, .hpp, .hh, .hxx, .h++ | Auto-installs for C/C++ projects | -| csharp | .cs | `.NET SDK` installed | -| dart | .dart | `dart` command available | -| deno | .ts, .tsx, .js, .jsx, .mjs | `deno` command available (auto-detects deno.json/deno.jsonc) | -| elixir-ls | .ex, .exs | `elixir` command available | -| eslint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue | `eslint` dependency in project | -| fsharp | .fs, .fsi, .fsx, .fsscript | `.NET SDK` installed | -| gleam | .gleam | `gleam` command available | -| gopls | .go | `go` command available | -| jdtls | .java | `Java SDK (version 21+)` installed | -| lua-ls | .lua | Auto-installs for Lua projects | -| ocaml-lsp | .ml, .mli | `ocamllsp` command available | -| php intelephense | .php | Auto-installs for PHP projects | -| pyright | .py, .pyi | `pyright` dependency installed | -| ruby-lsp (rubocop) | .rb, .rake, .gemspec, .ru | `ruby` and `gem` commands available | -| rust | .rs | `rust-analyzer` command available | -| sourcekit-lsp | .swift, .objc, .objcpp | `swift` installed (`xcode` on macOS) | -| svelte | .svelte | Auto-installs for Svelte projects | -| terraform | .tf, .tfvars | Auto-installs from GitHub releases | -| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | `typescript` dependency in project | -| vue | .vue | Auto-installs for Vue projects | -| yaml-ls | .yaml, .yml | Auto-installs Red Hat yaml-language-server | -| zls | .zig, .zon | `zig` command available | +| LSP Server | Extensions | Requirements | +| ------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------ | +| astro | .astro | Auto-installs for Astro projects | +| bash | .sh, .bash, .zsh, .ksh | Auto-installs bash-language-server | +| clangd | .c, .cpp, .cc, .cxx, .c++, .h, .hpp, .hh, .hxx, .h++ | Auto-installs for C/C++ projects | +| csharp | .cs | `.NET SDK` installed | +| dart | .dart | `dart` command available | +| deno | .ts, .tsx, .js, .jsx, .mjs | `deno` command available (auto-detects deno.json/deno.jsonc) | +| elixir-ls | .ex, .exs | `elixir` command available | +| eslint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue | `eslint` dependency in project | +| fsharp | .fs, .fsi, .fsx, .fsscript | `.NET SDK` installed | +| gleam | .gleam | `gleam` command available | +| gopls | .go | `go` command available | +| jdtls | .java | `Java SDK (version 21+)` installed | +| lua-ls | .lua | Auto-installs for Lua projects | +| ocaml-lsp | .ml, .mli | `ocamllsp` command available | +| oxlint | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts, .vue, .astro, .svelte | `oxlint` dependency in project | +| php intelephense | .php | Auto-installs for PHP projects | +| pyright | .py, .pyi | `pyright` dependency installed | +| ruby-lsp (rubocop) | .rb, .rake, .gemspec, .ru | `ruby` and `gem` commands available | +| rust | .rs | `rust-analyzer` command available | +| sourcekit-lsp | .swift, .objc, .objcpp | `swift` installed (`xcode` on macOS) | +| svelte | .svelte | Auto-installs for Svelte projects | +| terraform | .tf, .tfvars | Auto-installs from GitHub releases | +| typescript | .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts | `typescript` dependency in project | +| vue | .vue | Auto-installs for Vue projects | +| yaml-ls | .yaml, .yml | Auto-installs Red Hat yaml-language-server | +| zls | .zig, .zon | `zig` command available | LSP servers are automatically enabled when one of the above file extensions are detected and the requirements are met.