Start to model the background threads for InlayHintCache

Kirill Bulatov created

Change summary

crates/editor/src/editor.rs           |  27 
crates/editor/src/inlay_hint_cache.rs | 744 +++++++++++++++-------------
2 files changed, 399 insertions(+), 372 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -2613,23 +2613,21 @@ impl Editor {
             return;
         }
 
-        let multi_buffer_handle = self.buffer().clone();
-        let multi_buffer_snapshot = multi_buffer_handle.read(cx).snapshot(cx);
+        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
         let current_inlays = self
             .display_map
             .read(cx)
             .current_inlays()
             .cloned()
+            .filter(|inlay| Some(inlay.id) != self.copilot_state.suggestion.as_ref().map(|h| h.id))
             .collect();
         match reason {
             InlayRefreshReason::SettingsChange(new_settings) => self
                 .inlay_hint_cache
-                .spawn_settings_update(multi_buffer_handle, new_settings, current_inlays),
+                .spawn_settings_update(multi_buffer_snapshot, new_settings, current_inlays),
             InlayRefreshReason::Scroll(scrolled_to) => {
-                if let Some(new_query) = self
-                    .excerpt_visible_offsets(&multi_buffer_handle, cx)
-                    .into_iter()
-                    .find_map(|(buffer, _, excerpt_id)| {
+                if let Some(new_query) = self.excerpt_visible_offsets(cx).into_iter().find_map(
+                    |(buffer, _, excerpt_id)| {
                         let buffer_id = scrolled_to.anchor.buffer_id?;
                         if buffer_id == buffer.read(cx).remote_id()
                             && scrolled_to.anchor.excerpt_id == excerpt_id
@@ -2642,20 +2640,19 @@ impl Editor {
                         } else {
                             None
                         }
-                    })
-                {
+                    },
+                ) {
                     self.inlay_hint_cache.spawn_hints_update(
-                        multi_buffer_handle,
+                        multi_buffer_snapshot,
                         vec![new_query],
                         current_inlays,
                         false,
-                        cx,
                     )
                 }
             }
             InlayRefreshReason::VisibleExcerptsChange => {
                 let replacement_queries = self
-                    .excerpt_visible_offsets(&multi_buffer_handle, cx)
+                    .excerpt_visible_offsets(cx)
                     .into_iter()
                     .map(|(buffer, _, excerpt_id)| {
                         let buffer = buffer.read(cx);
@@ -2667,11 +2664,10 @@ impl Editor {
                     })
                     .collect::<Vec<_>>();
                 self.inlay_hint_cache.spawn_hints_update(
-                    multi_buffer_handle,
+                    multi_buffer_snapshot,
                     replacement_queries,
                     current_inlays,
                     true,
-                    cx,
                 )
             }
         };
@@ -2679,10 +2675,9 @@ impl Editor {
 
     fn excerpt_visible_offsets(
         &self,
-        multi_buffer: &ModelHandle<MultiBuffer>,
         cx: &mut ViewContext<'_, '_, Editor>,
     ) -> Vec<(ModelHandle<Buffer>, Range<usize>, ExcerptId)> {
-        let multi_buffer = multi_buffer.read(cx);
+        let multi_buffer = self.buffer().read(cx);
         let multi_buffer_snapshot = multi_buffer.snapshot(cx);
         let multi_buffer_visible_start = self
             .scroll_manager

crates/editor/src/inlay_hint_cache.rs 🔗

@@ -6,12 +6,12 @@ use crate::{
 };
 use anyhow::Context;
 use clock::Global;
+use futures::{stream::FuturesUnordered, FutureExt, StreamExt};
 use gpui::{ModelHandle, Task, ViewContext};
 use log::error;
 use project::{InlayHint, InlayHintKind};
 
 use collections::{hash_map, HashMap, HashSet};
-use util::post_inc;
 
 #[derive(Debug)]
 pub struct InlayHintCache {
@@ -21,6 +21,13 @@ pub struct InlayHintCache {
     hint_updates_tx: smol::channel::Sender<HintsUpdate>,
 }
 
+#[derive(Debug)]
+struct CacheSnapshot {
+    inlay_hints: HashMap<InlayId, InlayHint>,
+    hints_in_buffers: HashMap<u64, BufferHints<(Anchor, InlayId)>>,
+    allowed_hint_kinds: HashSet<Option<InlayHintKind>>,
+}
+
 #[derive(Clone, Debug)]
 struct BufferHints<H> {
     buffer_version: Global,
@@ -49,7 +56,82 @@ impl InlayHintCache {
         cx: &mut ViewContext<Editor>,
     ) -> Self {
         let (hint_updates_tx, hint_updates_rx) = smol::channel::unbounded();
-        spawn_hints_update_loop(hint_updates_rx, cx);
+        let (update_results_tx, update_results_rx) = smol::channel::unbounded();
+        spawn_hints_update_loop(hint_updates_rx, update_results_tx, cx);
+        cx.spawn(|editor, mut cx| async move {
+            while let Ok(update_result) = update_results_rx.recv().await {
+                let editor_absent = editor
+                    .update(&mut cx, |editor, cx| {
+                        let multi_buffer_snapshot = editor.buffer().read(cx).snapshot(cx);
+                        let inlay_hint_cache = &mut editor.inlay_hint_cache;
+                        if let Some(new_allowed_hint_kinds) = update_result.new_allowed_hint_kinds {
+                            inlay_hint_cache.allowed_hint_kinds = new_allowed_hint_kinds;
+                        }
+
+                        inlay_hint_cache.hints_in_buffers.retain(|_, buffer_hints| {
+                            buffer_hints.hints_per_excerpt.retain(|_, excerpt_hints| {
+                                excerpt_hints.retain(|(_, hint_id)| {
+                                    !update_result.remove_from_cache.contains(hint_id)
+                                });
+                                !excerpt_hints.is_empty()
+                            });
+                            !buffer_hints.hints_per_excerpt.is_empty()
+                        });
+                        inlay_hint_cache.inlay_hints.retain(|hint_id, _| {
+                            !update_result.remove_from_cache.contains(hint_id)
+                        });
+
+                        for (new_buffer_id, new_buffer_inlays) in update_result.add_to_cache {
+                            let cached_buffer_hints = inlay_hint_cache
+                                .hints_in_buffers
+                                .entry(new_buffer_id)
+                                .or_insert_with(|| {
+                                    BufferHints::new(new_buffer_inlays.buffer_version.clone())
+                                });
+                            if cached_buffer_hints
+                                .buffer_version
+                                .changed_since(&new_buffer_inlays.buffer_version)
+                            {
+                                continue;
+                            }
+                            for (excerpt_id, new_excerpt_inlays) in
+                                new_buffer_inlays.hints_per_excerpt
+                            {
+                                let cached_excerpt_hints = cached_buffer_hints
+                                    .hints_per_excerpt
+                                    .entry(excerpt_id)
+                                    .or_default();
+                                for (new_hint_position, new_hint, new_inlay_id) in
+                                    new_excerpt_inlays
+                                {
+                                    if let hash_map::Entry::Vacant(v) =
+                                        inlay_hint_cache.inlay_hints.entry(new_inlay_id)
+                                    {
+                                        v.insert(new_hint);
+                                        match cached_excerpt_hints.binary_search_by(|probe| {
+                                            new_hint_position.cmp(&probe.0, &multi_buffer_snapshot)
+                                        }) {
+                                            Ok(ix) | Err(ix) => cached_excerpt_hints
+                                                .insert(ix, (new_hint_position, new_inlay_id)),
+                                        }
+                                    }
+                                }
+                            }
+                        }
+
+                        let InlaySplice {
+                            to_remove,
+                            to_insert,
+                        } = update_result.splice;
+                        editor.splice_inlay_hints(to_remove, to_insert, cx)
+                    })
+                    .is_err();
+                if editor_absent {
+                    return;
+                }
+            }
+        })
+        .detach();
         Self {
             allowed_hint_kinds: allowed_hint_types(inlay_hint_settings),
             hints_in_buffers: HashMap::default(),
@@ -60,7 +142,7 @@ impl InlayHintCache {
 
     pub fn spawn_settings_update(
         &mut self,
-        multi_buffer: ModelHandle<MultiBuffer>,
+        multi_buffer_snapshot: MultiBufferSnapshot,
         inlay_hint_settings: editor_settings::InlayHints,
         current_inlays: Vec<Inlay>,
     ) {
@@ -71,8 +153,9 @@ impl InlayHintCache {
             } else {
                 self.hint_updates_tx
                     .send_blocking(HintsUpdate {
-                        multi_buffer,
-                        current_inlays,
+                        multi_buffer_snapshot,
+                        cache: self.snapshot(),
+                        visible_inlays: current_inlays,
                         kind: HintsUpdateKind::Clean,
                     })
                     .ok();
@@ -87,10 +170,10 @@ impl InlayHintCache {
 
         self.hint_updates_tx
             .send_blocking(HintsUpdate {
-                multi_buffer,
-                current_inlays,
+                multi_buffer_snapshot,
+                cache: self.snapshot(),
+                visible_inlays: current_inlays,
                 kind: HintsUpdateKind::AllowedHintKindsChanged {
-                    old: self.allowed_hint_kinds.clone(),
                     new: new_allowed_hint_kinds,
                 },
             })
@@ -99,11 +182,10 @@ impl InlayHintCache {
 
     pub fn spawn_hints_update(
         &mut self,
-        multi_buffer: ModelHandle<MultiBuffer>,
+        multi_buffer_snapshot: MultiBufferSnapshot,
         queries: Vec<InlayHintQuery>,
         current_inlays: Vec<Inlay>,
         conflicts_invalidate_cache: bool,
-        cx: &mut ViewContext<Editor>,
     ) {
         let conflicts_with_cache = conflicts_invalidate_cache
             && queries.iter().any(|update_query| {
@@ -167,8 +249,9 @@ impl InlayHintCache {
         for (queried_buffer, (buffer_version, excerpts)) in queries_per_buffer {
             self.hint_updates_tx
                 .send_blocking(HintsUpdate {
-                    multi_buffer,
-                    current_inlays,
+                    multi_buffer_snapshot: multi_buffer_snapshot.clone(),
+                    visible_inlays: current_inlays.clone(),
+                    cache: self.snapshot(),
                     kind: HintsUpdateKind::BufferUpdate {
                         invalidate_cache: conflicts_with_cache,
                         buffer_id: queried_buffer,
@@ -179,6 +262,16 @@ impl InlayHintCache {
                 .ok();
         }
     }
+
+    // TODO kb could be big and cloned per symbol input.
+    // Instead, use `Box`/`Arc`/`Rc`?
+    fn snapshot(&self) -> CacheSnapshot {
+        CacheSnapshot {
+            inlay_hints: self.inlay_hints.clone(),
+            hints_in_buffers: self.hints_in_buffers.clone(),
+            allowed_hint_kinds: self.allowed_hint_kinds.clone(),
+        }
+    }
 }
 
 #[derive(Debug, Default)]
@@ -188,15 +281,15 @@ struct InlaySplice {
 }
 
 struct HintsUpdate {
-    multi_buffer: ModelHandle<MultiBuffer>,
-    current_inlays: Vec<Inlay>,
+    multi_buffer_snapshot: MultiBufferSnapshot,
+    visible_inlays: Vec<Inlay>,
+    cache: CacheSnapshot,
     kind: HintsUpdateKind,
 }
 
 enum HintsUpdateKind {
     Clean,
     AllowedHintKindsChanged {
-        old: HashSet<Option<InlayHintKind>>,
         new: HashSet<Option<InlayHintKind>>,
     },
     BufferUpdate {
@@ -207,14 +300,7 @@ enum HintsUpdateKind {
     },
 }
 
-struct UpdateTaskHandle {
-    multi_buffer: ModelHandle<MultiBuffer>,
-    cancellation_tx: smol::channel::Sender<()>,
-    task_finish_rx: smol::channel::Receiver<UpdateTaskResult>,
-}
-
-struct UpdateTaskResult {
-    multi_buffer: ModelHandle<MultiBuffer>,
+struct UpdateResult {
     splice: InlaySplice,
     new_allowed_hint_kinds: Option<HashSet<Option<InlayHintKind>>>,
     remove_from_cache: HashSet<InlayId>,
@@ -237,7 +323,7 @@ impl HintsUpdate {
                     buffer_id: old_buffer_id,
                     buffer_version: old_buffer_version,
                     excerpts: old_excerpts,
-                    invalidate_cache: old_invalidate_cache,
+                    ..
                 },
                 HintsUpdateKind::BufferUpdate {
                     buffer_id: new_buffer_id,
@@ -257,12 +343,12 @@ impl HintsUpdate {
                         return Ok(());
                     } else {
                         let old_inlays = self
-                            .current_inlays
+                            .visible_inlays
                             .iter()
                             .map(|inlay| inlay.id)
                             .collect::<Vec<_>>();
                         let new_inlays = other
-                            .current_inlays
+                            .visible_inlays
                             .iter()
                             .map(|inlay| inlay.id)
                             .collect::<Vec<_>>();
@@ -280,180 +366,155 @@ impl HintsUpdate {
         Err(other)
     }
 
-    fn spawn(self, cx: &mut ViewContext<'_, '_, Editor>) -> UpdateTaskHandle {
-        let (task_finish_tx, task_finish_rx) = smol::channel::unbounded();
-        let (cancellation_tx, cancellation_rx) = smol::channel::bounded(1);
-
+    async fn run(self, result_sender: smol::channel::Sender<UpdateResult>) {
         match self.kind {
-            HintsUpdateKind::Clean => cx
-                .spawn(|editor, mut cx| async move {
-                    if let Some(splice) = editor.update(&mut cx, |editor, cx| {
-                        clean_cache(editor, self.current_inlays)
-                    })? {
-                        task_finish_tx
-                            .send(UpdateTaskResult {
-                                multi_buffer: self.multi_buffer.clone(),
-                                splice,
-                                new_allowed_hint_kinds: None,
-                                remove_from_cache: HashSet::default(),
-                                add_to_cache: HashMap::default(),
-                            })
-                            .await
-                            .ok();
-                    }
-                    anyhow::Ok(())
-                })
-                .detach_and_log_err(cx),
-            HintsUpdateKind::AllowedHintKindsChanged { old, new } => cx
-                .spawn(|editor, mut cx| async move {
-                    if let Some(splice) = editor.update(&mut cx, |editor, cx| {
-                        update_allowed_hint_kinds(
-                            &self.multi_buffer.read(cx).snapshot(cx),
-                            self.current_inlays,
-                            old,
-                            new,
-                            editor,
-                        )
-                    })? {
-                        task_finish_tx
-                            .send(UpdateTaskResult {
-                                multi_buffer: self.multi_buffer.clone(),
-                                splice,
-                                new_allowed_hint_kinds: None,
-                                remove_from_cache: HashSet::default(),
-                                add_to_cache: HashMap::default(),
-                            })
-                            .await
-                            .ok();
-                    }
-                    anyhow::Ok(())
-                })
-                .detach_and_log_err(cx),
+            HintsUpdateKind::Clean => {
+                if !self.cache.inlay_hints.is_empty() || !self.visible_inlays.is_empty() {
+                    result_sender
+                        .send(UpdateResult {
+                            splice: InlaySplice {
+                                to_remove: self
+                                    .visible_inlays
+                                    .iter()
+                                    .map(|inlay| inlay.id)
+                                    .collect(),
+                                to_insert: Vec::new(),
+                            },
+                            new_allowed_hint_kinds: None,
+                            remove_from_cache: self.cache.inlay_hints.keys().copied().collect(),
+                            add_to_cache: HashMap::default(),
+                        })
+                        .await
+                        .ok();
+                }
+            }
+            HintsUpdateKind::AllowedHintKindsChanged { new } => {
+                if let Some(splice) = new_allowed_hint_kinds_splice(
+                    &self.multi_buffer_snapshot,
+                    self.visible_inlays,
+                    &self.cache,
+                    &new,
+                ) {
+                    result_sender
+                        .send(UpdateResult {
+                            splice,
+                            new_allowed_hint_kinds: Some(new),
+                            remove_from_cache: HashSet::default(),
+                            add_to_cache: HashMap::default(),
+                        })
+                        .await
+                        .ok();
+                }
+            }
             HintsUpdateKind::BufferUpdate {
                 buffer_id,
                 buffer_version,
                 excerpts,
                 invalidate_cache,
-            } => todo!("TODO kb"),
-        }
-
-        UpdateTaskHandle {
-            multi_buffer: self.multi_buffer.clone(),
-            cancellation_tx,
-            task_finish_rx,
+            } => {
+                let mut tasks = excerpts
+                    .into_iter()
+                    .map(|excerpt_id| async move {
+                        //
+                        todo!("TODO kb")
+                    })
+                    .collect::<FuturesUnordered<_>>();
+                while let Some(update) = tasks.next().await {
+                    todo!("TODO kb")
+                }
+            }
         }
     }
 }
 
 fn spawn_hints_update_loop(
     hint_updates_rx: smol::channel::Receiver<HintsUpdate>,
+    update_results_tx: smol::channel::Sender<UpdateResult>,
     cx: &mut ViewContext<'_, '_, Editor>,
 ) {
-    cx.spawn(|editor, mut cx| async move {
-        let mut update = None::<HintsUpdate>;
-        let mut next_update = None::<HintsUpdate>;
-        loop {
-            if update.is_none() {
-                match hint_updates_rx.recv().await {
-                    Ok(first_task) => update = Some(first_task),
-                    Err(smol::channel::RecvError) => return,
+    cx.background()
+        .spawn(async move {
+            let mut update = None::<HintsUpdate>;
+            let mut next_update = None::<HintsUpdate>;
+            loop {
+                if update.is_none() {
+                    match hint_updates_rx.recv().await {
+                        Ok(first_task) => update = Some(first_task),
+                        Err(smol::channel::RecvError) => return,
+                    }
                 }
-            }
 
-            let mut updates_limit = 10;
-            'update_merge: loop {
-                match hint_updates_rx.try_recv() {
-                    Ok(new_update) => {
-                        match update.as_mut() {
-                            Some(update) => match update.merge(new_update) {
-                                Ok(()) => {}
-                                Err(new_update) => {
-                                    next_update = Some(new_update);
-                                    break 'update_merge;
-                                }
-                            },
-                            None => update = Some(new_update),
-                        };
+                let mut updates_limit = 10;
+                'update_merge: loop {
+                    match hint_updates_rx.try_recv() {
+                        Ok(new_update) => {
+                            match update.as_mut() {
+                                Some(update) => match update.merge(new_update) {
+                                    Ok(()) => {}
+                                    Err(new_update) => {
+                                        next_update = Some(new_update);
+                                        break 'update_merge;
+                                    }
+                                },
+                                None => update = Some(new_update),
+                            };
 
-                        if updates_limit == 0 {
-                            break 'update_merge;
+                            if updates_limit == 0 {
+                                break 'update_merge;
+                            }
+                            updates_limit -= 1;
                         }
-                        updates_limit -= 1;
+                        Err(smol::channel::TryRecvError::Empty) => break 'update_merge,
+                        Err(smol::channel::TryRecvError::Closed) => return,
                     }
-                    Err(smol::channel::TryRecvError::Empty) => break 'update_merge,
-                    Err(smol::channel::TryRecvError::Closed) => return,
                 }
-            }
-
-            if let Some(update) = update.take() {
-                let Ok(task_handle) = editor.update(&mut cx, |_, cx| update.spawn(cx)) else { return; };
-                while let Ok(update_task_result) = task_handle.task_finish_rx.recv().await {
-                    let Ok(()) = editor.update(&mut cx, |editor, cx| {
-                        let multi_buffer_snapshot = update_task_result.multi_buffer.read(cx).snapshot(cx);
-                        let inlay_hint_cache = &mut editor.inlay_hint_cache;
-
-                        if let Some(new_allowed_hint_kinds) = update_task_result.new_allowed_hint_kinds {
-                            inlay_hint_cache.allowed_hint_kinds = new_allowed_hint_kinds;
-                        }
 
-                        inlay_hint_cache.hints_in_buffers.retain(|_, buffer_hints| {
-                            buffer_hints.hints_per_excerpt.retain(|_, excerpt_hints| {
-                                excerpt_hints.retain(|(_, hint_id)| !update_task_result.remove_from_cache.contains(hint_id));
-                                !excerpt_hints.is_empty()
-                            });
-                            !buffer_hints.hints_per_excerpt.is_empty()
-                        });
-                        inlay_hint_cache.inlay_hints.retain(|hint_id, _| !update_task_result.remove_from_cache.contains(hint_id));
-
-                        for (new_buffer_id, new_buffer_inlays) in update_task_result.add_to_cache {
-                            let cached_buffer_hints = inlay_hint_cache.hints_in_buffers.entry(new_buffer_id).or_insert_with(|| BufferHints::new(new_buffer_inlays.buffer_version));
-                            if cached_buffer_hints.buffer_version.changed_since(&new_buffer_inlays.buffer_version) {
-                                continue;
-                            }
-                            for (excerpt_id, new_excerpt_inlays) in new_buffer_inlays.hints_per_excerpt {
-                                let cached_excerpt_hints = cached_buffer_hints.hints_per_excerpt.entry(excerpt_id).or_default();
-                                for (new_hint_position, new_hint, new_inlay_id) in new_excerpt_inlays {
-                                    if let hash_map::Entry::Vacant(v) = inlay_hint_cache.inlay_hints.entry(new_inlay_id) {
-                                        v.insert(new_hint);
-                                        match cached_excerpt_hints.binary_search_by(|probe| {
-                                            new_hint_position.cmp(&probe.0, &multi_buffer_snapshot)
-                                        }) {
-                                            Ok(ix) | Err(ix) => cached_excerpt_hints.insert(ix, (new_hint_position, new_inlay_id)),
+                if let Some(update) = update.take() {
+                    let (run_tx, run_rx) = smol::channel::unbounded();
+                    let mut update_handle = std::pin::pin!(update.run(run_tx).fuse());
+                    loop {
+                        futures::select_biased! {
+                            update_result = run_rx.recv().fuse() => {
+                                match update_result {
+                                    Ok(update_result) => {
+                                        if let Err(_) = update_results_tx.send(update_result).await {
+                                            return
                                         }
                                     }
+                                    Err(_) => break,
                                 }
                             }
+                            _ = &mut update_handle => {
+                                while let Ok(update_result) = run_rx.try_recv() {
+                                    if let Err(_) = update_results_tx.send(update_result).await {
+                                        return
+                                    }
+                                }
+                                break
+                            },
                         }
-
-                        let InlaySplice {
-                            to_remove,
-                            to_insert,
-                        } = update_task_result.splice;
-                        editor.splice_inlay_hints(to_remove, to_insert, cx)
-                    }) else { return; };
+                    }
                 }
+                update = next_update.take();
             }
-            update = next_update.take();
-        }
-    })
-    .detach()
+        })
+        .detach()
 }
 
-fn update_allowed_hint_kinds(
+fn new_allowed_hint_kinds_splice(
     multi_buffer_snapshot: &MultiBufferSnapshot,
     current_inlays: Vec<Inlay>,
-    old_kinds: HashSet<Option<InlayHintKind>>,
-    new_kinds: HashSet<Option<InlayHintKind>>,
-    editor: &mut Editor,
+    hints_cache: &CacheSnapshot,
+    new_kinds: &HashSet<Option<InlayHintKind>>,
 ) -> Option<InlaySplice> {
+    let old_kinds = &hints_cache.allowed_hint_kinds;
     if old_kinds == new_kinds {
         return None;
     }
 
     let mut to_remove = Vec::new();
     let mut to_insert = Vec::new();
-    let mut shown_hints_to_remove = group_inlays(&multi_buffer_snapshot, current_inlays);
-    let hints_cache = &editor.inlay_hint_cache;
+    let mut shown_hints_to_remove = group_inlays(current_inlays);
 
     for (buffer_id, cached_buffer_hints) in &hints_cache.hints_in_buffers {
         let shown_buffer_hints_to_remove = shown_hints_to_remove.entry(*buffer_id).or_default();
@@ -528,32 +589,6 @@ fn update_allowed_hint_kinds(
     })
 }
 
-fn clean_cache(editor: &mut Editor, current_inlays: Vec<Inlay>) -> Option<InlaySplice> {
-    let hints_cache = &mut editor.inlay_hint_cache;
-    if hints_cache.inlay_hints.is_empty() {
-        None
-    } else {
-        let splice = InlaySplice {
-            to_remove: current_inlays
-                .iter()
-                .filter(|inlay| {
-                    editor
-                        .copilot_state
-                        .suggestion
-                        .as_ref()
-                        .map(|inlay| inlay.id)
-                        != Some(inlay.id)
-                })
-                .map(|inlay| inlay.id)
-                .collect(),
-            to_insert: Vec::new(),
-        };
-        hints_cache.inlay_hints.clear();
-        hints_cache.hints_in_buffers.clear();
-        Some(splice)
-    }
-}
-
 fn allowed_hint_types(
     inlay_hint_settings: editor_settings::InlayHints,
 ) -> HashSet<Option<InlayHintKind>> {
@@ -649,10 +684,7 @@ fn fetch_queries(
     })
 }
 
-fn group_inlays(
-    multi_buffer_snapshot: &MultiBufferSnapshot,
-    inlays: Vec<Inlay>,
-) -> HashMap<u64, HashMap<ExcerptId, Vec<(Anchor, InlayId)>>> {
+fn group_inlays(inlays: Vec<Inlay>) -> HashMap<u64, HashMap<ExcerptId, Vec<(Anchor, InlayId)>>> {
     inlays.into_iter().fold(
         HashMap::<u64, HashMap<ExcerptId, Vec<(Anchor, InlayId)>>>::default(),
         |mut current_hints, inlay| {
@@ -669,168 +701,168 @@ fn group_inlays(
     )
 }
 
-async fn update_hints(
-    multi_buffer: ModelHandle<MultiBuffer>,
-    queries: Vec<InlayHintQuery>,
-    current_inlays: Vec<Inlay>,
-    invalidate_cache: bool,
-    cx: &mut ViewContext<'_, '_, Editor>,
-) -> Option<InlaySplice> {
-    let fetch_queries_task = fetch_queries(multi_buffer, queries.into_iter(), cx);
-    let new_hints = fetch_queries_task.await.context("inlay hints fetch")?;
-
-    let mut to_remove = Vec::new();
-    let mut to_insert = Vec::new();
-    let mut cache_hints_to_persist: HashMap<u64, (Global, HashMap<ExcerptId, HashSet<InlayId>>)> =
-        HashMap::default();
-
-    editor.update(&mut cx, |editor, cx| {
-        let multi_buffer_snapshot = task_multi_buffer.read(cx).snapshot(cx);
-        for (new_buffer_id, new_hints_per_buffer) in new_hints {
-            let cached_buffer_hints = editor
-                .inlay_hint_cache
-                .hints_in_buffers
-                .entry(new_buffer_id)
-                .or_insert_with(|| {
-                    BufferHints::new(new_hints_per_buffer.buffer_version.clone())
-                });
-
-            let buffer_cache_hints_to_persist =
-                cache_hints_to_persist.entry(new_buffer_id).or_insert_with(|| (new_hints_per_buffer.buffer_version.clone(), HashMap::default()));
-            if cached_buffer_hints
-                .buffer_version
-                .changed_since(&new_hints_per_buffer.buffer_version)
-            {
-                buffer_cache_hints_to_persist.0 = new_hints_per_buffer.buffer_version;
-                buffer_cache_hints_to_persist.1.extend(
-                    cached_buffer_hints.hints_per_excerpt.iter().map(
-                        |(excerpt_id, excerpt_hints)| {
-                            (
-                                *excerpt_id,
-                                excerpt_hints.iter().map(|(_, id)| *id).collect(),
-                            )
-                        },
-                    ),
-                );
-                continue;
-            }
-
-            let shown_buffer_hints = currently_shown_hints.get(&new_buffer_id);
-            for (new_excerpt_id, new_hints_per_excerpt) in
-                new_hints_per_buffer.hints_per_excerpt
-            {
-                let excerpt_cache_hints_to_persist = buffer_cache_hints_to_persist.1
-                    .entry(new_excerpt_id)
-                    .or_default();
-                let cached_excerpt_hints = cached_buffer_hints
-                    .hints_per_excerpt
-                    .entry(new_excerpt_id)
-                    .or_default();
-                let empty_shown_excerpt_hints = Vec::new();
-                let shown_excerpt_hints = shown_buffer_hints.and_then(|hints| hints.get(&new_excerpt_id)).unwrap_or(&empty_shown_excerpt_hints);
-                for new_hint in new_hints_per_excerpt {
-                    let new_hint_anchor = multi_buffer_snapshot
-                        .anchor_in_excerpt(new_excerpt_id, new_hint.position);
-                    let cache_insert_ix = match cached_excerpt_hints.binary_search_by(|probe| {
-                        new_hint_anchor.cmp(&probe.0, &multi_buffer_snapshot)
-                    }) {
-                        Ok(ix) => {
-                            let (_, cached_inlay_id) = cached_excerpt_hints[ix];
-                            let cache_hit = editor
-                                .inlay_hint_cache
-                                .inlay_hints
-                                .get(&cached_inlay_id)
-                                .filter(|cached_hint| cached_hint == &&new_hint)
-                                .is_some();
-                            if cache_hit {
-                                excerpt_cache_hints_to_persist
-                                    .insert(cached_inlay_id);
-                                None
-                            } else {
-                                Some(ix)
-                            }
-                        }
-                        Err(ix) => Some(ix),
-                    };
-
-                    let shown_inlay_id = match shown_excerpt_hints.binary_search_by(|probe| {
-                        probe.0.cmp(&new_hint_anchor, &multi_buffer_snapshot)
-                    }) {
-                        Ok(ix) => {{
-                            let (_, shown_inlay_id) = shown_excerpt_hints[ix];
-                            let shown_hint_found =  editor.inlay_hint_cache.inlay_hints.get(&shown_inlay_id)
-                                .filter(|cached_hint| cached_hint == &&new_hint).is_some();
-                            if shown_hint_found {
-                                Some(shown_inlay_id)
-                            } else {
-                                None
-                            }
-                        }},
-                        Err(_) => None,
-                    };
-
-                    if let Some(insert_ix) = cache_insert_ix {
-                        let hint_id = match shown_inlay_id {
-                            Some(shown_inlay_id) => shown_inlay_id,
-                            None => {
-                                let new_hint_id = InlayId(post_inc(&mut editor.next_inlay_id));
-                                if editor.inlay_hint_cache.allowed_hint_kinds.contains(&new_hint.kind)
-                                {
-                                    to_insert.push((new_hint_id, new_hint_anchor, new_hint.clone()));
-                                }
-                                new_hint_id
-                            }
-                        };
-                        excerpt_cache_hints_to_persist.insert(hint_id);
-                        cached_excerpt_hints.insert(insert_ix, (new_hint_anchor, hint_id));
-                        editor
-                            .inlay_hint_cache
-                            .inlay_hints
-                            .insert(hint_id, new_hint);
-                    }
-                }
-            }
-        }
-
-        if conflicts_with_cache {
-            for (shown_buffer_id, mut shown_hints_to_clean) in currently_shown_hints {
-                match cache_hints_to_persist.get(&shown_buffer_id) {
-                    Some(cached_buffer_hints) => {
-                        for (persisted_id, cached_hints) in &cached_buffer_hints.1 {
-                            shown_hints_to_clean.entry(*persisted_id).or_default()
-                                .retain(|(_, shown_id)| !cached_hints.contains(shown_id));
-                        }
-                    },
-                    None => {},
-                }
-                to_remove.extend(shown_hints_to_clean.into_iter()
-                    .flat_map(|(_, excerpt_hints)| excerpt_hints.into_iter().map(|(_, hint_id)| hint_id)));
-            }
-
-            editor.inlay_hint_cache.hints_in_buffers.retain(|buffer_id, buffer_hints| {
-                let Some(mut buffer_hints_to_persist) = cache_hints_to_persist.remove(buffer_id) else { return false; };
-                buffer_hints.buffer_version = buffer_hints_to_persist.0;
-                buffer_hints.hints_per_excerpt.retain(|excerpt_id, excerpt_hints| {
-                    let Some(excerpt_hints_to_persist) = buffer_hints_to_persist.1.remove(&excerpt_id) else { return false; };
-                    excerpt_hints.retain(|(_, hint_id)| {
-                        let retain = excerpt_hints_to_persist.contains(hint_id);
-                        if !retain {
-                            editor
-                                .inlay_hint_cache
-                                .inlay_hints
-                                .remove(hint_id);
-                        }
-                        retain
-                    });
-                    !excerpt_hints.is_empty()
-                });
-                !buffer_hints.hints_per_excerpt.is_empty()
-            });
-        }
-
-        Some(InlaySplice {
-            to_remove,
-            to_insert,
-        })
-    })
-}
+// async fn update_hints(
+//     multi_buffer: ModelHandle<MultiBuffer>,
+//     queries: Vec<InlayHintQuery>,
+//     current_inlays: Vec<Inlay>,
+//     invalidate_cache: bool,
+//     cx: &mut ViewContext<'_, '_, Editor>,
+// ) -> Option<InlaySplice> {
+//     let fetch_queries_task = fetch_queries(multi_buffer, queries.into_iter(), cx);
+//     let new_hints = fetch_queries_task.await.context("inlay hints fetch")?;
+
+//     let mut to_remove = Vec::new();
+//     let mut to_insert = Vec::new();
+//     let mut cache_hints_to_persist: HashMap<u64, (Global, HashMap<ExcerptId, HashSet<InlayId>>)> =
+//         HashMap::default();
+
+//     editor.update(&mut cx, |editor, cx| {
+//         let multi_buffer_snapshot = task_multi_buffer.read(cx).snapshot(cx);
+//         for (new_buffer_id, new_hints_per_buffer) in new_hints {
+//             let cached_buffer_hints = editor
+//                 .inlay_hint_cache
+//                 .hints_in_buffers
+//                 .entry(new_buffer_id)
+//                 .or_insert_with(|| {
+//                     BufferHints::new(new_hints_per_buffer.buffer_version.clone())
+//                 });
+
+//             let buffer_cache_hints_to_persist =
+//                 cache_hints_to_persist.entry(new_buffer_id).or_insert_with(|| (new_hints_per_buffer.buffer_version.clone(), HashMap::default()));
+//             if cached_buffer_hints
+//                 .buffer_version
+//                 .changed_since(&new_hints_per_buffer.buffer_version)
+//             {
+//                 buffer_cache_hints_to_persist.0 = new_hints_per_buffer.buffer_version;
+//                 buffer_cache_hints_to_persist.1.extend(
+//                     cached_buffer_hints.hints_per_excerpt.iter().map(
+//                         |(excerpt_id, excerpt_hints)| {
+//                             (
+//                                 *excerpt_id,
+//                                 excerpt_hints.iter().map(|(_, id)| *id).collect(),
+//                             )
+//                         },
+//                     ),
+//                 );
+//                 continue;
+//             }
+
+//             let shown_buffer_hints = currently_shown_hints.get(&new_buffer_id);
+//             for (new_excerpt_id, new_hints_per_excerpt) in
+//                 new_hints_per_buffer.hints_per_excerpt
+//             {
+//                 let excerpt_cache_hints_to_persist = buffer_cache_hints_to_persist.1
+//                     .entry(new_excerpt_id)
+//                     .or_default();
+//                 let cached_excerpt_hints = cached_buffer_hints
+//                     .hints_per_excerpt
+//                     .entry(new_excerpt_id)
+//                     .or_default();
+//                 let empty_shown_excerpt_hints = Vec::new();
+//                 let shown_excerpt_hints = shown_buffer_hints.and_then(|hints| hints.get(&new_excerpt_id)).unwrap_or(&empty_shown_excerpt_hints);
+//                 for new_hint in new_hints_per_excerpt {
+//                     let new_hint_anchor = multi_buffer_snapshot
+//                         .anchor_in_excerpt(new_excerpt_id, new_hint.position);
+//                     let cache_insert_ix = match cached_excerpt_hints.binary_search_by(|probe| {
+//                         new_hint_anchor.cmp(&probe.0, &multi_buffer_snapshot)
+//                     }) {
+//                         Ok(ix) => {
+//                             let (_, cached_inlay_id) = cached_excerpt_hints[ix];
+//                             let cache_hit = editor
+//                                 .inlay_hint_cache
+//                                 .inlay_hints
+//                                 .get(&cached_inlay_id)
+//                                 .filter(|cached_hint| cached_hint == &&new_hint)
+//                                 .is_some();
+//                             if cache_hit {
+//                                 excerpt_cache_hints_to_persist
+//                                     .insert(cached_inlay_id);
+//                                 None
+//                             } else {
+//                                 Some(ix)
+//                             }
+//                         }
+//                         Err(ix) => Some(ix),
+//                     };
+
+//                     let shown_inlay_id = match shown_excerpt_hints.binary_search_by(|probe| {
+//                         probe.0.cmp(&new_hint_anchor, &multi_buffer_snapshot)
+//                     }) {
+//                         Ok(ix) => {{
+//                             let (_, shown_inlay_id) = shown_excerpt_hints[ix];
+//                             let shown_hint_found =  editor.inlay_hint_cache.inlay_hints.get(&shown_inlay_id)
+//                                 .filter(|cached_hint| cached_hint == &&new_hint).is_some();
+//                             if shown_hint_found {
+//                                 Some(shown_inlay_id)
+//                             } else {
+//                                 None
+//                             }
+//                         }},
+//                         Err(_) => None,
+//                     };
+
+//                     if let Some(insert_ix) = cache_insert_ix {
+//                         let hint_id = match shown_inlay_id {
+//                             Some(shown_inlay_id) => shown_inlay_id,
+//                             None => {
+//                                 let new_hint_id = InlayId(post_inc(&mut editor.next_inlay_id));
+//                                 if editor.inlay_hint_cache.allowed_hint_kinds.contains(&new_hint.kind)
+//                                 {
+//                                     to_insert.push((new_hint_id, new_hint_anchor, new_hint.clone()));
+//                                 }
+//                                 new_hint_id
+//                             }
+//                         };
+//                         excerpt_cache_hints_to_persist.insert(hint_id);
+//                         cached_excerpt_hints.insert(insert_ix, (new_hint_anchor, hint_id));
+//                         editor
+//                             .inlay_hint_cache
+//                             .inlay_hints
+//                             .insert(hint_id, new_hint);
+//                     }
+//                 }
+//             }
+//         }
+
+//         if conflicts_with_cache {
+//             for (shown_buffer_id, mut shown_hints_to_clean) in currently_shown_hints {
+//                 match cache_hints_to_persist.get(&shown_buffer_id) {
+//                     Some(cached_buffer_hints) => {
+//                         for (persisted_id, cached_hints) in &cached_buffer_hints.1 {
+//                             shown_hints_to_clean.entry(*persisted_id).or_default()
+//                                 .retain(|(_, shown_id)| !cached_hints.contains(shown_id));
+//                         }
+//                     },
+//                     None => {},
+//                 }
+//                 to_remove.extend(shown_hints_to_clean.into_iter()
+//                     .flat_map(|(_, excerpt_hints)| excerpt_hints.into_iter().map(|(_, hint_id)| hint_id)));
+//             }
+
+//             editor.inlay_hint_cache.hints_in_buffers.retain(|buffer_id, buffer_hints| {
+//                 let Some(mut buffer_hints_to_persist) = cache_hints_to_persist.remove(buffer_id) else { return false; };
+//                 buffer_hints.buffer_version = buffer_hints_to_persist.0;
+//                 buffer_hints.hints_per_excerpt.retain(|excerpt_id, excerpt_hints| {
+//                     let Some(excerpt_hints_to_persist) = buffer_hints_to_persist.1.remove(&excerpt_id) else { return false; };
+//                     excerpt_hints.retain(|(_, hint_id)| {
+//                         let retain = excerpt_hints_to_persist.contains(hint_id);
+//                         if !retain {
+//                             editor
+//                                 .inlay_hint_cache
+//                                 .inlay_hints
+//                                 .remove(hint_id);
+//                         }
+//                         retain
+//                     });
+//                     !excerpt_hints.is_empty()
+//                 });
+//                 !buffer_hints.hints_per_excerpt.is_empty()
+//             });
+//         }
+
+//         Some(InlaySplice {
+//             to_remove,
+//             to_insert,
+//         })
+//     })
+// }