1use serde::de::{Deserialize, Deserializer};
18use serde::ser::{Serialize, SerializeSeq, Serializer};
19use serde_json::{self, Value};
20
21use std::collections::HashMap;
22
23use crate::plugins::PluginId;
24use crate::view::View;
25use crate::xi_rope::spans::Spans;
26use crate::xi_rope::{Interval, Rope};
27
28#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
29pub enum AnnotationType {
30 Selection,
31 Find,
32 Other(String),
33}
34
35impl AnnotationType {
36 fn as_str(&self) -> &str {
37 match self {
38 AnnotationType::Find => "find",
39 AnnotationType::Selection => "selection",
40 AnnotationType::Other(ref s) => s,
41 }
42 }
43}
44
45#[derive(Debug, Default, Clone, Copy, PartialEq)]
48pub struct AnnotationRange {
49 pub start_line: usize,
50 pub start_col: usize,
51 pub end_line: usize,
52 pub end_col: usize,
53}
54
55impl Serialize for AnnotationRange {
56 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
57 where
58 S: Serializer,
59 {
60 let mut seq = serializer.serialize_seq(Some(4))?;
61 seq.serialize_element(&self.start_line)?;
62 seq.serialize_element(&self.start_col)?;
63 seq.serialize_element(&self.end_line)?;
64 seq.serialize_element(&self.end_col)?;
65 seq.end()
66 }
67}
68
69impl<'de> Deserialize<'de> for AnnotationRange {
70 fn deserialize<D>(deserializer: D) -> Result<AnnotationRange, D::Error>
71 where
72 D: Deserializer<'de>,
73 {
74 let mut range = AnnotationRange { ..Default::default() };
75 let seq = <[usize; 4]>::deserialize(deserializer)?;
76
77 range.start_line = seq[0];
78 range.start_col = seq[1];
79 range.end_line = seq[2];
80 range.end_col = seq[3];
81
82 Ok(range)
83 }
84}
85
86#[derive(Debug, Clone)]
88pub struct Annotations {
89 pub items: Spans<Value>,
90 pub annotation_type: AnnotationType,
91}
92
93impl Annotations {
94 pub fn update(&mut self, interval: Interval, items: Spans<Value>) {
96 self.items.edit(interval, items);
97 }
98
99 pub fn invalidate(&mut self, interval: Interval) {
101 self.items.delete_intersecting(interval);
102 }
103}
104
105#[derive(Serialize, Deserialize, Debug, Clone)]
107pub struct AnnotationSlice {
108 annotation_type: AnnotationType,
109 ranges: Vec<AnnotationRange>,
111 payloads: Option<Vec<Value>>,
113}
114
115impl AnnotationSlice {
116 pub fn new(
117 annotation_type: AnnotationType,
118 ranges: Vec<AnnotationRange>,
119 payloads: Option<Vec<Value>>,
120 ) -> Self {
121 AnnotationSlice { annotation_type, ranges, payloads }
122 }
123
124 pub fn to_json(&self) -> Value {
126 json!({
127 "type": self.annotation_type.as_str(),
128 "ranges": self.ranges,
129 "payloads": self.payloads,
130 "n": self.ranges.len()
131 })
132 }
133}
134
135pub trait ToAnnotation {
138 fn get_annotations(&self, interval: Interval, view: &View, text: &Rope) -> AnnotationSlice;
140}
141
142pub struct AnnotationStore {
144 store: HashMap<PluginId, Vec<Annotations>>,
145}
146
147impl AnnotationStore {
148 pub fn new() -> Self {
149 AnnotationStore { store: HashMap::new() }
150 }
151
152 pub fn invalidate(&mut self, interval: Interval) {
154 self.store.values_mut().map(|v| v.iter_mut()).flatten().for_each(|a| a.invalidate(interval))
155 }
156
157 pub fn update(&mut self, source: PluginId, interval: Interval, item: Annotations) {
159 if !self.store.contains_key(&source) {
160 self.store.insert(source, vec![item]);
161 return;
162 }
163
164 let entry = self.store.get_mut(&source).unwrap();
165 if let Some(annotation) =
166 entry.iter_mut().find(|a| a.annotation_type == item.annotation_type)
167 {
168 annotation.update(interval, item.items);
169 } else {
170 entry.push(item);
171 }
172 }
173
174 pub fn iter_range<'c>(
177 &'c self,
178 view: &'c View,
179 text: &'c Rope,
180 interval: Interval,
181 ) -> impl Iterator<Item = AnnotationSlice> + 'c {
182 self.store.iter().flat_map(move |(_plugin, value)| {
183 value.iter().map(move |annotation| {
184 let payloads = annotation
185 .items
186 .subseq(interval)
187 .iter()
188 .map(|(_i, p)| p.clone())
189 .collect::<Vec<Value>>();
190
191 let ranges = annotation
192 .items
193 .subseq(interval)
194 .iter()
195 .map(|(i, _p)| {
196 let (start_line, start_col) = view.offset_to_line_col(text, i.start());
197 let (end_line, end_col) = view.offset_to_line_col(text, i.end());
198
199 AnnotationRange { start_line, start_col, end_line, end_col }
200 })
201 .collect::<Vec<AnnotationRange>>();
202
203 AnnotationSlice {
204 annotation_type: annotation.annotation_type.clone(),
205 ranges,
206 payloads: Some(payloads),
207 }
208 })
209 })
210 }
211
212 pub fn clear(&mut self, plugin: PluginId) {
214 self.store.remove(&plugin);
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221 use crate::plugins::PluginPid;
222 use crate::xi_rope::spans::SpansBuilder;
223
224 #[test]
225 fn test_annotation_range_serialization() {
226 let range = AnnotationRange { start_line: 1, start_col: 3, end_line: 4, end_col: 1 };
227
228 assert_eq!(json!(range).to_string(), "[1,3,4,1]")
229 }
230
231 #[test]
232 fn test_annotation_range_deserialization() {
233 let range: AnnotationRange = serde_json::from_str("[1,3,4,1]").unwrap();
234 assert_eq!(range, AnnotationRange { start_line: 1, start_col: 3, end_line: 4, end_col: 1 })
235 }
236
237 #[test]
238 fn test_annotation_slice_json() {
239 let range = AnnotationRange { start_line: 1, start_col: 3, end_line: 4, end_col: 1 };
240
241 let slice = AnnotationSlice {
242 annotation_type: AnnotationType::Find,
243 ranges: vec![range],
244 payloads: None,
245 };
246
247 assert_eq!(
248 slice.to_json().to_string(),
249 "{\"n\":1,\"payloads\":null,\"ranges\":[[1,3,4,1]],\"type\":\"find\"}"
250 )
251 }
252
253 #[test]
254 fn test_annotation_store_update() {
255 let mut store = AnnotationStore::new();
256
257 let mut sb = SpansBuilder::new(10);
258 sb.add_span(Interval::new(1, 5), json!(null));
259
260 assert_eq!(store.store.len(), 0);
261
262 store.update(
263 PluginPid(1),
264 Interval::new(1, 5),
265 Annotations { annotation_type: AnnotationType::Find, items: sb.build() },
266 );
267
268 assert_eq!(store.store.len(), 1);
269
270 sb = SpansBuilder::new(10);
271 sb.add_span(Interval::new(6, 8), json!(null));
272
273 store.update(
274 PluginPid(2),
275 Interval::new(6, 8),
276 Annotations { annotation_type: AnnotationType::Find, items: sb.build() },
277 );
278
279 assert_eq!(store.store.len(), 2);
280 }
281
282 #[test]
283 fn test_annotation_store_clear() {
284 let mut store = AnnotationStore::new();
285
286 let mut sb = SpansBuilder::new(10);
287 sb.add_span(Interval::new(1, 5), json!(null));
288
289 assert_eq!(store.store.len(), 0);
290
291 store.update(
292 PluginPid(1),
293 Interval::new(1, 5),
294 Annotations { annotation_type: AnnotationType::Find, items: sb.build() },
295 );
296
297 assert_eq!(store.store.len(), 1);
298
299 sb = SpansBuilder::new(10);
300 sb.add_span(Interval::new(6, 8), json!(null));
301
302 store.update(
303 PluginPid(2),
304 Interval::new(6, 8),
305 Annotations { annotation_type: AnnotationType::Find, items: sb.build() },
306 );
307
308 assert_eq!(store.store.len(), 2);
309
310 store.clear(PluginPid(1));
311
312 assert_eq!(store.store.len(), 1);
313
314 store.clear(PluginPid(1));
315
316 assert_eq!(store.store.len(), 1);
317 }
318}