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