Only skip /refresh inlay queries when vislble range is not updated

This commit is contained in:
Kirill Bulatov 2023-06-26 16:32:53 +03:00
parent 096bad1f73
commit 67214f0e55

View file

@ -57,6 +57,39 @@ struct ExcerptDimensions {
excerpt_visible_range_end: language::Anchor, excerpt_visible_range_end: language::Anchor,
} }
impl ExcerptQuery {
fn hints_fetch_ranges(&self, buffer: &BufferSnapshot) -> HintFetchRanges {
let visible_range =
self.dimensions.excerpt_visible_range_start..self.dimensions.excerpt_visible_range_end;
let mut other_ranges = Vec::new();
if self
.dimensions
.excerpt_range_start
.cmp(&self.dimensions.excerpt_visible_range_start, buffer)
.is_lt()
{
let mut end = self.dimensions.excerpt_visible_range_start;
end.offset -= 1;
other_ranges.push(self.dimensions.excerpt_range_start..end);
}
if self
.dimensions
.excerpt_range_end
.cmp(&self.dimensions.excerpt_visible_range_end, buffer)
.is_gt()
{
let mut start = self.dimensions.excerpt_visible_range_end;
start.offset += 1;
other_ranges.push(start..self.dimensions.excerpt_range_end);
}
HintFetchRanges {
visible_range,
other_ranges: other_ranges.into_iter().map(|range| range).collect(),
}
}
}
impl UpdateTask { impl UpdateTask {
fn new(invalidation_strategy: InvalidationStrategy, spawned_task: SpawnedTask) -> Self { fn new(invalidation_strategy: InvalidationStrategy, spawned_task: SpawnedTask) -> Self {
Self { Self {
@ -427,17 +460,18 @@ fn new_update_task(
buffer_snapshot: BufferSnapshot, buffer_snapshot: BufferSnapshot,
visible_hints: Arc<Vec<Inlay>>, visible_hints: Arc<Vec<Inlay>>,
cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>, cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
previous_task: Option<smol::channel::Receiver<()>>, task_before_refresh: Option<smol::channel::Receiver<()>>,
cx: &mut ViewContext<'_, '_, Editor>, cx: &mut ViewContext<'_, '_, Editor>,
) -> SpawnedTask { ) -> SpawnedTask {
let hints_fetch_tasks = hints_fetch_tasks(query, &buffer_snapshot, cx); let hints_fetch_tasks = query.hints_fetch_ranges(&buffer_snapshot);
let (is_running_tx, is_running_rx) = smol::channel::bounded(1); let (is_running_tx, is_running_rx) = smol::channel::bounded(1);
let is_refresh_task = task_before_refresh.is_some();
let _task = cx.spawn(|editor, cx| async move { let _task = cx.spawn(|editor, cx| async move {
let _is_running_tx = is_running_tx; let _is_running_tx = is_running_tx;
if let Some(previous_task) = previous_task { if let Some(task_before_refresh) = task_before_refresh {
previous_task.recv().await.ok(); task_before_refresh.recv().await.ok();
} }
let create_update_task = |range, hint_fetch_task| { let create_update_task = |range| {
fetch_and_update_hints( fetch_and_update_hints(
editor.clone(), editor.clone(),
multi_buffer_snapshot.clone(), multi_buffer_snapshot.clone(),
@ -446,14 +480,13 @@ fn new_update_task(
cached_excerpt_hints.as_ref().map(Arc::clone), cached_excerpt_hints.as_ref().map(Arc::clone),
query, query,
range, range,
hint_fetch_task,
cx.clone(), cx.clone(),
) )
}; };
let (visible_range, visible_range_hint_fetch_task) = hints_fetch_tasks.visible_range; if is_refresh_task {
let visible_range_has_updates = let visible_range_has_updates =
match create_update_task(visible_range, visible_range_hint_fetch_task).await { match create_update_task(hints_fetch_tasks.visible_range).await {
Ok(updated) => updated, Ok(updated) => updated,
Err(e) => { Err(e) => {
error!("inlay hint visible range update task failed: {e:#}"); error!("inlay hint visible range update task failed: {e:#}");
@ -462,12 +495,12 @@ fn new_update_task(
}; };
if visible_range_has_updates { if visible_range_has_updates {
let other_update_results = let other_update_results = futures::future::join_all(
futures::future::join_all(hints_fetch_tasks.other_ranges.into_iter().map( hints_fetch_tasks
|(fetch_range, hints_fetch_task)| { .other_ranges
create_update_task(fetch_range, hints_fetch_task) .into_iter()
}, .map(create_update_task),
)) )
.await; .await;
for result in other_update_results { for result in other_update_results {
@ -477,6 +510,20 @@ fn new_update_task(
} }
} }
} }
} else {
let task_update_results = futures::future::join_all(
std::iter::once(hints_fetch_tasks.visible_range)
.chain(hints_fetch_tasks.other_ranges.into_iter())
.map(create_update_task),
)
.await;
for result in task_update_results {
if let Err(e) = result {
error!("inlay hint update task failed: {e:#}");
}
}
}
}); });
SpawnedTask { SpawnedTask {
@ -494,12 +541,29 @@ async fn fetch_and_update_hints(
cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>, cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
query: ExcerptQuery, query: ExcerptQuery,
fetch_range: Range<language::Anchor>, fetch_range: Range<language::Anchor>,
hints_fetch_task: Task<anyhow::Result<Option<Vec<InlayHint>>>>,
mut cx: gpui::AsyncAppContext, mut cx: gpui::AsyncAppContext,
) -> anyhow::Result<bool> { ) -> anyhow::Result<bool> {
let inlay_hints_fetch_task = editor
.update(&mut cx, |editor, 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, fetch_range.clone(), cx)
}))
})
})
.ok()
.flatten();
let mut update_happened = false; let mut update_happened = false;
match hints_fetch_task.await.context("inlay hint fetch task")? { let Some(inlay_hints_fetch_task) = inlay_hints_fetch_task else { return Ok(update_happened) };
Some(new_hints) => {
let new_hints = inlay_hints_fetch_task
.await
.context("inlay hint fetch task")?;
let background_task_buffer_snapshot = buffer_snapshot.clone(); let background_task_buffer_snapshot = buffer_snapshot.clone();
let backround_fetch_range = fetch_range.clone(); let backround_fetch_range = fetch_range.clone();
if let Some(new_update) = cx if let Some(new_update) = cx
@ -559,11 +623,9 @@ async fn fetch_and_update_hints(
.allowed_hint_kinds .allowed_hint_kinds
.contains(&new_hint.kind) .contains(&new_hint.kind)
{ {
splice.to_insert.push(( splice
new_hint_position, .to_insert
new_inlay_id, .push((new_hint_position, new_inlay_id, new_hint.clone()));
new_hint.clone(),
));
} }
cached_excerpt_hints.hints.push((new_inlay_id, new_hint)); cached_excerpt_hints.hints.push((new_inlay_id, new_hint));
@ -586,9 +648,6 @@ async fn fetch_and_update_hints(
}) })
.ok(); .ok();
} }
}
None => {}
}
Ok(update_happened) Ok(update_happened)
} }
@ -713,77 +772,9 @@ fn allowed_hint_types(
new_allowed_hint_types new_allowed_hint_types
} }
struct HintFetchTasks { struct HintFetchRanges {
visible_range: ( visible_range: Range<language::Anchor>,
Range<language::Anchor>, other_ranges: Vec<Range<language::Anchor>>,
Task<anyhow::Result<Option<Vec<InlayHint>>>>,
),
other_ranges: Vec<(
Range<language::Anchor>,
Task<anyhow::Result<Option<Vec<InlayHint>>>>,
)>,
}
fn hints_fetch_tasks(
query: ExcerptQuery,
buffer: &BufferSnapshot,
cx: &mut ViewContext<'_, '_, Editor>,
) -> HintFetchTasks {
let visible_range =
query.dimensions.excerpt_visible_range_start..query.dimensions.excerpt_visible_range_end;
let mut other_ranges = Vec::new();
if query
.dimensions
.excerpt_range_start
.cmp(&query.dimensions.excerpt_visible_range_start, buffer)
.is_lt()
{
let mut end = query.dimensions.excerpt_visible_range_start;
end.offset -= 1;
other_ranges.push(query.dimensions.excerpt_range_start..end);
}
if query
.dimensions
.excerpt_range_end
.cmp(&query.dimensions.excerpt_visible_range_end, buffer)
.is_gt()
{
let mut start = query.dimensions.excerpt_visible_range_end;
start.offset += 1;
other_ranges.push(start..query.dimensions.excerpt_range_end);
}
let mut query_task_for_range = |range_to_query| {
cx.spawn(|editor, mut cx| async move {
let task = editor
.update(&mut cx, |editor, 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, range_to_query, cx)
}))
})
})
.ok()
.flatten();
anyhow::Ok(match task {
Some(task) => Some(task.await.context("inlays for buffer task")?),
None => None,
})
})
};
HintFetchTasks {
visible_range: (visible_range.clone(), query_task_for_range(visible_range)),
other_ranges: other_ranges
.into_iter()
.map(|range| (range.clone(), query_task_for_range(range)))
.collect(),
}
} }
fn contains_position( fn contains_position(