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