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