Cache anchors from all versions, remove out of range hints
This commit is contained in:
+73
-48
@@ -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")?;
|
||||
.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")?,
|
||||
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::<Vec<_>>();
|
||||
|
||||
cx.spawn(|editor, mut cx| async move {
|
||||
let mut hints_response: HashMap<
|
||||
let mut inlay_updates: HashMap<
|
||||
u64,
|
||||
(Global, HashMap<ExcerptId, OrderedByAnchorOffset<InlayHint>>),
|
||||
(
|
||||
Global,
|
||||
HashMap<ExcerptId, Option<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(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);
|
||||
|
||||
@@ -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<T>(pub BTreeMap<usize, (Anchor, T)>);
|
||||
pub struct OrderedByAnchorOffset<T>(pub BTreeMap<AnchorKey, (Anchor, T)>);
|
||||
|
||||
impl<T> OrderedByAnchorOffset<T> {
|
||||
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<Item = (Anchor, T)> {
|
||||
@@ -62,13 +72,19 @@ impl InlayCache {
|
||||
|
||||
pub fn update_inlays(
|
||||
&mut self,
|
||||
new_inlays: HashMap<u64, (Global, HashMap<ExcerptId, OrderedByAnchorOffset<InlayHint>>)>,
|
||||
inlay_updates: HashMap<
|
||||
u64,
|
||||
(
|
||||
Global,
|
||||
HashMap<ExcerptId, Option<OrderedByAnchorOffset<InlayHint>>>,
|
||||
),
|
||||
>,
|
||||
) -> 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(
|
||||
|
||||
Reference in New Issue
Block a user