From c09fe1ce8a199ddb0f84be55af61a472ad0e7c0d Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Tue, 12 Mar 2024 23:02:34 +0200 Subject: [PATCH] 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 --- crates/editor/src/editor.rs | 52 +++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 3333513290..e10fde467a 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -395,6 +395,7 @@ pub struct Editor { context_menu: RwLock>, mouse_context_menu: Option, completion_tasks: Vec<(CompletionId, Task>)>, + find_all_references_task_sources: Vec, next_completion_id: CompletionId, completion_documentation_pre_resolve_debounce: DebouncedDelay, available_code_actions: Option<(Model, 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, ) -> Option>> { - let buffer = self.buffer.read(cx); - let head = self.selections.newest::(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::(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(()) })) }