From 48982c3036bb76c856d6fa470e7ea1a082a59dd3 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Fri, 23 Jun 2023 00:11:09 +0300 Subject: [PATCH] Filter away new hints not in excerpt range --- crates/editor/src/inlay_hint_cache.rs | 139 ++++++++++++++++---------- 1 file changed, 87 insertions(+), 52 deletions(-) diff --git a/crates/editor/src/inlay_hint_cache.rs b/crates/editor/src/inlay_hint_cache.rs index 9044c6f509..d1e0a1b933 100644 --- a/crates/editor/src/inlay_hint_cache.rs +++ b/crates/editor/src/inlay_hint_cache.rs @@ -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 gpui::{ModelHandle, Task, ViewContext}; +use language::BufferSnapshot; use log::error; use project::{InlayHint, InlayHintKind}; use collections::{hash_map, HashMap, HashSet}; -use text::BufferSnapshot; use util::post_inc; pub struct InlayHintCache { @@ -39,6 +42,15 @@ pub struct HintsUpdateState { cache: Box, } +#[derive(Debug, Clone)] +struct ExcerptQuery { + buffer_id: u64, + excerpt_id: ExcerptId, + excerpt_range: Range, + cache_version: usize, + invalidate_cache: bool, +} + #[derive(Debug, Default)] pub struct InlaySplice { pub to_remove: Vec, @@ -135,7 +147,7 @@ impl InlayHintCache { let mut excerpts_to_query = editor .excerpt_visible_offsets(cx) .into_iter() - .map(|(buffer, _, excerpt_id)| (excerpt_id, buffer.read(cx).remote_id())) + .map(|(buffer, _, excerpt_id)| (excerpt_id, buffer)) .collect::>(); let update_state = get_update_state(editor, cx); @@ -160,18 +172,41 @@ impl InlayHintCache { } }); - for (excerpt_id, buffer_id) in excerpts_to_query { - update_tasks.insert( - excerpt_id, - new_update_task( - buffer_id, + 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, - update_state.clone(), invalidate_cache, - cx, - ), - ); + }; + update_tasks.insert( + excerpt_id, + new_update_task( + query, + update_state.clone(), + multi_buffer_snapshot, + buffer_snapshot, + cx, + ), + ); + } } }) .ok(); @@ -192,25 +227,16 @@ impl InlayHintCache { } fn new_update_task( - buffer_id: u64, - excerpt_id: ExcerptId, - cache_version: usize, + query: ExcerptQuery, state: HintsUpdateState, - invalidate_cache: bool, + multi_buffer_snapshot: MultiBufferSnapshot, + buffer_snapshot: BufferSnapshot, cx: &mut ViewContext<'_, '_, Editor>, ) -> InlayHintUpdateTask { - let hints_fetch_task = hints_fetch_task(buffer_id, excerpt_id, cx); + let hints_fetch_task = hints_fetch_task(query.clone(), cx); InlayHintUpdateTask { - version: cache_version, + version: query.cache_version, _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 { Ok(Some(new_hints)) => { let task_buffer_snapshot = buffer_snapshot.clone(); @@ -219,10 +245,11 @@ fn new_update_task( .spawn(async move { new_excerpt_hints_update_result( state, - excerpt_id, + query.excerpt_id, new_hints, - invalidate_cache, + query.invalidate_cache, &task_buffer_snapshot, + query.excerpt_range, ) }) .await @@ -254,7 +281,7 @@ fn new_update_task( for new_hint in new_update.add_to_cache { 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)); if editor .inlay_hint_cache @@ -299,7 +326,8 @@ fn new_update_task( } Ok(None) => {} 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, invalidate_cache: bool, buffer_snapshot: &BufferSnapshot, + excerpt_range: Range, ) -> Option { let mut add_to_cache: Vec = Vec::new(); let cached_excerpt_hints = state.cache.hints.get(&excerpt_id); @@ -454,6 +483,18 @@ fn new_excerpt_hints_update_result( .visible_inlays .iter() .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) .filter(|hint_id| !excerpt_hints_to_persist.contains_key(hint_id)), ); @@ -497,34 +538,28 @@ fn allowed_hint_types( } fn hints_fetch_task( - buffer_id: u64, - excerpt_id: ExcerptId, + query: ExcerptQuery, cx: &mut ViewContext<'_, '_, Editor>, ) -> Task>>> { cx.spawn(|editor, mut cx| async move { - let Ok(task) = editor + let task = editor .update(&mut cx, |editor, cx| { - Some({ - let multi_buffer = editor.buffer().read(cx); - let buffer_handle = multi_buffer.buffer(buffer_id)?; - let (_, excerpt_range) = multi_buffer - .excerpts_for_buffer(&buffer_handle, cx) - .into_iter() - .find(|(id, _)| id == &excerpt_id)?; - editor.project.as_ref()?.update(cx, |project, cx| { - project.inlay_hints( - buffer_handle, - excerpt_range.context, - cx, - ) + editor + .buffer() + .read(cx) + .buffer(query.buffer_id) + .and_then(|buffer| { + let project = editor.project.as_ref()?; + Some(project.update(cx, |project, cx| { + project.inlay_hints(buffer, query.excerpt_range, cx) + })) }) - }) - }) else { - return Ok(None); - }; + }) + .ok() + .flatten(); Ok(match task { Some(task) => Some(task.await.context("inlays for buffer task")?), - None => Some(Vec::new()), + None => None, }) }) }