Detailed changes
@@ -453,8 +453,6 @@ actions!(
CollapseAllDiffHunks,
/// Expands macros recursively at cursor position.
ExpandMacroRecursively,
- /// Finds all references to the symbol at cursor.
- FindAllReferences,
/// Finds the next match in the search.
FindNextMatch,
/// Finds the previous match in the search.
@@ -827,3 +825,20 @@ actions!(
WrapSelectionsInTag
]
);
+
+/// Finds all references to the symbol at cursor.
+#[derive(PartialEq, Clone, Deserialize, JsonSchema, Action)]
+#[action(namespace = editor)]
+#[serde(deny_unknown_fields)]
+pub struct FindAllReferences {
+ #[serde(default = "default_true")]
+ pub always_open_multibuffer: bool,
+}
+
+impl Default for FindAllReferences {
+ fn default() -> Self {
+ Self {
+ always_open_multibuffer: true,
+ }
+ }
+}
@@ -16815,7 +16815,7 @@ impl Editor {
GoToDefinitionFallback::None => Ok(Navigated::No),
GoToDefinitionFallback::FindAllReferences => {
match editor.update_in(cx, |editor, window, cx| {
- editor.find_all_references(&FindAllReferences, window, cx)
+ editor.find_all_references(&FindAllReferences::default(), window, cx)
})? {
Some(references) => references.await,
None => Ok(Navigated::No),
@@ -17371,20 +17371,21 @@ impl Editor {
pub fn find_all_references(
&mut self,
- _: &FindAllReferences,
+ action: &FindAllReferences,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Task<Result<Navigated>>> {
- let selection = self
- .selections
- .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
+ let always_open_multibuffer = action.always_open_multibuffer;
+ let selection = self.selections.newest_anchor();
let multi_buffer = self.buffer.read(cx);
- let head = selection.head();
-
let multi_buffer_snapshot = multi_buffer.snapshot(cx);
+ let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
+ let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
+ let head = selection_offset.head();
+
let head_anchor = multi_buffer_snapshot.anchor_at(
head,
- if head < selection.tail() {
+ if head < selection_offset.tail() {
Bias::Right
} else {
Bias::Left
@@ -17430,6 +17431,15 @@ impl Editor {
let buffer = location.buffer.read(cx);
(location.buffer, location.range.to_point(buffer))
})
+ // if special-casing the single-match case, remove ranges
+ // that intersect current selection
+ .filter(|(location_buffer, location)| {
+ if always_open_multibuffer || &buffer != location_buffer {
+ return true;
+ }
+
+ !location.contains_inclusive(&selection_point.range())
+ })
.into_group_map()
})?;
if locations.is_empty() {
@@ -17439,6 +17449,60 @@ impl Editor {
ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
ranges.dedup();
}
+ let mut num_locations = 0;
+ for ranges in locations.values_mut() {
+ ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
+ ranges.dedup();
+ num_locations += ranges.len();
+ }
+
+ if num_locations == 1 && !always_open_multibuffer {
+ let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
+ let target_range = target_ranges.first().unwrap().clone();
+
+ return editor.update_in(cx, |editor, window, cx| {
+ let range = target_range.to_point(target_buffer.read(cx));
+ let range = editor.range_for_match(&range);
+ let range = range.start..range.start;
+
+ if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
+ editor.go_to_singleton_buffer_range(range, window, cx);
+ } else {
+ let pane = workspace.read(cx).active_pane().clone();
+ window.defer(cx, move |window, cx| {
+ let target_editor: Entity<Self> =
+ workspace.update(cx, |workspace, cx| {
+ let pane = workspace.active_pane().clone();
+
+ let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
+ let keep_old_preview = preview_tabs_settings
+ .enable_keep_preview_on_code_navigation;
+ let allow_new_preview = preview_tabs_settings
+ .enable_preview_file_from_code_navigation;
+
+ workspace.open_project_item(
+ pane,
+ target_buffer.clone(),
+ true,
+ true,
+ keep_old_preview,
+ allow_new_preview,
+ window,
+ cx,
+ )
+ });
+ target_editor.update(cx, |target_editor, cx| {
+ // When selecting a definition in a different buffer, disable the nav history
+ // to avoid creating a history entry at the previous cursor location.
+ pane.update(cx, |pane, _| pane.disable_history());
+ target_editor.go_to_singleton_buffer_range(range, window, cx);
+ pane.update(cx, |pane, _| pane.enable_history());
+ });
+ });
+ }
+ Navigated::No
+ });
+ }
workspace.update_in(cx, |workspace, window, cx| {
let target = locations
@@ -17476,7 +17540,7 @@ impl Editor {
}))
}
- /// Opens a multibuffer with the given project locations in it
+ /// Opens a multibuffer with the given project locations in it.
pub fn open_locations_in_multibuffer(
workspace: &mut Workspace,
locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
@@ -22579,7 +22579,7 @@ async fn test_find_all_references_editor_reuse(cx: &mut TestAppContext) {
});
let navigated = cx
.update_editor(|editor, window, cx| {
- editor.find_all_references(&FindAllReferences, window, cx)
+ editor.find_all_references(&FindAllReferences::default(), window, cx)
})
.unwrap()
.await
@@ -22615,7 +22615,7 @@ async fn test_find_all_references_editor_reuse(cx: &mut TestAppContext) {
);
let navigated = cx
.update_editor(|editor, window, cx| {
- editor.find_all_references(&FindAllReferences, window, cx)
+ editor.find_all_references(&FindAllReferences::default(), window, cx)
})
.unwrap()
.await
@@ -22667,7 +22667,7 @@ async fn test_find_all_references_editor_reuse(cx: &mut TestAppContext) {
});
let navigated = cx
.update_editor(|editor, window, cx| {
- editor.find_all_references(&FindAllReferences, window, cx)
+ editor.find_all_references(&FindAllReferences::default(), window, cx)
})
.unwrap()
.await
@@ -28916,3 +28916,65 @@ async fn test_multibuffer_scroll_cursor_top_margin(cx: &mut TestAppContext) {
);
});
}
+
+#[gpui::test]
+async fn test_find_references_single_case(cx: &mut TestAppContext) {
+ init_test(cx, |_| {});
+ let mut cx = EditorLspTestContext::new_rust(
+ lsp::ServerCapabilities {
+ references_provider: Some(lsp::OneOf::Left(true)),
+ ..lsp::ServerCapabilities::default()
+ },
+ cx,
+ )
+ .await;
+
+ let before = indoc!(
+ r#"
+ fn main() {
+ let aˇbc = 123;
+ let xyz = abc;
+ }
+ "#
+ );
+ let after = indoc!(
+ r#"
+ fn main() {
+ let abc = 123;
+ let xyz = ˇabc;
+ }
+ "#
+ );
+
+ cx.lsp
+ .set_request_handler::<lsp::request::References, _, _>(async move |params, _| {
+ Ok(Some(vec![
+ lsp::Location {
+ uri: params.text_document_position.text_document.uri.clone(),
+ range: lsp::Range::new(lsp::Position::new(1, 8), lsp::Position::new(1, 11)),
+ },
+ lsp::Location {
+ uri: params.text_document_position.text_document.uri,
+ range: lsp::Range::new(lsp::Position::new(2, 14), lsp::Position::new(2, 17)),
+ },
+ ]))
+ });
+
+ cx.set_state(before);
+
+ let action = FindAllReferences {
+ always_open_multibuffer: false,
+ };
+
+ let navigated = cx
+ .update_editor(|editor, window, cx| editor.find_all_references(&action, window, cx))
+ .expect("should have spawned a task")
+ .await
+ .unwrap();
+
+ assert_eq!(navigated, Navigated::No);
+
+ cx.run_until_parked();
+
+ cx.assert_editor_state(after);
+}
@@ -168,7 +168,7 @@ impl Editor {
match EditorSettings::get_global(cx).go_to_definition_fallback {
GoToDefinitionFallback::None => None,
GoToDefinitionFallback::FindAllReferences => {
- editor.find_all_references(&FindAllReferences, window, cx)
+ editor.find_all_references(&FindAllReferences::default(), window, cx)
}
}
})
@@ -235,7 +235,10 @@ pub fn deploy_context_menu(
.action("Go to Declaration", Box::new(GoToDeclaration))
.action("Go to Type Definition", Box::new(GoToTypeDefinition))
.action("Go to Implementation", Box::new(GoToImplementation))
- .action("Find All References", Box::new(FindAllReferences))
+ .action(
+ "Find All References",
+ Box::new(FindAllReferences::default()),
+ )
.separator()
.action("Rename Symbol", Box::new(Rename))
.action("Format Buffer", Box::new(Format))
@@ -247,7 +247,10 @@ pub fn app_menus(cx: &mut App) -> Vec<Menu> {
MenuItem::action("Go to Definition", editor::actions::GoToDefinition),
MenuItem::action("Go to Declaration", editor::actions::GoToDeclaration),
MenuItem::action("Go to Type Definition", editor::actions::GoToTypeDefinition),
- MenuItem::action("Find All References", editor::actions::FindAllReferences),
+ MenuItem::action(
+ "Find All References",
+ editor::actions::FindAllReferences::default(),
+ ),
MenuItem::separator(),
MenuItem::action("Next Problem", editor::actions::GoToDiagnostic::default()),
MenuItem::action(