Generate InlayIds in InlayMap, prepare InlayCache for refactoring

Kirill Bulatov created

Change summary

crates/editor/src/display_map.rs           |   9 
crates/editor/src/display_map/fold_map.rs  |   3 
crates/editor/src/display_map/inlay_map.rs | 116 +--
crates/editor/src/display_map/tab_map.rs   |   2 
crates/editor/src/display_map/wrap_map.rs  |   4 
crates/editor/src/editor.rs                |  32 
crates/editor/src/inlay_cache.rs           | 690 +++++++++++------------
7 files changed, 391 insertions(+), 465 deletions(-)

Detailed changes

crates/editor/src/display_map.rs 🔗

@@ -246,11 +246,11 @@ impl DisplayMap {
     pub fn splice_inlays<T: Into<Rope>>(
         &mut self,
         to_remove: Vec<InlayId>,
-        to_insert: Vec<(InlayId, InlayProperties<T>)>,
+        to_insert: Vec<InlayProperties<T>>,
         cx: &mut ModelContext<Self>,
-    ) {
+    ) -> Vec<InlayId> {
         if to_remove.is_empty() && to_insert.is_empty() {
-            return;
+            return Vec::new();
         }
 
         let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
@@ -264,13 +264,14 @@ impl DisplayMap {
             .update(cx, |map, cx| map.sync(snapshot, edits, cx));
         self.block_map.read(snapshot, edits);
 
-        let (snapshot, edits) = self.inlay_map.splice(to_remove, to_insert);
+        let (snapshot, edits, new_inlay_ids) = self.inlay_map.splice(to_remove, to_insert);
         let (snapshot, edits) = self.fold_map.read(snapshot, edits);
         let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
         let (snapshot, edits) = self
             .wrap_map
             .update(cx, |map, cx| map.sync(snapshot, edits, cx));
         self.block_map.read(snapshot, edits);
+        new_inlay_ids
     }
 
     fn tab_size(buffer: &ModelHandle<MultiBuffer>, cx: &mut ModelContext<Self>) -> NonZeroU32 {

crates/editor/src/display_map/fold_map.rs 🔗

@@ -1475,7 +1475,6 @@ mod tests {
             Arc::new((HighlightStyle::default(), highlight_ranges)),
         );
 
-        let mut next_inlay_id = 0;
         for _ in 0..operations {
             log::info!("text: {:?}", buffer_snapshot.text());
             let mut buffer_edits = Vec::new();
@@ -1485,7 +1484,7 @@ mod tests {
                     snapshot_edits.extend(map.randomly_mutate(&mut rng));
                 }
                 40..=59 => {
-                    let (_, edits) = inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
+                    let (_, edits) = inlay_map.randomly_mutate(&mut rng);
                     inlay_edits = edits;
                 }
                 _ => buffer.update(cx, |buffer, cx| {

crates/editor/src/display_map/inlay_map.rs 🔗

@@ -13,11 +13,13 @@ use std::{
 };
 use sum_tree::{Bias, Cursor, SumTree};
 use text::Patch;
+use util::post_inc;
 
 pub struct InlayMap {
     snapshot: Mutex<InlaySnapshot>,
     inlays_by_id: HashMap<InlayId, Inlay>,
     inlays: Vec<Inlay>,
+    next_inlay_id: usize,
 }
 
 #[derive(Clone)]
@@ -297,8 +299,9 @@ impl InlayMap {
         (
             Self {
                 snapshot: Mutex::new(snapshot.clone()),
-                inlays_by_id: Default::default(),
-                inlays: Default::default(),
+                inlays_by_id: HashMap::default(),
+                inlays: Vec::new(),
+                next_inlay_id: 0,
             },
             snapshot,
         )
@@ -443,8 +446,8 @@ impl InlayMap {
     pub fn splice<T: Into<Rope>>(
         &mut self,
         to_remove: Vec<InlayId>,
-        to_insert: Vec<(InlayId, InlayProperties<T>)>,
-    ) -> (InlaySnapshot, Vec<InlayEdit>) {
+        to_insert: Vec<InlayProperties<T>>,
+    ) -> (InlaySnapshot, Vec<InlayEdit>, Vec<InlayId>) {
         let snapshot = self.snapshot.lock();
         let mut edits = BTreeSet::new();
 
@@ -456,12 +459,14 @@ impl InlayMap {
             }
         }
 
-        for (id, properties) in to_insert {
+        let mut new_inlay_ids = Vec::with_capacity(to_insert.len());
+        for properties in to_insert {
             let inlay = Inlay {
-                id,
+                id: InlayId(post_inc(&mut self.next_inlay_id)),
                 position: properties.position,
                 text: properties.text.into(),
             };
+            new_inlay_ids.push(inlay.id);
             self.inlays_by_id.insert(inlay.id, inlay.clone());
             match self
                 .inlays
@@ -485,17 +490,16 @@ impl InlayMap {
             .collect();
         let buffer_snapshot = snapshot.buffer.clone();
         drop(snapshot);
-        self.sync(buffer_snapshot, buffer_edits)
+        let (snapshot, edits) = self.sync(buffer_snapshot, buffer_edits);
+        (snapshot, edits, new_inlay_ids)
     }
 
     #[cfg(test)]
     pub(crate) fn randomly_mutate(
         &mut self,
-        next_inlay_id: &mut usize,
         rng: &mut rand::rngs::StdRng,
     ) -> (InlaySnapshot, Vec<InlayEdit>) {
         use rand::prelude::*;
-        use util::post_inc;
 
         let mut to_remove = Vec::new();
         let mut to_insert = Vec::new();
@@ -515,13 +519,10 @@ impl InlayMap {
                     bias,
                     text
                 );
-                to_insert.push((
-                    InlayId(post_inc(next_inlay_id)),
-                    InlayProperties {
-                        position: snapshot.buffer.anchor_at(position, bias),
-                        text,
-                    },
-                ));
+                to_insert.push(InlayProperties {
+                    position: snapshot.buffer.anchor_at(position, bias),
+                    text,
+                });
             } else {
                 to_remove.push(*self.inlays_by_id.keys().choose(rng).unwrap());
             }
@@ -529,7 +530,8 @@ impl InlayMap {
         log::info!("removing inlays: {:?}", to_remove);
 
         drop(snapshot);
-        self.splice(to_remove, to_insert)
+        let (snapshot, edits, _) = self.splice(to_remove, to_insert);
+        (snapshot, edits)
     }
 }
 
@@ -840,7 +842,6 @@ mod tests {
     use settings::SettingsStore;
     use std::env;
     use text::Patch;
-    use util::post_inc;
 
     #[gpui::test]
     fn test_basic_inlays(cx: &mut AppContext) {
@@ -848,17 +849,13 @@ mod tests {
         let buffer_edits = buffer.update(cx, |buffer, _| buffer.subscribe());
         let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
         assert_eq!(inlay_snapshot.text(), "abcdefghi");
-        let mut next_inlay_id = 0;
 
-        let (inlay_snapshot, _) = inlay_map.splice(
+        let (inlay_snapshot, _, _) = inlay_map.splice(
             Vec::new(),
-            vec![(
-                InlayId(post_inc(&mut next_inlay_id)),
-                InlayProperties {
-                    position: buffer.read(cx).snapshot(cx).anchor_after(3),
-                    text: "|123|",
-                },
-            )],
+            vec![InlayProperties {
+                position: buffer.read(cx).snapshot(cx).anchor_after(3),
+                text: "|123|",
+            }],
         );
         assert_eq!(inlay_snapshot.text(), "abc|123|defghi");
         assert_eq!(
@@ -928,23 +925,17 @@ mod tests {
         );
         assert_eq!(inlay_snapshot.text(), "abxyDzefghi");
 
-        let (inlay_snapshot, _) = inlay_map.splice(
+        let (inlay_snapshot, _, _) = inlay_map.splice(
             Vec::new(),
             vec![
-                (
-                    InlayId(post_inc(&mut next_inlay_id)),
-                    InlayProperties {
-                        position: buffer.read(cx).snapshot(cx).anchor_before(3),
-                        text: "|123|",
-                    },
-                ),
-                (
-                    InlayId(post_inc(&mut next_inlay_id)),
-                    InlayProperties {
-                        position: buffer.read(cx).snapshot(cx).anchor_after(3),
-                        text: "|456|",
-                    },
-                ),
+                InlayProperties {
+                    position: buffer.read(cx).snapshot(cx).anchor_before(3),
+                    text: "|123|",
+                },
+                InlayProperties {
+                    position: buffer.read(cx).snapshot(cx).anchor_after(3),
+                    text: "|456|",
+                },
             ],
         );
         assert_eq!(inlay_snapshot.text(), "abx|123||456|yDzefghi");
@@ -958,7 +949,7 @@ mod tests {
         assert_eq!(inlay_snapshot.text(), "abx|123|JKL|456|yDzefghi");
 
         // The inlays can be manually removed.
-        let (inlay_snapshot, _) = inlay_map
+        let (inlay_snapshot, _, _) = inlay_map
             .splice::<String>(inlay_map.inlays_by_id.keys().copied().collect(), Vec::new());
         assert_eq!(inlay_snapshot.text(), "abxJKLyDzefghi");
     }
@@ -969,30 +960,21 @@ mod tests {
         let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
         assert_eq!(inlay_snapshot.text(), "abc\ndef\nghi");
 
-        let (inlay_snapshot, _) = inlay_map.splice(
+        let (inlay_snapshot, _, _) = inlay_map.splice(
             Vec::new(),
             vec![
-                (
-                    InlayId(0),
-                    InlayProperties {
-                        position: buffer.read(cx).snapshot(cx).anchor_before(0),
-                        text: "|123|\n",
-                    },
-                ),
-                (
-                    InlayId(1),
-                    InlayProperties {
-                        position: buffer.read(cx).snapshot(cx).anchor_before(4),
-                        text: "|456|",
-                    },
-                ),
-                (
-                    InlayId(1),
-                    InlayProperties {
-                        position: buffer.read(cx).snapshot(cx).anchor_before(7),
-                        text: "\n|567|\n",
-                    },
-                ),
+                InlayProperties {
+                    position: buffer.read(cx).snapshot(cx).anchor_before(0),
+                    text: "|123|\n",
+                },
+                InlayProperties {
+                    position: buffer.read(cx).snapshot(cx).anchor_before(4),
+                    text: "|456|",
+                },
+                InlayProperties {
+                    position: buffer.read(cx).snapshot(cx).anchor_before(7),
+                    text: "\n|567|\n",
+                },
             ],
         );
         assert_eq!(inlay_snapshot.text(), "|123|\nabc\n|456|def\n|567|\n\nghi");
@@ -1023,8 +1005,6 @@ mod tests {
         log::info!("buffer text: {:?}", buffer_snapshot.text());
 
         let (mut inlay_map, mut inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
-        let mut next_inlay_id = 0;
-
         for _ in 0..operations {
             let mut inlay_edits = Patch::default();
 
@@ -1032,7 +1012,7 @@ mod tests {
             let mut buffer_edits = Vec::new();
             match rng.gen_range(0..=100) {
                 0..=50 => {
-                    let (snapshot, edits) = inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
+                    let (snapshot, edits) = inlay_map.randomly_mutate(&mut rng);
                     log::info!("mutated text: {:?}", snapshot.text());
                     inlay_edits = Patch::new(edits);
                 }

crates/editor/src/display_map/tab_map.rs 🔗

@@ -708,7 +708,7 @@ mod tests {
         fold_map.randomly_mutate(&mut rng);
         let (fold_snapshot, _) = fold_map.read(inlay_snapshot, vec![]);
         log::info!("FoldMap text: {:?}", fold_snapshot.text());
-        let (inlay_snapshot, _) = inlay_map.randomly_mutate(&mut 0, &mut rng);
+        let (inlay_snapshot, _) = inlay_map.randomly_mutate(&mut rng);
         log::info!("InlayMap text: {:?}", inlay_snapshot.text());
 
         let (tab_map, _) = TabMap::new(fold_snapshot.clone(), tab_size);

crates/editor/src/display_map/wrap_map.rs 🔗

@@ -1119,7 +1119,6 @@ mod tests {
         );
         log::info!("Wrapped text: {:?}", actual_text);
 
-        let mut next_inlay_id = 0;
         let mut edits = Vec::new();
         for _i in 0..operations {
             log::info!("{} ==============================================", _i);
@@ -1147,8 +1146,7 @@ mod tests {
                     }
                 }
                 40..=59 => {
-                    let (inlay_snapshot, inlay_edits) =
-                        inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
+                    let (inlay_snapshot, inlay_edits) = inlay_map.randomly_mutate(&mut rng);
                     let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
                     let (tabs_snapshot, tab_edits) =
                         tab_map.sync(fold_snapshot, fold_edits, tab_size);

crates/editor/src/editor.rs 🔗

@@ -2709,13 +2709,13 @@ impl Editor {
     fn splice_inlay_hints(
         &self,
         to_remove: Vec<InlayId>,
-        to_insert: Vec<(InlayId, Anchor, project::InlayHint)>,
+        to_insert: Vec<(Anchor, project::InlayHint)>,
         cx: &mut ViewContext<Self>,
     ) {
         let buffer = self.buffer.read(cx).read(cx);
-        let new_inlays: Vec<(InlayId, InlayProperties<String>)> = to_insert
+        let new_inlays = to_insert
             .into_iter()
-            .map(|(inlay_id, hint_anchor, hint)| {
+            .map(|(hint_anchor, hint)| {
                 let mut text = hint.text();
                 // TODO kb styling instead?
                 if hint.padding_right {
@@ -2725,13 +2725,10 @@ impl Editor {
                     text.insert(0, ' ');
                 }
 
-                (
-                    inlay_id,
-                    InlayProperties {
-                        position: hint_anchor.bias_left(&buffer),
-                        text,
-                    },
-                )
+                InlayProperties {
+                    position: hint_anchor.bias_left(&buffer),
+                    text,
+                }
             })
             .collect();
         drop(buffer);
@@ -3485,15 +3482,10 @@ impl Editor {
                 to_remove.push(suggestion.id);
             }
 
-            let to_insert = vec![(
-                // TODO kb check how can I get the unique id for the suggestion
-                // Move the generation of the id inside the map
-                InlayId(usize::MAX),
-                InlayProperties {
-                    position: cursor,
-                    text: text.clone(),
-                },
-            )];
+            let to_insert = vec![InlayProperties {
+                position: cursor,
+                text: text.clone(),
+            }];
             self.display_map.update(cx, move |map, cx| {
                 map.splice_inlays(to_remove, to_insert, cx)
             });
@@ -7664,7 +7656,6 @@ fn inlay_hint_query(
     cx: &mut ViewContext<'_, '_, Editor>,
 ) -> Option<InlayHintQuery> {
     let buffer = buffer.read(cx);
-    let buffer_snapshot = buffer.snapshot();
     let max_buffer_len = buffer.len();
     let visible_offset_range_len = excerpt_visible_offset_range.len();
 
@@ -7677,7 +7668,6 @@ fn inlay_hint_query(
             .saturating_add(visible_offset_range_len),
     );
     Some(InlayHintQuery {
-        buffer_path: buffer_snapshot.resolve_file_path(cx, true)?,
         buffer_id: buffer.remote_id(),
         buffer_version: buffer.version().clone(),
         excerpt_id,

crates/editor/src/inlay_cache.rs 🔗

@@ -1,19 +1,13 @@
-use std::{
-    cmp,
-    ops::Range,
-    path::{Path, PathBuf},
-};
+use std::ops::Range;
 
 use crate::{editor_settings, scroll::ScrollAnchor, Anchor, Editor, ExcerptId, MultiBuffer};
-use anyhow::Context;
-use clock::{Global, Local};
+use clock::Global;
 use gpui::{ModelHandle, Task, ViewContext};
-use log::error;
 use project::{InlayHint, InlayHintKind};
-use util::post_inc;
 
-use collections::{hash_map, BTreeMap, HashMap, HashSet};
+use collections::{HashMap, HashSet};
 
+// TODO kb move to inlay_map along with the next one?
 #[derive(Debug, Clone)]
 pub struct Inlay {
     pub id: InlayId,
@@ -36,48 +30,14 @@ pub enum InlayRefreshReason {
 
 #[derive(Debug, Clone, Default)]
 pub struct InlayCache {
-    inlays_per_buffer: HashMap<PathBuf, BufferInlays>,
+    inlays_per_buffer: HashMap<u64, BufferInlays>,
     allowed_hint_kinds: HashSet<Option<InlayHintKind>>,
-    next_inlay_id: usize,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct AnchorKey {
-    offset: usize,
-    version: Local,
-}
-
-#[derive(Clone, Debug)]
-pub struct OrderedByAnchorOffset<T>(pub BTreeMap<AnchorKey, (Anchor, T)>);
-
-impl<T> OrderedByAnchorOffset<T> {
-    pub fn add(&mut self, anchor: Anchor, t: T) {
-        let key = AnchorKey {
-            offset: anchor.text_anchor.offset,
-            version: anchor.text_anchor.timestamp,
-        };
-        self.0.insert(key, (anchor, t));
-    }
-
-    fn into_ordered_elements(self) -> impl Iterator<Item = (Anchor, T)> {
-        self.0.into_values()
-    }
-
-    fn ordered_elements(&self) -> impl Iterator<Item = &(Anchor, T)> {
-        self.0.values()
-    }
-}
-
-impl<T> Default for OrderedByAnchorOffset<T> {
-    fn default() -> Self {
-        Self(BTreeMap::default())
-    }
 }
 
 #[derive(Clone, Debug, Default)]
 struct BufferInlays {
     buffer_version: Global,
-    inlays_per_excerpts: HashMap<ExcerptId, OrderedByAnchorOffset<(InlayId, InlayHint)>>,
+    ordered_by_anchor_inlays: Vec<(Anchor, InlayId, InlayHint)>,
 }
 
 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -86,12 +46,11 @@ pub struct InlayId(pub usize);
 #[derive(Debug, Default)]
 pub struct InlaySplice {
     pub to_remove: Vec<InlayId>,
-    pub to_insert: Vec<(InlayId, Anchor, InlayHint)>,
+    pub to_insert: Vec<(Anchor, InlayHint)>,
 }
 
 pub struct InlayHintQuery {
     pub buffer_id: u64,
-    pub buffer_path: PathBuf,
     pub buffer_version: Global,
     pub excerpt_id: ExcerptId,
     pub excerpt_offset_query_range: Range<usize>,
@@ -100,307 +59,8 @@ pub struct InlayHintQuery {
 impl InlayCache {
     pub fn new(inlay_hint_settings: editor_settings::InlayHints) -> Self {
         Self {
-            inlays_per_buffer: HashMap::default(),
             allowed_hint_kinds: allowed_inlay_hint_types(inlay_hint_settings),
-            next_inlay_id: 0,
-        }
-    }
-
-    pub fn append_inlays(
-        &mut self,
-        multi_buffer: ModelHandle<MultiBuffer>,
-        ranges_to_add: impl Iterator<Item = InlayHintQuery>,
-        cx: &mut ViewContext<Editor>,
-    ) -> Task<anyhow::Result<InlaySplice>> {
-        self.fetch_inlays(multi_buffer, ranges_to_add, false, cx)
-    }
-
-    pub fn replace_inlays(
-        &mut self,
-        multi_buffer: ModelHandle<MultiBuffer>,
-        new_ranges: impl Iterator<Item = InlayHintQuery>,
-        cx: &mut ViewContext<Editor>,
-    ) -> Task<anyhow::Result<InlaySplice>> {
-        self.fetch_inlays(multi_buffer, new_ranges, true, cx)
-    }
-
-    fn fetch_inlays(
-        &mut self,
-        multi_buffer: ModelHandle<MultiBuffer>,
-        inlay_fetch_ranges: impl Iterator<Item = InlayHintQuery>,
-        replace_old: bool,
-        cx: &mut ViewContext<Editor>,
-    ) -> Task<anyhow::Result<InlaySplice>> {
-        let mut inlay_fetch_tasks = Vec::new();
-        for inlay_fetch_range in inlay_fetch_ranges {
-            let inlays_up_to_date = self.inlays_up_to_date(
-                &inlay_fetch_range.buffer_path,
-                &inlay_fetch_range.buffer_version,
-                inlay_fetch_range.excerpt_id,
-            );
-            let task_multi_buffer = multi_buffer.clone();
-            let task = cx.spawn(|editor, mut cx| async move {
-                if inlays_up_to_date {
-                    anyhow::Ok((inlay_fetch_range, None))
-                } else {
-                    let Some(buffer_handle) = cx.read(|cx| task_multi_buffer.read(cx).buffer(inlay_fetch_range.buffer_id))
-                        else { return Ok((inlay_fetch_range, Some(Vec::new()))) };
-                    let task = editor
-                        .update(&mut cx, |editor, cx| {
-                            editor.project.as_ref().map(|project| {
-                                project.update(cx, |project, cx| {
-                                    project.query_inlay_hints_for_buffer(
-                                        buffer_handle,
-                                        inlay_fetch_range.excerpt_offset_query_range.clone(),
-                                        cx,
-                                    )
-                                })
-                            })
-                        })
-                        .context("inlays fecth task spawn")?;
-
-                    Ok((inlay_fetch_range, match task {
-                        Some(task) => task.await.context("inlays for buffer task")?,
-                        None => Some(Vec::new()),
-                    }))
-                }
-            });
-            inlay_fetch_tasks.push(task);
-        }
-
-        let final_task = cx.spawn(|editor, mut cx| async move {
-            let mut inlay_updates: HashMap<
-                PathBuf,
-                (
-                    Global,
-                    HashMap<ExcerptId, Option<(Range<usize>, OrderedByAnchorOffset<InlayHint>)>>,
-                ),
-            > = HashMap::default();
-            let multi_buffer_snapshot =
-                editor.read_with(&cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))?;
-
-            for task_result in futures::future::join_all(inlay_fetch_tasks).await {
-                match task_result {
-                    Ok((inlay_fetch_range, response_inlays)) => {
-                        // TODO kb different caching now
-                        let inlays_per_excerpt = HashMap::from_iter([(
-                            inlay_fetch_range.excerpt_id,
-                            response_inlays
-                                .map(|excerpt_inlays| {
-                                    excerpt_inlays.into_iter().fold(
-                                        OrderedByAnchorOffset::default(),
-                                        |mut ordered_inlays, inlay| {
-                                            let anchor = multi_buffer_snapshot.anchor_in_excerpt(
-                                                inlay_fetch_range.excerpt_id,
-                                                inlay.position,
-                                            );
-                                            ordered_inlays.add(anchor, inlay);
-                                            ordered_inlays
-                                        },
-                                    )
-                                })
-                                .map(|inlays| {
-                                    (inlay_fetch_range.excerpt_offset_query_range, inlays)
-                                }),
-                        )]);
-                        match inlay_updates.entry(inlay_fetch_range.buffer_path) {
-                            hash_map::Entry::Occupied(mut o) => {
-                                o.get_mut().1.extend(inlays_per_excerpt);
-                            }
-                            hash_map::Entry::Vacant(v) => {
-                                v.insert((inlay_fetch_range.buffer_version, inlays_per_excerpt));
-                            }
-                        }
-                    }
-                    Err(e) => error!("Failed to update inlays for buffer: {e:#}"),
-                }
-            }
-
-            let updates = if !inlay_updates.is_empty() {
-                let inlays_update = editor.update(&mut cx, |editor, _| {
-                    editor.inlay_cache.apply_fetch_inlays(inlay_updates)
-                })?;
-                inlays_update
-            } else {
-                InlaySplice::default()
-            };
-
-            anyhow::Ok(updates)
-        });
-
-        final_task
-    }
-
-    fn inlays_up_to_date(
-        &self,
-        buffer_path: &Path,
-        buffer_version: &Global,
-        excerpt_id: ExcerptId,
-    ) -> bool {
-        let Some(buffer_inlays) = self.inlays_per_buffer.get(buffer_path) else { return false };
-        let buffer_up_to_date = buffer_version == &buffer_inlays.buffer_version
-            || buffer_inlays.buffer_version.changed_since(&buffer_version);
-        buffer_up_to_date && buffer_inlays.inlays_per_excerpts.contains_key(&excerpt_id)
-    }
-
-    fn apply_fetch_inlays(
-        &mut self,
-        fetched_inlays: HashMap<
-            PathBuf,
-            (
-                Global,
-                HashMap<ExcerptId, Option<(Range<usize>, OrderedByAnchorOffset<InlayHint>)>>,
-            ),
-        >,
-    ) -> InlaySplice {
-        let mut old_inlays = self.inlays_per_buffer.clone();
-        let mut to_remove = Vec::new();
-        let mut to_insert = Vec::new();
-
-        for (buffer_path, (buffer_version, new_buffer_inlays)) in fetched_inlays {
-            match old_inlays.remove(&buffer_path) {
-                Some(mut old_buffer_inlays) => {
-                    for (excerpt_id, new_excerpt_inlays) in new_buffer_inlays {
-                        let (_, mut new_excerpt_inlays) = match new_excerpt_inlays {
-                            Some((excerpt_offset_range, new_inlays)) => (
-                                excerpt_offset_range,
-                                new_inlays.into_ordered_elements().fuse().peekable(),
-                            ),
-                            None => continue,
-                        };
-                        if self.inlays_up_to_date(&buffer_path, &buffer_version, excerpt_id) {
-                            continue;
-                        }
-
-                        let self_inlays_per_buffer = self
-                            .inlays_per_buffer
-                            .get_mut(&buffer_path)
-                            .expect("element expected: `old_inlays.remove` returned `Some`");
-
-                        if old_buffer_inlays
-                            .inlays_per_excerpts
-                            .remove(&excerpt_id)
-                            .is_some()
-                        {
-                            let self_excerpt_inlays = self_inlays_per_buffer
-                                .inlays_per_excerpts
-                                .get_mut(&excerpt_id)
-                                .expect("element expected: `old_excerpt_inlays` is `Some`");
-                            let mut hints_to_add = Vec::<(Anchor, (InlayId, InlayHint))>::new();
-                            // TODO kb update inner buffer_id and version with the new data?
-                            self_excerpt_inlays.0.retain(
-                                |_, (old_anchor, (old_inlay_id, old_inlay))| {
-                                    let mut retain = false;
-
-                                    while let Some(new_offset) = new_excerpt_inlays
-                                        .peek()
-                                        .map(|(new_anchor, _)| new_anchor.text_anchor.offset)
-                                    {
-                                        let old_offset = old_anchor.text_anchor.offset;
-                                        match new_offset.cmp(&old_offset) {
-                                            cmp::Ordering::Less => {
-                                                let (new_anchor, new_inlay) =
-                                                    new_excerpt_inlays.next().expect(
-                                                        "element expected: `peek` returned `Some`",
-                                                    );
-                                                hints_to_add.push((
-                                                    new_anchor,
-                                                    (
-                                                        InlayId(post_inc(&mut self.next_inlay_id)),
-                                                        new_inlay,
-                                                    ),
-                                                ));
-                                            }
-                                            cmp::Ordering::Equal => {
-                                                let (new_anchor, new_inlay) =
-                                                    new_excerpt_inlays.next().expect(
-                                                        "element expected: `peek` returned `Some`",
-                                                    );
-                                                if &new_inlay == old_inlay {
-                                                    retain = true;
-                                                } else {
-                                                    hints_to_add.push((
-                                                        new_anchor,
-                                                        (
-                                                            InlayId(post_inc(
-                                                                &mut self.next_inlay_id,
-                                                            )),
-                                                            new_inlay,
-                                                        ),
-                                                    ));
-                                                }
-                                            }
-                                            cmp::Ordering::Greater => break,
-                                        }
-                                    }
-
-                                    if !retain {
-                                        to_remove.push(*old_inlay_id);
-                                    }
-                                    retain
-                                },
-                            );
-
-                            for (new_anchor, (id, new_inlay)) in hints_to_add {
-                                self_excerpt_inlays.add(new_anchor, (id, new_inlay.clone()));
-                                to_insert.push((id, new_anchor, new_inlay));
-                            }
-                        }
-
-                        for (new_anchor, new_inlay) in new_excerpt_inlays {
-                            let id = InlayId(post_inc(&mut self.next_inlay_id));
-                            self_inlays_per_buffer
-                                .inlays_per_excerpts
-                                .entry(excerpt_id)
-                                .or_default()
-                                .add(new_anchor, (id, new_inlay.clone()));
-                            to_insert.push((id, new_anchor, new_inlay));
-                        }
-                    }
-                }
-                None => {
-                    let mut inlays_per_excerpts: HashMap<
-                        ExcerptId,
-                        OrderedByAnchorOffset<(InlayId, InlayHint)>,
-                    > = HashMap::default();
-                    for (new_excerpt_id, new_ordered_inlays) in new_buffer_inlays {
-                        if let Some((_, new_ordered_inlays)) = new_ordered_inlays {
-                            for (new_anchor, new_inlay) in
-                                new_ordered_inlays.into_ordered_elements()
-                            {
-                                let id = InlayId(post_inc(&mut self.next_inlay_id));
-                                inlays_per_excerpts
-                                    .entry(new_excerpt_id)
-                                    .or_default()
-                                    .add(new_anchor, (id, new_inlay.clone()));
-                                to_insert.push((id, new_anchor, new_inlay));
-                            }
-                        }
-                    }
-                    self.inlays_per_buffer.insert(
-                        buffer_path,
-                        BufferInlays {
-                            buffer_version,
-                            inlays_per_excerpts,
-                        },
-                    );
-                }
-            }
-        }
-
-        for (_, old_buffer_inlays) in old_inlays {
-            for (_, old_excerpt_inlays) in old_buffer_inlays.inlays_per_excerpts {
-                for (_, (id_to_remove, _)) in old_excerpt_inlays.into_ordered_elements() {
-                    to_remove.push(id_to_remove);
-                }
-            }
-        }
-
-        to_insert.retain(|(_, _, new_hint)| self.allowed_hint_kinds.contains(&new_hint.kind));
-
-        InlaySplice {
-            to_remove,
-            to_insert,
+            inlays_per_buffer: HashMap::default(),
         }
     }
 
@@ -420,22 +80,17 @@ impl InlayCache {
             .collect::<HashSet<_>>();
         let mut to_remove = Vec::new();
         let mut to_insert = Vec::new();
-        for (anchor, (inlay_id, inlay_hint)) in self
+        for (_, inlay_id, inlay_hint) in self
             .inlays_per_buffer
             .iter()
-            .map(|(_, buffer_inlays)| {
-                buffer_inlays
-                    .inlays_per_excerpts
-                    .iter()
-                    .map(|(_, excerpt_inlays)| excerpt_inlays.ordered_elements())
-                    .flatten()
-            })
+            .map(|(_, buffer_inlays)| buffer_inlays.ordered_by_anchor_inlays.iter())
             .flatten()
         {
             if removed_hint_kinds.contains(&inlay_hint.kind) {
                 to_remove.push(*inlay_id);
             } else if new_allowed_hint_kinds.contains(&inlay_hint.kind) {
-                to_insert.push((*inlay_id, *anchor, inlay_hint.to_owned()));
+                todo!("TODO kb: agree with InlayMap how splice works")
+                // to_insert.push((*inlay_id, *anchor, inlay_hint.to_owned()));
             }
         }
 
@@ -450,20 +105,323 @@ impl InlayCache {
     pub fn clear(&mut self) -> Vec<InlayId> {
         self.inlays_per_buffer
             .drain()
-            .map(|(_, buffer_inlays)| {
+            .flat_map(|(_, buffer_inlays)| {
                 buffer_inlays
-                    .inlays_per_excerpts
+                    .ordered_by_anchor_inlays
                     .into_iter()
-                    .map(|(_, excerpt_inlays)| {
-                        excerpt_inlays
-                            .into_ordered_elements()
-                            .map(|(_, (id, _))| id)
-                    })
-                    .flatten()
+                    .map(|(_, id, _)| id)
             })
-            .flatten()
             .collect()
     }
+
+    pub fn append_inlays(
+        &mut self,
+        multi_buffer: ModelHandle<MultiBuffer>,
+        ranges_to_add: impl Iterator<Item = InlayHintQuery>,
+        cx: &mut ViewContext<Editor>,
+    ) -> Task<anyhow::Result<InlaySplice>> {
+        self.fetch_inlays(multi_buffer, ranges_to_add, false, cx)
+    }
+
+    pub fn replace_inlays(
+        &mut self,
+        multi_buffer: ModelHandle<MultiBuffer>,
+        new_ranges: impl Iterator<Item = InlayHintQuery>,
+        cx: &mut ViewContext<Editor>,
+    ) -> Task<anyhow::Result<InlaySplice>> {
+        self.fetch_inlays(multi_buffer, new_ranges, true, cx)
+    }
+
+    fn fetch_inlays(
+        &mut self,
+        multi_buffer: ModelHandle<MultiBuffer>,
+        inlay_fetch_ranges: impl Iterator<Item = InlayHintQuery>,
+        replace_old: bool,
+        cx: &mut ViewContext<Editor>,
+    ) -> Task<anyhow::Result<InlaySplice>> {
+        // TODO kb
+        todo!("TODO kb")
+    }
+
+    // fn fetch_inlays(
+    //     &mut self,
+    //     multi_buffer: ModelHandle<MultiBuffer>,
+    //     inlay_fetch_ranges: impl Iterator<Item = InlayHintQuery>,
+    //     replace_old: bool,
+    //     cx: &mut ViewContext<Editor>,
+    // ) -> Task<anyhow::Result<InlaySplice>> {
+    //     let mut inlay_fetch_tasks = Vec::new();
+    //     for inlay_fetch_range in inlay_fetch_ranges {
+    //         let inlays_up_to_date = self.inlays_up_to_date(
+    //             &inlay_fetch_range.buffer_path,
+    //             &inlay_fetch_range.buffer_version,
+    //             inlay_fetch_range.excerpt_id,
+    //         );
+    //         let task_multi_buffer = multi_buffer.clone();
+    //         let task = cx.spawn(|editor, mut cx| async move {
+    //             if inlays_up_to_date {
+    //                 anyhow::Ok((inlay_fetch_range, None))
+    //             } else {
+    //                 let Some(buffer_handle) = cx.read(|cx| task_multi_buffer.read(cx).buffer(inlay_fetch_range.buffer_id))
+    //                     else { return Ok((inlay_fetch_range, Some(Vec::new()))) };
+    //                 let task = editor
+    //                     .update(&mut cx, |editor, cx| {
+    //                         editor.project.as_ref().map(|project| {
+    //                             project.update(cx, |project, cx| {
+    //                                 project.query_inlay_hints_for_buffer(
+    //                                     buffer_handle,
+    //                                     inlay_fetch_range.excerpt_offset_query_range.clone(),
+    //                                     cx,
+    //                                 )
+    //                             })
+    //                         })
+    //                     })
+    //                     .context("inlays fecth task spawn")?;
+
+    //                 Ok((inlay_fetch_range, match task {
+    //                     Some(task) => task.await.context("inlays for buffer task")?,
+    //                     None => Some(Vec::new()),
+    //                 }))
+    //             }
+    //         });
+    //         inlay_fetch_tasks.push(task);
+    //     }
+
+    //     let final_task = cx.spawn(|editor, mut cx| async move {
+    //         let mut inlay_updates: HashMap<
+    //             PathBuf,
+    //             (
+    //                 Global,
+    //                 HashMap<ExcerptId, Option<(Range<usize>, OrderedByAnchorOffset<InlayHint>)>>,
+    //             ),
+    //         > = HashMap::default();
+    //         let multi_buffer_snapshot =
+    //             editor.read_with(&cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))?;
+
+    //         for task_result in futures::future::join_all(inlay_fetch_tasks).await {
+    //             match task_result {
+    //                 Ok((inlay_fetch_range, response_inlays)) => {
+    //                     // TODO kb different caching now
+    //                     let inlays_per_excerpt = HashMap::from_iter([(
+    //                         inlay_fetch_range.excerpt_id,
+    //                         response_inlays
+    //                             .map(|excerpt_inlays| {
+    //                                 excerpt_inlays.into_iter().fold(
+    //                                     OrderedByAnchorOffset::default(),
+    //                                     |mut ordered_inlays, inlay| {
+    //                                         let anchor = multi_buffer_snapshot.anchor_in_excerpt(
+    //                                             inlay_fetch_range.excerpt_id,
+    //                                             inlay.position,
+    //                                         );
+    //                                         ordered_inlays.add(anchor, inlay);
+    //                                         ordered_inlays
+    //                                     },
+    //                                 )
+    //                             })
+    //                             .map(|inlays| {
+    //                                 (inlay_fetch_range.excerpt_offset_query_range, inlays)
+    //                             }),
+    //                     )]);
+    //                     match inlay_updates.entry(inlay_fetch_range.buffer_path) {
+    //                         hash_map::Entry::Occupied(mut o) => {
+    //                             o.get_mut().1.extend(inlays_per_excerpt);
+    //                         }
+    //                         hash_map::Entry::Vacant(v) => {
+    //                             v.insert((inlay_fetch_range.buffer_version, inlays_per_excerpt));
+    //                         }
+    //                     }
+    //                 }
+    //                 Err(e) => error!("Failed to update inlays for buffer: {e:#}"),
+    //             }
+    //         }
+
+    //         let updates = if !inlay_updates.is_empty() {
+    //             let inlays_update = editor.update(&mut cx, |editor, _| {
+    //                 editor.inlay_cache.apply_fetch_inlays(inlay_updates)
+    //             })?;
+    //             inlays_update
+    //         } else {
+    //             InlaySplice::default()
+    //         };
+
+    //         anyhow::Ok(updates)
+    //     });
+
+    //     final_task
+    // }
+
+    // fn inlays_up_to_date(
+    //     &self,
+    //     buffer_path: &Path,
+    //     buffer_version: &Global,
+    //     excerpt_id: ExcerptId,
+    // ) -> bool {
+    //     let Some(buffer_inlays) = self.inlays_per_buffer.get(buffer_path) else { return false };
+    //     let buffer_up_to_date = buffer_version == &buffer_inlays.buffer_version
+    //         || buffer_inlays.buffer_version.changed_since(&buffer_version);
+    //     buffer_up_to_date && buffer_inlays.inlays_per_excerpts.contains_key(&excerpt_id)
+    // }
+
+    // fn apply_fetch_inlays(
+    //     &mut self,
+    //     fetched_inlays: HashMap<
+    //         PathBuf,
+    //         (
+    //             Global,
+    //             HashMap<ExcerptId, Option<(Range<usize>, OrderedByAnchorOffset<InlayHint>)>>,
+    //         ),
+    //     >,
+    // ) -> InlaySplice {
+    //     let mut old_inlays = self.inlays_per_buffer.clone();
+    //     let mut to_remove = Vec::new();
+    //     let mut to_insert = Vec::new();
+
+    //     for (buffer_path, (buffer_version, new_buffer_inlays)) in fetched_inlays {
+    //         match old_inlays.remove(&buffer_path) {
+    //             Some(mut old_buffer_inlays) => {
+    //                 for (excerpt_id, new_excerpt_inlays) in new_buffer_inlays {
+    //                     let (_, mut new_excerpt_inlays) = match new_excerpt_inlays {
+    //                         Some((excerpt_offset_range, new_inlays)) => (
+    //                             excerpt_offset_range,
+    //                             new_inlays.into_ordered_elements().fuse().peekable(),
+    //                         ),
+    //                         None => continue,
+    //                     };
+    //                     if self.inlays_up_to_date(&buffer_path, &buffer_version, excerpt_id) {
+    //                         continue;
+    //                     }
+
+    //                     let self_inlays_per_buffer = self
+    //                         .inlays_per_buffer
+    //                         .get_mut(&buffer_path)
+    //                         .expect("element expected: `old_inlays.remove` returned `Some`");
+
+    //                     if old_buffer_inlays
+    //                         .inlays_per_excerpts
+    //                         .remove(&excerpt_id)
+    //                         .is_some()
+    //                     {
+    //                         let self_excerpt_inlays = self_inlays_per_buffer
+    //                             .inlays_per_excerpts
+    //                             .get_mut(&excerpt_id)
+    //                             .expect("element expected: `old_excerpt_inlays` is `Some`");
+    //                         let mut hints_to_add = Vec::<(Anchor, (InlayId, InlayHint))>::new();
+    //                         // TODO kb update inner buffer_id and version with the new data?
+    //                         self_excerpt_inlays.0.retain(
+    //                             |_, (old_anchor, (old_inlay_id, old_inlay))| {
+    //                                 let mut retain = false;
+
+    //                                 while let Some(new_offset) = new_excerpt_inlays
+    //                                     .peek()
+    //                                     .map(|(new_anchor, _)| new_anchor.text_anchor.offset)
+    //                                 {
+    //                                     let old_offset = old_anchor.text_anchor.offset;
+    //                                     match new_offset.cmp(&old_offset) {
+    //                                         cmp::Ordering::Less => {
+    //                                             let (new_anchor, new_inlay) =
+    //                                                 new_excerpt_inlays.next().expect(
+    //                                                     "element expected: `peek` returned `Some`",
+    //                                                 );
+    //                                             hints_to_add.push((
+    //                                                 new_anchor,
+    //                                                 (
+    //                                                     InlayId(post_inc(&mut self.next_inlay_id)),
+    //                                                     new_inlay,
+    //                                                 ),
+    //                                             ));
+    //                                         }
+    //                                         cmp::Ordering::Equal => {
+    //                                             let (new_anchor, new_inlay) =
+    //                                                 new_excerpt_inlays.next().expect(
+    //                                                     "element expected: `peek` returned `Some`",
+    //                                                 );
+    //                                             if &new_inlay == old_inlay {
+    //                                                 retain = true;
+    //                                             } else {
+    //                                                 hints_to_add.push((
+    //                                                     new_anchor,
+    //                                                     (
+    //                                                         InlayId(post_inc(
+    //                                                             &mut self.next_inlay_id,
+    //                                                         )),
+    //                                                         new_inlay,
+    //                                                     ),
+    //                                                 ));
+    //                                             }
+    //                                         }
+    //                                         cmp::Ordering::Greater => break,
+    //                                     }
+    //                                 }
+
+    //                                 if !retain {
+    //                                     to_remove.push(*old_inlay_id);
+    //                                 }
+    //                                 retain
+    //                             },
+    //                         );
+
+    //                         for (new_anchor, (id, new_inlay)) in hints_to_add {
+    //                             self_excerpt_inlays.add(new_anchor, (id, new_inlay.clone()));
+    //                             to_insert.push((id, new_anchor, new_inlay));
+    //                         }
+    //                     }
+
+    //                     for (new_anchor, new_inlay) in new_excerpt_inlays {
+    //                         let id = InlayId(post_inc(&mut self.next_inlay_id));
+    //                         self_inlays_per_buffer
+    //                             .inlays_per_excerpts
+    //                             .entry(excerpt_id)
+    //                             .or_default()
+    //                             .add(new_anchor, (id, new_inlay.clone()));
+    //                         to_insert.push((id, new_anchor, new_inlay));
+    //                     }
+    //                 }
+    //             }
+    //             None => {
+    //                 let mut inlays_per_excerpts: HashMap<
+    //                     ExcerptId,
+    //                     OrderedByAnchorOffset<(InlayId, InlayHint)>,
+    //                 > = HashMap::default();
+    //                 for (new_excerpt_id, new_ordered_inlays) in new_buffer_inlays {
+    //                     if let Some((_, new_ordered_inlays)) = new_ordered_inlays {
+    //                         for (new_anchor, new_inlay) in
+    //                             new_ordered_inlays.into_ordered_elements()
+    //                         {
+    //                             let id = InlayId(post_inc(&mut self.next_inlay_id));
+    //                             inlays_per_excerpts
+    //                                 .entry(new_excerpt_id)
+    //                                 .or_default()
+    //                                 .add(new_anchor, (id, new_inlay.clone()));
+    //                             to_insert.push((id, new_anchor, new_inlay));
+    //                         }
+    //                     }
+    //                 }
+    //                 self.inlays_per_buffer.insert(
+    //                     buffer_path,
+    //                     BufferInlays {
+    //                         buffer_version,
+    //                         inlays_per_excerpts,
+    //                     },
+    //                 );
+    //             }
+    //         }
+    //     }
+
+    //     for (_, old_buffer_inlays) in old_inlays {
+    //         for (_, old_excerpt_inlays) in old_buffer_inlays.inlays_per_excerpts {
+    //             for (_, (id_to_remove, _)) in old_excerpt_inlays.into_ordered_elements() {
+    //                 to_remove.push(id_to_remove);
+    //             }
+    //         }
+    //     }
+
+    //     to_insert.retain(|(_, _, new_hint)| self.allowed_hint_kinds.contains(&new_hint.kind));
+
+    //     InlaySplice {
+    //         to_remove,
+    //         to_insert,
+    //     }
+    // }
 }
 
 fn allowed_inlay_hint_types(