Do not allow concurrent FindAllReferences requests for the same multibuffer anchors (#9242)

FindAllReferences LSP requests might take a long time to complete, and
currently Zed allows multiple requests spawned concurrently for the same
Anchor in the multi buffer. That results in multiple search results'
multi buffers appearing, sometimes at once, which is not what we want.

Part of https://github.com/zed-industries/zed/issues/5351 that helps to
reduce the amount of search results after clicks that did not resolve
instantly.


Release Notes:

- Improved FindAllReferences action by not allowing concurrent requests
for the same multi buffer source
This commit is contained in:
Kirill Bulatov 2024-03-12 23:02:34 +02:00 committed by GitHub
parent 64219ba49f
commit c09fe1ce8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -395,6 +395,7 @@ pub struct Editor {
context_menu: RwLock<Option<ContextMenu>>,
mouse_context_menu: Option<MouseContextMenu>,
completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
find_all_references_task_sources: Vec<Anchor>,
next_completion_id: CompletionId,
completion_documentation_pre_resolve_debounce: DebouncedDelay,
available_code_actions: Option<(Model<Buffer>, Arc<[CodeAction]>)>,
@ -1534,6 +1535,7 @@ impl Editor {
context_menu: RwLock::new(None),
mouse_context_menu: None,
completion_tasks: Default::default(),
find_all_references_task_sources: Vec::new(),
next_completion_id: 0,
completion_documentation_pre_resolve_debounce: DebouncedDelay::new(),
next_inlay_id: 0,
@ -7887,15 +7889,40 @@ impl Editor {
_: &FindAllReferences,
cx: &mut ViewContext<Self>,
) -> Option<Task<Result<()>>> {
let buffer = self.buffer.read(cx);
let head = self.selections.newest::<usize>(cx).head();
let (buffer, head) = buffer.text_anchor_for_position(head, cx)?;
let replica_id = self.replica_id(cx);
let multi_buffer = self.buffer.read(cx);
let selection = self.selections.newest::<usize>(cx);
let head = selection.head();
let multi_buffer_snapshot = multi_buffer.snapshot(cx);
let head_anchor = multi_buffer_snapshot.anchor_at(
head,
if head < selection.tail() {
Bias::Right
} else {
Bias::Left
},
);
match self
.find_all_references_task_sources
.binary_search_by(|task_anchor| task_anchor.cmp(&head_anchor, &multi_buffer_snapshot))
{
Ok(_) => {
log::info!(
"Ignoring repeated FindAllReferences invocation with the position of already running task"
);
return None;
}
Err(i) => {
self.find_all_references_task_sources.insert(i, head_anchor);
}
}
let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
let replica_id = self.replica_id(cx);
let workspace = self.workspace()?;
let project = workspace.read(cx).project().clone();
let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
Some(cx.spawn(|editor, mut cx| async move {
let open_task = cx.spawn(|editor, mut cx| async move {
let mut locations = references.await?;
let snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
let head_offset = text::ToOffset::to_offset(&head, &snapshot);
@ -7977,6 +8004,21 @@ impl Editor {
})?;
Ok(())
});
Some(cx.spawn(|editor, mut cx| async move {
open_task.await?;
editor.update(&mut cx, |editor, _| {
if let Ok(i) =
editor
.find_all_references_task_sources
.binary_search_by(|task_anchor| {
task_anchor.cmp(&head_anchor, &multi_buffer_snapshot)
})
{
editor.find_all_references_task_sources.remove(i);
}
})?;
anyhow::Ok(())
}))
}