Summary
runWorkspaceDiagnostics (clients/lsp/index.ts) computes project-wide diagnostics by walking every LSP-supported source file under the root (collectWorkspaceDiagnosticFiles) and issuing a per-file touchFile(... {diagnostics:"document", clientScope:"all"}) across WORKSPACE_DIAGNOSTICS_CONCURRENCY workers. Its own comment calls this "intentionally expensive." It is — every file must be opened (didOpen) and individually pulled/awaited.
The LSP spec (3.17+) defines a bulk workspace/diagnostic pull: a single request that returns diagnostics for the entire project from the server's already-built model, without opening every file. tsserver, pyright/basedpyright, and rust-analyzer all advertise diagnosticProvider.workspaceDiagnostics: true.
We already detect the capability — client.ts populates workspaceDiagnosticsSupport.mode = "pull" and applyDynamicCapabilities honors a dynamic workspace/diagnostic registration — but we never issue the bulk request. The detected capability is only used to choose per-file pull-vs-push; the project-wide path still brute-forces the file walk.
Proposal
Add a workspaceDiagnostic() client method that issues a real workspace/diagnostic request (with previousResultIds for the incremental report form), and have runWorkspaceDiagnostics prefer it when the active server advertises workspaceDiagnostics, falling back to the current file-walk when it does not (or for files no server claims).
Expected win: project-wide diagnostics without N didOpens — the server returns the whole report it has already computed. Also sidesteps the read-your-writes freshness gymnastics (relates to #179; #180 closed) since the server owns the project model.
Notes / caveats
- Servers may return
RelatedFullDocumentDiagnosticReport vs unchanged partials — need result-id caching to exploit the incremental form.
- Some servers stream via
$/progress (partial result) — the client must assemble partials.
- Coverage gap: bulk pull only covers files the server's project model includes; mixed-language roots still need the per-file fallback for the other languages. Keep the walk as the fallback, not a removal.
- Source: LSP 3.18 feature-gap audit. Cheap sibling wins (
typeDefinition, declaration) already shipped; this is the high-value, higher-effort item left.
Acceptance
Summary
runWorkspaceDiagnostics(clients/lsp/index.ts) computes project-wide diagnostics by walking every LSP-supported source file under the root (collectWorkspaceDiagnosticFiles) and issuing a per-filetouchFile(... {diagnostics:"document", clientScope:"all"})acrossWORKSPACE_DIAGNOSTICS_CONCURRENCYworkers. Its own comment calls this "intentionally expensive." It is — every file must be opened (didOpen) and individually pulled/awaited.The LSP spec (3.17+) defines a bulk
workspace/diagnosticpull: a single request that returns diagnostics for the entire project from the server's already-built model, without opening every file. tsserver, pyright/basedpyright, and rust-analyzer all advertisediagnosticProvider.workspaceDiagnostics: true.We already detect the capability —
client.tspopulatesworkspaceDiagnosticsSupport.mode = "pull"andapplyDynamicCapabilitieshonors a dynamicworkspace/diagnosticregistration — but we never issue the bulk request. The detected capability is only used to choose per-file pull-vs-push; the project-wide path still brute-forces the file walk.Proposal
Add a
workspaceDiagnostic()client method that issues a realworkspace/diagnosticrequest (withpreviousResultIdsfor the incremental report form), and haverunWorkspaceDiagnosticsprefer it when the active server advertisesworkspaceDiagnostics, falling back to the current file-walk when it does not (or for files no server claims).Expected win: project-wide diagnostics without N
didOpens — the server returns the whole report it has already computed. Also sidesteps the read-your-writes freshness gymnastics (relates to #179; #180 closed) since the server owns the project model.Notes / caveats
RelatedFullDocumentDiagnosticReportvsunchangedpartials — need result-id caching to exploit the incremental form.$/progress(partial result) — the client must assemble partials.typeDefinition,declaration) already shipped; this is the high-value, higher-effort item left.Acceptance
workspaceDiagnostic()client method (full + incremental report forms, partial-result assembly)runWorkspaceDiagnosticsprefers bulk pull when advertised, falls back to the file walk otherwise