logiguard fork: GPUI xdg-activation keyboard-focus serial fix
Some checks failed
Update All Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Triage Project Sync (#84) / Sync triage project (push) Has been cancelled
release_nightly / notify_on_failure (push) Has been cancelled
release_nightly / check_style (push) Has been cancelled
release_nightly / run_tests_windows (push) Has been cancelled
release_nightly / clippy_windows (push) Has been cancelled
release_nightly / bundle_linux_aarch64 (push) Has been cancelled
release_nightly / bundle_linux_x86_64 (push) Has been cancelled
release_nightly / bundle_mac_aarch64 (push) Has been cancelled
release_nightly / bundle_mac_x86_64 (push) Has been cancelled
release_nightly / bundle_windows_aarch64 (push) Has been cancelled
release_nightly / bundle_windows_x86_64 (push) Has been cancelled
release_nightly / build_nix_linux_x86_64 (push) Has been cancelled
release_nightly / build_nix_mac_aarch64 (push) Has been cancelled
release_nightly / update_nightly_tag (push) Has been cancelled
Hotfix Review Monitor / check-hotfix-reviews (push) Has been cancelled
Stale PR Review Reminder / check-stale-prs (push) Has been cancelled
Update Weekly Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Bump collab-staging Tag / update-collab-staging-tag (push) Has been cancelled
compliance_check / scheduled_compliance_check (push) Has been cancelled
Some checks failed
Update All Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Triage Project Sync (#84) / Sync triage project (push) Has been cancelled
release_nightly / notify_on_failure (push) Has been cancelled
release_nightly / check_style (push) Has been cancelled
release_nightly / run_tests_windows (push) Has been cancelled
release_nightly / clippy_windows (push) Has been cancelled
release_nightly / bundle_linux_aarch64 (push) Has been cancelled
release_nightly / bundle_linux_x86_64 (push) Has been cancelled
release_nightly / bundle_mac_aarch64 (push) Has been cancelled
release_nightly / bundle_mac_x86_64 (push) Has been cancelled
release_nightly / bundle_windows_aarch64 (push) Has been cancelled
release_nightly / bundle_windows_x86_64 (push) Has been cancelled
release_nightly / build_nix_linux_x86_64 (push) Has been cancelled
release_nightly / build_nix_mac_aarch64 (push) Has been cancelled
release_nightly / update_nightly_tag (push) Has been cancelled
Hotfix Review Monitor / check-hotfix-reviews (push) Has been cancelled
Stale PR Review Reminder / check-stale-prs (push) Has been cancelled
Update Weekly Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Bump collab-staging Tag / update-collab-staging-tag (push) Has been cancelled
compliance_check / scheduled_compliance_check (push) Has been cancelled
Single-commit orphan branch: full zed-industries/zed @ 8c74db0 source tree with a 3-file patch applied (no upstream history). Patch (crates/gpui_linux/src/linux/wayland/): - serial.rs: add SerialKind::KeyboardEnter - client.rs: store wl_keyboard.enter serial; add latest_serial_of() - window.rs: activate() uses keyboard-enter serial (Mutter focus gate) Mutter honors window activation only when the token carries the keyboard- focus serial from wl_keyboard.enter; GPUI used a stale mouse-press serial. See docs/tray-window-focus-wayland.md in logiguard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
607
crates/tab_switcher/src/tab_switcher_tests.rs
Normal file
607
crates/tab_switcher/src/tab_switcher_tests.rs
Normal file
@@ -0,0 +1,607 @@
|
||||
use super::*;
|
||||
use editor::Editor;
|
||||
use gpui::{TestAppContext, VisualTestContext};
|
||||
use menu::SelectPrevious;
|
||||
use project::{Project, ProjectPath};
|
||||
use serde_json::json;
|
||||
use util::{path, rel_path::rel_path};
|
||||
use workspace::{ActivatePreviousItem, AppState, MultiWorkspace, Workspace, item::test::TestItem};
|
||||
|
||||
#[ctor::ctor]
|
||||
fn init_logger() {
|
||||
zlog::init_test();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_with_prev_tab_selected_and_cycle_on_toggle_action(
|
||||
cx: &mut gpui::TestAppContext,
|
||||
) {
|
||||
let app_state = init_test(cx);
|
||||
|
||||
app_state
|
||||
.fs
|
||||
.as_fake()
|
||||
.insert_tree(
|
||||
path!("/root"),
|
||||
json!({
|
||||
"1.txt": "First file",
|
||||
"2.txt": "Second file",
|
||||
"3.txt": "Third file",
|
||||
"4.txt": "Fourth file",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;
|
||||
let (multi_workspace, cx) =
|
||||
cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
|
||||
let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
|
||||
|
||||
let tab_1 = open_buffer("1.txt", &workspace, cx).await;
|
||||
let tab_2 = open_buffer("2.txt", &workspace, cx).await;
|
||||
let tab_3 = open_buffer("3.txt", &workspace, cx).await;
|
||||
let tab_4 = open_buffer("4.txt", &workspace, cx).await;
|
||||
|
||||
// Starts with the previously opened item selected
|
||||
let tab_switcher = open_tab_switcher(false, &workspace, cx);
|
||||
tab_switcher.update(cx, |tab_switcher, _| {
|
||||
assert_eq!(tab_switcher.delegate.matches.len(), 4);
|
||||
assert_match_at_position(tab_switcher, 0, tab_4.boxed_clone());
|
||||
assert_match_selection(tab_switcher, 1, tab_3.boxed_clone());
|
||||
assert_match_at_position(tab_switcher, 2, tab_2.boxed_clone());
|
||||
assert_match_at_position(tab_switcher, 3, tab_1.boxed_clone());
|
||||
});
|
||||
|
||||
cx.dispatch_action(Toggle { select_last: false });
|
||||
cx.dispatch_action(Toggle { select_last: false });
|
||||
tab_switcher.update(cx, |tab_switcher, _| {
|
||||
assert_eq!(tab_switcher.delegate.matches.len(), 4);
|
||||
assert_match_at_position(tab_switcher, 0, tab_4.boxed_clone());
|
||||
assert_match_at_position(tab_switcher, 1, tab_3.boxed_clone());
|
||||
assert_match_at_position(tab_switcher, 2, tab_2.boxed_clone());
|
||||
assert_match_selection(tab_switcher, 3, tab_1.boxed_clone());
|
||||
});
|
||||
|
||||
cx.dispatch_action(SelectPrevious);
|
||||
tab_switcher.update(cx, |tab_switcher, _| {
|
||||
assert_eq!(tab_switcher.delegate.matches.len(), 4);
|
||||
assert_match_at_position(tab_switcher, 0, tab_4.boxed_clone());
|
||||
assert_match_at_position(tab_switcher, 1, tab_3.boxed_clone());
|
||||
assert_match_selection(tab_switcher, 2, tab_2.boxed_clone());
|
||||
assert_match_at_position(tab_switcher, 3, tab_1.boxed_clone());
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_with_last_tab_selected(cx: &mut gpui::TestAppContext) {
|
||||
let app_state = init_test(cx);
|
||||
|
||||
app_state
|
||||
.fs
|
||||
.as_fake()
|
||||
.insert_tree(
|
||||
path!("/root"),
|
||||
json!({
|
||||
"1.txt": "First file",
|
||||
"2.txt": "Second file",
|
||||
"3.txt": "Third file",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;
|
||||
let (multi_workspace, cx) =
|
||||
cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
|
||||
let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
|
||||
|
||||
let tab_1 = open_buffer("1.txt", &workspace, cx).await;
|
||||
let tab_2 = open_buffer("2.txt", &workspace, cx).await;
|
||||
let tab_3 = open_buffer("3.txt", &workspace, cx).await;
|
||||
|
||||
// Starts with the last item selected
|
||||
let tab_switcher = open_tab_switcher(true, &workspace, cx);
|
||||
tab_switcher.update(cx, |tab_switcher, _| {
|
||||
assert_eq!(tab_switcher.delegate.matches.len(), 3);
|
||||
assert_match_at_position(tab_switcher, 0, tab_3);
|
||||
assert_match_at_position(tab_switcher, 1, tab_2);
|
||||
assert_match_selection(tab_switcher, 2, tab_1);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_item_on_modifiers_release(cx: &mut gpui::TestAppContext) {
|
||||
let app_state = init_test(cx);
|
||||
|
||||
app_state
|
||||
.fs
|
||||
.as_fake()
|
||||
.insert_tree(
|
||||
path!("/root"),
|
||||
json!({
|
||||
"1.txt": "First file",
|
||||
"2.txt": "Second file",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;
|
||||
let (multi_workspace, cx) =
|
||||
cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
|
||||
let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
|
||||
|
||||
let tab_1 = open_buffer("1.txt", &workspace, cx).await;
|
||||
let tab_2 = open_buffer("2.txt", &workspace, cx).await;
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::control());
|
||||
let tab_switcher = open_tab_switcher(false, &workspace, cx);
|
||||
tab_switcher.update(cx, |tab_switcher, _| {
|
||||
assert_eq!(tab_switcher.delegate.matches.len(), 2);
|
||||
assert_match_at_position(tab_switcher, 0, tab_2.boxed_clone());
|
||||
assert_match_selection(tab_switcher, 1, tab_1.boxed_clone());
|
||||
});
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::none());
|
||||
cx.read(|cx| {
|
||||
let active_editor = workspace.read(cx).active_item_as::<Editor>(cx).unwrap();
|
||||
assert_eq!(active_editor.read(cx).title(cx), "1.txt");
|
||||
});
|
||||
assert_tab_switcher_is_closed(workspace, cx);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_on_empty_pane(cx: &mut gpui::TestAppContext) {
|
||||
let app_state = init_test(cx);
|
||||
app_state.fs.as_fake().insert_tree("/root", json!({})).await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
|
||||
let (multi_workspace, cx) =
|
||||
cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
|
||||
let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::control());
|
||||
let tab_switcher = open_tab_switcher(false, &workspace, cx);
|
||||
tab_switcher.update(cx, |tab_switcher, _| {
|
||||
assert!(tab_switcher.delegate.matches.is_empty());
|
||||
});
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::none());
|
||||
assert_tab_switcher_is_closed(workspace, cx);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_with_single_item(cx: &mut gpui::TestAppContext) {
|
||||
let app_state = init_test(cx);
|
||||
app_state
|
||||
.fs
|
||||
.as_fake()
|
||||
.insert_tree(path!("/root"), json!({"1.txt": "Single file"}))
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;
|
||||
let (multi_workspace, cx) =
|
||||
cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
|
||||
let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
|
||||
|
||||
let tab = open_buffer("1.txt", &workspace, cx).await;
|
||||
|
||||
let tab_switcher = open_tab_switcher(false, &workspace, cx);
|
||||
tab_switcher.update(cx, |tab_switcher, _| {
|
||||
assert_eq!(tab_switcher.delegate.matches.len(), 1);
|
||||
assert_match_selection(tab_switcher, 0, tab);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_close_selected_item(cx: &mut gpui::TestAppContext) {
|
||||
let app_state = init_test(cx);
|
||||
app_state
|
||||
.fs
|
||||
.as_fake()
|
||||
.insert_tree(
|
||||
path!("/root"),
|
||||
json!({
|
||||
"1.txt": "First file",
|
||||
"2.txt": "Second file",
|
||||
"3.txt": "Third file",
|
||||
"4.txt": "Fourth file",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;
|
||||
let (multi_workspace, cx) =
|
||||
cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
|
||||
let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
|
||||
|
||||
let tab_1 = open_buffer("1.txt", &workspace, cx).await;
|
||||
let tab_3 = open_buffer("3.txt", &workspace, cx).await;
|
||||
let tab_2 = open_buffer("2.txt", &workspace, cx).await;
|
||||
let tab_4 = open_buffer("4.txt", &workspace, cx).await;
|
||||
|
||||
// After opening all buffers, let's navigate to the previous item two times, finishing with:
|
||||
//
|
||||
// 1.txt | [3.txt] | 2.txt | 4.txt
|
||||
//
|
||||
// With 3.txt being the active item in the pane.
|
||||
cx.dispatch_action(ActivatePreviousItem::default());
|
||||
cx.dispatch_action(ActivatePreviousItem::default());
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::control());
|
||||
let tab_switcher = open_tab_switcher(false, &workspace, cx);
|
||||
tab_switcher.update(cx, |tab_switcher, _| {
|
||||
assert_eq!(tab_switcher.delegate.matches.len(), 4);
|
||||
assert_match_at_position(tab_switcher, 0, tab_3.boxed_clone());
|
||||
assert_match_selection(tab_switcher, 1, tab_2.boxed_clone());
|
||||
assert_match_at_position(tab_switcher, 2, tab_4.boxed_clone());
|
||||
assert_match_at_position(tab_switcher, 3, tab_1.boxed_clone());
|
||||
});
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::control());
|
||||
cx.dispatch_action(CloseSelectedItem);
|
||||
tab_switcher.update(cx, |tab_switcher, _| {
|
||||
assert_eq!(tab_switcher.delegate.matches.len(), 3);
|
||||
assert_match_selection(tab_switcher, 0, tab_3);
|
||||
assert_match_at_position(tab_switcher, 1, tab_4);
|
||||
assert_match_at_position(tab_switcher, 2, tab_1);
|
||||
});
|
||||
|
||||
// Still switches tab on modifiers release
|
||||
cx.simulate_modifiers_change(Modifiers::none());
|
||||
cx.read(|cx| {
|
||||
let active_editor = workspace.read(cx).active_item_as::<Editor>(cx).unwrap();
|
||||
assert_eq!(active_editor.read(cx).title(cx), "3.txt");
|
||||
});
|
||||
assert_tab_switcher_is_closed(workspace, cx);
|
||||
}
|
||||
|
||||
fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
|
||||
cx.update(|cx| {
|
||||
let state = AppState::test(cx);
|
||||
theme_settings::init(theme::LoadThemes::JustBase, cx);
|
||||
super::init(cx);
|
||||
editor::init(cx);
|
||||
state
|
||||
})
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn open_tab_switcher(
|
||||
select_last: bool,
|
||||
workspace: &Entity<Workspace>,
|
||||
cx: &mut VisualTestContext,
|
||||
) -> Entity<Picker<TabSwitcherDelegate>> {
|
||||
cx.dispatch_action(Toggle { select_last });
|
||||
get_active_tab_switcher(workspace, cx)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn get_active_tab_switcher(
|
||||
workspace: &Entity<Workspace>,
|
||||
cx: &mut VisualTestContext,
|
||||
) -> Entity<Picker<TabSwitcherDelegate>> {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace
|
||||
.active_modal::<TabSwitcher>(cx)
|
||||
.expect("tab switcher is not open")
|
||||
.read(cx)
|
||||
.picker
|
||||
.clone()
|
||||
})
|
||||
}
|
||||
|
||||
async fn open_buffer(
|
||||
file_path: &str,
|
||||
workspace: &Entity<Workspace>,
|
||||
cx: &mut gpui::VisualTestContext,
|
||||
) -> Box<dyn ItemHandle> {
|
||||
let project = workspace.read_with(cx, |workspace, _| workspace.project().clone());
|
||||
let worktree_id = project.update(cx, |project, cx| {
|
||||
let worktree = project.worktrees(cx).last().expect("worktree not found");
|
||||
worktree.read(cx).id()
|
||||
});
|
||||
let project_path = ProjectPath {
|
||||
worktree_id,
|
||||
path: rel_path(file_path).into(),
|
||||
};
|
||||
workspace
|
||||
.update_in(cx, move |workspace, window, cx| {
|
||||
workspace.open_path(project_path, None, true, window, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_match_selection(
|
||||
tab_switcher: &Picker<TabSwitcherDelegate>,
|
||||
expected_selection_index: usize,
|
||||
expected_item: Box<dyn ItemHandle>,
|
||||
) {
|
||||
assert_eq!(
|
||||
tab_switcher.delegate.selected_index(),
|
||||
expected_selection_index,
|
||||
"item is not selected"
|
||||
);
|
||||
assert_match_at_position(tab_switcher, expected_selection_index, expected_item);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_match_at_position(
|
||||
tab_switcher: &Picker<TabSwitcherDelegate>,
|
||||
match_index: usize,
|
||||
expected_item: Box<dyn ItemHandle>,
|
||||
) {
|
||||
let match_item = tab_switcher
|
||||
.delegate
|
||||
.matches
|
||||
.get(match_index)
|
||||
.unwrap_or_else(|| panic!("Tab Switcher has no match for index {match_index}"));
|
||||
assert_eq!(match_item.item.item_id(), expected_item.item_id());
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_tab_switcher_is_closed(workspace: Entity<Workspace>, cx: &mut VisualTestContext) {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
assert!(
|
||||
workspace.active_modal::<TabSwitcher>(cx).is_none(),
|
||||
"tab switcher is still open"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn open_tab_switcher_for_active_pane(
|
||||
workspace: &Entity<Workspace>,
|
||||
cx: &mut VisualTestContext,
|
||||
) -> Entity<Picker<TabSwitcherDelegate>> {
|
||||
cx.dispatch_action(OpenInActivePane);
|
||||
get_active_tab_switcher(workspace, cx)
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_in_active_pane_deduplicates_files_by_path(cx: &mut gpui::TestAppContext) {
|
||||
let app_state = init_test(cx);
|
||||
app_state
|
||||
.fs
|
||||
.as_fake()
|
||||
.insert_tree(
|
||||
path!("/root"),
|
||||
json!({
|
||||
"1.txt": "",
|
||||
"2.txt": "",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;
|
||||
let (multi_workspace, cx) =
|
||||
cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
|
||||
let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
|
||||
|
||||
open_buffer("1.txt", &workspace, cx).await;
|
||||
open_buffer("2.txt", &workspace, cx).await;
|
||||
|
||||
workspace.update_in(cx, |workspace, window, cx| {
|
||||
workspace.split_pane(
|
||||
workspace.active_pane().clone(),
|
||||
workspace::SplitDirection::Right,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
open_buffer("1.txt", &workspace, cx).await;
|
||||
|
||||
let tab_switcher = open_tab_switcher_for_active_pane(&workspace, cx);
|
||||
|
||||
tab_switcher.read_with(cx, |picker, _cx| {
|
||||
assert_eq!(
|
||||
picker.delegate.matches.len(),
|
||||
2,
|
||||
"should show 2 unique files despite 3 tabs"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_in_active_pane_clones_files_to_current_pane(cx: &mut gpui::TestAppContext) {
|
||||
let app_state = init_test(cx);
|
||||
app_state
|
||||
.fs
|
||||
.as_fake()
|
||||
.insert_tree(path!("/root"), json!({"1.txt": ""}))
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;
|
||||
let (multi_workspace, cx) =
|
||||
cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
|
||||
let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
|
||||
|
||||
open_buffer("1.txt", &workspace, cx).await;
|
||||
|
||||
workspace.update_in(cx, |workspace, window, cx| {
|
||||
workspace.split_pane(
|
||||
workspace.active_pane().clone(),
|
||||
workspace::SplitDirection::Right,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let panes = workspace.read_with(cx, |workspace, _| workspace.panes().to_vec());
|
||||
|
||||
let tab_switcher = open_tab_switcher_for_active_pane(&workspace, cx);
|
||||
tab_switcher.update(cx, |picker, _| {
|
||||
picker.delegate.selected_index = 0;
|
||||
});
|
||||
|
||||
cx.dispatch_action(menu::Confirm);
|
||||
cx.run_until_parked();
|
||||
|
||||
let editor_1 = panes[0].read_with(cx, |pane, cx| {
|
||||
pane.active_item()
|
||||
.and_then(|item| item.act_as::<Editor>(cx))
|
||||
.expect("pane 1 should have editor")
|
||||
});
|
||||
|
||||
let editor_2 = panes[1].read_with(cx, |pane, cx| {
|
||||
pane.active_item()
|
||||
.and_then(|item| item.act_as::<Editor>(cx))
|
||||
.expect("pane 2 should have editor")
|
||||
});
|
||||
|
||||
assert_ne!(
|
||||
editor_1.entity_id(),
|
||||
editor_2.entity_id(),
|
||||
"should clone to new instance"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_in_active_pane_moves_terminals_to_current_pane(cx: &mut gpui::TestAppContext) {
|
||||
let app_state = init_test(cx);
|
||||
let project = Project::test(app_state.fs.clone(), [], cx).await;
|
||||
let (multi_workspace, cx) =
|
||||
cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
|
||||
let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
|
||||
|
||||
let test_item = cx.new(|cx| TestItem::new(cx).with_label("terminal"));
|
||||
workspace.update_in(cx, |workspace, window, cx| {
|
||||
workspace.add_item_to_active_pane(Box::new(test_item.clone()), None, true, window, cx);
|
||||
});
|
||||
|
||||
workspace.update_in(cx, |workspace, window, cx| {
|
||||
workspace.split_pane(
|
||||
workspace.active_pane().clone(),
|
||||
workspace::SplitDirection::Right,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
let panes = workspace.read_with(cx, |workspace, _| workspace.panes().to_vec());
|
||||
|
||||
let tab_switcher = open_tab_switcher_for_active_pane(&workspace, cx);
|
||||
tab_switcher.update(cx, |picker, _| {
|
||||
picker.delegate.selected_index = 0;
|
||||
});
|
||||
|
||||
cx.dispatch_action(menu::Confirm);
|
||||
cx.run_until_parked();
|
||||
|
||||
assert!(
|
||||
!panes[0].read_with(cx, |pane, _| {
|
||||
pane.items()
|
||||
.any(|item| item.item_id() == test_item.item_id())
|
||||
}),
|
||||
"should be removed from pane 1"
|
||||
);
|
||||
assert!(
|
||||
panes[1].read_with(cx, |pane, _| {
|
||||
pane.items()
|
||||
.any(|item| item.item_id() == test_item.item_id())
|
||||
}),
|
||||
"should be moved to pane 2"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_open_in_active_pane_closes_file_in_all_panes(cx: &mut gpui::TestAppContext) {
|
||||
let app_state = init_test(cx);
|
||||
app_state
|
||||
.fs
|
||||
.as_fake()
|
||||
.insert_tree(path!("/root"), json!({"1.txt": ""}))
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;
|
||||
let (multi_workspace, cx) =
|
||||
cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
|
||||
let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
|
||||
|
||||
open_buffer("1.txt", &workspace, cx).await;
|
||||
|
||||
workspace.update_in(cx, |workspace, window, cx| {
|
||||
workspace.split_pane(
|
||||
workspace.active_pane().clone(),
|
||||
workspace::SplitDirection::Right,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
open_buffer("1.txt", &workspace, cx).await;
|
||||
|
||||
let panes = workspace.read_with(cx, |workspace, _| workspace.panes().to_vec());
|
||||
|
||||
let tab_switcher = open_tab_switcher_for_active_pane(&workspace, cx);
|
||||
tab_switcher.update(cx, |picker, _| {
|
||||
picker.delegate.selected_index = 0;
|
||||
});
|
||||
|
||||
cx.dispatch_action(CloseSelectedItem);
|
||||
cx.run_until_parked();
|
||||
|
||||
for pane in &panes {
|
||||
assert_eq!(
|
||||
pane.read_with(cx, |pane, _| pane.items_len()),
|
||||
0,
|
||||
"all panes should be empty"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_toggle_all_stays_open_after_closing_last_tab_in_active_pane(
|
||||
cx: &mut gpui::TestAppContext,
|
||||
) {
|
||||
let app_state = init_test(cx);
|
||||
app_state
|
||||
.fs
|
||||
.as_fake()
|
||||
.insert_tree(
|
||||
path!("/root"),
|
||||
json!({
|
||||
"a.txt": "",
|
||||
"b.txt": "",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;
|
||||
let (multi_workspace, cx) =
|
||||
cx.add_window_view(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
|
||||
let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone());
|
||||
|
||||
let tab_a = open_buffer("a.txt", &workspace, cx).await;
|
||||
workspace.update_in(cx, |workspace, window, cx| {
|
||||
workspace.split_pane(
|
||||
workspace.active_pane().clone(),
|
||||
workspace::SplitDirection::Right,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
open_buffer("b.txt", &workspace, cx).await;
|
||||
|
||||
// Right pane (with b.txt) is now the active pane.
|
||||
cx.dispatch_action(ToggleAll);
|
||||
let tab_switcher = get_active_tab_switcher(&workspace, cx);
|
||||
|
||||
tab_switcher.update(cx, |picker, _| {
|
||||
assert_eq!(picker.delegate.matches.len(), 2);
|
||||
// Explicitly select b.txt (index 0, the most recently activated item)
|
||||
// to close the last tab in the active (right) pane.
|
||||
picker.delegate.selected_index = 0;
|
||||
});
|
||||
|
||||
cx.dispatch_action(CloseSelectedItem);
|
||||
cx.run_until_parked();
|
||||
|
||||
// Tab switcher must remain open with a.txt as the only match
|
||||
let tab_switcher = get_active_tab_switcher(&workspace, cx);
|
||||
tab_switcher.update(cx, |picker, cx| {
|
||||
assert_eq!(picker.delegate.matches.len(), 1);
|
||||
assert_match_at_position(picker, 0, tab_a.boxed_clone());
|
||||
let _ = cx;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user