1- import { DiagnosticCollection , Disposable , EventEmitter } from 'vscode'
2- import { LeanDiagnostic , LeanPublishDiagnosticsParams , p2cConverter } from './utils/converters'
1+ import { CancellationToken , DiagnosticCollection , Disposable , EventEmitter } from 'vscode'
32import { DocumentUri } from 'vscode-languageserver-protocol'
3+ import { CoalescingSyncQueue } from './utils/coalescingSyncQueue'
4+ import { LeanDiagnostic , LeanPublishDiagnosticsParams , p2cConverter } from './utils/converters'
45
56export type DiagnosticChangeKind = 'replace' | 'append'
67
@@ -26,15 +27,39 @@ export class DiagnosticChangeEvent {
2627 }
2728}
2829
30+ type SyncQueueEntry = {
31+ accumulatedParams : LeanPublishDiagnosticsParams
32+ pendingKind : DiagnosticChangeKind
33+ pendingBatch : LeanDiagnostic [ ]
34+ }
35+
36+ function combineEntries ( existing : SyncQueueEntry , incoming : SyncQueueEntry ) : SyncQueueEntry {
37+ if ( incoming . pendingKind === 'replace' ) {
38+ return incoming
39+ }
40+ incoming . pendingKind satisfies 'append'
41+ return {
42+ accumulatedParams : incoming . accumulatedParams ,
43+ pendingKind : existing . pendingKind ,
44+ pendingBatch : [ ...existing . pendingBatch , ...incoming . pendingBatch ] ,
45+ }
46+ }
47+
2948export class LeanClientDiagnosticCollection implements Disposable {
3049 readonly vsCodeCollection : DiagnosticCollection
3150 private diags : Map < DocumentUri , LeanPublishDiagnosticsParams > = new Map ( )
3251
3352 private diagnosticsChangedEmitter = new EventEmitter < DiagnosticChangeEvent > ( )
3453 onDidChangeDiagnostics = this . diagnosticsChangedEmitter . event
3554
55+ private syncQueue : CoalescingSyncQueue < SyncQueueEntry >
56+
3657 constructor ( vsCodeCollection : DiagnosticCollection ) {
3758 this . vsCodeCollection = vsCodeCollection
59+ this . syncQueue = new CoalescingSyncQueue (
60+ ( uri : string , entry : SyncQueueEntry , token : CancellationToken ) => this . syncToCollection ( uri , entry , token ) ,
61+ ( existing , incoming ) => combineEntries ( existing , incoming )
62+ )
3863 }
3964
4065 private static determineChangeKind (
@@ -63,20 +88,33 @@ export class LeanClientDiagnosticCollection implements Disposable {
6388 }
6489
6590 const accumulatedParams = { ...params , diagnostics : accumulated }
66-
6791 this . diags . set ( accumulatedParams . uri , accumulatedParams )
68- void this . syncToCollection ( accumulatedParams )
69- this . diagnosticsChangedEmitter . fire ( new DiagnosticChangeEvent ( kind , params , accumulated ) )
92+
93+ const entry : SyncQueueEntry = {
94+ accumulatedParams,
95+ pendingKind : kind ,
96+ pendingBatch : [ ...params . diagnostics ] ,
97+ }
98+
99+ this . syncQueue . enqueue ( accumulatedParams . uri , entry )
70100 }
71101
72- private async syncToCollection ( p : LeanPublishDiagnosticsParams ) : Promise < void > {
73- const nonSilent = p . diagnostics . filter ( d => ! d . isSilent )
74- const uri = p2cConverter . asUri ( p . uri )
75- const vsCodeDiags = await p2cConverter . asDiagnostics ( nonSilent )
76- this . vsCodeCollection . set ( uri , vsCodeDiags )
102+ private async syncToCollection ( _uri : string , entry : SyncQueueEntry , token : CancellationToken ) : Promise < void > {
103+ const nonSilentDiagnostics = entry . accumulatedParams . diagnostics . filter ( d => ! d . isSilent )
104+ const vsUri = p2cConverter . asUri ( entry . accumulatedParams . uri )
105+ const vsDiags = await p2cConverter . asDiagnostics ( nonSilentDiagnostics , token )
106+ if ( token . isCancellationRequested ) {
107+ return
108+ }
109+ this . vsCodeCollection . set ( vsUri , vsDiags )
110+ const collapsedParams = { ...entry . accumulatedParams , diagnostics : entry . pendingBatch }
111+ this . diagnosticsChangedEmitter . fire (
112+ new DiagnosticChangeEvent ( entry . pendingKind , collapsedParams , entry . accumulatedParams . diagnostics ) ,
113+ )
77114 }
78115
79116 dispose ( ) : void {
117+ this . syncQueue . dispose ( )
80118 this . diagnosticsChangedEmitter . dispose ( )
81119 }
82120}
0 commit comments