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 33335132905c7f1f9b0337d3a1a4cbb97b9662a0..e10fde467a56468707d22651b3529e6f1f03e6a5 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(()) })) }