Filter away new hints not in excerpt range

This commit is contained in:
Kirill Bulatov 2023-06-23 00:11:09 +03:00
parent 316e19ce94
commit 48982c3036

View file

@ -1,13 +1,16 @@
use std::cmp; use std::{cmp, ops::Range};
use crate::{display_map::Inlay, editor_settings, Anchor, Editor, ExcerptId, InlayId, MultiBuffer}; use crate::{
display_map::Inlay, editor_settings, Anchor, Editor, ExcerptId, InlayId, MultiBuffer,
MultiBufferSnapshot,
};
use anyhow::Context; use anyhow::Context;
use gpui::{ModelHandle, Task, ViewContext}; use gpui::{ModelHandle, Task, ViewContext};
use language::BufferSnapshot;
use log::error; use log::error;
use project::{InlayHint, InlayHintKind}; use project::{InlayHint, InlayHintKind};
use collections::{hash_map, HashMap, HashSet}; use collections::{hash_map, HashMap, HashSet};
use text::BufferSnapshot;
use util::post_inc; use util::post_inc;
pub struct InlayHintCache { pub struct InlayHintCache {
@ -39,6 +42,15 @@ pub struct HintsUpdateState {
cache: Box<CacheSnapshot>, cache: Box<CacheSnapshot>,
} }
#[derive(Debug, Clone)]
struct ExcerptQuery {
buffer_id: u64,
excerpt_id: ExcerptId,
excerpt_range: Range<language::Anchor>,
cache_version: usize,
invalidate_cache: bool,
}
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct InlaySplice { pub struct InlaySplice {
pub to_remove: Vec<InlayId>, pub to_remove: Vec<InlayId>,
@ -135,7 +147,7 @@ impl InlayHintCache {
let mut excerpts_to_query = editor let mut excerpts_to_query = editor
.excerpt_visible_offsets(cx) .excerpt_visible_offsets(cx)
.into_iter() .into_iter()
.map(|(buffer, _, excerpt_id)| (excerpt_id, buffer.read(cx).remote_id())) .map(|(buffer, _, excerpt_id)| (excerpt_id, buffer))
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();
let update_state = get_update_state(editor, cx); let update_state = get_update_state(editor, cx);
@ -160,19 +172,42 @@ impl InlayHintCache {
} }
}); });
for (excerpt_id, buffer_id) in excerpts_to_query { for (excerpt_id, buffer_handle) in excerpts_to_query {
let (multi_buffer_snapshot, excerpt_range) =
editor.buffer.update(cx, |multi_buffer, cx| {
let multi_buffer_snapshot = multi_buffer.snapshot(cx);
(
multi_buffer_snapshot,
multi_buffer
.excerpts_for_buffer(&buffer_handle, cx)
.into_iter()
.find(|(id, _)| id == &excerpt_id)
.map(|(_, range)| range.context),
)
});
if let Some(excerpt_range) = excerpt_range {
let buffer = buffer_handle.read(cx);
let buffer_snapshot = buffer.snapshot();
let query = ExcerptQuery {
buffer_id: buffer.remote_id(),
excerpt_id,
excerpt_range,
cache_version,
invalidate_cache,
};
update_tasks.insert( update_tasks.insert(
excerpt_id, excerpt_id,
new_update_task( new_update_task(
buffer_id, query,
excerpt_id,
cache_version,
update_state.clone(), update_state.clone(),
invalidate_cache, multi_buffer_snapshot,
buffer_snapshot,
cx, cx,
), ),
); );
} }
}
}) })
.ok(); .ok();
}) })
@ -192,25 +227,16 @@ impl InlayHintCache {
} }
fn new_update_task( fn new_update_task(
buffer_id: u64, query: ExcerptQuery,
excerpt_id: ExcerptId,
cache_version: usize,
state: HintsUpdateState, state: HintsUpdateState,
invalidate_cache: bool, multi_buffer_snapshot: MultiBufferSnapshot,
buffer_snapshot: BufferSnapshot,
cx: &mut ViewContext<'_, '_, Editor>, cx: &mut ViewContext<'_, '_, Editor>,
) -> InlayHintUpdateTask { ) -> InlayHintUpdateTask {
let hints_fetch_task = hints_fetch_task(buffer_id, excerpt_id, cx); let hints_fetch_task = hints_fetch_task(query.clone(), cx);
InlayHintUpdateTask { InlayHintUpdateTask {
version: cache_version, version: query.cache_version,
_task: cx.spawn(|editor, mut cx| async move { _task: cx.spawn(|editor, mut cx| async move {
let Some((multi_buffer_snapshot, buffer_snapshot)) = editor
.update(&mut cx, |editor, cx| {
let multi_buffer = editor.buffer().read(cx);
let multi_buffer_snapshot = multi_buffer.snapshot(cx);
let buffer_snapshot = multi_buffer.buffer(buffer_id)?.read(cx).snapshot();
Some((multi_buffer_snapshot, buffer_snapshot))
}).ok().flatten() else { return; };
match hints_fetch_task.await { match hints_fetch_task.await {
Ok(Some(new_hints)) => { Ok(Some(new_hints)) => {
let task_buffer_snapshot = buffer_snapshot.clone(); let task_buffer_snapshot = buffer_snapshot.clone();
@ -219,10 +245,11 @@ fn new_update_task(
.spawn(async move { .spawn(async move {
new_excerpt_hints_update_result( new_excerpt_hints_update_result(
state, state,
excerpt_id, query.excerpt_id,
new_hints, new_hints,
invalidate_cache, query.invalidate_cache,
&task_buffer_snapshot, &task_buffer_snapshot,
query.excerpt_range,
) )
}) })
.await .await
@ -254,7 +281,7 @@ fn new_update_task(
for new_hint in new_update.add_to_cache { for new_hint in new_update.add_to_cache {
let new_hint_position = multi_buffer_snapshot let new_hint_position = multi_buffer_snapshot
.anchor_in_excerpt(excerpt_id, new_hint.position); .anchor_in_excerpt(query.excerpt_id, new_hint.position);
let new_inlay_id = InlayId(post_inc(&mut editor.next_inlay_id)); let new_inlay_id = InlayId(post_inc(&mut editor.next_inlay_id));
if editor if editor
.inlay_hint_cache .inlay_hint_cache
@ -299,7 +326,8 @@ fn new_update_task(
} }
Ok(None) => {} Ok(None) => {}
Err(e) => error!( Err(e) => error!(
"Failed to fecth hints for excerpt {excerpt_id:?} in buffer {buffer_id} : {e}" "Failed to fecth hints for excerpt {:?} in buffer {} : {}",
query.excerpt_id, query.buffer_id, e
), ),
} }
}), }),
@ -416,6 +444,7 @@ fn new_excerpt_hints_update_result(
new_excerpt_hints: Vec<InlayHint>, new_excerpt_hints: Vec<InlayHint>,
invalidate_cache: bool, invalidate_cache: bool,
buffer_snapshot: &BufferSnapshot, buffer_snapshot: &BufferSnapshot,
excerpt_range: Range<language::Anchor>,
) -> Option<ExcerptHintsUpdate> { ) -> Option<ExcerptHintsUpdate> {
let mut add_to_cache: Vec<InlayHint> = Vec::new(); let mut add_to_cache: Vec<InlayHint> = Vec::new();
let cached_excerpt_hints = state.cache.hints.get(&excerpt_id); let cached_excerpt_hints = state.cache.hints.get(&excerpt_id);
@ -454,6 +483,18 @@ fn new_excerpt_hints_update_result(
.visible_inlays .visible_inlays
.iter() .iter()
.filter(|hint| hint.position.excerpt_id == excerpt_id) .filter(|hint| hint.position.excerpt_id == excerpt_id)
.filter(|hint| {
excerpt_range
.start
.cmp(&hint.position.text_anchor, buffer_snapshot)
.is_le()
})
.filter(|hint| {
excerpt_range
.end
.cmp(&hint.position.text_anchor, buffer_snapshot)
.is_ge()
})
.map(|inlay_hint| inlay_hint.id) .map(|inlay_hint| inlay_hint.id)
.filter(|hint_id| !excerpt_hints_to_persist.contains_key(hint_id)), .filter(|hint_id| !excerpt_hints_to_persist.contains_key(hint_id)),
); );
@ -497,34 +538,28 @@ fn allowed_hint_types(
} }
fn hints_fetch_task( fn hints_fetch_task(
buffer_id: u64, query: ExcerptQuery,
excerpt_id: ExcerptId,
cx: &mut ViewContext<'_, '_, Editor>, cx: &mut ViewContext<'_, '_, Editor>,
) -> Task<anyhow::Result<Option<Vec<InlayHint>>>> { ) -> Task<anyhow::Result<Option<Vec<InlayHint>>>> {
cx.spawn(|editor, mut cx| async move { cx.spawn(|editor, mut cx| async move {
let Ok(task) = editor let task = editor
.update(&mut cx, |editor, cx| { .update(&mut cx, |editor, cx| {
Some({ editor
let multi_buffer = editor.buffer().read(cx); .buffer()
let buffer_handle = multi_buffer.buffer(buffer_id)?; .read(cx)
let (_, excerpt_range) = multi_buffer .buffer(query.buffer_id)
.excerpts_for_buffer(&buffer_handle, cx) .and_then(|buffer| {
.into_iter() let project = editor.project.as_ref()?;
.find(|(id, _)| id == &excerpt_id)?; Some(project.update(cx, |project, cx| {
editor.project.as_ref()?.update(cx, |project, cx| { project.inlay_hints(buffer, query.excerpt_range, cx)
project.inlay_hints( }))
buffer_handle,
excerpt_range.context,
cx,
)
}) })
}) })
}) else { .ok()
return Ok(None); .flatten();
};
Ok(match task { Ok(match task {
Some(task) => Some(task.await.context("inlays for buffer task")?), Some(task) => Some(task.await.context("inlays for buffer task")?),
None => Some(Vec::new()), None => None,
}) })
}) })
} }