diff options
| author | Adam Malczewski <[email protected]> | 2026-06-24 16:48:46 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-24 16:48:46 +0900 |
| commit | 8f6114be790016bd954fcfccbe80a88bd0cb758e (patch) | |
| tree | 6be223628e35ce83759314f6fcce2161daa370ba /packages/lsp/src/diagnostics.ts | |
| parent | 4935c268dd53592ec264c1b3eaa9805b3e069df5 (diff) | |
| download | dispatch-8f6114be790016bd954fcfccbe80a88bd0cb758e.tar.gz dispatch-8f6114be790016bd954fcfccbe80a88bd0cb758e.zip | |
feat(lsp+tool-edit-file): multi-server diagnostics + per-edit auto-append
LSP extension:
- Multi-server aggregation: query ALL connected servers matching the
file's extension (not just the first), merge diagnostics tagged by source
- Incremental sync: capture each server's textDocumentSync.change during
initialize; compute prefix/suffix diff ranges for change:2 servers;
full content for change:1 (generic, works for any LSP)
- New diff.ts: pure computeChangeRange + offsetToPosition (O(n), tested)
- Buffer sync: change(filePath, newText) sends didChange with post-edit
in-memory content; openWithText for first open; tracks open doc text
- languageId mapping: extended with .rb/.rbs/.c/.cpp/etc. (was 'unknown')
- waitForDiagnostics: accepts text override + timeoutMs; returns
{ formatted, slow, timedOut }; polls for publishDiagnostics push
- DiagnosticsStore: hasReceivedPush/clearReceived tracking; formatFiltered
with minSeverity (1=Error, 2=Warning) for edit_file integration
- LspService.getDiagnostics: service method for cross-extension use
tool-edit-file:
- After successful edit, calls LSP getDiagnostics with post-edit buffer
- Only appends diagnostics with severity ≤ 2 (errors+warnings, no noise)
- Appends slow warning (>10s): 'LSP is taking unusually long...'
- 60s timeout; graceful degradation when no LSP available
- Optional dep on @dispatch/lsp (getService pattern, not manifest depOn)
1468 vitest pass (was 1453, +15 new diff tests).
Diffstat (limited to 'packages/lsp/src/diagnostics.ts')
| -rw-r--r-- | packages/lsp/src/diagnostics.ts | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/packages/lsp/src/diagnostics.ts b/packages/lsp/src/diagnostics.ts index ea18811..bc7ac0a 100644 --- a/packages/lsp/src/diagnostics.ts +++ b/packages/lsp/src/diagnostics.ts @@ -34,9 +34,11 @@ const severityNames: Record<number, string> = { export class DiagnosticsStore { private pushDiagnostics = new Map<string, readonly Diagnostic[]>(); private pullDiagnostics = new Map<string, readonly Diagnostic[]>(); + private pushReceived = new Set<string>(); setPushDiagnostics(params: PublishDiagnosticsParams): void { this.pushDiagnostics.set(params.uri, params.diagnostics); + this.pushReceived.add(params.uri); } setPullDiagnostics(uri: string, report: DocumentDiagnosticReport): void { @@ -45,14 +47,32 @@ export class DiagnosticsStore { } } + /** True if the server has pushed at least one publishDiagnostics for this URI. */ + hasReceivedPush(uri: string): boolean { + return this.pushReceived.has(uri); + } + + /** Clear the "received" flag so the next waitForDiagnostics poll detects fresh pushes. */ + clearReceived(uri: string): void { + this.pushReceived.delete(uri); + } + getMerged(uri: string): readonly Diagnostic[] { const push = this.pushDiagnostics.get(uri) ?? []; const pull = this.pullDiagnostics.get(uri) ?? []; return dedupeDiagnostics([...push, ...pull]); } - format(uri: string): string { - const diags = this.getMerged(uri); + /** + * Format diagnostics for a URI, optionally filtering by minimum severity. + * `minSeverity` includes only diagnostics with severity ≤ the given value + * (1=Error, 2=Warning, 3=Info, 4=Hint). Omit to include all. + */ + formatFiltered(uri: string, minSeverity?: number): string { + let diags = this.getMerged(uri); + if (minSeverity !== undefined) { + diags = diags.filter((d) => (d.severity ?? 0) <= minSeverity); + } if (diags.length === 0) return ""; const lines: string[] = []; for (const d of diags) { @@ -65,6 +85,10 @@ export class DiagnosticsStore { } return lines.join("\n"); } + + format(uri: string): string { + return this.formatFiltered(uri); + } } function diagnosticKey(d: Diagnostic): string { |
