From ef78fd8bae991cc7d816dba8e2f37916cc6dd441 Mon Sep 17 00:00:00 2001 From: Luke Parker <10430890+Hona@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:26:59 +1000 Subject: [PATCH] fix: debounce LSP diagnostics to get complete results (#5600) --- packages/opencode/src/lsp/client.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/lsp/client.ts b/packages/opencode/src/lsp/client.ts index f06c2c938..b66bb9933 100644 --- a/packages/opencode/src/lsp/client.ts +++ b/packages/opencode/src/lsp/client.ts @@ -13,6 +13,8 @@ import { withTimeout } from "../util/timeout" import { Instance } from "../project/instance" import { Filesystem } from "../util/filesystem" +const DIAGNOSTICS_DEBOUNCE_MS = 150 + export namespace LSPClient { const log = Log.create({ service: "lsp.client" }) @@ -188,13 +190,18 @@ export namespace LSPClient { ) log.info("waiting for diagnostics", { path: normalizedPath }) let unsub: () => void + let debounceTimer: ReturnType | undefined return await withTimeout( new Promise((resolve) => { unsub = Bus.subscribe(Event.Diagnostics, (event) => { if (event.properties.path === normalizedPath && event.properties.serverID === result.serverID) { - log.info("got diagnostics", { path: normalizedPath }) - unsub?.() - resolve() + // Debounce to allow LSP to send follow-up diagnostics (e.g., semantic after syntax) + if (debounceTimer) clearTimeout(debounceTimer) + debounceTimer = setTimeout(() => { + log.info("got diagnostics", { path: normalizedPath }) + unsub?.() + resolve() + }, DIAGNOSTICS_DEBOUNCE_MS) } }) }), @@ -202,6 +209,7 @@ export namespace LSPClient { ) .catch(() => {}) .finally(() => { + if (debounceTimer) clearTimeout(debounceTimer) unsub?.() }) },