diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index cc4978a5dadc1b19a61f419938d64a07ef953580..5e8237b8323c9707f8c27f661ea79c1e56474b99 100644 --- a/crates/editor/src/editor.rs +++ b/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::>(); 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, cx: &mut ViewContext<'_, '_, Editor>, ) -> Vec<(ModelHandle, Range, 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 diff --git a/crates/editor/src/inlay_hint_cache.rs b/crates/editor/src/inlay_hint_cache.rs index 1058266771041b594e681c71d6e8b5bdb76bc26b..0d03787d24b5b4f68ea35be03cdc99773b6d1c89 100644 --- a/crates/editor/src/inlay_hint_cache.rs +++ b/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, } +#[derive(Debug)] +struct CacheSnapshot { + inlay_hints: HashMap, + hints_in_buffers: HashMap>, + allowed_hint_kinds: HashSet>, +} + #[derive(Clone, Debug)] struct BufferHints { buffer_version: Global, @@ -49,7 +56,82 @@ impl InlayHintCache { cx: &mut ViewContext, ) -> 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, + multi_buffer_snapshot: MultiBufferSnapshot, inlay_hint_settings: editor_settings::InlayHints, current_inlays: Vec, ) { @@ -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, + multi_buffer_snapshot: MultiBufferSnapshot, queries: Vec, current_inlays: Vec, conflicts_invalidate_cache: bool, - cx: &mut ViewContext, ) { 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, - current_inlays: Vec, + multi_buffer_snapshot: MultiBufferSnapshot, + visible_inlays: Vec, + cache: CacheSnapshot, kind: HintsUpdateKind, } enum HintsUpdateKind { Clean, AllowedHintKindsChanged { - old: HashSet>, new: HashSet>, }, BufferUpdate { @@ -207,14 +300,7 @@ enum HintsUpdateKind { }, } -struct UpdateTaskHandle { - multi_buffer: ModelHandle, - cancellation_tx: smol::channel::Sender<()>, - task_finish_rx: smol::channel::Receiver, -} - -struct UpdateTaskResult { - multi_buffer: ModelHandle, +struct UpdateResult { splice: InlaySplice, new_allowed_hint_kinds: Option>>, remove_from_cache: HashSet, @@ -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::>(); let new_inlays = other - .current_inlays + .visible_inlays .iter() .map(|inlay| inlay.id) .collect::>(); @@ -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) { 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::>(); + while let Some(update) = tasks.next().await { + todo!("TODO kb") + } + } } } } fn spawn_hints_update_loop( hint_updates_rx: smol::channel::Receiver, + update_results_tx: smol::channel::Sender, cx: &mut ViewContext<'_, '_, Editor>, ) { - cx.spawn(|editor, mut cx| async move { - let mut update = None::; - let mut next_update = None::; - 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::; + let mut next_update = None::; + 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, - old_kinds: HashSet>, - new_kinds: HashSet>, - editor: &mut Editor, + hints_cache: &CacheSnapshot, + new_kinds: &HashSet>, ) -> Option { + 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) -> Option { - 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> { @@ -649,10 +684,7 @@ fn fetch_queries( }) } -fn group_inlays( - multi_buffer_snapshot: &MultiBufferSnapshot, - inlays: Vec, -) -> HashMap>> { +fn group_inlays(inlays: Vec) -> HashMap>> { inlays.into_iter().fold( HashMap::>>::default(), |mut current_hints, inlay| { @@ -669,168 +701,168 @@ fn group_inlays( ) } -async fn update_hints( - multi_buffer: ModelHandle, - queries: Vec, - current_inlays: Vec, - invalidate_cache: bool, - cx: &mut ViewContext<'_, '_, Editor>, -) -> Option { - 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>)> = - 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, +// queries: Vec, +// current_inlays: Vec, +// invalidate_cache: bool, +// cx: &mut ViewContext<'_, '_, Editor>, +// ) -> Option { +// 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>)> = +// 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, +// }) +// }) +// }