1use std::cmp;
2
3use crate::{Anchor, ExcerptId};
4use clock::{Global, Local};
5use project::InlayHint;
6use util::post_inc;
7
8use collections::{BTreeMap, HashMap};
9
10#[derive(Clone, Debug, Default)]
11pub struct InlayCache {
12 inlays_per_buffer: HashMap<u64, BufferInlays>,
13 next_inlay_id: usize,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct AnchorKey {
18 offset: usize,
19 version: Local,
20}
21
22#[derive(Clone, Debug)]
23pub struct OrderedByAnchorOffset<T>(pub BTreeMap<AnchorKey, (Anchor, T)>);
24
25impl<T> OrderedByAnchorOffset<T> {
26 pub fn add(&mut self, anchor: Anchor, t: T) {
27 let key = AnchorKey {
28 offset: anchor.text_anchor.offset,
29 version: anchor.text_anchor.timestamp,
30 };
31 self.0.insert(key, (anchor, t));
32 }
33
34 fn into_ordered_elements(self) -> impl Iterator<Item = (Anchor, T)> {
35 self.0.into_values()
36 }
37}
38
39impl<T> Default for OrderedByAnchorOffset<T> {
40 fn default() -> Self {
41 Self(BTreeMap::default())
42 }
43}
44
45#[derive(Clone, Debug, Default)]
46struct BufferInlays {
47 buffer_version: Global,
48 inlays_per_excerpts: HashMap<ExcerptId, OrderedByAnchorOffset<(InlayId, InlayHint)>>,
49}
50
51#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
52pub struct InlayId(pub usize);
53
54#[derive(Debug)]
55pub struct InlaysUpdate {
56 pub to_remove: Vec<InlayId>,
57 pub to_insert: Vec<(InlayId, Anchor, InlayHint)>,
58}
59
60impl InlayCache {
61 pub fn inlays_up_to_date(
62 &self,
63 buffer_id: u64,
64 buffer_version: &Global,
65 excerpt_id: ExcerptId,
66 ) -> bool {
67 let Some(buffer_inlays) = self.inlays_per_buffer.get(&buffer_id) else { return false };
68 let buffer_up_to_date = buffer_version == &buffer_inlays.buffer_version
69 || buffer_inlays.buffer_version.changed_since(buffer_version);
70 buffer_up_to_date && buffer_inlays.inlays_per_excerpts.contains_key(&excerpt_id)
71 }
72
73 pub fn update_inlays(
74 &mut self,
75 inlay_updates: HashMap<
76 u64,
77 (
78 Global,
79 HashMap<ExcerptId, Option<OrderedByAnchorOffset<InlayHint>>>,
80 ),
81 >,
82 ) -> InlaysUpdate {
83 let mut old_inlays = self.inlays_per_buffer.clone();
84 let mut to_remove = Vec::new();
85 let mut to_insert = Vec::new();
86
87 for (buffer_id, (buffer_version, new_buffer_inlays)) in inlay_updates {
88 match old_inlays.remove(&buffer_id) {
89 Some(mut old_buffer_inlays) => {
90 for (excerpt_id, new_excerpt_inlays) in new_buffer_inlays {
91 if self.inlays_up_to_date(buffer_id, &buffer_version, excerpt_id) {
92 continue;
93 }
94
95 let self_inlays_per_buffer = self
96 .inlays_per_buffer
97 .get_mut(&buffer_id)
98 .expect("element expected: `old_inlays.remove` returned `Some`");
99 let mut new_excerpt_inlays = match new_excerpt_inlays {
100 Some(new_inlays) => {
101 new_inlays.into_ordered_elements().fuse().peekable()
102 }
103 None => continue,
104 };
105 if old_buffer_inlays
106 .inlays_per_excerpts
107 .remove(&excerpt_id)
108 .is_some()
109 {
110 let self_excerpt_inlays = self_inlays_per_buffer
111 .inlays_per_excerpts
112 .get_mut(&excerpt_id)
113 .expect("element expected: `old_excerpt_inlays` is `Some`");
114 let mut hints_to_add = Vec::<(Anchor, (InlayId, InlayHint))>::new();
115 self_excerpt_inlays.0.retain(
116 |_, (old_anchor, (old_inlay_id, old_inlay))| {
117 let mut retain = false;
118
119 while let Some(new_offset) = new_excerpt_inlays
120 .peek()
121 .map(|(new_anchor, _)| new_anchor.text_anchor.offset)
122 {
123 let old_offset = old_anchor.text_anchor.offset;
124 match new_offset.cmp(&old_offset) {
125 cmp::Ordering::Less => {
126 let (new_anchor, new_inlay) =
127 new_excerpt_inlays.next().expect(
128 "element expected: `peek` returned `Some`",
129 );
130 hints_to_add.push((
131 new_anchor,
132 (
133 InlayId(post_inc(&mut self.next_inlay_id)),
134 new_inlay,
135 ),
136 ));
137 }
138 cmp::Ordering::Equal => {
139 let (new_anchor, new_inlay) =
140 new_excerpt_inlays.next().expect(
141 "element expected: `peek` returned `Some`",
142 );
143 if &new_inlay == old_inlay {
144 retain = true;
145 } else {
146 hints_to_add.push((
147 new_anchor,
148 (
149 InlayId(post_inc(
150 &mut self.next_inlay_id,
151 )),
152 new_inlay,
153 ),
154 ));
155 }
156 }
157 cmp::Ordering::Greater => break,
158 }
159 }
160
161 if !retain {
162 to_remove.push(*old_inlay_id);
163 }
164 retain
165 },
166 );
167
168 for (new_anchor, (id, new_inlay)) in hints_to_add {
169 self_excerpt_inlays.add(new_anchor, (id, new_inlay.clone()));
170 to_insert.push((id, new_anchor, new_inlay));
171 }
172 }
173
174 for (new_anchor, new_inlay) in new_excerpt_inlays {
175 let id = InlayId(post_inc(&mut self.next_inlay_id));
176 self_inlays_per_buffer
177 .inlays_per_excerpts
178 .entry(excerpt_id)
179 .or_default()
180 .add(new_anchor, (id, new_inlay.clone()));
181 to_insert.push((id, new_anchor, new_inlay));
182 }
183 }
184 }
185 None => {
186 let mut inlays_per_excerpts: HashMap<
187 ExcerptId,
188 OrderedByAnchorOffset<(InlayId, InlayHint)>,
189 > = HashMap::default();
190 for (new_excerpt_id, new_ordered_inlays) in new_buffer_inlays {
191 if let Some(new_ordered_inlays) = new_ordered_inlays {
192 for (new_anchor, new_inlay) in
193 new_ordered_inlays.into_ordered_elements()
194 {
195 let id = InlayId(post_inc(&mut self.next_inlay_id));
196 inlays_per_excerpts
197 .entry(new_excerpt_id)
198 .or_default()
199 .add(new_anchor, (id, new_inlay.clone()));
200 to_insert.push((id, new_anchor, new_inlay));
201 }
202 }
203 }
204 self.inlays_per_buffer.insert(
205 buffer_id,
206 BufferInlays {
207 buffer_version,
208 inlays_per_excerpts,
209 },
210 );
211 }
212 }
213 }
214
215 for (_, old_buffer_inlays) in old_inlays {
216 for (_, old_excerpt_inlays) in old_buffer_inlays.inlays_per_excerpts {
217 for (_, (id_to_remove, _)) in old_excerpt_inlays.into_ordered_elements() {
218 to_remove.push(id_to_remove);
219 }
220 }
221 }
222
223 InlaysUpdate {
224 to_remove,
225 to_insert,
226 }
227 }
228}