Finish rest of the inlay cache logic

This commit is contained in:
Kirill Bulatov
2023-06-29 22:25:49 +03:00
parent ddcbc73bf0
commit debdc3603e
2 changed files with 151 additions and 45 deletions
+1 -1
View File
@@ -2700,7 +2700,7 @@ impl Editor {
.update(&mut cx, |editor, cx| {
editor.inlay_hint_cache.replace_hints(
multi_buffer_handle,
replacement_queries.into_iter(),
replacement_queries,
currently_shown_inlay_hints,
cx,
)
+150 -44
View File
@@ -1,4 +1,4 @@
use std::ops::Range;
use std::{cmp, ops::Range};
use crate::{
editor_settings, scroll::ScrollAnchor, Anchor, Editor, ExcerptId, InlayId, MultiBuffer,
@@ -63,6 +63,7 @@ pub struct InlaySplice {
pub to_insert: Vec<(InlayId, Anchor, InlayHint)>,
}
#[derive(Debug)]
pub struct InlayHintQuery {
pub buffer_id: u64,
pub buffer_version: Global,
@@ -186,6 +187,7 @@ impl InlayHintCache {
ids_to_remove
}
// TODO kb deduplicate into replace_hints?
pub fn append_hints(
&mut self,
multi_buffer: ModelHandle<MultiBuffer>,
@@ -230,29 +232,44 @@ impl InlayHintCache {
)
}
for new_hint in new_excerpt_hints.hints {
let hint_anchor = multi_buffer_snapshot
let new_hint_anchor = multi_buffer_snapshot
.anchor_in_excerpt(new_excerpt_id, new_hint.position);
let insert_ix =
match cached_excerpt_hints.hints.binary_search_by(|probe| {
hint_anchor.cmp(&probe.0, &multi_buffer_snapshot)
new_hint_anchor.cmp(&probe.0, &multi_buffer_snapshot)
}) {
Ok(ix) | Err(ix) => ix,
Ok(ix) => {
let (_, cached_inlay_id) = cached_excerpt_hints.hints[ix];
let cached_hint = editor
.inlay_hint_cache
.inlay_hints
.get(&cached_inlay_id)
.unwrap();
if cached_hint == &new_hint {
None
} else {
Some(ix)
}
}
Err(ix) => Some(ix),
};
let new_hint_id = InlayId(post_inc(&mut editor.next_inlay_id));
cached_excerpt_hints
.hints
.insert(insert_ix, (hint_anchor, new_hint_id));
editor
.inlay_hint_cache
.inlay_hints
.insert(new_hint_id, new_hint.clone());
if editor
.inlay_hint_cache
.allowed_hint_kinds
.contains(&new_hint.kind)
{
to_insert.push((new_hint_id, hint_anchor, new_hint));
if let Some(insert_ix) = insert_ix {
let new_hint_id = InlayId(post_inc(&mut editor.next_inlay_id));
cached_excerpt_hints
.hints
.insert(insert_ix, (new_hint_anchor, new_hint_id));
editor
.inlay_hint_cache
.inlay_hints
.insert(new_hint_id, new_hint.clone());
if editor
.inlay_hint_cache
.allowed_hint_kinds
.contains(&new_hint.kind)
{
to_insert.push((new_hint_id, new_hint_anchor, new_hint));
}
}
}
}
@@ -269,11 +286,11 @@ impl InlayHintCache {
pub fn replace_hints(
&mut self,
multi_buffer: ModelHandle<MultiBuffer>,
mut range_updates: impl Iterator<Item = InlayHintQuery>,
range_updates: Vec<InlayHintQuery>,
mut currently_shown_hints: HashMap<u64, HashMap<ExcerptId, Vec<(Anchor, InlayId)>>>,
cx: &mut ViewContext<Editor>,
) -> Task<anyhow::Result<InlaySplice>> {
let conflicts_with_cache = range_updates.any(|update_query| {
let conflicts_with_cache = range_updates.iter().any(|update_query| {
let Some(cached_buffer_hints) = self.hints_in_buffers.get(&update_query.buffer_id)
else { return false };
if cached_buffer_hints
@@ -293,7 +310,11 @@ impl InlayHintCache {
}
});
let queries = filter_queries(range_updates, &self.hints_in_buffers, conflicts_with_cache);
let queries = filter_queries(
range_updates.into_iter(),
&self.hints_in_buffers,
conflicts_with_cache,
);
let task_multi_buffer = multi_buffer.clone();
let fetch_queries_task = fetch_queries(multi_buffer, queries.into_iter(), cx);
let mut to_remove = Vec::new();
@@ -329,37 +350,115 @@ impl InlayHintCache {
.hints_per_excerpt
.entry(new_excerpt_id)
.or_default();
let shown_excerpt_hints = shown_buffer_hints
let mut shown_excerpt_hints = shown_buffer_hints
.remove(&new_excerpt_id)
.unwrap_or_default();
.unwrap_or_default()
.into_iter()
.fuse()
.peekable();
if conflicts_with_cache {
cached_excerpt_hints.cached_excerpt_offsets.clear();
// TODO kb need to add such into to_delete and do not cause extra changes
// cached_excerpt_hints.hints.clear();
// editor.inlay_hint_cache.inlay_hints.clear();
todo!("TODO kb")
} else {
for new_range in new_hints_per_excerpt.cached_excerpt_offsets {
insert_and_merge_ranges(
&mut cached_excerpt_hints.cached_excerpt_offsets,
&new_range,
)
}
for new_hint in new_hints_per_excerpt.hints {
let hint_anchor = multi_buffer_snapshot
.anchor_in_excerpt(new_excerpt_id, new_hint.position);
cached_excerpt_hints.hints.clear();
}
for new_hint in new_hints_per_excerpt.hints {
let new_hint_anchor = multi_buffer_snapshot
.anchor_in_excerpt(new_excerpt_id, new_hint.position);
let insert_ix = if conflicts_with_cache {
let mut no_matching_inlay_displayed = true;
loop {
match shown_excerpt_hints.peek() {
Some((shown_anchor, shown_id)) => {
match shown_anchor
.cmp(&new_hint_anchor, &multi_buffer_snapshot)
{
cmp::Ordering::Less => {
editor
.inlay_hint_cache
.inlay_hints
.remove(shown_id);
to_remove.push(*shown_id);
shown_excerpt_hints.next();
}
cmp::Ordering::Equal => {
match editor
.inlay_hint_cache
.inlay_hints
.get(shown_id)
{
Some(cached_hint)
if cached_hint == &new_hint =>
{
no_matching_inlay_displayed = false;
}
_ => to_remove.push(*shown_id),
}
shown_excerpt_hints.next();
break;
}
cmp::Ordering::Greater => break,
}
}
None => break,
}
}
if no_matching_inlay_displayed {
let insert_ix =
match cached_excerpt_hints.hints.binary_search_by(|probe| {
new_hint_anchor.cmp(&probe.0, &multi_buffer_snapshot)
}) {
Ok(ix) => {
let (_, cached_inlay_id) =
cached_excerpt_hints.hints[ix];
let cached_hint = editor
.inlay_hint_cache
.inlay_hints
.get(&cached_inlay_id)
.unwrap();
if cached_hint == &new_hint {
None
} else {
Some(ix)
}
}
Err(ix) => Some(ix),
};
insert_ix
} else {
None
}
} else {
let insert_ix =
match cached_excerpt_hints.hints.binary_search_by(|probe| {
hint_anchor.cmp(&probe.0, &multi_buffer_snapshot)
new_hint_anchor.cmp(&probe.0, &multi_buffer_snapshot)
}) {
Ok(ix) | Err(ix) => ix,
Ok(ix) => {
let (_, cached_inlay_id) =
cached_excerpt_hints.hints[ix];
let cached_hint = editor
.inlay_hint_cache
.inlay_hints
.get(&cached_inlay_id)
.unwrap();
if cached_hint == &new_hint {
None
} else {
Some(ix)
}
}
Err(ix) => Some(ix),
};
insert_ix
};
if let Some(insert_ix) = insert_ix {
let new_hint_id = InlayId(post_inc(&mut editor.next_inlay_id));
cached_excerpt_hints
.hints
.insert(insert_ix, (hint_anchor, new_hint_id));
.insert(insert_ix, (new_hint_anchor, new_hint_id));
editor
.inlay_hint_cache
.inlay_hints
@@ -369,11 +468,18 @@ impl InlayHintCache {
.allowed_hint_kinds
.contains(&new_hint.kind)
{
to_insert.push((new_hint_id, hint_anchor, new_hint));
to_insert.push((new_hint_id, new_hint_anchor, new_hint));
}
}
}
for new_range in new_hints_per_excerpt.cached_excerpt_offsets {
insert_and_merge_ranges(
&mut cached_excerpt_hints.cached_excerpt_offsets,
&new_range,
)
}
if cached_excerpt_hints.hints.is_empty() {
cached_buffer_hints
.hints_per_excerpt
@@ -521,7 +627,7 @@ fn insert_and_merge_ranges(cache: &mut Vec<Range<usize>>, new_range: &Range<usiz
// Check if the new range overlaps with the previous range in the cache
if index > 0 && cache[index - 1].end >= new_range.start {
// Merge with the previous range
cache[index - 1].end = std::cmp::max(cache[index - 1].end, new_range.end);
cache[index - 1].end = cmp::max(cache[index - 1].end, new_range.end);
} else {
// Insert the new range, as it doesn't overlap with the previous range
cache.insert(index, new_range.clone());
@@ -530,7 +636,7 @@ fn insert_and_merge_ranges(cache: &mut Vec<Range<usize>>, new_range: &Range<usiz
// Merge overlaps with subsequent ranges
let mut i = index;
while i + 1 < cache.len() && cache[i].end >= cache[i + 1].start {
cache[i].end = std::cmp::max(cache[i].end, cache[i + 1].end);
cache[i].end = cmp::max(cache[i].end, cache[i + 1].end);
cache.remove(i + 1);
i += 1;
}