Always open new project search view workspace::NewSearch action (#3581)

This commit is contained in:
Kirill Bulatov 2023-12-11 13:45:41 +02:00 committed by GitHub
commit 36d2ab4537
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 156 additions and 82 deletions

View File

@ -1075,8 +1075,7 @@ impl ProjectSearchView {
}); });
} }
// Re-activate the most recently activated search or the most recent if it has been closed. // Add another search tab to the workspace.
// If no search exists in the workspace, create a new one.
fn deploy( fn deploy(
workspace: &mut Workspace, workspace: &mut Workspace,
_: &workspace::NewSearch, _: &workspace::NewSearch,
@ -1087,19 +1086,6 @@ impl ProjectSearchView {
state.0.retain(|project, _| project.is_upgradable(cx)) state.0.retain(|project, _| project.is_upgradable(cx))
}); });
let active_search = cx
.global::<ActiveSearches>()
.0
.get(&workspace.project().downgrade());
let existing = active_search
.and_then(|active_search| {
workspace
.items_of_type::<ProjectSearchView>(cx)
.find(|search| search == active_search)
})
.or_else(|| workspace.item_of_type::<ProjectSearchView>(cx));
let query = workspace.active_item(cx).and_then(|item| { let query = workspace.active_item(cx).and_then(|item| {
let editor = item.act_as::<Editor>(cx)?; let editor = item.act_as::<Editor>(cx)?;
let query = editor.query_suggestion(cx); let query = editor.query_suggestion(cx);
@ -1110,28 +1096,22 @@ impl ProjectSearchView {
} }
}); });
let search = if let Some(existing) = existing { let settings = cx
workspace.activate_item(&existing, cx); .global::<ActiveSettings>()
existing .0
.get(&workspace.project().downgrade());
let settings = if let Some(settings) = settings {
Some(settings.clone())
} else { } else {
let settings = cx None
.global::<ActiveSettings>()
.0
.get(&workspace.project().downgrade());
let settings = if let Some(settings) = settings {
Some(settings.clone())
} else {
None
};
let model = cx.add_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));
let view = cx.add_view(|cx| ProjectSearchView::new(model, cx, settings));
workspace.add_item(Box::new(view.clone()), cx);
view
}; };
let model = cx.add_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));
let search = cx.add_view(|cx| ProjectSearchView::new(model, cx, settings));
workspace.add_item(Box::new(search.clone()), cx);
search.update(cx, |search, cx| { search.update(cx, |search, cx| {
if let Some(query) = query { if let Some(query) = query {
search.set_query(&query, cx); search.set_query(&query, cx);
@ -2306,29 +2286,86 @@ pub mod tests {
workspace.update(cx, |workspace, cx| { workspace.update(cx, |workspace, cx| {
ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx) ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
}); });
deterministic.run_until_parked();
let Some(search_view_2) = cx.read(|cx| {
workspace
.read(cx)
.active_pane()
.read(cx)
.active_item()
.and_then(|item| item.downcast::<ProjectSearchView>())
}) else {
panic!("Search view expected to appear after new search event trigger")
};
let search_view_id_2 = search_view_2.id();
assert_ne!(
search_view_2, search_view,
"New search view should be open after `workspace::NewSearch` event"
);
search_view.update(cx, |search_view, cx| { search_view.update(cx, |search_view, cx| {
assert_eq!(search_view.query_editor.read(cx).text(cx), "two", "Query should be updated to first search result after search view 2nd open in a row"); assert_eq!(search_view.query_editor.read(cx).text(cx), "TWO", "First search view should not have an updated query");
assert_eq!( assert_eq!(
search_view search_view
.results_editor .results_editor
.update(cx, |editor, cx| editor.display_text(cx)), .update(cx, |editor, cx| editor.display_text(cx)),
"\n\nconst THREE: usize = one::ONE + two::TWO;\n\n\nconst TWO: usize = one::ONE + one::ONE;", "\n\nconst THREE: usize = one::ONE + two::TWO;\n\n\nconst TWO: usize = one::ONE + one::ONE;",
"Results should be unchanged after search view 2nd open in a row" "Results of the first search view should not update too"
); );
assert!( assert!(
search_view.query_editor.is_focused(cx), !search_view.query_editor.is_focused(cx),
"Focus should be moved into query editor again after search view 2nd open in a row" "Focus should be moved away from the first search view"
);
});
search_view_2.update(cx, |search_view_2, cx| {
assert_eq!(
search_view_2.query_editor.read(cx).text(cx),
"two",
"New search view should get the query from the text cursor was at during the event spawn (first search view's first result)"
);
assert_eq!(
search_view_2
.results_editor
.update(cx, |editor, cx| editor.display_text(cx)),
"",
"No search results should be in the 2nd view yet, as we did not spawn a search for it"
);
assert!(
search_view_2.query_editor.is_focused(cx),
"Focus should be moved into query editor fo the new window"
);
});
search_view_2.update(cx, |search_view_2, cx| {
search_view_2
.query_editor
.update(cx, |query_editor, cx| query_editor.set_text("FOUR", cx));
search_view_2.search(cx);
});
deterministic.run_until_parked();
search_view_2.update(cx, |search_view_2, cx| {
assert_eq!(
search_view_2
.results_editor
.update(cx, |editor, cx| editor.display_text(cx)),
"\n\nconst FOUR: usize = one::ONE + three::THREE;",
"New search view with the updated query should have new search results"
);
assert!(
search_view_2.results_editor.is_focused(cx),
"Search view with mismatching query should be focused after search results are available",
); );
}); });
cx.spawn(|mut cx| async move { cx.spawn(|mut cx| async move {
window.dispatch_action(search_view_id, &ToggleFocus, &mut cx); window.dispatch_action(search_view_id_2, &ToggleFocus, &mut cx);
}) })
.detach(); .detach();
deterministic.run_until_parked(); deterministic.run_until_parked();
search_view.update(cx, |search_view, cx| { search_view_2.update(cx, |search_view_2, cx| {
assert!( assert!(
search_view.results_editor.is_focused(cx), search_view_2.results_editor.is_focused(cx),
"Search view with matching query should switch focus to the results editor after the toggle focus event", "Search view with matching query should switch focus to the results editor after the toggle focus event",
); );
}); });

View File

@ -1075,8 +1075,7 @@ impl ProjectSearchView {
}); });
} }
// Re-activate the most recently activated search or the most recent if it has been closed. // Add another search tab to the workspace.
// If no search exists in the workspace, create a new one.
fn deploy( fn deploy(
workspace: &mut Workspace, workspace: &mut Workspace,
_: &workspace::NewSearch, _: &workspace::NewSearch,
@ -1087,19 +1086,6 @@ impl ProjectSearchView {
state.0.retain(|project, _| project.is_upgradable(cx)) state.0.retain(|project, _| project.is_upgradable(cx))
}); });
let active_search = cx
.global::<ActiveSearches>()
.0
.get(&workspace.project().downgrade());
let existing = active_search
.and_then(|active_search| {
workspace
.items_of_type::<ProjectSearchView>(cx)
.find(|search| search == active_search)
})
.or_else(|| workspace.item_of_type::<ProjectSearchView>(cx));
let query = workspace.active_item(cx).and_then(|item| { let query = workspace.active_item(cx).and_then(|item| {
let editor = item.act_as::<Editor>(cx)?; let editor = item.act_as::<Editor>(cx)?;
let query = editor.query_suggestion(cx); let query = editor.query_suggestion(cx);
@ -1110,28 +1096,22 @@ impl ProjectSearchView {
} }
}); });
let search = if let Some(existing) = existing { let settings = cx
workspace.activate_item(&existing, cx); .global::<ActiveSettings>()
existing .0
.get(&workspace.project().downgrade());
let settings = if let Some(settings) = settings {
Some(settings.clone())
} else { } else {
let settings = cx None
.global::<ActiveSettings>()
.0
.get(&workspace.project().downgrade());
let settings = if let Some(settings) = settings {
Some(settings.clone())
} else {
None
};
let model = cx.add_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));
let view = cx.add_view(|cx| ProjectSearchView::new(model, cx, settings));
workspace.add_item(Box::new(view.clone()), cx);
view
}; };
let model = cx.add_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));
let search = cx.add_view(|cx| ProjectSearchView::new(model, cx, settings));
workspace.add_item(Box::new(search.clone()), cx);
search.update(cx, |search, cx| { search.update(cx, |search, cx| {
if let Some(query) = query { if let Some(query) = query {
search.set_query(&query, cx); search.set_query(&query, cx);
@ -2306,29 +2286,86 @@ pub mod tests {
workspace.update(cx, |workspace, cx| { workspace.update(cx, |workspace, cx| {
ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx) ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
}); });
deterministic.run_until_parked();
let Some(search_view_2) = cx.read(|cx| {
workspace
.read(cx)
.active_pane()
.read(cx)
.active_item()
.and_then(|item| item.downcast::<ProjectSearchView>())
}) else {
panic!("Search view expected to appear after new search event trigger")
};
let search_view_id_2 = search_view_2.id();
assert_ne!(
search_view_2, search_view,
"New search view should be open after `workspace::NewSearch` event"
);
search_view.update(cx, |search_view, cx| { search_view.update(cx, |search_view, cx| {
assert_eq!(search_view.query_editor.read(cx).text(cx), "two", "Query should be updated to first search result after search view 2nd open in a row"); assert_eq!(search_view.query_editor.read(cx).text(cx), "TWO", "First search view should not have an updated query");
assert_eq!( assert_eq!(
search_view search_view
.results_editor .results_editor
.update(cx, |editor, cx| editor.display_text(cx)), .update(cx, |editor, cx| editor.display_text(cx)),
"\n\nconst THREE: usize = one::ONE + two::TWO;\n\n\nconst TWO: usize = one::ONE + one::ONE;", "\n\nconst THREE: usize = one::ONE + two::TWO;\n\n\nconst TWO: usize = one::ONE + one::ONE;",
"Results should be unchanged after search view 2nd open in a row" "Results of the first search view should not update too"
); );
assert!( assert!(
search_view.query_editor.is_focused(cx), !search_view.query_editor.is_focused(cx),
"Focus should be moved into query editor again after search view 2nd open in a row" "Focus should be moved away from the first search view"
);
});
search_view_2.update(cx, |search_view_2, cx| {
assert_eq!(
search_view_2.query_editor.read(cx).text(cx),
"two",
"New search view should get the query from the text cursor was at during the event spawn (first search view's first result)"
);
assert_eq!(
search_view_2
.results_editor
.update(cx, |editor, cx| editor.display_text(cx)),
"",
"No search results should be in the 2nd view yet, as we did not spawn a search for it"
);
assert!(
search_view_2.query_editor.is_focused(cx),
"Focus should be moved into query editor fo the new window"
);
});
search_view_2.update(cx, |search_view_2, cx| {
search_view_2
.query_editor
.update(cx, |query_editor, cx| query_editor.set_text("FOUR", cx));
search_view_2.search(cx);
});
deterministic.run_until_parked();
search_view_2.update(cx, |search_view_2, cx| {
assert_eq!(
search_view_2
.results_editor
.update(cx, |editor, cx| editor.display_text(cx)),
"\n\nconst FOUR: usize = one::ONE + three::THREE;",
"New search view with the updated query should have new search results"
);
assert!(
search_view_2.results_editor.is_focused(cx),
"Search view with mismatching query should be focused after search results are available",
); );
}); });
cx.spawn(|mut cx| async move { cx.spawn(|mut cx| async move {
window.dispatch_action(search_view_id, &ToggleFocus, &mut cx); window.dispatch_action(search_view_id_2, &ToggleFocus, &mut cx);
}) })
.detach(); .detach();
deterministic.run_until_parked(); deterministic.run_until_parked();
search_view.update(cx, |search_view, cx| { search_view_id_2.update(cx, |search_view_2, cx| {
assert!( assert!(
search_view.results_editor.is_focused(cx), search_view_2.results_editor.is_focused(cx),
"Search view with matching query should switch focus to the results editor after the toggle focus event", "Search view with matching query should switch focus to the results editor after the toggle focus event",
); );
}); });