1 module served.linters.diagnosticmanager; 2 3 import std.array : array; 4 import std.algorithm : map, sort; 5 6 import served.utils.memory; 7 import served.types; 8 9 enum NumDiagnosticProviders = 3; 10 alias DiagnosticCollection = PublishDiagnosticsParams[]; 11 DiagnosticCollection[NumDiagnosticProviders] diagnostics; 12 13 DiagnosticCollection combinedDiagnostics; 14 DocumentUri[] publishedUris; 15 16 void combineDiagnostics() 17 { 18 combinedDiagnostics.length = 0; 19 foreach (provider; diagnostics) 20 { 21 foreach (errors; provider) 22 { 23 size_t index = combinedDiagnostics.length; 24 foreach (i, existing; combinedDiagnostics) 25 { 26 if (existing.uri == errors.uri) 27 { 28 index = i; 29 break; 30 } 31 } 32 if (index == combinedDiagnostics.length) 33 combinedDiagnostics ~= PublishDiagnosticsParams(errors.uri); 34 combinedDiagnostics[index].diagnostics ~= errors.diagnostics; 35 } 36 } 37 } 38 39 /// Returns a reference to existing diagnostics for a given url in a given slot or creates a new array for them and returns the reference for it. 40 /// Params: 41 /// slot = the diagnostic provider slot to edit 42 /// uri = the document uri to attach the diagnostics array for 43 ref auto createDiagnosticsFor(int slot)(string uri) 44 { 45 static assert(slot < NumDiagnosticProviders); 46 foreach (ref existing; diagnostics[slot]) 47 if (existing.uri == uri) 48 return existing.diagnostics; 49 50 return pushRef(diagnostics[slot], PublishDiagnosticsParams(uri, null)).diagnostics; 51 } 52 53 private ref T pushRef(T)(ref T[] arr, T value) 54 { 55 auto len = arr.length++; 56 return arr[len] = value; 57 } 58 59 void updateDiagnostics(string uriHint = "") 60 { 61 combineDiagnostics(); 62 foreach (diagnostics; combinedDiagnostics) 63 { 64 if (!uriHint.length || diagnostics.uri == uriHint) 65 { 66 // TODO: related information 67 RequestMessageRaw request; 68 request.method = "textDocument/publishDiagnostics"; 69 request.paramsJson = diagnostics.serializeJson; 70 rpc.send(request); 71 } 72 } 73 74 // clear old diagnostics 75 auto diags = combinedDiagnostics.map!"a.uri".array; 76 auto sorted = diags.sort!"a<b"; 77 foreach (submitted; publishedUris) 78 { 79 if (!sorted.contains(submitted)) 80 { 81 RequestMessageRaw request; 82 request.method = "textDocument/publishDiagnostics"; 83 request.paramsJson = PublishDiagnosticsParams(submitted, null).serializeJson; 84 rpc.send(request); 85 } 86 } 87 destroyUnset(publishedUris); 88 publishedUris = diags; 89 }