diff options
author | Kevin DeLorey <[email protected]> | 2020-02-09 16:25:47 +0000 |
---|---|---|
committer | Kevin DeLorey <[email protected]> | 2020-02-09 16:37:43 +0000 |
commit | a957c473fdb79880c39b73dc9e0c923093cf16ac (patch) | |
tree | f998b548f530ce604651e0e6af314ed2ec74b3b5 /crates/ra_lsp_server/src/diagnostics.rs | |
parent | 22caf982b99c54058e2e9200aeea0e61cada284a (diff) | |
parent | 1b9b13b4b4a75b5531c3f046ce6bf72d681f2732 (diff) |
Merge branch 'master' into kdelorey/complete-trait-impl
Diffstat (limited to 'crates/ra_lsp_server/src/diagnostics.rs')
-rw-r--r-- | crates/ra_lsp_server/src/diagnostics.rs | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/crates/ra_lsp_server/src/diagnostics.rs b/crates/ra_lsp_server/src/diagnostics.rs new file mode 100644 index 000000000..ea08bce24 --- /dev/null +++ b/crates/ra_lsp_server/src/diagnostics.rs | |||
@@ -0,0 +1,85 @@ | |||
1 | //! Book keeping for keeping diagnostics easily in sync with the client. | ||
2 | use lsp_types::{CodeActionOrCommand, Diagnostic, Range}; | ||
3 | use ra_ide::FileId; | ||
4 | use std::{collections::HashMap, sync::Arc}; | ||
5 | |||
6 | pub type CheckFixes = Arc<HashMap<FileId, Vec<Fix>>>; | ||
7 | |||
8 | #[derive(Debug, Default, Clone)] | ||
9 | pub struct DiagnosticCollection { | ||
10 | pub native: HashMap<FileId, Vec<Diagnostic>>, | ||
11 | pub check: HashMap<FileId, Vec<Diagnostic>>, | ||
12 | pub check_fixes: CheckFixes, | ||
13 | } | ||
14 | |||
15 | #[derive(Debug, Clone)] | ||
16 | pub struct Fix { | ||
17 | pub range: Range, | ||
18 | pub action: CodeActionOrCommand, | ||
19 | } | ||
20 | |||
21 | #[derive(Debug)] | ||
22 | pub enum DiagnosticTask { | ||
23 | ClearCheck, | ||
24 | AddCheck(FileId, Diagnostic, Vec<CodeActionOrCommand>), | ||
25 | SetNative(FileId, Vec<Diagnostic>), | ||
26 | } | ||
27 | |||
28 | impl DiagnosticCollection { | ||
29 | pub fn clear_check(&mut self) -> Vec<FileId> { | ||
30 | Arc::make_mut(&mut self.check_fixes).clear(); | ||
31 | self.check.drain().map(|(key, _value)| key).collect() | ||
32 | } | ||
33 | |||
34 | pub fn add_check_diagnostic( | ||
35 | &mut self, | ||
36 | file_id: FileId, | ||
37 | diagnostic: Diagnostic, | ||
38 | fixes: Vec<CodeActionOrCommand>, | ||
39 | ) { | ||
40 | let diagnostics = self.check.entry(file_id).or_default(); | ||
41 | for existing_diagnostic in diagnostics.iter() { | ||
42 | if are_diagnostics_equal(&existing_diagnostic, &diagnostic) { | ||
43 | return; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | let check_fixes = Arc::make_mut(&mut self.check_fixes); | ||
48 | check_fixes | ||
49 | .entry(file_id) | ||
50 | .or_default() | ||
51 | .extend(fixes.into_iter().map(|action| Fix { range: diagnostic.range, action })); | ||
52 | diagnostics.push(diagnostic); | ||
53 | } | ||
54 | |||
55 | pub fn set_native_diagnostics(&mut self, file_id: FileId, diagnostics: Vec<Diagnostic>) { | ||
56 | self.native.insert(file_id, diagnostics); | ||
57 | } | ||
58 | |||
59 | pub fn diagnostics_for(&self, file_id: FileId) -> impl Iterator<Item = &Diagnostic> { | ||
60 | let native = self.native.get(&file_id).into_iter().flatten(); | ||
61 | let check = self.check.get(&file_id).into_iter().flatten(); | ||
62 | native.chain(check) | ||
63 | } | ||
64 | |||
65 | pub fn handle_task(&mut self, task: DiagnosticTask) -> Vec<FileId> { | ||
66 | match task { | ||
67 | DiagnosticTask::ClearCheck => self.clear_check(), | ||
68 | DiagnosticTask::AddCheck(file_id, diagnostic, fixes) => { | ||
69 | self.add_check_diagnostic(file_id, diagnostic, fixes); | ||
70 | vec![file_id] | ||
71 | } | ||
72 | DiagnosticTask::SetNative(file_id, diagnostics) => { | ||
73 | self.set_native_diagnostics(file_id, diagnostics); | ||
74 | vec![file_id] | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | |||
80 | fn are_diagnostics_equal(left: &Diagnostic, right: &Diagnostic) -> bool { | ||
81 | left.source == right.source | ||
82 | && left.severity == right.severity | ||
83 | && left.range == right.range | ||
84 | && left.message == right.message | ||
85 | } | ||