1use crate::Diagnostic;
2use std::{
3 cmp::{Ordering, Reverse},
4 iter,
5 ops::Range,
6};
7use sum_tree::{self, Bias, SumTree};
8use text::{Anchor, FromAnchor, PointUtf16, ToOffset};
9
10#[derive(Clone, Default)]
11pub struct DiagnosticSet {
12 diagnostics: SumTree<DiagnosticEntry<Anchor>>,
13}
14
15#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct DiagnosticEntry<T> {
17 pub range: Range<T>,
18 pub diagnostic: Diagnostic,
19}
20
21#[derive(Clone, Debug)]
22pub struct Summary {
23 start: Anchor,
24 end: Anchor,
25 min_start: Anchor,
26 max_end: Anchor,
27 count: usize,
28}
29
30impl DiagnosticSet {
31 pub fn from_sorted_entries<I>(iter: I, buffer: &text::Snapshot) -> Self
32 where
33 I: IntoIterator<Item = DiagnosticEntry<Anchor>>,
34 {
35 Self {
36 diagnostics: SumTree::from_iter(iter, buffer),
37 }
38 }
39
40 pub fn reset<I>(&mut self, iter: I, buffer: &text::Snapshot)
41 where
42 I: IntoIterator<Item = DiagnosticEntry<PointUtf16>>,
43 {
44 let mut entries = iter.into_iter().collect::<Vec<_>>();
45 entries.sort_unstable_by_key(|entry| (entry.range.start, Reverse(entry.range.end)));
46 self.diagnostics = SumTree::from_iter(
47 entries.into_iter().map(|entry| DiagnosticEntry {
48 range: buffer.anchor_before(entry.range.start)
49 ..buffer.anchor_after(entry.range.end),
50 diagnostic: entry.diagnostic,
51 }),
52 buffer,
53 );
54 }
55
56 pub fn iter(&self) -> impl Iterator<Item = &DiagnosticEntry<Anchor>> {
57 self.diagnostics.iter()
58 }
59
60 pub fn range<'a, T, O>(
61 &'a self,
62 range: Range<T>,
63 buffer: &'a text::Snapshot,
64 inclusive: bool,
65 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
66 where
67 T: 'a + ToOffset,
68 O: FromAnchor,
69 {
70 let end_bias = if inclusive { Bias::Right } else { Bias::Left };
71 let range = buffer.anchor_before(range.start)..buffer.anchor_at(range.end, end_bias);
72 let mut cursor = self.diagnostics.filter::<_, ()>(
73 {
74 move |summary: &Summary| {
75 let start_cmp = range.start.cmp(&summary.max_end, buffer).unwrap();
76 let end_cmp = range.end.cmp(&summary.min_start, buffer).unwrap();
77 if inclusive {
78 start_cmp <= Ordering::Equal && end_cmp >= Ordering::Equal
79 } else {
80 start_cmp == Ordering::Less && end_cmp == Ordering::Greater
81 }
82 }
83 },
84 buffer,
85 );
86
87 iter::from_fn({
88 move || {
89 if let Some(diagnostic) = cursor.item() {
90 cursor.next(buffer);
91 Some(diagnostic.resolve(buffer))
92 } else {
93 None
94 }
95 }
96 })
97 }
98
99 pub fn group<'a, O: FromAnchor>(
100 &'a self,
101 group_id: usize,
102 buffer: &'a text::Snapshot,
103 ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>> {
104 self.iter()
105 .filter(move |entry| entry.diagnostic.group_id == group_id)
106 .map(|entry| entry.resolve(buffer))
107 }
108}
109
110impl sum_tree::Item for DiagnosticEntry<Anchor> {
111 type Summary = Summary;
112
113 fn summary(&self) -> Self::Summary {
114 Summary {
115 start: self.range.start.clone(),
116 end: self.range.end.clone(),
117 min_start: self.range.start.clone(),
118 max_end: self.range.end.clone(),
119 count: 1,
120 }
121 }
122}
123
124impl DiagnosticEntry<Anchor> {
125 pub fn resolve<O: FromAnchor>(&self, buffer: &text::Snapshot) -> DiagnosticEntry<O> {
126 DiagnosticEntry {
127 range: O::from_anchor(&self.range.start, buffer)
128 ..O::from_anchor(&self.range.end, buffer),
129 diagnostic: self.diagnostic.clone(),
130 }
131 }
132}
133
134impl Default for Summary {
135 fn default() -> Self {
136 Self {
137 start: Anchor::min(),
138 end: Anchor::max(),
139 min_start: Anchor::max(),
140 max_end: Anchor::min(),
141 count: 0,
142 }
143 }
144}
145
146impl sum_tree::Summary for Summary {
147 type Context = text::Snapshot;
148
149 fn add_summary(&mut self, other: &Self, buffer: &Self::Context) {
150 if other
151 .min_start
152 .cmp(&self.min_start, buffer)
153 .unwrap()
154 .is_lt()
155 {
156 self.min_start = other.min_start.clone();
157 }
158 if other.max_end.cmp(&self.max_end, buffer).unwrap().is_gt() {
159 self.max_end = other.max_end.clone();
160 }
161 self.start = other.start.clone();
162 self.end = other.end.clone();
163 self.count += other.count;
164 }
165}