diff options
author | Aram Drevekenin <aram@poor.dev> | 2023-02-15 16:16:53 +0100 |
---|---|---|
committer | Aram Drevekenin <aram@poor.dev> | 2023-02-15 16:16:53 +0100 |
commit | c560f31b4552992ed29b3857cc65297f70047ed4 (patch) | |
tree | e9fb0847271a5b3c1a341b5cb5f6da53a92838e9 | |
parent | 5dd319c8528ee5f25580baee94596e639513f3b9 (diff) |
fix(ux): move pane forward/backwards also with floating panes
21 files changed, 184 insertions, 16 deletions
diff --git a/default-plugins/status-bar/src/second_line.rs b/default-plugins/status-bar/src/second_line.rs index aa251cec1..b7c8a9cec 100644 --- a/default-plugins/status-bar/src/second_line.rs +++ b/default-plugins/status-bar/src/second_line.rs @@ -210,6 +210,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<Key>)> { &[Action::MovePane(Some(Dir::Left))], &[Action::MovePane(Some(Dir::Down))], &[Action::MovePane(Some(Dir::Up))], &[Action::MovePane(Some(Dir::Right))]])), (s("Next pane"), s("Next"), action_key(&km, &[Action::MovePane(None)])), + (s("Previous pane"), s("Previous"), action_key(&km, &[Action::MovePaneBackwards])), ]} else if mi.mode == IM::Scroll { vec![ (s("Scroll"), s("Scroll"), action_key_group(&km, &[&[Action::ScrollDown], &[Action::ScrollUp]])), diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap index 00c75da3d..d797b10ba 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__send_command_through_the_cli.snap @@ -25,5 +25,5 @@ expression: last_snapshot │ ││ │ │ ││ │ └──────────────────────────────────────────────────────────┘└ [ EXIT CODE: 0 ] <ENTER> to re-run, <Ctrl-c> to exit ────┘ - Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT BASE + Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap index 9eb969e7e..01f65fb12 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_floating_panes.snap @@ -25,5 +25,5 @@ expression: last_snapshot │ │ │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ - Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT BASE + Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT (FLOATING PANES VISIBLE): Press Ctrl+p, <w> to hide. diff --git a/zellij-server/src/panes/floating_panes/floating_pane_grid.rs b/zellij-server/src/panes/floating_panes/floating_pane_grid.rs index 55ea46dd5..9f034956d 100644 --- a/zellij-server/src/panes/floating_panes/floating_pane_grid.rs +++ b/zellij-server/src/panes/floating_panes/floating_pane_grid.rs @@ -703,6 +703,58 @@ impl<'a> FloatingPaneGrid<'a> { .copied(); next_index } + pub fn next_selectable_pane_id(&self, current_pane_id: &PaneId) -> Option<PaneId> { + let panes = self.panes.borrow(); + let mut panes: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes + .iter() + .filter(|(_, p)| p.selectable()) + .map(|(p_id, p)| (*p_id, p)) + .collect(); + panes.sort_by(|(_a_id, a_pane), (_b_id, b_pane)| { + if a_pane.y() == b_pane.y() { + a_pane.x().cmp(&b_pane.x()) + } else { + a_pane.y().cmp(&b_pane.y()) + } + }); + let active_pane_position = panes + .iter() + .position(|(id, _)| id == current_pane_id) + .unwrap(); + + let next_active_pane_id = panes + .get(active_pane_position + 1) + .or_else(|| panes.get(0)) + .map(|p| p.0) + .unwrap(); + Some(next_active_pane_id) + } + pub fn previous_selectable_pane_id(&self, current_pane_id: &PaneId) -> Option<PaneId> { + let panes = self.panes.borrow(); + let mut panes: Vec<(PaneId, &&mut Box<dyn Pane>)> = panes + .iter() + .filter(|(_, p)| p.selectable()) + .map(|(p_id, p)| (*p_id, p)) + .collect(); + panes.sort_by(|(_a_id, a_pane), (_b_id, b_pane)| { + if a_pane.y() == b_pane.y() { + a_pane.x().cmp(&b_pane.x()) + } else { + a_pane.y().cmp(&b_pane.y()) + } + }); + let active_pane_position = panes + .iter() + .position(|(id, _)| id == current_pane_id)?; + + let last_pane = panes.last()?; + let previous_active_pane_id = if active_pane_position == 0 { + last_pane.0 + } else { + panes.get(active_pane_position - 1)?.0 + }; + Some(previous_active_pane_id) + } pub fn find_room_for_new_pane(&self) -> Option<PaneGeom> { let panes = self.panes.borrow(); let pane_geoms: Vec<PaneGeom> = panes.values().map(|p| p.position_and_size()).collect(); diff --git a/zellij-server/src/panes/floating_panes/mod.rs b/zellij-server/src/panes/floating_panes/mod.rs index 77abda645..34a5fc320 100644 --- a/zellij-server/src/panes/floating_panes/mod.rs +++ b/zellij-server/src/panes/floating_panes/mod.rs @@ -592,6 +592,45 @@ impl FloatingPanes { self.set_force_render(); } } + pub fn move_active_pane(&mut self, search_backwards: bool, os_api: &mut Box<dyn ServerOsApi>, client_id: ClientId) { + let active_pane_id = self.get_active_pane_id(client_id).unwrap(); + + let new_position_id = { + let pane_grid = FloatingPaneGrid::new( + &mut self.panes, + &mut self.desired_pane_positions, + *self.display_area.borrow(), + *self.viewport.borrow(), + ); + if search_backwards { + pane_grid.previous_selectable_pane_id(&active_pane_id) + } else { + pane_grid.next_selectable_pane_id(&active_pane_id) + } + }; + if let Some(new_position_id) = new_position_id { + let current_position = self.panes.get(&active_pane_id).unwrap(); + let prev_geom = current_position.position_and_size(); + let prev_geom_override = current_position.geom_override(); + + let new_position = self.panes.get_mut(&new_position_id).unwrap(); + let next_geom = new_position.position_and_size(); + let next_geom_override = new_position.geom_override(); + new_position.set_geom(prev_geom); + if let Some(geom) = prev_geom_override { + new_position.set_geom_override(geom); + } + new_position.set_should_render(true); + + let current_position = self.panes.get_mut(&active_pane_id).unwrap(); + current_position.set_geom(next_geom); + if let Some(geom) = next_geom_override { + current_position.set_geom_override(geom); + } + current_position.set_should_render(true); + self.set_pane_frames(os_api); + } + } pub fn move_clients_out_of_pane(&mut self, pane_id: PaneId) { let active_panes: Vec<(ClientId, PaneId)> = self .active_panes diff --git a/zellij-server/src/panes/tiled_panes/mod.rs b/zellij-server/src/panes/tiled_panes/mod.rs index dca3afd84..411e0178e 100644 --- a/zellij-server/src/panes/tiled_panes/mod.rs +++ b/zellij-server/src/panes/tiled_panes/mod.rs @@ -1017,7 +1017,7 @@ impl TiledPanes { self.set_pane_frames(self.draw_pane_frames); } } - pub fn move_active_pane(&mut self, client_id: ClientId) { + pub fn move_active_pane(&mut self, search_backwards: bool, client_id: ClientId) { let active_pane_id = self.get_active_pane_id(client_id).unwrap(); let new_position_id = { @@ -1027,7 +1027,11 @@ impl TiledPanes { *self.display_area.borrow(), *self.viewport.borrow(), ); - pane_grid.next_selectable_pane_id(&active_pane_id) + if search_backwards { + pane_grid.previous_selectable_pane_id(&active_pane_id) + } else { + pane_grid.next_selectable_pane_id(&active_pane_id) + } }; if self.panes.get(&new_position_id).map(|p| p.current_geom().is_stacked).unwrap_or(false) { let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide).focus_pane(&new_position_id); diff --git a/zellij-server/src/panes/tiled_panes/stacked_panes.rs b/zellij-server/src/panes/tiled_panes/stacked_panes.rs index 40f5bb1b1..3a3531de8 100644 --- a/zellij-server/src/panes/tiled_panes/stacked_panes.rs +++ b/zellij-server/src/panes/tiled_panes/stacked_panes.rs @@ -93,8 +93,6 @@ impl <'a>StackedPanes <'a>{ panes.get_mut(&flexible_pane_id).with_context(err_context)?.set_geom(flexible_pane); for (i, (pid, _position)) in all_stacked_pane_positions.iter().enumerate() { - // if (i < position_of_pane_to_focus && i < position_of_flexible_pane) || (i > position_of_pane_to_focus && i > position_of_flexible_pane) { - // continue; if i > position_of_pane_to_focus && i <= position_of_flexible_pane { // the flexible pane has moved up the stack, we need to push this pane down let pane = panes.get_mut(pid).with_context(err_context)?; diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index 46f20c08b..028a81489 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -165,6 +165,12 @@ pub(crate) fn route_action( .send_to_screen(screen_instr) .with_context(err_context)?; }, + Action::MovePaneBackwards => { + session + .senders + .send_to_screen(ScreenInstruction::MovePaneBackwards(client_id)) + .with_context(err_context)?; + }, Action::DumpScreen(val, full) => { session .senders diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index ae18707cd..6d101ac6e 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -149,6 +149,7 @@ pub enum ScreenInstruction { MoveFocusRight(ClientId), MoveFocusRightOrNextTab(ClientId), MovePane(ClientId), + MovePaneBackwards(ClientId), MovePaneUp(ClientId), MovePaneDown(ClientId), MovePaneRight(ClientId), @@ -287,6 +288,7 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenContext::MoveFocusRightOrNextTab }, ScreenInstruction::MovePane(..) => ScreenContext::MovePane, + ScreenInstruction::MovePaneBackwards(..) => ScreenContext::MovePaneBackwards, ScreenInstruction::MovePaneDown(..) => ScreenContext::MovePaneDown, ScreenInstruction::MovePaneUp(..) => ScreenContext::MovePaneUp, ScreenInstruction::MovePaneRight(..) => ScreenContext::MovePaneRight, @@ -1660,6 +1662,16 @@ pub(crate) fn screen_thread_main( screen.render()?; screen.unblock_input()?; }, + ScreenInstruction::MovePaneBackwards(client_id) => { + active_tab_and_connected_client_id!( + screen, + client_id, + |tab: &mut Tab, client_id: ClientId| tab.move_active_pane_backwards(client_id) + ); + screen.update_tabs()?; // update tabs so that the ui indication will be send to the plugins + screen.render()?; + screen.unblock_input()?; + }, ScreenInstruction::MovePaneDown(client_id) => { active_tab_and_connected_client_id!( screen, diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index a6c439e2a..99f471da5 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -2061,7 +2061,26 @@ impl Tab { if self.tiled_panes.fullscreen_is_active() { return; } - self.tiled_panes.move_active_pane(client_id); + let search_backwards = false; + if self.floating_panes.panes_are_visible() { + self.floating_panes.move_active_pane(search_backwards, &mut self.os_api, client_id); + } else { + self.tiled_panes.move_active_pane(search_backwards, client_id); + } + } + pub fn move_active_pane_backwards(&mut self, client_id: ClientId) { + if !self.has_selectable_panes() { + return; + } + if self.tiled_panes.fullscreen_is_active() { + return; + } + let search_backwards = true; + if self.floating_panes.panes_are_visible() { + self.floating_panes.move_active_pane(search_backwards, &mut self.os_api, client_id); + } else { + self.tiled_panes.move_active_pane(search_backwards, client_id); + } } pub fn move_active_pane_down(&mut self, client_id: ClientId) { if self.floating_panes.panes_are_visible() { diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index 00acac666..9a3d685ad 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -1222,7 +1222,7 @@ pub fn send_cli_move_pane_action() { server_receiver ); let cli_action = CliAction::MovePane { - direction: Direction::Right, + direction: Some(Direction::Right), }; send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); diff --git a/zellij-utils/assets/config/default.kdl b/zellij-utils/assets/config/default.kdl index df39c0de9..6131efc27 100644 --- a/zellij-utils/assets/config/default.kdl +++ b/zellij-utils/assets/config/default.kdl @@ -40,6 +40,7 @@ keybinds { move { bind "Ctrl h" { SwitchToMode "Normal"; } bind "n" "Tab" { MovePane; } + bind "p" { MovePaneBackwards; } bind "h" "Left" { MovePane "Left"; } bind "j" "Down" { MovePane "Down"; } bind "k" "Up" { MovePane "Up"; } diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs index 660dc6d3c..4facc6443 100644 --- a/zellij-utils/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -197,9 +197,11 @@ pub enum CliAction { /// Move focus to the pane or tab (if on screen edge) in the specified direction /// [right|left|up|down] MoveFocusOrTab { direction: Direction }, - /// Change the location of the focused pane in the specified direction + /// Change the location of the focused pane in the specified direction or rotate forwrads /// [right|left|up|down] - MovePane { direction: Direction }, + MovePane { direction: Option<Direction> }, + /// Rotate the location of the previous pane backwards + MovePaneBackwards, /// Dump the focused pane to a file DumpScreen { path: PathBuf, diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index 87f4ac3ec..0ea1190f6 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -285,6 +285,7 @@ pub enum ScreenContext { MoveFocusRight, MoveFocusRightOrNextTab, MovePane, + MovePaneBackwards, MovePaneDown, MovePaneUp, MovePaneRight, diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index 2aca3107c..8183f3263 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -115,6 +115,7 @@ pub enum Action { /// If there is no pane in the direction, move to previous/next Tab. MoveFocusOrTab(Direction), MovePane(Option<Direction>), + MovePaneBackwards, /// Dumps the screen to a file DumpScreen(String, bool), /// Scroll up in focus pane. @@ -219,7 +220,8 @@ impl Action { CliAction::FocusPreviousPane => Ok(vec![Action::FocusPreviousPane]), CliAction::MoveFocus { direction } => Ok(vec![Action::MoveFocus(direction)]), CliAction::MoveFocusOrTab { direction } => Ok(vec![Action::MoveFocusOrTab(direction)]), - CliAction::MovePane { direction } => Ok(vec![Action::MovePane(Some(direction))]), + CliAction::MovePane { direction } => Ok(vec![Action::MovePane(direction)]), + CliAction::MovePaneBackwards => Ok(vec![Action::MovePaneBackwards]), CliAction::DumpScreen { path, full } => Ok(vec![Action::DumpScreen( path.as_os_str().to_string_lossy().into(), full, diff --git a/zellij-utils/src/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs index 8801f4612..cfe098cd6 100644 --- a/zellij-utils/src/kdl/mod.rs +++ b/zellij-utils/src/kdl/mod.rs @@ -453,6 +453,7 @@ impl Action { Ok(Action::MovePane(Some(direction))) } }, + "MovePaneBackwards" => Ok(Action::MovePaneBackwards), "DumpScreen" => Ok(Action::DumpScreen(string, false)), "NewPane" => { if string.is_empty() { @@ -727,6 +728,11 @@ impl TryFrom<&KdlNode> for Action { action_arguments, kdl_action ), + "MovePaneBackwards" => parse_kdl_action_char_or_string_arguments!( + action_name, + action_arguments, + kdl_action + ), "DumpScreen" => parse_kdl_action_char_or_string_arguments!( action_name, action_arguments, diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap index 056a687ca..2d5aea7b4 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap @@ -1,6 +1,6 @@ --- source: zellij-utils/src/setup.rs -assertion_line: 600 +assertion_line: 621 expression: "format!(\"{:#?}\", config)" --- Config { @@ -2737,6 +2737,11 @@ Config { None, ), ], + Char( + 'p', + ): [ + MovePaneBackwards, + ], Alt( Char( '+', diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap index 5e72b510f..8e94086a5 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap @@ -1,6 +1,6 @@ --- source: zellij-utils/src/setup.rs -assertion_line: 658 +assertion_line: 679 expression: "format!(\"{:#?}\", config)" --- Config { @@ -2737,6 +2737,11 @@ Config { None, ), ], + Char( + 'p', + ): [ + MovePaneBackwards, + ], Alt( Char( |