inlay_cache.rs

  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}