mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-27 09:13:21 +03:00
This PR reverts #6924, for the reasons stated in https://github.com/zed-industries/zed/pull/6924#issuecomment-2033076300. It also fixes an issue were the `find_all_references_task_sources` wasn't cleaned up in all cases. Release Notes: - N/A --------- Co-authored-by: Marshall <marshall@zed.dev> Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
This commit is contained in:
parent
65cde17063
commit
7d5048e909
@ -125,7 +125,7 @@ use ui::{
|
||||
h_flex, prelude::*, ButtonSize, ButtonStyle, IconButton, IconName, IconSize, ListItem, Popover,
|
||||
Tooltip,
|
||||
};
|
||||
use util::{maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
|
||||
use util::{defer, maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
|
||||
use workspace::Toast;
|
||||
use workspace::{
|
||||
searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId,
|
||||
@ -7853,9 +7853,10 @@ impl Editor {
|
||||
Bias::Left
|
||||
},
|
||||
);
|
||||
|
||||
match self
|
||||
.find_all_references_task_sources
|
||||
.binary_search_by(|task_anchor| task_anchor.cmp(&head_anchor, &multi_buffer_snapshot))
|
||||
.binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
|
||||
{
|
||||
Ok(_) => {
|
||||
log::info!(
|
||||
@ -7873,66 +7874,27 @@ impl Editor {
|
||||
let workspace = self.workspace()?;
|
||||
let project = workspace.read(cx).project().clone();
|
||||
let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
|
||||
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);
|
||||
|
||||
// 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() {
|
||||
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(
|
||||
workspace.active_pane().clone(),
|
||||
target.buffer.clone(),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
target_editor.update(cx, |target_editor, cx| {
|
||||
target_editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
s.select_ranges([range]);
|
||||
Some(cx.spawn(|editor, mut cx| async move {
|
||||
let _cleanup = defer({
|
||||
let mut cx = cx.clone();
|
||||
move || {
|
||||
let _ = editor.update(&mut cx, |editor, _| {
|
||||
if let Ok(i) =
|
||||
editor
|
||||
.find_all_references_task_sources
|
||||
.binary_search_by(|anchor| {
|
||||
anchor.cmp(&head_anchor, &multi_buffer_snapshot)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
});
|
||||
{
|
||||
editor.find_all_references_task_sources.remove(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let locations = references.await?;
|
||||
if locations.is_empty() {
|
||||
return anyhow::Ok(());
|
||||
}
|
||||
|
||||
workspace.update(&mut cx, |workspace, cx| {
|
||||
@ -7952,24 +7914,7 @@ impl Editor {
|
||||
Self::open_locations_in_multibuffer(
|
||||
workspace, locations, replica_id, title, false, cx,
|
||||
);
|
||||
})?;
|
||||
|
||||
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(())
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -8498,105 +8498,6 @@ 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);
|
||||
}
|
||||
"});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_addition_reverts(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
@ -702,10 +702,7 @@ mod tests {
|
||||
use gpui::Modifiers;
|
||||
use indoc::indoc;
|
||||
use language::language_settings::InlayHintSettings;
|
||||
use lsp::{
|
||||
request::{GotoDefinition, GotoTypeDefinition},
|
||||
References,
|
||||
};
|
||||
use lsp::request::{GotoDefinition, GotoTypeDefinition};
|
||||
use util::assert_set_eq;
|
||||
use workspace::item::Item;
|
||||
|
||||
@ -1270,147 +1267,4 @@ mod tests {
|
||||
cx.simulate_click(screen_coord, Modifiers::secondary_key());
|
||||
assert_eq!(cx.opened_url(), Some("https://zed.dev/releases".into()));
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_cmd_click_back_and_forth(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
let mut cx = EditorLspTestContext::new_rust(lsp::ServerCapabilities::default(), cx).await;
|
||||
cx.set_state(indoc! {"
|
||||
fn test() {
|
||||
do_work();
|
||||
}ˇ
|
||||
|
||||
fn do_work() {
|
||||
test();
|
||||
}
|
||||
"});
|
||||
|
||||
// cmd-click on `test` definition and usage, and expect Zed to allow going back and forth,
|
||||
// because cmd-click first searches for definitions to go to, and then fall backs to symbol usages to go to.
|
||||
let definition_hover_point = cx.pixel_position(indoc! {"
|
||||
fn testˇ() {
|
||||
do_work();
|
||||
}
|
||||
|
||||
fn do_work() {
|
||||
test();
|
||||
}
|
||||
"});
|
||||
let definition_display_point = cx.display_point(indoc! {"
|
||||
fn testˇ() {
|
||||
do_work();
|
||||
}
|
||||
|
||||
fn do_work() {
|
||||
test();
|
||||
}
|
||||
"});
|
||||
let definition_range = cx.lsp_range(indoc! {"
|
||||
fn «test»() {
|
||||
do_work();
|
||||
}
|
||||
|
||||
fn do_work() {
|
||||
test();
|
||||
}
|
||||
"});
|
||||
let reference_hover_point = cx.pixel_position(indoc! {"
|
||||
fn test() {
|
||||
do_work();
|
||||
}
|
||||
|
||||
fn do_work() {
|
||||
testˇ();
|
||||
}
|
||||
"});
|
||||
let reference_display_point = cx.display_point(indoc! {"
|
||||
fn test() {
|
||||
do_work();
|
||||
}
|
||||
|
||||
fn do_work() {
|
||||
testˇ();
|
||||
}
|
||||
"});
|
||||
let reference_range = cx.lsp_range(indoc! {"
|
||||
fn test() {
|
||||
do_work();
|
||||
}
|
||||
|
||||
fn do_work() {
|
||||
«test»();
|
||||
}
|
||||
"});
|
||||
let expected_uri = cx.buffer_lsp_url.clone();
|
||||
cx.lsp
|
||||
.handle_request::<GotoDefinition, _, _>(move |params, _| {
|
||||
let expected_uri = expected_uri.clone();
|
||||
async move {
|
||||
assert_eq!(
|
||||
params.text_document_position_params.text_document.uri,
|
||||
expected_uri
|
||||
);
|
||||
let position = params.text_document_position_params.position;
|
||||
Ok(Some(lsp::GotoDefinitionResponse::Link(
|
||||
if position.line == reference_display_point.row()
|
||||
&& position.character == reference_display_point.column()
|
||||
{
|
||||
vec![lsp::LocationLink {
|
||||
origin_selection_range: None,
|
||||
target_uri: params.text_document_position_params.text_document.uri,
|
||||
target_range: definition_range,
|
||||
target_selection_range: definition_range,
|
||||
}]
|
||||
} else {
|
||||
// We cannot navigate to the definition outside of its reference point
|
||||
Vec::new()
|
||||
},
|
||||
)))
|
||||
}
|
||||
});
|
||||
let expected_uri = cx.buffer_lsp_url.clone();
|
||||
cx.lsp.handle_request::<References, _, _>(move |params, _| {
|
||||
let expected_uri = expected_uri.clone();
|
||||
async move {
|
||||
assert_eq!(
|
||||
params.text_document_position.text_document.uri,
|
||||
expected_uri
|
||||
);
|
||||
let position = params.text_document_position.position;
|
||||
// Zed should not look for references if GotoDefinition works or returns non-empty result
|
||||
assert_eq!(position.line, definition_display_point.row());
|
||||
assert_eq!(position.character, definition_display_point.column());
|
||||
Ok(Some(vec![lsp::Location {
|
||||
uri: params.text_document_position.text_document.uri,
|
||||
range: reference_range,
|
||||
}]))
|
||||
}
|
||||
});
|
||||
|
||||
for _ in 0..5 {
|
||||
cx.simulate_click(definition_hover_point, Modifiers::secondary_key());
|
||||
cx.background_executor.run_until_parked();
|
||||
cx.assert_editor_state(indoc! {"
|
||||
fn test() {
|
||||
do_work();
|
||||
}
|
||||
|
||||
fn do_work() {
|
||||
«testˇ»();
|
||||
}
|
||||
"});
|
||||
|
||||
cx.simulate_click(reference_hover_point, Modifiers::secondary_key());
|
||||
cx.background_executor.run_until_parked();
|
||||
cx.assert_editor_state(indoc! {"
|
||||
fn «testˇ»() {
|
||||
do_work();
|
||||
}
|
||||
|
||||
fn do_work() {
|
||||
test();
|
||||
}
|
||||
"});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -367,6 +367,7 @@ impl<F: FnOnce()> Drop for Deferred<F> {
|
||||
}
|
||||
|
||||
/// Run the given function when the returned value is dropped (unless it's cancelled).
|
||||
#[must_use]
|
||||
pub fn defer<F: FnOnce()>(f: F) -> Deferred<F> {
|
||||
Deferred(Some(f))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user