strop_engine/editor/
diagnostics.rs1use strop_lsp::{ResolvedDiag, Severity};
6
7use super::Editor;
8
9pub struct DocumentDiagnostics {
10 pub revision: strop_core::id::BufferRevision,
11 pub items: Vec<ResolvedDiag>,
12}
13
14impl Editor {
15 pub fn diag_counts(&self, idx: strop_core::id::DocumentId) -> (usize, usize) {
17 let mut e = 0;
18 let mut w = 0;
19 for d in self.diags_for(idx).into_iter().flatten() {
20 match d.severity {
21 Severity::Error => e += 1,
22 Severity::Warning => w += 1,
23 _ => {}
24 }
25 }
26 (e, w)
27 }
28
29 pub(super) fn diags_for(&self, idx: strop_core::id::DocumentId) -> Option<&[ResolvedDiag]> {
32 let cached = self.diags.get(&idx)?;
33 (self.docs.get(idx)?.buf.revision() == cached.revision).then_some(cached.items.as_slice())
34 }
35
36 pub fn diag_message_at(
39 &self,
40 idx: strop_core::id::DocumentId,
41 line_1based: usize,
42 ) -> Option<(Severity, &str)> {
43 self.diags_for(idx)?
44 .iter()
45 .filter(|d| d.line.get() + 1 == line_1based)
46 .min_by_key(|d| d.severity)
47 .map(|d| (d.severity, d.message.as_str()))
48 }
49
50 pub fn diag_ranges_at(
54 &self,
55 idx: strop_core::id::DocumentId,
56 line_1based: usize,
57 ) -> Vec<(usize, usize, Severity)> {
58 self.diags_for(idx)
59 .map(|ds| {
60 ds.iter()
61 .filter(|d| d.line.get() + 1 == line_1based)
62 .map(|d| {
63 (
64 d.col.get(),
65 d.end_col.get().max(d.col.get() + 1),
66 d.severity,
67 )
68 })
69 .collect()
70 })
71 .unwrap_or_default()
72 }
73
74 pub fn diag_severity_at(
78 &self,
79 idx: strop_core::id::DocumentId,
80 line_1based: usize,
81 ) -> Option<Severity> {
82 let diags = self.diags_for(idx)?;
83 let mut best: Option<Severity> = None;
84 for d in diags {
85 if d.line.get() + 1 == line_1based {
86 best = Some(best.map_or(d.severity, |b: Severity| b.min(d.severity)));
87 }
88 }
89 best
90 }
91}