diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index fac7d4033b9089588eba6561600cb82867000797..9bd9e3daebd1a226ff221fe4c08300f0996be4b8 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -2596,81 +2596,106 @@ impl Editor { return; } + struct HintRequestKey { + buffer_id: u64, + buffer_version: Global, + excerpt_id: ExcerptId, + } + let multi_buffer = self.buffer(); let multi_buffer_snapshot = multi_buffer.read(cx).snapshot(cx); let hint_fetch_tasks = multi_buffer_snapshot .excerpts() - .filter_map(|(excerpt_id, buffer_snapshot, excerpt_range)| { + .map(|(excerpt_id, buffer_snapshot, excerpt_range)| { // TODO kb every time I reopen the same buffer, it's different. // Find a way to understand it's the same buffer. Use paths? let buffer_id = buffer_snapshot.remote_id(); let buffer_version = buffer_snapshot.version().clone(); - let buffer_handle = multi_buffer.read(cx).buffer(buffer_id)?; - if self - .inlay_hint_cache - .inlays_up_to_date(buffer_id, &buffer_version, excerpt_id) - { - return None; - } + let buffer_handle = multi_buffer.read(cx).buffer(buffer_id); + let hints_up_to_date = + self.inlay_hint_cache + .inlays_up_to_date(buffer_id, &buffer_version, excerpt_id); + let key = HintRequestKey { + buffer_id, + buffer_version, + excerpt_id, + }; - let task = cx.spawn(|editor, mut cx| async move { - let task = editor - .update(&mut cx, |editor, cx| { - editor.project.as_ref().map(|project| { - project.update(cx, |project, cx| { - project.inlay_hints_for_buffer( - buffer_handle, - excerpt_range.context, - cx, - ) + cx.spawn(|editor, mut cx| async move { + if hints_up_to_date { + anyhow::Ok((key, None)) + } else { + let Some(buffer_handle) = buffer_handle else { return Ok((key, Some(Vec::new()))) }; + let max_buffer_offset = cx.read(|cx| buffer_handle.read(cx).len()); + let excerpt_range = excerpt_range.context; + let query_start = excerpt_range.start.offset; + let query_end = excerpt_range.end.offset.min(max_buffer_offset); + let task = editor + .update(&mut cx, |editor, cx| { + editor.project.as_ref().map(|project| { + project.update(cx, |project, cx| { + project.inlay_hints_for_buffer( + buffer_handle, + query_start..query_end, + cx, + ) + }) }) }) - }) - .context("inlay hints fecth task spawn")?; - - anyhow::Ok(( - buffer_id, - buffer_version, - excerpt_id, - match task { - Some(task) => task.await.context("inlay hints for buffer task")?, + .context("inlay hints fecth task spawn")?; + + Ok((key, Some(match task { + Some(task) => { + let mut new_hints = task.await.context("inlay hints for buffer task")?; + new_hints.retain(|hint| { + let hint_offset = hint.position.offset; + query_start <= hint_offset && hint_offset <= query_end + }); + new_hints + }, None => Vec::new(), - }, - )) - }); - Some(task) + }))) + } + }) }) .collect::>(); cx.spawn(|editor, mut cx| async move { - let mut hints_response: HashMap< + let mut inlay_updates: HashMap< u64, - (Global, HashMap>), + ( + Global, + HashMap>>, + ), > = 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(hint_fetch_tasks).await { match task_result { - Ok((buffer_id, buffer_version, excerpt_id, excerpt_hints)) => { + Ok((request_key, response_inlays)) => { let excerpt_hints_response = HashMap::from_iter([( - excerpt_id, - excerpt_hints.into_iter().fold( - OrderedByAnchorOffset::default(), - |mut ordered_hints, hint| { - let anchor = multi_buffer_snapshot - .anchor_in_excerpt(excerpt_id, hint.position); - ordered_hints.add(anchor, hint); - ordered_hints - }, - ), + request_key.excerpt_id, + response_inlays.map(|excerpt_hints| { + excerpt_hints.into_iter().fold( + OrderedByAnchorOffset::default(), + |mut ordered_hints, hint| { + let anchor = multi_buffer_snapshot.anchor_in_excerpt( + request_key.excerpt_id, + hint.position, + ); + ordered_hints.add(anchor, hint); + ordered_hints + }, + ) + }), )]); - match hints_response.entry(buffer_id) { + match inlay_updates.entry(request_key.buffer_id) { hash_map::Entry::Occupied(mut o) => { o.get_mut().1.extend(excerpt_hints_response); } hash_map::Entry::Vacant(v) => { - v.insert((buffer_version, excerpt_hints_response)); + v.insert((request_key.buffer_version, excerpt_hints_response)); } } } @@ -2678,12 +2703,12 @@ impl Editor { } } - if !hints_response.is_empty() { + if !inlay_updates.is_empty() { let InlaysUpdate { to_remove, to_insert, } = editor.update(&mut cx, |editor, _| { - editor.inlay_hint_cache.update_inlays(hints_response) + editor.inlay_hint_cache.update_inlays(inlay_updates) })?; editor.update(&mut cx, |editor, cx| { @@ -7244,7 +7269,7 @@ impl Editor { } multi_buffer::Event::Reparsed => { cx.emit(Event::Reparsed); - true + false } multi_buffer::Event::DirtyChanged => { cx.emit(Event::DirtyChanged); diff --git a/crates/editor/src/inlay_cache.rs b/crates/editor/src/inlay_cache.rs index e5c48dcba2f7f7350956680bf4df54f0aa13f510..d1b14f33428378b617151a7381512ac366d79987 100644 --- a/crates/editor/src/inlay_cache.rs +++ b/crates/editor/src/inlay_cache.rs @@ -1,7 +1,7 @@ use std::cmp; use crate::{Anchor, ExcerptId}; -use clock::Global; +use clock::{Global, Local}; use project::InlayHint; use util::post_inc; @@ -13,12 +13,22 @@ pub struct InlayCache { 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(pub BTreeMap); +pub struct OrderedByAnchorOffset(pub BTreeMap); impl OrderedByAnchorOffset { pub fn add(&mut self, anchor: Anchor, t: T) { - self.0.insert(anchor.text_anchor.offset, (anchor, 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 { @@ -62,13 +72,19 @@ impl InlayCache { pub fn update_inlays( &mut self, - new_inlays: HashMap>)>, + inlay_updates: HashMap< + u64, + ( + Global, + HashMap>>, + ), + >, ) -> InlaysUpdate { let mut old_inlays = self.inlays_per_buffer.clone(); let mut to_remove = Vec::new(); let mut to_insert = Vec::new(); - for (buffer_id, (buffer_version, new_buffer_inlays)) in new_inlays { + for (buffer_id, (buffer_version, new_buffer_inlays)) in inlay_updates { match old_inlays.remove(&buffer_id) { Some(mut old_buffer_inlays) => { for (excerpt_id, new_excerpt_inlays) in new_buffer_inlays { @@ -80,8 +96,12 @@ impl InlayCache { .inlays_per_buffer .get_mut(&buffer_id) .expect("element expected: `old_inlays.remove` returned `Some`"); - let mut new_excerpt_inlays = - new_excerpt_inlays.into_ordered_elements().fuse().peekable(); + let mut new_excerpt_inlays = match new_excerpt_inlays { + Some(new_inlays) => { + new_inlays.into_ordered_elements().fuse().peekable() + } + None => continue, + }; if old_buffer_inlays .inlays_per_excerpts .remove(&excerpt_id) @@ -168,13 +188,17 @@ impl InlayCache { OrderedByAnchorOffset<(InlayId, InlayHint)>, > = HashMap::default(); for (new_excerpt_id, new_ordered_inlays) in new_buffer_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)); + 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(