mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-20 02:47:34 +03:00
Go to reference when there's only one (#6924)
Fixes #4796 - Improved Go To Definition usability when there's a single reference ([4796](https://github.com/zed-industries/zed/issues/4796)) --------- Co-authored-by: Kirill Bulatov <kirill@zed.com>
This commit is contained in:
parent
81886a9baf
commit
c94852b843
@ -7663,12 +7663,64 @@ impl Editor {
|
|||||||
let workspace = self.workspace()?;
|
let workspace = self.workspace()?;
|
||||||
let project = workspace.read(cx).project().clone();
|
let project = workspace.read(cx).project().clone();
|
||||||
let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
|
let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
|
||||||
Some(cx.spawn(|_, mut cx| async move {
|
Some(cx.spawn(|editor, mut cx| async move {
|
||||||
let locations = references.await?;
|
let mut locations = references.await?;
|
||||||
|
let snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
|
||||||
|
let head_offset = text::ToOffset::to_offset(&head, &snapshot);
|
||||||
|
|
||||||
|
// LSP may return references that contain the item itself we requested `find_all_references` for (eg. rust-analyzer)
|
||||||
|
// So we will remove it from locations
|
||||||
|
// If there is only one reference, we will not do this filter cause it may make locations empty
|
||||||
|
if locations.len() > 1 {
|
||||||
|
cx.update(|cx| {
|
||||||
|
locations.retain(|location| {
|
||||||
|
// fn foo(x : i64) {
|
||||||
|
// ^
|
||||||
|
// println!(x);
|
||||||
|
// }
|
||||||
|
// It is ok to find reference when caret being at ^ (the end of the word)
|
||||||
|
// So we turn offset into inclusive to include the end of the word
|
||||||
|
!location
|
||||||
|
.range
|
||||||
|
.to_offset(location.buffer.read(cx))
|
||||||
|
.to_inclusive()
|
||||||
|
.contains(&head_offset)
|
||||||
|
});
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
if locations.is_empty() {
|
if locations.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there is one reference, just open it directly
|
||||||
|
if locations.len() == 1 {
|
||||||
|
let target = locations.pop().unwrap();
|
||||||
|
|
||||||
|
return editor.update(&mut cx, |editor, cx| {
|
||||||
|
let range = target.range.to_offset(target.buffer.read(cx));
|
||||||
|
let range = editor.range_for_match(&range);
|
||||||
|
|
||||||
|
if Some(&target.buffer) == editor.buffer().read(cx).as_singleton().as_ref() {
|
||||||
|
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||||
|
s.select_ranges([range]);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cx.window_context().defer(move |cx| {
|
||||||
|
let target_editor: View<Self> =
|
||||||
|
workspace.update(cx, |workspace, cx| {
|
||||||
|
workspace.open_project_item(target.buffer.clone(), cx)
|
||||||
|
});
|
||||||
|
target_editor.update(cx, |target_editor, cx| {
|
||||||
|
target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||||
|
s.select_ranges([range]);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
workspace.update(&mut cx, |workspace, cx| {
|
workspace.update(&mut cx, |workspace, cx| {
|
||||||
let title = locations
|
let title = locations
|
||||||
.first()
|
.first()
|
||||||
|
@ -8430,6 +8430,105 @@ async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_find_all_references(cx: &mut gpui::TestAppContext) {
|
||||||
|
init_test(cx, |_| {});
|
||||||
|
|
||||||
|
let mut cx = EditorLspTestContext::new_rust(
|
||||||
|
lsp::ServerCapabilities {
|
||||||
|
document_formatting_provider: Some(lsp::OneOf::Left(true)),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
cx.set_state(indoc! {"
|
||||||
|
fn foo(«paramˇ»: i64) {
|
||||||
|
println!(param);
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
cx.lsp
|
||||||
|
.handle_request::<lsp::request::References, _, _>(move |_, _| async move {
|
||||||
|
Ok(Some(vec![
|
||||||
|
lsp::Location {
|
||||||
|
uri: lsp::Url::from_file_path("/root/dir/file.rs").unwrap(),
|
||||||
|
range: lsp::Range::new(lsp::Position::new(0, 7), lsp::Position::new(0, 12)),
|
||||||
|
},
|
||||||
|
lsp::Location {
|
||||||
|
uri: lsp::Url::from_file_path("/root/dir/file.rs").unwrap(),
|
||||||
|
range: lsp::Range::new(lsp::Position::new(1, 13), lsp::Position::new(1, 18)),
|
||||||
|
},
|
||||||
|
]))
|
||||||
|
});
|
||||||
|
|
||||||
|
let references = cx
|
||||||
|
.update_editor(|editor, cx| editor.find_all_references(&FindAllReferences, cx))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
|
||||||
|
cx.executor().start_waiting();
|
||||||
|
references.await.unwrap();
|
||||||
|
|
||||||
|
cx.assert_editor_state(indoc! {"
|
||||||
|
fn foo(param: i64) {
|
||||||
|
println!(«paramˇ»);
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
let references = cx
|
||||||
|
.update_editor(|editor, cx| editor.find_all_references(&FindAllReferences, cx))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
|
||||||
|
cx.executor().start_waiting();
|
||||||
|
references.await.unwrap();
|
||||||
|
|
||||||
|
cx.assert_editor_state(indoc! {"
|
||||||
|
fn foo(«paramˇ»: i64) {
|
||||||
|
println!(param);
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
cx.set_state(indoc! {"
|
||||||
|
fn foo(param: i64) {
|
||||||
|
let a = param;
|
||||||
|
let aˇ = param;
|
||||||
|
let a = param;
|
||||||
|
println!(param);
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
cx.lsp
|
||||||
|
.handle_request::<lsp::request::References, _, _>(move |_, _| async move {
|
||||||
|
Ok(Some(vec![lsp::Location {
|
||||||
|
uri: lsp::Url::from_file_path("/root/dir/file.rs").unwrap(),
|
||||||
|
range: lsp::Range::new(lsp::Position::new(2, 8), lsp::Position::new(2, 9)),
|
||||||
|
}]))
|
||||||
|
});
|
||||||
|
|
||||||
|
let references = cx
|
||||||
|
.update_editor(|editor, cx| editor.find_all_references(&FindAllReferences, cx))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
|
||||||
|
cx.executor().start_waiting();
|
||||||
|
references.await.unwrap();
|
||||||
|
|
||||||
|
cx.assert_editor_state(indoc! {"
|
||||||
|
fn foo(param: i64) {
|
||||||
|
let a = param;
|
||||||
|
let «aˇ» = param;
|
||||||
|
let a = param;
|
||||||
|
println!(param);
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
}
|
||||||
|
|
||||||
fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
|
fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
|
||||||
let point = DisplayPoint::new(row as u32, column as u32);
|
let point = DisplayPoint::new(row as u32, column as u32);
|
||||||
point..point
|
point..point
|
||||||
|
Loading…
Reference in New Issue
Block a user