From 8b9710e56c041cae4bdc0b865dc4d13bc04edebf Mon Sep 17 00:00:00 2001 From: Stephen Collings Date: Mon, 9 Mar 2026 16:04:08 +0000 Subject: [PATCH] fix: Multiple jdtls LSPs eating memory in java monorepos (#12123) --- packages/opencode/src/lsp/server.ts | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/lsp/server.ts b/packages/opencode/src/lsp/server.ts index e09fbc97f..405c67285 100644 --- a/packages/opencode/src/lsp/server.ts +++ b/packages/opencode/src/lsp/server.ts @@ -1130,7 +1130,30 @@ export namespace LSPServer { export const JDTLS: Info = { id: "jdtls", - root: NearestRoot(["pom.xml", "build.gradle", "build.gradle.kts", ".project", ".classpath"]), + root: async (file) => { + // Without exclusions, NearestRoot defaults to instance directory so we can't + // distinguish between a) no project found and b) project found at instance dir. + // So we can't choose the root from (potential) monorepo markers first. + // Look for potential subproject markers first while excluding potential monorepo markers. + const settingsMarkers = ["settings.gradle", "settings.gradle.kts"] + const gradleMarkers = ["gradlew", "gradlew.bat"] + const exclusionsForMonorepos = gradleMarkers.concat(settingsMarkers) + + const [projectRoot, wrapperRoot, settingsRoot] = await Promise.all([ + NearestRoot( + ["pom.xml", "build.gradle", "build.gradle.kts", ".project", ".classpath"], + exclusionsForMonorepos, + )(file), + NearestRoot(gradleMarkers, settingsMarkers)(file), + NearestRoot(settingsMarkers)(file), + ]) + + // If projectRoot is undefined we know we are in a monorepo or no project at all. + // So can safely fall through to the other roots + if (projectRoot) return projectRoot + if (wrapperRoot) return wrapperRoot + if (settingsRoot) return settingsRoot + }, extensions: [".java"], async spawn(root) { const java = which("java")