summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--packages/opencode/src/lsp/server.ts88
1 files changed, 88 insertions, 0 deletions
diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts
index e4b77be04..c680c2896 100644
--- a/packages/opencode/src/lsp/server.ts
+++ b/packages/opencode/src/lsp/server.ts
@@ -1,5 +1,6 @@
import { spawn, type ChildProcessWithoutNullStreams } from "child_process"
import path from "path"
+import os from "os"
import { Global } from "../global"
import { Log } from "../util/log"
import { BunProc } from "../bun"
@@ -706,4 +707,91 @@ export namespace LSPServer {
}
},
}
+
+ export const JDTLS: Info = {
+ id: "jdtls",
+ root: NearestRoot(["pom.xml", "build.gradle", "build.gradle.kts", ".project", ".classpath"]),
+ extensions: [".java"],
+ async spawn(root) {
+ const java = Bun.which("java")
+ if (!java) {
+ log.error("Java 21 or newer is required to run the JDTLS. Please install it first.")
+ return
+ }
+ const javaMajorVersion = await $`java -version`
+ .quiet()
+ .nothrow()
+ .then(({ stderr }) => {
+ const m = /"(\d+)\.\d+\.\d+"/.exec(stderr.toString())
+ return !m ? undefined : parseInt(m[1])
+ })
+ if (javaMajorVersion == null || javaMajorVersion < 21) {
+ log.error("JDTLS requires at least Java 21.")
+ return
+ }
+ const distPath = path.join(Global.Path.bin, "jdtls")
+ const launcherDir = path.join(distPath, "plugins")
+ const installed = await fs.exists(launcherDir)
+ if (!installed) {
+ if (Flag.OPENCODE_DISABLE_LSP_DOWNLOAD) return
+ log.info("Downloading JDTLS LSP server.")
+ await fs.mkdir(distPath, { recursive: true })
+ const releaseURL =
+ "https://www.eclipse.org/downloads/download.php?file=/jdtls/snapshots/jdt-language-server-latest.tar.gz"
+ const archivePath = path.join(distPath, "release.tar.gz")
+ await $`curl -L -o '${archivePath}' '${releaseURL}'`.quiet().nothrow()
+ await $`tar -xzf ${archivePath}`.cwd(distPath).quiet().nothrow()
+ await fs.rm(archivePath, { force: true })
+ }
+ const jarFileName = await $`ls org.eclipse.equinox.launcher_*.jar`
+ .cwd(launcherDir)
+ .quiet()
+ .nothrow()
+ .then(({ stdout }) => stdout.toString().trim())
+ const launcherJar = path.join(launcherDir, jarFileName)
+ if (!(await fs.exists(launcherJar))) {
+ log.error(`Failed to locate the JDTLS launcher module in the installed directory: ${distPath}.`)
+ return
+ }
+ const configFile = path.join(
+ distPath,
+ (() => {
+ switch (process.platform) {
+ case "darwin":
+ return "config_mac"
+ case "linux":
+ return "config_linux"
+ case "win32":
+ return "config_windows"
+ default:
+ return "config_linux"
+ }
+ })(),
+ )
+ const dataDir = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-jdtls-data"))
+ return {
+ process: spawn(
+ java,
+ [
+ "-jar",
+ launcherJar,
+ "-configuration",
+ configFile,
+ "-data",
+ dataDir,
+ "-Declipse.application=org.eclipse.jdt.ls.core.id1",
+ "-Dosgi.bundles.defaultStartLevel=4",
+ "-Declipse.product=org.eclipse.jdt.ls.core.product",
+ "-Dlog.level=ALL",
+ "--add-modules=ALL-SYSTEM",
+ "--add-opens java.base/java.util=ALL-UNNAMED",
+ "--add-opens java.base/java.lang=ALL-UNNAMED",
+ ],
+ {
+ cwd: root,
+ },
+ ),
+ }
+ },
+ }
}