Skip to content

Commit b94d064

Browse files
committed
Update client.ts
1 parent e8e3c53 commit b94d064

1 file changed

Lines changed: 46 additions & 39 deletions

File tree

packages/opencode/src/lsp/client.ts

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,7 @@ export async function create(input: { serverID: string; server: LSPServer.Handle
115115
const diagnostics = new Map<string, Diagnostic[]>()
116116
const diagnosticRegistrations = new Map<string, CapabilityRegistration>()
117117
function updateDiagnostics(filePath: string, next: Diagnostic[]) {
118-
const exists = diagnostics.has(filePath)
119118
diagnostics.set(filePath, next)
120-
if (!exists && input.serverID === "typescript") return
121119
Bus.publish(Event.Diagnostics, { path: filePath, serverID: input.serverID })
122120
}
123121
connection.onNotification("textDocument/publishDiagnostics", (params) => {
@@ -127,6 +125,12 @@ export async function create(input: { serverID: string; server: LSPServer.Handle
127125
path: filePath,
128126
count: params.diagnostics.length,
129127
})
128+
// tsserver emits an initial empty publish before analysis completes; store
129+
// it so the next publish is treated as an update, but don't broadcast it.
130+
if (input.serverID === "typescript" && !diagnostics.has(filePath)) {
131+
diagnostics.set(filePath, params.diagnostics)
132+
return
133+
}
130134
updateDiagnostics(filePath, params.diagnostics)
131135
})
132136
connection.onRequest("window/workDoneProgress/create", (params) => {
@@ -384,47 +388,50 @@ export async function create(input: { serverID: string; server: LSPServer.Handle
384388
path.isAbsolute(request.path) ? request.path : path.resolve(input.directory, request.path),
385389
)
386390
log.info("waiting for diagnostics", { path: normalizedPath })
387-
let unsub: (() => void) | undefined
391+
392+
const canPull = hasStaticPullDiagnostics || diagnosticRegistrations.size > 0
393+
const timeout = canPull ? DIAGNOSTICS_PULL_WAIT_TIMEOUT_MS : DIAGNOSTICS_WAIT_TIMEOUT_MS
394+
395+
// Shared stop flag: whichever branch wins the race (or the outer
396+
// timeout) sets this so the other branch bails before issuing more work.
397+
let stopped = false
388398
let debounceTimer: ReturnType<typeof setTimeout> | undefined
389-
let done = false
390-
let resolvePushed: (() => void) | undefined
391-
const timeout = hasStaticPullDiagnostics || diagnosticRegistrations.size > 0
392-
? DIAGNOSTICS_PULL_WAIT_TIMEOUT_MS
393-
: DIAGNOSTICS_WAIT_TIMEOUT_MS
394-
return await withTimeout(
395-
Promise.race([
396-
new Promise<void>((resolve) => {
397-
resolvePushed = resolve
398-
unsub = Bus.subscribe(Event.Diagnostics, (event) => {
399-
if (event.properties.path !== normalizedPath || event.properties.serverID !== result.serverID) return
400-
if (debounceTimer) clearTimeout(debounceTimer)
401-
debounceTimer = setTimeout(() => {
402-
log.info("got diagnostics", { path: normalizedPath })
403-
resolve()
404-
}, DIAGNOSTICS_DEBOUNCE_MS)
405-
})
406-
}),
407-
(async () => {
408-
let firstHandledAt: number | undefined
409-
while (!done) {
410-
const handled = await requestDiagnostics(normalizedPath)
411-
if (handled) {
412-
firstHandledAt = firstHandledAt ?? Date.now()
413-
if (Date.now() - firstHandledAt >= DIAGNOSTICS_SETTLE_MS) {
414-
log.info("got diagnostics", { path: normalizedPath })
415-
return
416-
}
417-
}
418-
await new Promise((resolve) => setTimeout(resolve, DIAGNOSTICS_POLL_MS))
399+
let unsub: (() => void) | undefined
400+
401+
const waitForPush = new Promise<void>((resolve) => {
402+
unsub = Bus.subscribe(Event.Diagnostics, (event) => {
403+
if (event.properties.path !== normalizedPath || event.properties.serverID !== result.serverID) return
404+
if (debounceTimer) clearTimeout(debounceTimer)
405+
debounceTimer = setTimeout(() => {
406+
log.info("got diagnostics", { path: normalizedPath })
407+
stopped = true
408+
resolve()
409+
}, DIAGNOSTICS_DEBOUNCE_MS)
410+
})
411+
})
412+
413+
const waitForPull = async () => {
414+
let firstHandledAt: number | undefined
415+
while (!stopped) {
416+
const handled = await requestDiagnostics(normalizedPath)
417+
if (stopped) return
418+
if (handled) {
419+
firstHandledAt = firstHandledAt ?? Date.now()
420+
if (Date.now() - firstHandledAt >= DIAGNOSTICS_SETTLE_MS) {
421+
log.info("got diagnostics", { path: normalizedPath })
422+
stopped = true
423+
return
419424
}
420-
})(),
421-
]),
422-
timeout,
423-
)
425+
}
426+
await new Promise((resolve) => setTimeout(resolve, DIAGNOSTICS_POLL_MS))
427+
}
428+
}
429+
430+
const race = canPull ? Promise.race([waitForPush, waitForPull()]) : waitForPush
431+
return await withTimeout(race, timeout)
424432
.catch(() => {})
425433
.finally(() => {
426-
done = true
427-
resolvePushed?.()
434+
stopped = true
428435
if (debounceTimer) clearTimeout(debounceTimer)
429436
unsub?.()
430437
})

0 commit comments

Comments
 (0)