From a37d3e5889476bbac209d20f89886daa3e9d3992 Mon Sep 17 00:00:00 2001 From: Aram Drevekenin Date: Thu, 12 Aug 2021 14:50:00 +0200 Subject: [PATCH] feat(ui): pane frames (new pane UI) (#643) * work * resize working * move focus working * close pane working * selection and fullscreen working * pane title line * titles and conditional scroll title * whole tab resize working * plugin frames working * plugin splitting working * truncate pane frame titles * cleanup * panes always draw their own borders - also fix gap * toggle pane frames * move toggle to screen and fix some bugs * fix plugin frame toggle * fix terminal window resize * fix scrolling and fullscreen bugs * unit tests passing * e2e tests passing and new test for new frames added * refactor: TerminalPane and PluginPane * refactor: Tab * refactor: moar Tab * refactor: Boundaries * only render and calculate boundaries when there are no pane frames * refactor: Layout * fix(grid): properly resize when coming back from alternative viewport * style: remove commented code * style: fmt * style: fmt * style: fmt + clippy * docs(changelog): update change --- CHANGELOG.md | 1 + default-plugins/status-bar/src/main.rs | 6 +- default-plugins/strider/src/state.rs | 6 +- default-plugins/tab-bar/src/line.rs | 6 +- src/tests/e2e/cases.rs | 140 ++- src/tests/e2e/remote_runner.rs | 53 +- ...sts__e2e__cases__accepts_basic_layout.snap | 48 +- ...lly_when_active_terminal_is_too_small.snap | 4 +- ...zellij__tests__e2e__cases__close_pane.snap | 4 +- ...e2e__cases__detach_and_attach_session.snap | 44 +- ...ts__e2e__cases__focus_pane_with_mouse.snap | 42 +- .../zellij__tests__e2e__cases__lock_mode.snap | 4 +- ...llij__tests__e2e__cases__open_new_tab.snap | 4 +- ...ellij__tests__e2e__cases__resize_pane.snap | 44 +- ...s__e2e__cases__resize_terminal_window.snap | 44 +- ...__e2e__cases__scrolling_inside_a_pane.snap | 44 +- ...s__scrolling_inside_a_pane_with_mouse.snap | 42 +- ...2e__cases__split_terminals_vertically.snap | 44 +- ...e2e__cases__start_without_pane_frames.snap | 29 + ..._e2e__cases__starts_with_one_terminal.snap | 4 +- ...s__e2e__cases__toggle_pane_fullscreen.snap | 10 +- zellij-server/src/panes/grid.rs | 88 +- zellij-server/src/panes/plugin_pane.rs | 195 +++- zellij-server/src/panes/terminal_pane.rs | 201 +++- zellij-server/src/panes/unit/grid_tests.rs | 4 +- .../src/panes/unit/terminal_pane_tests.rs | 2 +- zellij-server/src/route.rs | 6 + zellij-server/src/screen.rs | 17 + zellij-server/src/tab.rs | 868 +++++++++++++---- zellij-server/src/ui/boundaries.rs | 159 ++- zellij-server/src/ui/mod.rs | 1 + zellij-server/src/ui/pane_boundaries_frame.rs | 277 ++++++ zellij-server/src/ui/pane_resizer.rs | 64 +- zellij-server/src/ui/title_telescope.rs | 0 zellij-server/src/unit/screen_tests.rs | 9 +- zellij-server/src/unit/tab_tests.rs | 915 +++++++++--------- zellij-server/src/wasm_vm.rs | 16 +- zellij-utils/assets/config/default.yaml | 2 + zellij-utils/assets/layouts/default.yaml | 2 + .../assets/layouts/disable-status-bar.yaml | 1 + zellij-utils/assets/layouts/strider.yaml | 2 + zellij-utils/src/errors.rs | 1 + zellij-utils/src/input/actions.rs | 2 + zellij-utils/src/input/layout.rs | 22 +- zellij-utils/src/input/mod.rs | 1 + zellij-utils/src/input/options.rs | 5 + zellij-utils/src/pane_size.rs | 14 +- zellij-utils/src/shared.rs | 2 +- 48 files changed, 2420 insertions(+), 1079 deletions(-) create mode 100644 src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap create mode 100644 zellij-server/src/ui/pane_boundaries_frame.rs create mode 100644 zellij-server/src/ui/title_telescope.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 97f68875b..fa985b353 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) * Bound by default to `^c` in `scroll` mode, scrolls to bottom and exists the scroll mode * Simplify deserialization slightly (https://github.com/zellij-org/zellij/pull/633) * Fix update plugin attributes on inactive tab (https://github.com/zellij-org/zellij/pull/634) +* New pane UI: draw pane frames - can be disabled with ctrl-p + z, or through configuration (https://github.com/zellij-org/zellij/pull/643) ## [0.15.0] - 2021-07-19 * Kill children properly (https://github.com/zellij-org/zellij/pull/601) diff --git a/default-plugins/status-bar/src/main.rs b/default-plugins/status-bar/src/main.rs index 83eb50c9a..dba373f6b 100644 --- a/default-plugins/status-bar/src/main.rs +++ b/default-plugins/status-bar/src/main.rs @@ -154,7 +154,11 @@ impl ZellijPlugin for State { let colored_elements = color_elements(self.mode_info.palette); let superkey = superkey(colored_elements, separator); - let ctrl_keys = ctrl_keys(&self.mode_info, cols - superkey.len, separator); + let ctrl_keys = ctrl_keys( + &self.mode_info, + cols.saturating_sub(superkey.len), + separator, + ); let first_line = format!("{}{}", superkey, ctrl_keys); let second_line = keybinds(&self.mode_info, cols); diff --git a/default-plugins/strider/src/state.rs b/default-plugins/strider/src/state.rs index 0d96ae0b9..0ae84ab29 100644 --- a/default-plugins/strider/src/state.rs +++ b/default-plugins/strider/src/state.rs @@ -47,10 +47,10 @@ impl FsEntry { FsEntry::Dir(_, s) => s.to_string(), FsEntry::File(_, s) => pb::convert(*s as f64), }; - let space = width - info.len(); + let space = width.saturating_sub(info.len()); let name = self.name(); - if space - 1 < name.len() { - [&name[..space - 2], &info].join("~ ") + if space.saturating_sub(1) < name.len() { + [&name[..space.saturating_sub(2)], &info].join("~ ") } else { let padding = " ".repeat(space - name.len()); [name, padding, info].concat() diff --git a/default-plugins/tab-bar/src/line.rs b/default-plugins/tab-bar/src/line.rs index 3ebeaac31..fc18abfd1 100644 --- a/default-plugins/tab-bar/src/line.rs +++ b/default-plugins/tab-bar/src/line.rs @@ -191,7 +191,7 @@ pub fn tab_line( &mut tabs_before_active, &mut tabs_after_active, &mut tabs_to_render, - cols - prefix.len, + cols.saturating_sub(prefix.len), ); let mut tab_line: Vec = vec![]; @@ -200,7 +200,7 @@ pub fn tab_line( &mut tabs_before_active, &mut tabs_to_render, &mut tab_line, - cols - prefix.len, + cols.saturating_sub(prefix.len), palette, tab_separator(capabilities), ); @@ -210,7 +210,7 @@ pub fn tab_line( add_next_tabs_msg( &mut tabs_after_active, &mut tab_line, - cols - prefix.len, + cols.saturating_sub(prefix.len), palette, tab_separator(capabilities), ); diff --git a/src/tests/e2e/cases.rs b/src/tests/e2e/cases.rs index 8d41d44f9..d28ae2f76 100644 --- a/src/tests/e2e/cases.rs +++ b/src/tests/e2e/cases.rs @@ -221,26 +221,26 @@ pub fn scrolling_inside_a_pane() { let mut step_is_complete = false; if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { // cursor is in the newly opened second pane - remote_terminal.send_key(&format!("{:0<57}", "line1 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line2 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line3 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line4 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line5 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line6 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line7 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line8 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line9 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line10 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line11 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line12 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line13 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line14 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line15 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line16 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line17 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line18 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line19 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<58}", "line20 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<56}", "line1 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line2 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line3 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line4 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line5 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line6 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line7 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line8 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line9 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line10 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line11 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line12 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line13 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line14 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line15 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line16 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line17 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line18 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line19 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<57}", "line20 ").as_bytes()); step_is_complete = true; } step_is_complete @@ -250,7 +250,7 @@ pub fn scrolling_inside_a_pane() { name: "Scroll up inside pane", instruction: |mut remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.cursor_position_is(119, 20) { + if remote_terminal.cursor_position_is(118, 20) { // all lines have been written to the pane remote_terminal.send_key(&SCROLL_MODE); remote_terminal.send_key(&SCROLL_UP_IN_SCROLL_MODE); @@ -263,7 +263,7 @@ pub fn scrolling_inside_a_pane() { name: "Wait for scroll to finish", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.cursor_position_is(119, 20) + if remote_terminal.cursor_position_is(118, 20) && remote_terminal.snapshot_contains("line1 ") { // scrolled up one line @@ -321,7 +321,7 @@ pub fn toggle_pane_fullscreen() { name: "Wait for pane to become fullscreen", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.cursor_position_is(2, 0) { + if remote_terminal.cursor_position_is(2, 2) { // cursor is in full screen pane now step_is_complete = true; } @@ -785,9 +785,9 @@ pub fn accepts_basic_layout() { name: "Wait for app to load", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.cursor_position_is(2, 0) - && remote_terminal.snapshot_contains("$ █ │$") - && remote_terminal.snapshot_contains("$ ") { + if remote_terminal.cursor_position_is(3, 1) + && remote_terminal.snapshot_contains("$ █ ││$") + && remote_terminal.snapshot_contains("$ ") { step_is_complete = true; } step_is_complete @@ -839,7 +839,7 @@ fn focus_pane_with_mouse() { name: "Wait for left pane to be focused", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.cursor_position_is(2, 2) && remote_terminal.tip_appears() { + if remote_terminal.cursor_position_is(3, 2) && remote_terminal.tip_appears() { // cursor is in the newly opened second pane step_is_complete = true; } @@ -884,26 +884,26 @@ pub fn scrolling_inside_a_pane_with_mouse() { let mut step_is_complete = false; if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { // cursor is in the newly opened second pane - remote_terminal.send_key(&format!("{:0<57}", "line1 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line2 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line3 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line4 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line5 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line6 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line7 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line8 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line9 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line10 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line11 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line12 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line13 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line14 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line15 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line16 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line17 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line18 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<59}", "line19 ").as_bytes()); - remote_terminal.send_key(&format!("{:0<58}", "line20 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<56}", "line1 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line2 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line3 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line4 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line5 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line6 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line7 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line8 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line9 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line10 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line11 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line12 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line13 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line14 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line15 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line16 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line17 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line18 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<58}", "line19 ").as_bytes()); + remote_terminal.send_key(&format!("{:0<57}", "line20 ").as_bytes()); step_is_complete = true; } step_is_complete @@ -913,7 +913,7 @@ pub fn scrolling_inside_a_pane_with_mouse() { name: "Scroll up inside pane", instruction: |mut remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.cursor_position_is(119, 20) { + if remote_terminal.cursor_position_is(118, 20) { // all lines have been written to the pane remote_terminal.send_key(&normal_mouse_report(Position::new(2, 64), 64)); step_is_complete = true; @@ -925,7 +925,7 @@ pub fn scrolling_inside_a_pane_with_mouse() { name: "Wait for scroll to finish", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.cursor_position_is(119, 20) + if remote_terminal.cursor_position_is(118, 20) && remote_terminal.snapshot_contains("line1 ") { // scrolled up one line @@ -937,3 +937,45 @@ pub fn scrolling_inside_a_pane_with_mouse() { .run_all_steps(); assert_snapshot!(last_snapshot); } + +#[test] +#[ignore] +pub fn start_without_pane_frames() { + let fake_win_size = PositionAndSize { + cols: 120, + rows: 24, + x: 0, + y: 0, + ..Default::default() + }; + + let last_snapshot = RemoteRunner::new_without_frames("no_pane_frames", fake_win_size, None) + .add_step(Step { + name: "Split pane to the right", + instruction: |mut remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(2, 1) + { + remote_terminal.send_key(&PANE_MODE); + remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); + // back to normal mode after split + remote_terminal.send_key(&ENTER); + step_is_complete = true; + } + step_is_complete + }, + }) + .add_step(Step { + name: "Wait for new pane to appear", + instruction: |remote_terminal: RemoteTerminal| -> bool { + let mut step_is_complete = false; + if remote_terminal.cursor_position_is(62, 1) && remote_terminal.tip_appears() { + // cursor is in the newly opened second pane + step_is_complete = true; + } + step_is_complete + }, + }) + .run_all_steps(); + assert_snapshot!(last_snapshot); +} diff --git a/src/tests/e2e/remote_runner.rs b/src/tests/e2e/remote_runner.rs index 053df477a..09ca8eae9 100644 --- a/src/tests/e2e/remote_runner.rs +++ b/src/tests/e2e/remote_runner.rs @@ -57,6 +57,13 @@ fn start_zellij(channel: &mut ssh2::Channel, session_name: Option<&String>) { channel.flush().unwrap(); } +fn start_zellij_without_frames(channel: &mut ssh2::Channel) { + channel + .write_all(format!("{} options --no-pane-frames\n", ZELLIJ_EXECUTABLE_LOCATION).as_bytes()) + .unwrap(); + channel.flush().unwrap(); +} + fn start_zellij_with_layout( channel: &mut ssh2::Channel, layout_path: &str, @@ -136,7 +143,8 @@ impl<'a> RemoteTerminal<'a> { self.current_snapshot.contains("Tip:") } pub fn status_bar_appears(&self) -> bool { - self.current_snapshot.contains("Ctrl +") && !self.current_snapshot.contains("─────") + self.current_snapshot.contains("Ctrl +") + // self.current_snapshot.contains("Ctrl +") && !self.current_snapshot.contains("─────") // this is a bug that happens because the app draws borders around the status bar momentarily on first render } pub fn snapshot_contains(&self, text: &str) -> bool { @@ -198,6 +206,7 @@ pub struct RemoteRunner { retries_left: usize, win_size: PositionAndSize, layout_file_name: Option<&'static str>, + without_frames: bool, } impl RemoteRunner { @@ -209,7 +218,7 @@ impl RemoteRunner { let sess = ssh_connect(); let mut channel = sess.channel_session().unwrap(); let vte_parser = vte::Parser::new(); - let terminal_output = TerminalPane::new(0, win_size, Palette::default()); + let terminal_output = TerminalPane::new(0, win_size, Palette::default(), 0); // 0 is the pane index setup_remote_environment(&mut channel, win_size); start_zellij(&mut channel, session_name.as_ref()); RemoteRunner { @@ -224,6 +233,33 @@ impl RemoteRunner { retries_left: 3, win_size, layout_file_name: None, + without_frames: false, + } + } + pub fn new_without_frames( + test_name: &'static str, + win_size: PositionAndSize, + session_name: Option, + ) -> Self { + let sess = ssh_connect(); + let mut channel = sess.channel_session().unwrap(); + let vte_parser = vte::Parser::new(); + let terminal_output = TerminalPane::new(0, win_size, Palette::default(), 0); // 0 is the pane index + setup_remote_environment(&mut channel, win_size); + start_zellij_without_frames(&mut channel); + RemoteRunner { + steps: vec![], + channel, + terminal_output, + vte_parser, + session_name, + test_name, + currently_running_step: None, + current_step_index: 0, + retries_left: 3, + win_size, + layout_file_name: None, + without_frames: true, } } pub fn new_with_layout( @@ -232,12 +268,11 @@ impl RemoteRunner { layout_file_name: &'static str, session_name: Option, ) -> Self { - // let layout_file_name = local_layout_path.file_name().unwrap(); - let remote_path = Path::new(ZELLIJ_LAYOUT_PATH).join(layout_file_name); // TODO: not hardcoded + let remote_path = Path::new(ZELLIJ_LAYOUT_PATH).join(layout_file_name); let sess = ssh_connect(); let mut channel = sess.channel_session().unwrap(); let vte_parser = vte::Parser::new(); - let terminal_output = TerminalPane::new(0, win_size, Palette::default()); + let terminal_output = TerminalPane::new(0, win_size, Palette::default(), 0); // 0 is the pane index setup_remote_environment(&mut channel, win_size); start_zellij_with_layout( &mut channel, @@ -256,6 +291,7 @@ impl RemoteRunner { retries_left: 3, win_size, layout_file_name: Some(layout_file_name), + without_frames: false, } } pub fn add_step(mut self, step: Step) -> Self { @@ -315,6 +351,13 @@ impl RemoteRunner { new_runner.replace_steps(self.steps.clone()); drop(std::mem::replace(self, new_runner)); self.run_all_steps() + } else if self.without_frames { + let mut new_runner = + RemoteRunner::new_without_frames(self.test_name, self.win_size, session_name); + new_runner.retries_left = self.retries_left - 1; + new_runner.replace_steps(self.steps.clone()); + drop(std::mem::replace(self, new_runner)); + self.run_all_steps() } else { let mut new_runner = RemoteRunner::new(self.test_name, self.win_size, session_name); new_runner.retries_left = self.retries_left - 1; diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__accepts_basic_layout.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__accepts_basic_layout.snap index 5556153a5..02ded6de5 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__accepts_basic_layout.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__accepts_basic_layout.snap @@ -3,27 +3,27 @@ source: src/tests/e2e/cases.rs expression: last_snapshot --- -$ █ │$ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ -───────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────── -$ - - - - +┌ Pane #1 ─────────────┐┌ Pane #2 ─────────────────────────────────────────────────────────────────────────────────────┐ +│$ █ ││$ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +└──────────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────┘ +┌ Pane #3 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│$ │ +│ │ +│ │ +└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__cannot_split_terminals_vertically_when_active_terminal_is_too_small.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__cannot_split_terminals_vertically_when_active_terminal_is_too_small.snap index 23ffc097d..91c83a443 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__cannot_split_terminals_vertically_when_active_terminal_is_too_small.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__cannot_split_terminals_vertically_when_active_terminal_is_too_small.snap @@ -1,10 +1,10 @@ --- -source: src/tests/integration/e2e.rs +source: src/tests/e2e/cases.rs expression: last_snapshot --- - +──────── $ Hi!█ diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__close_pane.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__close_pane.snap index 32f6d26f2..e74870283 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__close_pane.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__close_pane.snap @@ -1,10 +1,10 @@ --- -source: src/tests/integration/e2e.rs +source: src/tests/e2e/cases.rs expression: last_snapshot --- Zellij  Tab #1  - +─ Pane #1 ────────────────────────────────────────────────────────────────────────────────────────────────────────────── $ █ diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap index 983331aa2..92484dd68 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__detach_and_attach_session.snap @@ -1,29 +1,29 @@ --- -source: src/tests/integration/e2e.rs +source: src/tests/e2e/cases.rs expression: last_snapshot --- Zellij  Tab #1  - -$ │$ I am some text█ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - +┌ Pane #1 ─────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐ +│$ ││$ I am some text█ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  SCROLL  SESSION  QUIT  Tip: Alt + n => open new pane. Alt + [] or hjkl => navigate between panes. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap index 79e84810d..5a4097606 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__focus_pane_with_mouse.snap @@ -4,26 +4,26 @@ expression: last_snapshot --- Zellij  Tab #1  - -$ █ │$ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - +┌ Pane #1 ─────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐ +│$ █ ││$ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  SCROLL  SESSION  QUIT  Tip: Alt + n => open new pane. Alt + [] or hjkl => navigate between panes. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__lock_mode.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__lock_mode.snap index bc54e6753..0796484c6 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__lock_mode.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__lock_mode.snap @@ -1,10 +1,10 @@ --- -source: src/tests/integration/e2e.rs +source: src/tests/e2e/cases.rs expression: last_snapshot --- Zellij  Tab #1  - +─ Pane #1 ────────────────────────────────────────────────────────────────────────────────────────────────────────────── $ nabc█ diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__open_new_tab.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__open_new_tab.snap index 9b8267835..f9b84f68d 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__open_new_tab.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__open_new_tab.snap @@ -1,10 +1,10 @@ --- -source: src/tests/integration/e2e.rs +source: src/tests/e2e/cases.rs expression: last_snapshot --- Zellij  Tab #1  Tab #2  - +─ Pane #1 ────────────────────────────────────────────────────────────────────────────────────────────────────────────── $ █ diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap index 5f1ed7f64..ae130ab5b 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_pane.snap @@ -1,29 +1,29 @@ --- -source: src/tests/integration/e2e.rs +source: src/tests/e2e/cases.rs expression: last_snapshot --- Zellij  Tab #1  - -$ │$ █ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - +┌ Pane #1 ───────────────────────────────────────┐┌ Pane #2 ───────────────────────────────────────────────────────────┐ +│$ ││$ █ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +└────────────────────────────────────────────────┘└────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  SCROLL  SESSION  QUIT  Tip: Alt + n => open new pane. Alt + [] or hjkl => navigate between panes. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap index a57d4849a..b329e8c6d 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__resize_terminal_window.snap @@ -1,29 +1,29 @@ --- -source: src/tests/integration/e2e.rs +source: src/tests/e2e/cases.rs expression: last_snapshot --- Zellij  Tab #1  - -$ │$ █ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - +┌ Pane #1 ─────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐ +│$ ││$ █ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +└──────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  SCROLL  SESSION  QUIT  Tip: Alt + n => open new pane. Alt + [] or hjkl => navigate between panes. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane.snap index a609be4f2..a33ab400c 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane.snap @@ -1,29 +1,29 @@ --- -source: src/tests/integration/e2e.rs +source: src/tests/e2e/cases.rs expression: last_snapshot --- Zellij  Tab #1  - -$ │$ line1 000000000000000000000000000000000000000000000000000 - │line2 00000000000000000000000000000000000000000000000000000 - │line3 00000000000000000000000000000000000000000000000000000 - │line4 00000000000000000000000000000000000000000000000000000 - │line5 00000000000000000000000000000000000000000000000000000 - │line6 00000000000000000000000000000000000000000000000000000 - │line7 00000000000000000000000000000000000000000000000000000 - │line8 00000000000000000000000000000000000000000000000000000 - │line9 00000000000000000000000000000000000000000000000000000 - │line10 0000000000000000000000000000000000000000000000000000 - │line11 0000000000000000000000000000000000000000000000000000 - │line12 0000000000000000000000000000000000000000000000000000 - │line13 0000000000000000000000000000000000000000000000000000 - │line14 0000000000000000000000000000000000000000000000000000 - │line15 0000000000000000000000000000000000000000000000000000 - │line16 0000000000000000000000000000000000000000000000000000 - │line17 0000000000000000000000000000000000000000000000000000 - │line18 0000000000000000000000000000000000000000000000000000 - │line19 000000000000000000000000000000000000000000000000000█ - +┌ Pane #1 ─────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────── SCROLL: 1/1 ┐ +│$ ││$ line1 00000000000000000000000000000000000000000000000000│ +│ ││line2 0000000000000000000000000000000000000000000000000000│ +│ ││line3 0000000000000000000000000000000000000000000000000000│ +│ ││line4 0000000000000000000000000000000000000000000000000000│ +│ ││line5 0000000000000000000000000000000000000000000000000000│ +│ ││line6 0000000000000000000000000000000000000000000000000000│ +│ ││line7 0000000000000000000000000000000000000000000000000000│ +│ ││line8 0000000000000000000000000000000000000000000000000000│ +│ ││line9 0000000000000000000000000000000000000000000000000000│ +│ ││line10 000000000000000000000000000000000000000000000000000│ +│ ││line11 000000000000000000000000000000000000000000000000000│ +│ ││line12 000000000000000000000000000000000000000000000000000│ +│ ││line13 000000000000000000000000000000000000000000000000000│ +│ ││line14 000000000000000000000000000000000000000000000000000│ +│ ││line15 000000000000000000000000000000000000000000000000000│ +│ ││line16 000000000000000000000000000000000000000000000000000│ +│ ││line17 000000000000000000000000000000000000000000000000000│ +│ ││line18 000000000000000000000000000000000000000000000000000│ +│ ││line19 00000000000000000000000000000000000000000000000000█│ +└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  SCROLL  SESSION  QUIT  <↓↑> Scroll / Scroll Page / Select pane diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap index bff403764..dfed0611d 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__scrolling_inside_a_pane_with_mouse.snap @@ -4,26 +4,26 @@ expression: last_snapshot --- Zellij  Tab #1  - -$ │$ line1 000000000000000000000000000000000000000000000000000 - │line2 00000000000000000000000000000000000000000000000000000 - │line3 00000000000000000000000000000000000000000000000000000 - │line4 00000000000000000000000000000000000000000000000000000 - │line5 00000000000000000000000000000000000000000000000000000 - │line6 00000000000000000000000000000000000000000000000000000 - │line7 00000000000000000000000000000000000000000000000000000 - │line8 00000000000000000000000000000000000000000000000000000 - │line9 00000000000000000000000000000000000000000000000000000 - │line10 0000000000000000000000000000000000000000000000000000 - │line11 0000000000000000000000000000000000000000000000000000 - │line12 0000000000000000000000000000000000000000000000000000 - │line13 0000000000000000000000000000000000000000000000000000 - │line14 0000000000000000000000000000000000000000000000000000 - │line15 0000000000000000000000000000000000000000000000000000 - │line16 0000000000000000000000000000000000000000000000000000 - │line17 0000000000000000000000000000000000000000000000000000 - │line18 0000000000000000000000000000000000000000000000000000 - │line19 000000000000000000000000000000000000000000000000000█ - +┌ Pane #1 ─────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────── SCROLL: 1/1 ┐ +│$ ││$ line1 00000000000000000000000000000000000000000000000000│ +│ ││line2 0000000000000000000000000000000000000000000000000000│ +│ ││line3 0000000000000000000000000000000000000000000000000000│ +│ ││line4 0000000000000000000000000000000000000000000000000000│ +│ ││line5 0000000000000000000000000000000000000000000000000000│ +│ ││line6 0000000000000000000000000000000000000000000000000000│ +│ ││line7 0000000000000000000000000000000000000000000000000000│ +│ ││line8 0000000000000000000000000000000000000000000000000000│ +│ ││line9 0000000000000000000000000000000000000000000000000000│ +│ ││line10 000000000000000000000000000000000000000000000000000│ +│ ││line11 000000000000000000000000000000000000000000000000000│ +│ ││line12 000000000000000000000000000000000000000000000000000│ +│ ││line13 000000000000000000000000000000000000000000000000000│ +│ ││line14 000000000000000000000000000000000000000000000000000│ +│ ││line15 000000000000000000000000000000000000000000000000000│ +│ ││line16 000000000000000000000000000000000000000000000000000│ +│ ││line17 000000000000000000000000000000000000000000000000000│ +│ ││line18 000000000000000000000000000000000000000000000000000│ +│ ││line19 00000000000000000000000000000000000000000000000000█│ +└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  SCROLL  SESSION  QUIT  Tip: Alt + n => open new pane. Alt + [] or hjkl => navigate between panes. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap index bbb5b068a..36f0e6d89 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__split_terminals_vertically.snap @@ -1,29 +1,29 @@ --- -source: src/tests/integration/e2e.rs +source: src/tests/e2e/cases.rs expression: last_snapshot --- Zellij  Tab #1  - -$ │$ █ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - │ - +┌ Pane #1 ─────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐ +│$ ││$ █ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  SCROLL  SESSION  QUIT  Tip: Alt + n => open new pane. Alt + [] or hjkl => navigate between panes. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap new file mode 100644 index 000000000..85c6db546 --- /dev/null +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__start_without_pane_frames.snap @@ -0,0 +1,29 @@ +--- +source: src/tests/e2e/cases.rs +expression: last_snapshot + +--- + Zellij  Tab #1  +$ │$ █ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + │ + Ctrl + LOCK 

PANE  TAB  RESIZE  SCROLL  SESSION  QUIT  + Tip: Alt + n => open new pane. Alt + [] or hjkl => navigate between panes. diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__starts_with_one_terminal.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__starts_with_one_terminal.snap index 32f6d26f2..e74870283 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__starts_with_one_terminal.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__starts_with_one_terminal.snap @@ -1,10 +1,10 @@ --- -source: src/tests/integration/e2e.rs +source: src/tests/e2e/cases.rs expression: last_snapshot --- Zellij  Tab #1  - +─ Pane #1 ────────────────────────────────────────────────────────────────────────────────────────────────────────────── $ █ diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_pane_fullscreen.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_pane_fullscreen.snap index 98ddffc76..9108099d5 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_pane_fullscreen.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__toggle_pane_fullscreen.snap @@ -1,8 +1,10 @@ --- -source: src/tests/integration/e2e.rs +source: src/tests/e2e/cases.rs expression: last_snapshot --- + Zellij  Tab #1  +─ Pane #2 ────────────────────────────────────────────────────────────────────────────────────────────────────────────── $ █ @@ -23,7 +25,5 @@ $ █ - - - - + Ctrl + LOCK 

PANE  TAB  RESIZE  SCROLL  SESSION  QUIT  + Tip: Alt + n => open new pane. Alt + [] or hjkl => navigate between panes. diff --git a/zellij-server/src/panes/grid.rs b/zellij-server/src/panes/grid.rs index df9b7a9ce..2ae2fe9cc 100644 --- a/zellij-server/src/panes/grid.rs +++ b/zellij-server/src/panes/grid.rs @@ -10,7 +10,8 @@ use std::{ use zellij_utils::{position::Position, vte, zellij_tile}; const TABSTOP_WIDTH: usize = 8; // TODO: is this always right? -const SCROLL_BACK: usize = 10_000; +pub const SCROLL_BACK: usize = 10_000; +pub const MAX_TITLE_STACK_SIZE: usize = 1000; use vte::{Params, Perform}; use zellij_tile::data::{Palette, PaletteColor}; @@ -308,6 +309,7 @@ pub struct Grid { preceding_char: Option, colors: Palette, output_buffer: OutputBuffer, + title_stack: Vec, pub should_render: bool, pub cursor_key_mode: bool, // DECCKM - when set, cursor keys should send ANSI direction codes (eg. "OD") instead of the arrow keys (eg. "") pub erasure_mode: bool, // ERM @@ -318,6 +320,7 @@ pub struct Grid { pub height: usize, pub pending_messages_to_pty: Vec>, pub selection: Selection, + pub title: Option, } impl Debug for Grid { @@ -358,6 +361,8 @@ impl Grid { colors, output_buffer: Default::default(), selection: Default::default(), + title_stack: vec![], + title: None, } } pub fn render_full_viewport(&mut self) { @@ -404,6 +409,23 @@ impl Grid { pub fn cursor_shape(&self) -> CursorShape { self.cursor.get_shape() } + pub fn scrollback_position_and_length(&self) -> (usize, usize) { + // (position, length) + let mut scrollback_buffer_count = 0; + for row in self.lines_above.iter() { + let row_width = row.width(); + // rows in lines_above are unwrapped, so we need to account for that + if row_width > self.width { + scrollback_buffer_count += (row_width as f64 / self.width as f64).ceil() as usize; + } else { + scrollback_buffer_count += 1; + } + } + ( + self.lines_below.len(), + (scrollback_buffer_count + self.lines_below.len()), + ) + } fn set_horizontal_tabstop(&mut self) { self.horizontal_tabstops.insert(self.cursor.x); } @@ -475,8 +497,17 @@ impl Grid { if !self.lines_above.is_empty() && self.viewport.len() == self.height { let line_to_push_down = self.viewport.pop().unwrap(); self.lines_below.insert(0, line_to_push_down); - let line_to_insert_at_viewport_top = self.lines_above.pop_back().unwrap(); - self.viewport.insert(0, line_to_insert_at_viewport_top); + + transfer_rows_down( + &mut self.lines_above, + &mut self.viewport, + 1, + None, + Some(self.width), + ); + + // let line_to_insert_at_viewport_top = self.lines_above.pop_back().unwrap(); + // self.viewport.insert(0, line_to_insert_at_viewport_top); self.selection.move_down(1); } self.output_buffer.update_all_lines(); @@ -497,6 +528,24 @@ impl Grid { self.output_buffer.update_all_lines(); } } + fn force_change_size(&mut self, new_rows: usize, new_columns: usize) { + // this is an ugly hack - it's here because sometimes we need to change_size to the + // existing size (eg. when resizing an alternative_grid to the current height/width) and + // the change_size method is a no-op in that case. Should be fixed by making the + // change_size method atomic + let intermediate_rows = if new_rows == self.height { + new_rows + 1 + } else { + new_rows + }; + let intermediate_columns = if new_columns == self.width { + new_columns + 1 + } else { + new_columns + }; + self.change_size(intermediate_rows, intermediate_columns); + self.change_size(new_rows, new_columns); + } pub fn change_size(&mut self, new_rows: usize, new_columns: usize) { self.selection.reset(); if new_columns != self.width { @@ -1200,7 +1249,7 @@ impl Grid { let empty_row = Row::from_columns(vec![EMPTY_TERMINAL_CHARACTER; self.width]); // get the row from lines_above, viewport, or lines below depending on index - let row = if l < 0 { + let row = if l < 0 && self.lines_above.len() > l.abs() as usize { let offset_from_end = l.abs(); &self.lines_above[self .lines_above @@ -1211,8 +1260,12 @@ impl Grid { } else if (l as usize) < self.height { // index is in viewport but there is no line &empty_row - } else { + } else if self.lines_below.len() > (l as usize).saturating_sub(self.viewport.len()) { &self.lines_below[(l as usize) - self.viewport.len()] + } else { + // can't find the line, this probably it's on the pane border + // is on the pane border + continue; }; let excess_width = row.excess_width(); @@ -1242,6 +1295,22 @@ impl Grid { self.output_buffer.update_line(l as usize); } } + fn set_title(&mut self, title: String) { + self.title = Some(title); + } + fn push_current_title_to_stack(&mut self) { + if self.title_stack.len() > MAX_TITLE_STACK_SIZE { + self.title_stack.remove(0); + } + if let Some(title) = self.title.as_ref() { + self.title_stack.push(title.clone()); + } + } + fn pop_title_from_stack(&mut self) { + if let Some(popped_title) = self.title_stack.pop() { + self.title = Some(popped_title); + } + } } impl Perform for Grid { @@ -1311,7 +1380,7 @@ impl Perform for Grid { // Set window title. b"0" | b"2" => { if params.len() >= 2 { - let _title = params[1..] + let title = params[1..] .iter() .flat_map(|x| str::from_utf8(x)) .collect::>() @@ -1319,6 +1388,7 @@ impl Perform for Grid { .trim() .to_owned(); // TBD: do something with title? + self.set_title(title); } } @@ -1521,7 +1591,7 @@ impl Perform for Grid { } self.alternative_lines_above_viewport_and_cursor = None; self.clear_viewport_before_rendering = true; - self.change_size(self.height, self.width); // the alternative_viewport might have been of a different size... + self.force_change_size(self.height, self.width); // the alternative_viewport might have been of a different size... self.mark_for_rerender(); } Some(25) => { @@ -1758,10 +1828,10 @@ impl Perform for Grid { .push(text_area_report.as_bytes().to_vec()); } 22 => { - // TODO: push title + self.push_current_title_to_stack(); } 23 => { - // TODO: pop title + self.pop_title_from_stack(); } _ => {} } diff --git a/zellij-server/src/panes/plugin_pane.rs b/zellij-server/src/panes/plugin_pane.rs index 256ceaea1..3bac21ebd 100644 --- a/zellij-server/src/panes/plugin_pane.rs +++ b/zellij-server/src/panes/plugin_pane.rs @@ -2,10 +2,13 @@ use std::sync::mpsc::channel; use std::time::Instant; use std::unimplemented; -use crate::panes::PaneId; +use crate::panes::{PaneDecoration, PaneId}; use crate::pty::VteBytes; use crate::tab::Pane; +use crate::ui::pane_boundaries_frame::PaneBoundariesFrame; use crate::wasm_vm::PluginInstruction; +use zellij_utils::shared::ansi_len; +use zellij_utils::zellij_tile::prelude::PaletteColor; use zellij_utils::{channels::SenderWithContext, pane_size::PositionAndSize}; pub(crate) struct PluginPane { @@ -15,8 +18,11 @@ pub(crate) struct PluginPane { pub invisible_borders: bool, pub position_and_size: PositionAndSize, pub position_and_size_override: Option, + pub content_position_and_size: PositionAndSize, pub send_plugin_instructions: SenderWithContext, pub active_at: Instant, + pub pane_title: String, + pane_decoration: PaneDecoration, } impl PluginPane { @@ -24,6 +30,7 @@ impl PluginPane { pid: u32, position_and_size: PositionAndSize, send_plugin_instructions: SenderWithContext, + title: String, ) -> Self { Self { pid, @@ -34,8 +41,48 @@ impl PluginPane { position_and_size_override: None, send_plugin_instructions, active_at: Instant::now(), + pane_decoration: PaneDecoration::ContentOffset((0, 0)), + content_position_and_size: position_and_size, + pane_title: title, } } + pub fn get_content_x(&self) -> usize { + self.get_content_posision_and_size().x + } + pub fn get_content_y(&self) -> usize { + self.get_content_posision_and_size().y + } + pub fn get_content_columns(&self) -> usize { + // content columns might differ from the pane's columns if the pane has a frame + // in that case they would be 2 less + self.get_content_posision_and_size().cols + } + pub fn get_content_rows(&self) -> usize { + // content rows might differ from the pane's rows if the pane has a frame + // in that case they would be 2 less + self.get_content_posision_and_size().rows + } + pub fn get_content_posision_and_size(&self) -> PositionAndSize { + self.content_position_and_size + } + fn redistribute_space(&mut self) { + let position_and_size = self + .position_and_size_override + .unwrap_or_else(|| self.position_and_size()); + match &mut self.pane_decoration { + PaneDecoration::BoundariesFrame(boundaries_frame) => { + boundaries_frame.change_pos_and_size(position_and_size); + self.content_position_and_size = boundaries_frame.content_position_and_size(); + } + PaneDecoration::ContentOffset((content_columns_offset, content_rows_offset)) => { + self.content_position_and_size = position_and_size; + self.content_position_and_size.cols = + position_and_size.cols - *content_columns_offset; + self.content_position_and_size.rows = position_and_size.rows - *content_rows_offset; + } + }; + self.set_should_render(true); + } } impl Pane for PluginPane { @@ -62,13 +109,20 @@ impl Pane for PluginPane { .unwrap_or(self.position_and_size) .cols } + fn get_content_columns(&self) -> usize { + self.get_content_columns() + } + fn get_content_rows(&self) -> usize { + self.get_content_rows() + } fn reset_size_and_position_override(&mut self) { self.position_and_size_override = None; + self.redistribute_space(); self.should_render = true; } fn change_pos_and_size(&mut self, position_and_size: &PositionAndSize) { self.position_and_size = *position_and_size; - self.should_render = true; + self.redistribute_space(); } // FIXME: This is obviously a bit outdated and needs the x and y moved into `size` fn override_size_and_position(&mut self, x: usize, y: usize, size: &PositionAndSize) { @@ -80,7 +134,7 @@ impl Pane for PluginPane { ..Default::default() }; self.position_and_size_override = Some(position_and_size_override); - self.should_render = true; + self.redistribute_space(); } fn handle_pty_bytes(&mut self, _event: VteBytes) { unimplemented!() @@ -103,6 +157,11 @@ impl Pane for PluginPane { fn set_should_render(&mut self, should_render: bool) { self.should_render = should_render; } + fn set_should_render_boundaries(&mut self, should_render: bool) { + if let PaneDecoration::BoundariesFrame(boundaries_frame) = &mut self.pane_decoration { + boundaries_frame.set_should_render(should_render); + } + } fn selectable(&self) -> bool { self.selectable } @@ -127,19 +186,70 @@ impl Pane for PluginPane { // is more performant, it causes some problems when the pane to the left should be // rendered and has wide characters (eg. Chinese characters or emoji) // as a (hopefully) temporary hack, we render all panes until we find a better solution + let mut vte_output = String::new(); let (buf_tx, buf_rx) = channel(); self.send_plugin_instructions .send(PluginInstruction::Render( buf_tx, self.pid, - self.rows(), - self.columns(), + self.get_content_rows(), + self.get_content_columns(), )) .unwrap(); self.should_render = false; - Some(buf_rx.recv().unwrap()) + let contents = buf_rx.recv().unwrap(); + if let PaneDecoration::BoundariesFrame(boundaries_frame) = &mut self.pane_decoration { + if let Some(boundaries_frame_vte) = boundaries_frame.render() { + vte_output.push_str(&boundaries_frame_vte); + } + } + for (index, line) in contents.lines().enumerate() { + let actual_len = ansi_len(line); + let line_to_print = if actual_len > self.get_content_columns() { + let mut line = String::from(line); + line.truncate(self.get_content_columns()); + line + } else { + [ + line, + &str::repeat(" ", self.get_content_columns() - ansi_len(line)), + ] + .concat() + }; + + vte_output.push_str(&format!( + "\u{1b}[{};{}H\u{1b}[m{}", + self.get_content_y() + 1 + index, + self.get_content_x() + 1, + line_to_print, + )); // goto row/col and reset styles + let line_len = line_to_print.len(); + if line_len < self.get_content_columns() { + // pad line + for _ in line_len..self.get_content_columns() { + vte_output.push(' '); + } + } + } + let total_line_count = contents.lines().count(); + if total_line_count < self.get_content_rows() { + // pad lines + for line_index in total_line_count..self.get_content_rows() { + let x = self.get_content_x(); + let y = self.get_content_y(); + vte_output.push_str(&format!( + "\u{1b}[{};{}H\u{1b}[m", + y + line_index + 1, + x + 1 + )); // goto row/col and reset styles + for _col_index in 0..self.get_content_columns() { + vte_output.push(' '); + } + } + } + Some(vte_output) } else { None } @@ -150,50 +260,66 @@ impl Pane for PluginPane { fn reduce_height_down(&mut self, count: usize) { self.position_and_size.y += count; self.position_and_size.rows -= count; + self.redistribute_space(); self.should_render = true; } fn increase_height_down(&mut self, count: usize) { self.position_and_size.rows += count; + self.redistribute_space(); self.should_render = true; } fn increase_height_up(&mut self, count: usize) { self.position_and_size.y -= count; self.position_and_size.rows += count; + self.redistribute_space(); self.should_render = true; } fn reduce_height_up(&mut self, count: usize) { self.position_and_size.rows -= count; + self.redistribute_space(); self.should_render = true; } fn reduce_width_right(&mut self, count: usize) { self.position_and_size.x += count; self.position_and_size.cols -= count; + self.redistribute_space(); self.should_render = true; } fn reduce_width_left(&mut self, count: usize) { self.position_and_size.cols -= count; + self.redistribute_space(); self.should_render = true; } fn increase_width_left(&mut self, count: usize) { self.position_and_size.x -= count; self.position_and_size.cols += count; + self.redistribute_space(); self.should_render = true; } fn increase_width_right(&mut self, count: usize) { self.position_and_size.cols += count; + self.redistribute_space(); self.should_render = true; } fn push_down(&mut self, count: usize) { self.position_and_size.y += count; + self.redistribute_space(); + self.should_render = true; } fn push_right(&mut self, count: usize) { self.position_and_size.x += count; + self.redistribute_space(); + self.should_render = true; } fn pull_left(&mut self, count: usize) { self.position_and_size.x -= count; + self.redistribute_space(); + self.should_render = true; } fn pull_up(&mut self, count: usize) { self.position_and_size.y -= count; + self.redistribute_space(); + self.should_render = true; } fn scroll_up(&mut self, _count: usize) { //unimplemented!() @@ -231,4 +357,61 @@ impl Pane for PluginPane { fn set_active_at(&mut self, time: Instant) { self.active_at = time; } + fn set_boundary_color(&mut self, color: Option) { + if let PaneDecoration::BoundariesFrame(boundaries_frame) = &mut self.pane_decoration { + boundaries_frame.set_color(color); + } + } + fn offset_content_columns(&mut self, by: usize) { + if !self.selectable { + return; + } + if let PaneDecoration::ContentOffset(content_offset) = &mut self.pane_decoration { + content_offset.0 = by; + } else { + self.pane_decoration = PaneDecoration::ContentOffset((by, 0)); + } + self.redistribute_space(); + self.set_should_render(true); + } + fn offset_content_rows(&mut self, by: usize) { + if !self.selectable { + return; + } + if let PaneDecoration::ContentOffset(content_offset) = &mut self.pane_decoration { + content_offset.1 = by; + } else { + self.pane_decoration = PaneDecoration::ContentOffset((0, by)); + } + self.redistribute_space(); + self.set_should_render(true); + } + fn show_boundaries_frame(&mut self, should_render_only_title: bool) { + if !self.selectable { + return; + } + let position_and_size = self + .position_and_size_override + .unwrap_or(self.position_and_size); + if let PaneDecoration::BoundariesFrame(boundaries_frame) = &mut self.pane_decoration { + boundaries_frame.render_only_title(should_render_only_title); + self.content_position_and_size = boundaries_frame.content_position_and_size(); + } else { + let mut boundaries_frame = + PaneBoundariesFrame::new(position_and_size, self.pane_title.clone()); + boundaries_frame.render_only_title(should_render_only_title); + self.content_position_and_size = boundaries_frame.content_position_and_size(); + self.pane_decoration = PaneDecoration::BoundariesFrame(boundaries_frame); + } + self.redistribute_space(); + self.set_should_render(true); + } + fn remove_boundaries_frame(&mut self) { + if !self.selectable { + return; + } + self.pane_decoration = PaneDecoration::ContentOffset((0, 0)); + self.redistribute_space(); + self.set_should_render(true); + } } diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs index 0dc28aa74..658ecaf63 100644 --- a/zellij-server/src/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -6,6 +6,7 @@ use std::fmt::Debug; use std::os::unix::io::RawFd; use std::time::{self, Instant}; use zellij_tile::data::Palette; + use zellij_utils::pane_size::PositionAndSize; use crate::panes::AnsiCode; @@ -20,22 +21,32 @@ use crate::tab::Pane; pub const SELECTION_SCROLL_INTERVAL_MS: u64 = 10; +use crate::ui::pane_boundaries_frame::PaneBoundariesFrame; + #[derive(PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy, Debug)] pub enum PaneId { Terminal(RawFd), Plugin(u32), // FIXME: Drop the trait object, make this a wrapper for the struct? } +pub enum PaneDecoration { + BoundariesFrame(PaneBoundariesFrame), + ContentOffset((usize, usize)), // (columns, rows) +} + pub struct TerminalPane { pub grid: Grid, pub pid: RawFd, pub selectable: bool, - pub position_and_size: PositionAndSize, - pub position_and_size_override: Option, + position_and_size: PositionAndSize, + position_and_size_override: Option, pub active_at: Instant, pub colors: Palette, vte_parser: vte::Parser, selection_scrolled_at: time::Instant, + content_position_and_size: PositionAndSize, + pane_title: String, + pane_decoration: PaneDecoration, } impl Pane for TerminalPane { @@ -51,24 +62,29 @@ impl Pane for TerminalPane { fn columns(&self) -> usize { self.get_columns() } + fn get_content_columns(&self) -> usize { + self.get_content_columns() + } + fn get_content_rows(&self) -> usize { + self.get_content_rows() + } fn reset_size_and_position_override(&mut self) { self.position_and_size_override = None; - self.reflow_lines(); + self.redistribute_space(); } fn change_pos_and_size(&mut self, position_and_size: &PositionAndSize) { self.position_and_size = *position_and_size; - self.reflow_lines(); + self.redistribute_space(); } fn override_size_and_position(&mut self, x: usize, y: usize, size: &PositionAndSize) { - let position_and_size_override = PositionAndSize { + self.position_and_size_override = Some(PositionAndSize { x, y, rows: size.rows, cols: size.cols, ..Default::default() - }; - self.position_and_size_override = Some(position_and_size_override); - self.reflow_lines(); + }); + self.redistribute_space(); } fn handle_pty_bytes(&mut self, bytes: VteBytes) { for byte in bytes.iter() { @@ -78,7 +94,17 @@ impl Pane for TerminalPane { } fn cursor_coordinates(&self) -> Option<(usize, usize)> { // (x, y) - self.grid.cursor_coordinates() + let (x_offset, y_offset) = match &self.pane_decoration { + PaneDecoration::BoundariesFrame(boundries_frame) => { + let (content_columns_offset, content_rows_offset) = + boundries_frame.content_offset(); + (content_columns_offset, content_rows_offset) + } + PaneDecoration::ContentOffset(_) => (0, 0), + }; + self.grid + .cursor_coordinates() + .map(|(x, y)| (x + x_offset, y + y_offset)) } fn adjust_input_to_terminal(&self, input_bytes: Vec) -> Vec { // there are some cases in which the terminal state means that input sent to it @@ -134,7 +160,14 @@ impl Pane for TerminalPane { fn set_should_render(&mut self, should_render: bool) { self.grid.should_render = should_render; } + fn set_should_render_boundaries(&mut self, should_render: bool) { + if let PaneDecoration::BoundariesFrame(boundaries_frame) = &mut self.pane_decoration { + boundaries_frame.set_should_render(should_render); + } + } fn render_full_viewport(&mut self) { + // this marks the pane for a full re-render, rather than just rendering the + // diff as it usually does with the OutputBuffer self.grid.render_full_viewport(); } fn selectable(&self) -> bool { @@ -173,10 +206,10 @@ impl Pane for TerminalPane { } self.grid.clear_viewport_before_rendering = false; } - let max_width = self.columns(); + let max_width = self.get_content_columns(); for character_chunk in self.grid.read_changes() { - let pane_x = self.get_x(); - let pane_y = self.get_y(); + let pane_x = self.get_content_x(); + let pane_y = self.get_content_y(); let chunk_absolute_x = pane_x + character_chunk.x; let chunk_absolute_y = pane_y + character_chunk.y; let terminal_characters = character_chunk.terminal_characters; @@ -212,6 +245,13 @@ impl Pane for TerminalPane { } character_styles.clear(); } + if let PaneDecoration::BoundariesFrame(boundaries_frame) = &mut self.pane_decoration { + boundaries_frame.update_scroll(self.grid.scrollback_position_and_length()); + boundaries_frame.update_title(self.grid.title.as_ref()); + if let Some(boundaries_frame_vte) = boundaries_frame.render() { + vte_output.push_str(&boundaries_frame_vte); + } + } self.set_should_render(false); Some(vte_output) } else { @@ -224,50 +264,54 @@ impl Pane for TerminalPane { fn reduce_height_down(&mut self, count: usize) { self.position_and_size.y += count; self.position_and_size.rows -= count; - self.reflow_lines(); + self.redistribute_space(); } fn increase_height_down(&mut self, count: usize) { self.position_and_size.rows += count; - self.reflow_lines(); + self.redistribute_space(); } fn increase_height_up(&mut self, count: usize) { self.position_and_size.y -= count; self.position_and_size.rows += count; - self.reflow_lines(); + self.redistribute_space(); } fn reduce_height_up(&mut self, count: usize) { self.position_and_size.rows -= count; - self.reflow_lines(); + self.redistribute_space(); } fn reduce_width_right(&mut self, count: usize) { self.position_and_size.x += count; self.position_and_size.cols -= count; - self.reflow_lines(); + self.redistribute_space(); } fn reduce_width_left(&mut self, count: usize) { self.position_and_size.cols -= count; - self.reflow_lines(); + self.redistribute_space(); } fn increase_width_left(&mut self, count: usize) { self.position_and_size.x -= count; self.position_and_size.cols += count; - self.reflow_lines(); + self.redistribute_space(); } fn increase_width_right(&mut self, count: usize) { self.position_and_size.cols += count; - self.reflow_lines(); + self.redistribute_space(); } fn push_down(&mut self, count: usize) { self.position_and_size.y += count; + self.redistribute_space(); } fn push_right(&mut self, count: usize) { self.position_and_size.x += count; + self.redistribute_space(); } fn pull_left(&mut self, count: usize) { self.position_and_size.x -= count; + self.redistribute_space(); } fn pull_up(&mut self, count: usize) { self.position_and_size.y -= count; + self.redistribute_space(); } fn scroll_up(&mut self, count: usize) { self.grid.move_viewport_up(count); @@ -337,12 +381,69 @@ impl Pane for TerminalPane { fn get_selected_text(&self) -> Option { self.grid.get_selected_text() } + + fn set_boundary_color(&mut self, color: Option) { + if let PaneDecoration::BoundariesFrame(boundaries_frame) = &mut self.pane_decoration { + if boundaries_frame.color != color { + boundaries_frame.set_color(color); + self.set_should_render(true); + } + } + } + fn relative_position(&self, position_on_screen: &Position) -> Position { + let pane_position_and_size = self.get_content_posision_and_size(); + position_on_screen.relative_to(&pane_position_and_size) + } + fn offset_content_columns(&mut self, by: usize) { + if let PaneDecoration::ContentOffset(content_offset) = &mut self.pane_decoration { + content_offset.0 = by; + } else { + self.pane_decoration = PaneDecoration::ContentOffset((by, 0)); + } + self.redistribute_space(); + } + fn offset_content_rows(&mut self, by: usize) { + if let PaneDecoration::ContentOffset(content_offset) = &mut self.pane_decoration { + content_offset.1 = by; + } else { + self.pane_decoration = PaneDecoration::ContentOffset((0, by)); + } + self.redistribute_space(); + } + fn show_boundaries_frame(&mut self, only_title: bool) { + let position_and_size = self + .position_and_size_override + .unwrap_or(self.position_and_size); + if let PaneDecoration::BoundariesFrame(boundaries_frame) = &mut self.pane_decoration { + boundaries_frame.render_only_title(only_title); + self.content_position_and_size = boundaries_frame.content_position_and_size(); + } else { + let mut boundaries_frame = + PaneBoundariesFrame::new(position_and_size, self.pane_title.clone()); + boundaries_frame.render_only_title(only_title); + self.content_position_and_size = boundaries_frame.content_position_and_size(); + self.pane_decoration = PaneDecoration::BoundariesFrame(boundaries_frame); + } + self.redistribute_space(); + } + fn remove_boundaries_frame(&mut self) { + self.pane_decoration = PaneDecoration::ContentOffset((0, 0)); + self.redistribute_space(); + } } impl TerminalPane { - pub fn new(pid: RawFd, position_and_size: PositionAndSize, palette: Palette) -> TerminalPane { + pub fn new( + pid: RawFd, + position_and_size: PositionAndSize, + palette: Palette, + pane_position: usize, + ) -> TerminalPane { + let initial_pane_title = format!("Pane #{}", pane_position); let grid = Grid::new(position_and_size.rows, position_and_size.cols, palette); TerminalPane { + pane_decoration: PaneDecoration::ContentOffset((0, 0)), + content_position_and_size: position_and_size, pid, grid, selectable: true, @@ -352,35 +453,55 @@ impl TerminalPane { active_at: Instant::now(), colors: palette, selection_scrolled_at: time::Instant::now(), + pane_title: initial_pane_title, } } pub fn get_x(&self) -> usize { - match self.position_and_size_override { + match self.position_and_size_override.as_ref() { Some(position_and_size_override) => position_and_size_override.x, - None => self.position_and_size.x as usize, + None => self.position_and_size.x, } } pub fn get_y(&self) -> usize { - match self.position_and_size_override { + match self.position_and_size_override.as_ref() { Some(position_and_size_override) => position_and_size_override.y, - None => self.position_and_size.y as usize, + None => self.position_and_size.y, } } pub fn get_columns(&self) -> usize { - match &self.position_and_size_override.as_ref() { + match self.position_and_size_override.as_ref() { Some(position_and_size_override) => position_and_size_override.cols, - None => self.position_and_size.cols as usize, + None => self.position_and_size.cols, } } pub fn get_rows(&self) -> usize { - match &self.position_and_size_override.as_ref() { + match self.position_and_size_override.as_ref() { Some(position_and_size_override) => position_and_size_override.rows, - None => self.position_and_size.rows as usize, + None => self.position_and_size.rows, } } + pub fn get_content_x(&self) -> usize { + self.get_content_posision_and_size().x + } + pub fn get_content_y(&self) -> usize { + self.get_content_posision_and_size().y + } + pub fn get_content_columns(&self) -> usize { + // content columns might differ from the pane's columns if the pane has a frame + // in that case they would be 2 less + self.get_content_posision_and_size().cols + } + pub fn get_content_rows(&self) -> usize { + // content rows might differ from the pane's rows if the pane has a frame + // in that case they would be 2 less + self.get_content_posision_and_size().rows + } + pub fn get_content_posision_and_size(&self) -> PositionAndSize { + self.content_position_and_size + } fn reflow_lines(&mut self) { - let rows = self.get_rows(); - let columns = self.get_columns(); + let rows = self.get_content_rows(); + let columns = self.get_content_columns(); self.grid.change_size(rows, columns); self.set_should_render(true); } @@ -391,6 +512,24 @@ impl TerminalPane { // (x, y) self.grid.cursor_coordinates() } + fn redistribute_space(&mut self) { + let position_and_size = self + .position_and_size_override + .unwrap_or_else(|| self.position_and_size()); + match &mut self.pane_decoration { + PaneDecoration::BoundariesFrame(boundaries_frame) => { + boundaries_frame.change_pos_and_size(position_and_size); + self.content_position_and_size = boundaries_frame.content_position_and_size(); + } + PaneDecoration::ContentOffset((content_columns_offset, content_rows_offset)) => { + self.content_position_and_size = position_and_size; + self.content_position_and_size.cols = + position_and_size.cols - *content_columns_offset; + self.content_position_and_size.rows = position_and_size.rows - *content_rows_offset; + } + }; + self.reflow_lines(); + } } #[cfg(test)] diff --git a/zellij-server/src/panes/unit/grid_tests.rs b/zellij-server/src/panes/unit/grid_tests.rs index 0facc0663..9592ff413 100644 --- a/zellij-server/src/panes/unit/grid_tests.rs +++ b/zellij-server/src/panes/unit/grid_tests.rs @@ -608,9 +608,9 @@ fn copy_selected_text_from_lines_below() { grid.move_viewport_up(40); - grid.start_selection(&Position::new(63, 6)); + grid.start_selection(&Position::new(35, 6)); // check for widechar, 📦 occupies columns 34, 35, and gets selected even if only the first column is selected - grid.end_selection(Some(&Position::new(65, 35))); + grid.end_selection(Some(&Position::new(37, 35))); let text = grid.get_selected_text(); assert_eq!( text.unwrap(), diff --git a/zellij-server/src/panes/unit/terminal_pane_tests.rs b/zellij-server/src/panes/unit/terminal_pane_tests.rs index f3abf91a2..70e4e1724 100644 --- a/zellij-server/src/panes/unit/terminal_pane_tests.rs +++ b/zellij-server/src/panes/unit/terminal_pane_tests.rs @@ -15,7 +15,7 @@ pub fn scrolling_inside_a_pane() { }; let pid = 1; let palette = Palette::default(); - let mut terminal_pane = TerminalPane::new(pid, fake_win_size, palette); + let mut terminal_pane = TerminalPane::new(pid, fake_win_size, palette, 0); // 0 is the pane index let mut text_to_fill_pane = String::new(); for i in 0..30 { text_to_fill_pane.push_str(&format!("\rline {}\n", i + 1)); diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index 29a864aa1..3959a19aa 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -151,6 +151,12 @@ fn route_action( .send_to_screen(ScreenInstruction::ToggleActiveTerminalFullscreen) .unwrap(); } + Action::TogglePaneFrames => { + session + .senders + .send_to_screen(ScreenInstruction::TogglePaneFrames) + .unwrap(); + } Action::NewPane(direction) => { let shell = session.default_shell.clone(); let pty_instr = match direction { diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index b348540fb..4a62dad09 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -56,6 +56,7 @@ pub(crate) enum ScreenInstruction { ClearScroll, CloseFocusedPane, ToggleActiveTerminalFullscreen, + TogglePaneFrames, SetSelectable(PaneId, bool, usize), SetFixedHeight(PaneId, usize, usize), SetFixedWidth(PaneId, usize, usize), @@ -112,6 +113,7 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenInstruction::ToggleActiveTerminalFullscreen => { ScreenContext::ToggleActiveTerminalFullscreen } + ScreenInstruction::TogglePaneFrames => ScreenContext::TogglePaneFrames, ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable, ScreenInstruction::SetInvisibleBorders(..) => ScreenContext::SetInvisibleBorders, ScreenInstruction::SetFixedHeight(..) => ScreenContext::SetFixedHeight, @@ -153,6 +155,7 @@ pub(crate) struct Screen { mode_info: ModeInfo, colors: Palette, session_state: Arc>, + draw_pane_frames: bool, } impl Screen { @@ -163,6 +166,7 @@ impl Screen { max_panes: Option, mode_info: ModeInfo, session_state: Arc>, + draw_pane_frames: bool, ) -> Self { Screen { bus, @@ -173,6 +177,7 @@ impl Screen { tabs: BTreeMap::new(), mode_info, session_state, + draw_pane_frames, } } @@ -193,6 +198,7 @@ impl Screen { self.mode_info.clone(), self.colors, self.session_state.clone(), + self.draw_pane_frames, ); self.active_tab_index = Some(tab_index); self.tabs.insert(tab_index, tab); @@ -359,6 +365,7 @@ impl Screen { self.mode_info.clone(), self.colors, self.session_state.clone(), + self.draw_pane_frames, ); tab.apply_layout(layout, new_pids, tab_index); self.active_tab_index = Some(tab_index); @@ -405,6 +412,7 @@ impl Screen { self.mode_info = mode_info; for tab in self.tabs.values_mut() { tab.mode_info = self.mode_info.clone(); + tab.mark_active_pane_for_rerender(); } } pub fn move_focus_left_or_previous_tab(&mut self) { @@ -430,6 +438,7 @@ pub(crate) fn screen_thread_main( session_state: Arc>, ) { let capabilities = config_options.simplified_ui; + let draw_pane_frames = !config_options.no_pane_frames; let mut screen = Screen::new( bus, @@ -443,6 +452,7 @@ pub(crate) fn screen_thread_main( }, ), session_state, + draw_pane_frames, ); loop { let (event, mut err_ctx) = screen @@ -663,6 +673,13 @@ pub(crate) fn screen_thread_main( .unwrap() .toggle_active_pane_fullscreen(); } + ScreenInstruction::TogglePaneFrames => { + screen.draw_pane_frames = !screen.draw_pane_frames; + for (_, tab) in screen.tabs.iter_mut() { + tab.set_pane_frames(screen.draw_pane_frames); + } + screen.render(); + } ScreenInstruction::NewTab(pane_id) => { screen.new_tab(pane_id); screen diff --git a/zellij-server/src/tab.rs b/zellij-server/src/tab.rs index 0662be225..8f12f8836 100644 --- a/zellij-server/src/tab.rs +++ b/zellij-server/src/tab.rs @@ -24,53 +24,73 @@ use std::{ cmp::Reverse, collections::{BTreeMap, HashSet}, }; -use zellij_tile::data::{Event, ModeInfo, Palette}; +use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, PaletteColor}; use zellij_utils::{ input::{ layout::{Layout, Run}, parse_keys, }, pane_size::PositionAndSize, - shared::adjust_to_size, }; const CURSOR_HEIGHT_WIDTH_RATIO: usize = 4; // this is not accurate and kind of a magic number, TODO: look into this // MIN_TERMINAL_HEIGHT here must be larger than the height of any of the status bars // this is a dirty hack until we implement fixed panes -const MIN_TERMINAL_HEIGHT: usize = 3; -const MIN_TERMINAL_WIDTH: usize = 4; +const MIN_TERMINAL_HEIGHT: usize = 5; +const MIN_TERMINAL_WIDTH: usize = 5; type BorderAndPaneIds = (usize, Vec); -fn split_vertically_with_gap(rect: &PositionAndSize) -> (PositionAndSize, PositionAndSize) { - let width_of_each_half = (rect.cols - 1) / 2; +fn split_vertically(rect: &PositionAndSize) -> (PositionAndSize, PositionAndSize) { + let width_of_each_half = rect.cols / 2; let mut first_rect = *rect; let mut second_rect = *rect; if rect.cols % 2 == 0 { - first_rect.cols = width_of_each_half + 1; - } else { first_rect.cols = width_of_each_half; + } else { + first_rect.cols = width_of_each_half + 1; } - second_rect.x = first_rect.x + first_rect.cols + 1; + second_rect.x = first_rect.x + first_rect.cols; second_rect.cols = width_of_each_half; (first_rect, second_rect) } -fn split_horizontally_with_gap(rect: &PositionAndSize) -> (PositionAndSize, PositionAndSize) { - let height_of_each_half = (rect.rows - 1) / 2; +fn split_horizontally(rect: &PositionAndSize) -> (PositionAndSize, PositionAndSize) { + let height_of_each_half = rect.rows / 2; let mut first_rect = *rect; let mut second_rect = *rect; if rect.rows % 2 == 0 { - first_rect.rows = height_of_each_half + 1; - } else { first_rect.rows = height_of_each_half; + } else { + first_rect.rows = height_of_each_half + 1; } - second_rect.y = first_rect.y + first_rect.rows + 1; + second_rect.y = first_rect.y + first_rect.rows; second_rect.rows = height_of_each_half; (first_rect, second_rect) } +fn pane_content_offset( + position_and_size: &PositionAndSize, + viewport: &PositionAndSize, +) -> (usize, usize) { + // (columns_offset, rows_offset) + // if the pane is not on the bottom or right edge on the screen, we need to reserve one space + // from its content to leave room for the boundary between it and the next pane (if it doesn't + // draw its own frame) + let columns_offset = if position_and_size.x + position_and_size.cols < viewport.cols { + 1 + } else { + 0 + }; + let rows_offset = if position_and_size.y + position_and_size.rows < viewport.rows { + 1 + } else { + 0 + }; + (columns_offset, rows_offset) +} + pub(crate) struct Tab { pub index: usize, pub position: usize, @@ -79,7 +99,8 @@ pub(crate) struct Tab { panes_to_hide: HashSet, active_terminal: Option, max_panes: Option, - full_screen_ws: PositionAndSize, + viewport: PositionAndSize, // includes all selectable panes + display_area: PositionAndSize, // includes all panes (including eg. the status bar and tab bar in the default layout) fullscreen_is_active: bool, os_api: Box, pub senders: ThreadSenders, @@ -88,6 +109,7 @@ pub(crate) struct Tab { session_state: Arc>, pub mode_info: ModeInfo, pub colors: Palette, + draw_pane_frames: bool, } #[derive(Clone, Debug, Default, Serialize, Deserialize)] @@ -117,6 +139,7 @@ pub trait Pane { fn position_and_size_override(&self) -> Option; fn should_render(&self) -> bool; fn set_should_render(&mut self, should_render: bool); + fn set_should_render_boundaries(&mut self, _should_render: bool) {} fn selectable(&self) -> bool; fn set_selectable(&mut self, selectable: bool); fn set_invisible_borders(&mut self, invisible_borders: bool); @@ -165,19 +188,19 @@ pub trait Pane { self.y() + self.rows() } fn is_directly_right_of(&self, other: &dyn Pane) -> bool { - self.x() == other.x() + other.columns() + 1 + self.x() == other.x() + other.columns() } fn is_directly_left_of(&self, other: &dyn Pane) -> bool { - self.x() + self.columns() + 1 == other.x() + self.x() + self.columns() == other.x() } fn is_directly_below(&self, other: &dyn Pane) -> bool { - self.y() == other.y() + other.rows() + 1 + self.y() == other.y() + other.rows() } fn is_directly_above(&self, other: &dyn Pane) -> bool { - self.y() + self.rows() + 1 == other.y() + self.y() + self.rows() == other.y() } fn horizontally_overlaps_with(&self, other: &dyn Pane) -> bool { - (self.y() >= other.y() && self.y() <= (other.y() + other.rows())) + (self.y() >= other.y() && self.y() < (other.y() + other.rows())) || ((self.y() + self.rows()) <= (other.y() + other.rows()) && (self.y() + self.rows()) > other.y()) || (self.y() <= other.y() && (self.y() + self.rows() >= (other.y() + other.rows()))) @@ -188,7 +211,7 @@ pub trait Pane { - std::cmp::max(self.y(), other.y()) } fn vertically_overlaps_with(&self, other: &dyn Pane) -> bool { - (self.x() >= other.x() && self.x() <= (other.x() + other.columns())) + (self.x() >= other.x() && self.x() < (other.x() + other.columns())) || ((self.x() + self.columns()) <= (other.x() + other.columns()) && (self.x() + self.columns()) > other.x()) || (self.x() <= other.x() @@ -243,6 +266,21 @@ pub trait Pane { None => position.relative_to(&self.position_and_size()), } } + fn get_content_rows(&self) -> usize { + // content rows might differ from the pane's rows if the pane has a frame + // in that case they would be 2 less + self.rows() + } + fn get_content_columns(&self) -> usize { + // content columns might differ from the pane's columns if the pane has a frame + // in that case they would be 2 less + self.columns() + } + fn set_boundary_color(&mut self, _color: Option) {} + fn offset_content_columns(&mut self, _by: usize) {} + fn offset_content_rows(&mut self, _by: usize) {} + fn show_boundaries_frame(&mut self, _render_only_title: bool) {} + fn remove_boundaries_frame(&mut self) {} } impl Tab { @@ -252,7 +290,7 @@ impl Tab { index: usize, position: usize, name: String, - full_screen_ws: &PositionAndSize, + viewport: &PositionAndSize, os_api: Box, senders: ThreadSenders, max_panes: Option, @@ -260,9 +298,14 @@ impl Tab { mode_info: ModeInfo, colors: Palette, session_state: Arc>, + draw_pane_frames: bool, ) -> Self { let panes = if let Some(PaneId::Terminal(pid)) = pane_id { - let new_terminal = TerminalPane::new(pid, *full_screen_ws, colors); + let pane_title_only = true; + let mut new_terminal = TerminalPane::new(pid, *viewport, colors, 1); + if draw_pane_frames { + new_terminal.show_boundaries_frame(pane_title_only); + } os_api.set_terminal_size_using_fd( new_terminal.pid, new_terminal.columns() as u16, @@ -289,7 +332,8 @@ impl Tab { max_panes, panes_to_hide: HashSet::new(), active_terminal: pane_id, - full_screen_ws: *full_screen_ws, + viewport: *viewport, + display_area: *viewport, fullscreen_is_active: false, synchronize_is_active: false, os_api, @@ -298,21 +342,36 @@ impl Tab { mode_info, colors, session_state, + draw_pane_frames, } } pub fn apply_layout(&mut self, layout: Layout, new_pids: Vec, tab_index: usize) { - // TODO: this should be an attribute on Screen instead of full_screen_ws + // TODO: this should be an attribute on Screen instead of viewport let free_space = PositionAndSize { x: 0, y: 0, - rows: self.full_screen_ws.rows, - cols: self.full_screen_ws.cols, + rows: self.viewport.rows, + cols: self.viewport.cols, ..Default::default() }; self.panes_to_hide.clear(); let positions_in_layout = layout.position_panes_in_space(&free_space); + + for (layout, position_and_size) in &positions_in_layout { + // we need to do this first because it decides the size of the screen + // which we use for other stuff in the main loop below (eg. which type of frames the + // panes should have) + if layout.borderless { + self.offset_viewport(position_and_size); + } + } + let mut positions_and_size = positions_in_layout.iter(); + let total_borderless_panes = layout.total_borderless_panes(); + let total_panes_with_border = positions_in_layout + .len() + .saturating_sub(total_borderless_panes); for (pane_kind, terminal_pane) in self.panes.iter_mut() { // for now the layout only supports terminal panes if let PaneId::Terminal(pid) = pane_kind { @@ -335,6 +394,7 @@ impl Tab { } } let mut new_pids = new_pids.iter(); + for (layout, position_and_size) in positions_and_size { // A plugin pane if let Some(Run::Plugin(Some(plugin))) = &layout.run { @@ -343,11 +403,18 @@ impl Tab { .send_to_plugin(PluginInstruction::Load(pid_tx, plugin.clone(), tab_index)) .unwrap(); let pid = pid_rx.recv().unwrap(); - let new_plugin = PluginPane::new( + let draw_pane_frames = self.draw_pane_frames && !layout.borderless; + let pane_title_only = !layout.borderless && total_panes_with_border == 1; + let title = String::from(plugin.as_path().as_os_str().to_string_lossy()); + let mut new_plugin = PluginPane::new( pid, *position_and_size, self.senders.to_plugin.as_ref().unwrap().clone(), + title, ); + if draw_pane_frames && !layout.borderless { + new_plugin.show_boundaries_frame(pane_title_only); + } self.panes.insert(PaneId::Plugin(pid), Box::new(new_plugin)); // Send an initial mode update to the newly loaded plugin only! self.senders @@ -359,11 +426,28 @@ impl Tab { } else { // there are still panes left to fill, use the pids we received in this method let pid = new_pids.next().unwrap(); // if this crashes it means we got less pids than there are panes in this layout - let new_terminal = TerminalPane::new(*pid, *position_and_size, self.colors); + let next_selectable_pane_position = self.get_next_selectable_pane_position(); + let pane_title_only = + next_selectable_pane_position == 1 && total_panes_with_border == 1; + let draw_pane_frames = self.draw_pane_frames && !layout.borderless; + let mut new_terminal = TerminalPane::new( + *pid, + *position_and_size, + self.colors, + next_selectable_pane_position, + ); + if draw_pane_frames { + new_terminal.show_boundaries_frame(pane_title_only); + } else { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(position_and_size, &self.viewport); + new_terminal.offset_content_columns(pane_columns_offset); + new_terminal.offset_content_rows(pane_rows_offset); + } self.os_api.set_terminal_size_using_fd( new_terminal.pid, - new_terminal.columns() as u16, - new_terminal.rows() as u16, + new_terminal.get_content_columns() as u16, + new_terminal.get_content_rows() as u16, ); self.panes .insert(PaneId::Terminal(*pid), Box::new(new_terminal)); @@ -387,7 +471,17 @@ impl Tab { } if !self.has_panes() { if let PaneId::Terminal(term_pid) = pid { - let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws, self.colors); + let next_selectable_pane_position = self.get_next_selectable_pane_position(); + let pane_title_only = next_selectable_pane_position == 1; + let mut new_terminal = TerminalPane::new( + term_pid, + self.viewport, + self.colors, + next_selectable_pane_position, + ); + if self.draw_pane_frames { + new_terminal.show_boundaries_frame(pane_title_only); + } self.os_api.set_terminal_size_using_fd( new_terminal.pid, new_terminal.columns() as u16, @@ -424,6 +518,7 @@ impl Tab { return; // likely no terminal large enough to split } let terminal_id_to_split = terminal_id_to_split.unwrap(); + let next_selectable_pane_position = self.get_next_selectable_pane_position(); let terminal_to_split = self.panes.get_mut(&terminal_id_to_split).unwrap(); let terminal_ws = PositionAndSize { rows: terminal_to_split.rows(), @@ -436,40 +531,90 @@ impl Tab { && terminal_to_split.rows() > terminal_to_split.min_height() * 2 { if let PaneId::Terminal(term_pid) = pid { - let (top_winsize, bottom_winsize) = split_horizontally_with_gap(&terminal_ws); - let new_terminal = TerminalPane::new(term_pid, bottom_winsize, self.colors); + let (top_winsize, bottom_winsize) = split_horizontally(&terminal_ws); + let pane_title_only = next_selectable_pane_position == 1; + let mut new_terminal = TerminalPane::new( + term_pid, + bottom_winsize, + self.colors, + next_selectable_pane_position, + ); + if self.draw_pane_frames { + new_terminal.show_boundaries_frame(pane_title_only); + } else { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&bottom_winsize, &self.viewport); + new_terminal.offset_content_columns(pane_columns_offset); + new_terminal.offset_content_rows(pane_rows_offset); + } self.os_api.set_terminal_size_using_fd( new_terminal.pid, - bottom_winsize.cols as u16, - bottom_winsize.rows as u16, + new_terminal.get_content_columns() as u16, + new_terminal.get_content_rows() as u16, ); + if self.draw_pane_frames { + let only_title = false; + terminal_to_split.show_boundaries_frame(only_title); + } else { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&top_winsize, &self.viewport); + terminal_to_split.offset_content_columns(pane_columns_offset); + terminal_to_split.offset_content_rows(pane_rows_offset); + } terminal_to_split.change_pos_and_size(&top_winsize); + let terminal_to_split_content_columns = terminal_to_split.get_content_columns(); + let terminal_to_split_content_rows = terminal_to_split.get_content_rows(); self.panes.insert(pid, Box::new(new_terminal)); if let PaneId::Terminal(terminal_id_to_split) = terminal_id_to_split { self.os_api.set_terminal_size_using_fd( terminal_id_to_split, - top_winsize.cols as u16, - top_winsize.rows as u16, + terminal_to_split_content_columns as u16, + terminal_to_split_content_rows as u16, ); } self.active_terminal = Some(pid); } } else if terminal_to_split.columns() > terminal_to_split.min_width() * 2 { if let PaneId::Terminal(term_pid) = pid { - let (left_winsize, right_winsize) = split_vertically_with_gap(&terminal_ws); - let new_terminal = TerminalPane::new(term_pid, right_winsize, self.colors); + let (left_winsize, right_winsize) = split_vertically(&terminal_ws); + let pane_title_only = next_selectable_pane_position == 1; + let mut new_terminal = TerminalPane::new( + term_pid, + right_winsize, + self.colors, + next_selectable_pane_position, + ); + if self.draw_pane_frames { + new_terminal.show_boundaries_frame(pane_title_only); + } else { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&right_winsize, &self.viewport); + new_terminal.offset_content_columns(pane_columns_offset); + new_terminal.offset_content_rows(pane_rows_offset); + } self.os_api.set_terminal_size_using_fd( new_terminal.pid, - right_winsize.cols as u16, - right_winsize.rows as u16, + new_terminal.get_content_columns() as u16, + new_terminal.get_content_rows() as u16, ); + if self.draw_pane_frames { + let only_title = false; + terminal_to_split.show_boundaries_frame(only_title); + } else { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&left_winsize, &self.viewport); + terminal_to_split.offset_content_columns(pane_columns_offset); + terminal_to_split.offset_content_rows(pane_rows_offset); + } terminal_to_split.change_pos_and_size(&left_winsize); + let terminal_to_split_content_columns = terminal_to_split.get_content_columns(); + let terminal_to_split_content_rows = terminal_to_split.get_content_rows(); self.panes.insert(pid, Box::new(new_terminal)); if let PaneId::Terminal(terminal_id_to_split) = terminal_id_to_split { self.os_api.set_terminal_size_using_fd( terminal_id_to_split, - left_winsize.cols as u16, - left_winsize.rows as u16, + terminal_to_split_content_columns as u16, + terminal_to_split_content_rows as u16, ); } } @@ -485,20 +630,29 @@ impl Tab { } if !self.has_panes() { if let PaneId::Terminal(term_pid) = pid { - let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws, self.colors); + let next_selectable_pane_position = self.get_next_selectable_pane_position(); + let pane_title_only = next_selectable_pane_position == 1; + let mut new_terminal = TerminalPane::new( + term_pid, + self.viewport, + self.colors, + next_selectable_pane_position, + ); + if self.draw_pane_frames { + new_terminal.show_boundaries_frame(pane_title_only); + } self.os_api.set_terminal_size_using_fd( new_terminal.pid, - new_terminal.columns() as u16, - new_terminal.rows() as u16, + new_terminal.get_content_columns() as u16, + new_terminal.get_content_rows() as u16, ); self.panes.insert(pid, Box::new(new_terminal)); self.active_terminal = Some(pid); } } else if let PaneId::Terminal(term_pid) = pid { - // TODO: check minimum size of active terminal let active_pane_id = &self.get_active_pane_id().unwrap(); let active_pane = self.panes.get_mut(active_pane_id).unwrap(); - if active_pane.rows() < MIN_TERMINAL_HEIGHT * 2 + 1 { + if active_pane.rows() < MIN_TERMINAL_HEIGHT * 2 { self.senders .send_to_pty(PtyInstruction::ClosePane(pid)) // we can't open this pane, close the pty .unwrap(); @@ -511,23 +665,50 @@ impl Tab { cols: active_pane.columns(), ..Default::default() }; - let (top_winsize, bottom_winsize) = split_horizontally_with_gap(&terminal_ws); + let (top_winsize, bottom_winsize) = split_horizontally(&terminal_ws); + if self.draw_pane_frames { + let only_title = false; + active_pane.show_boundaries_frame(only_title); + } else { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&top_winsize, &self.viewport); + active_pane.offset_content_columns(pane_columns_offset); + active_pane.offset_content_rows(pane_rows_offset); + } active_pane.change_pos_and_size(&top_winsize); - let new_terminal = TerminalPane::new(term_pid, bottom_winsize, self.colors); + let active_pane_content_columns = active_pane.get_content_columns(); + let active_pane_content_rows = active_pane.get_content_rows(); + + let next_selectable_pane_position = self.get_next_selectable_pane_position(); + let pane_title_only = next_selectable_pane_position == 1; + let mut new_terminal = TerminalPane::new( + term_pid, + bottom_winsize, + self.colors, + next_selectable_pane_position, + ); + if self.draw_pane_frames { + new_terminal.show_boundaries_frame(pane_title_only); + } else { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&bottom_winsize, &self.viewport); + new_terminal.offset_content_columns(pane_columns_offset); + new_terminal.offset_content_rows(pane_rows_offset); + } self.os_api.set_terminal_size_using_fd( new_terminal.pid, - bottom_winsize.cols as u16, - bottom_winsize.rows as u16, + new_terminal.get_content_columns() as u16, + new_terminal.get_content_rows() as u16, ); self.panes.insert(pid, Box::new(new_terminal)); if let PaneId::Terminal(active_terminal_pid) = active_pane_id { self.os_api.set_terminal_size_using_fd( *active_terminal_pid, - top_winsize.cols as u16, - top_winsize.rows as u16, + active_pane_content_columns as u16, + active_pane_content_rows as u16, ); } @@ -542,11 +723,21 @@ impl Tab { } if !self.has_panes() { if let PaneId::Terminal(term_pid) = pid { - let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws, self.colors); + let next_selectable_pane_position = self.get_next_selectable_pane_position(); + let pane_title_only = next_selectable_pane_position == 1; + let mut new_terminal = TerminalPane::new( + term_pid, + self.viewport, + self.colors, + next_selectable_pane_position, + ); + if self.draw_pane_frames { + new_terminal.show_boundaries_frame(pane_title_only); + } self.os_api.set_terminal_size_using_fd( new_terminal.pid, - new_terminal.columns() as u16, - new_terminal.rows() as u16, + new_terminal.get_content_columns() as u16, + new_terminal.get_content_rows() as u16, ); self.panes.insert(pid, Box::new(new_terminal)); self.active_terminal = Some(pid); @@ -555,7 +746,7 @@ impl Tab { // TODO: check minimum size of active terminal let active_pane_id = &self.get_active_pane_id().unwrap(); let active_pane = self.panes.get_mut(active_pane_id).unwrap(); - if active_pane.columns() < MIN_TERMINAL_WIDTH * 2 + 1 { + if active_pane.columns() < MIN_TERMINAL_WIDTH * 2 { self.senders .send_to_pty(PtyInstruction::ClosePane(pid)) // we can't open this pane, close the pty .unwrap(); @@ -568,23 +759,50 @@ impl Tab { cols: active_pane.columns(), ..Default::default() }; - let (left_winsize, right_winsize) = split_vertically_with_gap(&terminal_ws); + let (left_winsize, right_winsize) = split_vertically(&terminal_ws); + if self.draw_pane_frames { + let only_title = false; + active_pane.show_boundaries_frame(only_title); + } else { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&left_winsize, &self.viewport); + active_pane.offset_content_columns(pane_columns_offset); + active_pane.offset_content_rows(pane_rows_offset); + } active_pane.change_pos_and_size(&left_winsize); - let new_terminal = TerminalPane::new(term_pid, right_winsize, self.colors); + let active_pane_content_columns = active_pane.get_content_columns(); + let active_pane_content_rows = active_pane.get_content_rows(); + + let next_selectable_pane_position = self.get_next_selectable_pane_position(); + let pane_title_only = next_selectable_pane_position == 1; + let mut new_terminal = TerminalPane::new( + term_pid, + right_winsize, + self.colors, + next_selectable_pane_position, + ); + if self.draw_pane_frames { + new_terminal.show_boundaries_frame(pane_title_only); + } else { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&right_winsize, &self.viewport); + new_terminal.offset_content_columns(pane_columns_offset); + new_terminal.offset_content_rows(pane_rows_offset); + } self.os_api.set_terminal_size_using_fd( new_terminal.pid, - right_winsize.cols as u16, - right_winsize.rows as u16, + new_terminal.get_content_columns() as u16, + new_terminal.get_content_rows() as u16, ); self.panes.insert(pid, Box::new(new_terminal)); if let PaneId::Terminal(active_terminal_pid) = active_pane_id { self.os_api.set_terminal_size_using_fd( *active_terminal_pid, - left_winsize.cols as u16, - left_winsize.rows as u16, + active_pane_content_columns as u16, + active_pane_content_rows as u16, ); } @@ -673,36 +891,51 @@ impl Tab { if let Some(active_pane_id) = self.get_active_pane_id() { if self.fullscreen_is_active { for terminal_id in self.panes_to_hide.iter() { - self.panes - .get_mut(terminal_id) - .unwrap() - .set_should_render(true); + let pane = self.panes.get_mut(terminal_id).unwrap(); + pane.set_should_render(true); + pane.set_should_render_boundaries(true); } self.panes_to_hide.clear(); + let selectable_pane_count = self.get_selectable_pane_count(); let active_terminal = self.panes.get_mut(&active_pane_id).unwrap(); + if selectable_pane_count > 1 && self.draw_pane_frames { + let only_title = false; + active_terminal.show_boundaries_frame(only_title); + } + if !self.draw_pane_frames { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&active_terminal.position_and_size(), &self.viewport); + active_terminal.offset_content_columns(pane_columns_offset); + active_terminal.offset_content_rows(pane_rows_offset); + } active_terminal.reset_size_and_position_override(); } else { let panes = self.get_panes(); - let pane_ids_to_hide = - panes.filter_map( - |(&id, _)| { - if id != active_pane_id { - Some(id) - } else { - None - } - }, - ); + let pane_ids_to_hide = panes.filter_map(|(&id, _pane)| { + if id != active_pane_id && self.is_inside_viewport(&id) { + Some(id) + } else { + None + } + }); self.panes_to_hide = pane_ids_to_hide.collect(); if self.panes_to_hide.is_empty() { // nothing to do, pane is already as fullscreen as it can be, let's bail return; } else { let active_terminal = self.panes.get_mut(&active_pane_id).unwrap(); + if self.draw_pane_frames { + // full screen panes don't need their full frame + let only_title = true; + active_terminal.show_boundaries_frame(only_title); + } else { + active_terminal.offset_content_rows(0); + active_terminal.offset_content_columns(0); + } active_terminal.override_size_and_position( - self.full_screen_ws.x, - self.full_screen_ws.y, - &self.full_screen_ws, + self.viewport.x, + self.viewport.y, + &self.viewport, ); } } @@ -710,8 +943,8 @@ impl Tab { if let PaneId::Terminal(active_pid) = active_pane_id { self.os_api.set_terminal_size_using_fd( active_pid, - active_terminal.columns() as u16, - active_terminal.rows() as u16, + active_terminal.get_content_columns() as u16, + active_terminal.get_content_rows() as u16, ); } self.set_force_render(); @@ -725,6 +958,7 @@ impl Tab { pub fn set_force_render(&mut self) { for pane in self.panes.values_mut() { pane.set_should_render(true); + pane.set_should_render_boundaries(true); pane.render_full_viewport(); } } @@ -734,6 +968,48 @@ impl Tab { pub fn toggle_sync_panes_is_active(&mut self) { self.synchronize_is_active = !self.synchronize_is_active; } + pub fn mark_active_pane_for_rerender(&mut self) { + if let Some(active_terminal) = self + .active_terminal + .and_then(|active_terminal_id| self.panes.get_mut(&active_terminal_id)) + { + active_terminal.set_should_render(true) + } + // .and_then(|active_terminal_id| self.panes.get_mut(&active_terminal_id)) { + // active_terminal.set_should_render(true) + // } + } + pub fn set_pane_frames(&mut self, draw_pane_frames: bool) { + self.draw_pane_frames = draw_pane_frames; + let selectable_pane_count = self.panes.iter().filter(|(_, p)| p.selectable()).count(); + for (pane_id, pane) in self.panes.iter_mut() { + if draw_pane_frames { + let should_render_only_title = (selectable_pane_count == 1 + && self.active_terminal == Some(*pane_id)) + || (self.fullscreen_is_active && self.active_terminal == Some(*pane_id)); + pane.offset_content_rows(0); + pane.offset_content_columns(0); + pane.show_boundaries_frame(should_render_only_title); + } else { + let position_and_size = pane + .position_and_size_override() + .unwrap_or_else(|| pane.position_and_size()); + pane.remove_boundaries_frame(); + + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&position_and_size, &self.viewport); + pane.offset_content_columns(pane_columns_offset); + pane.offset_content_rows(pane_rows_offset); + } + if let PaneId::Terminal(pid) = pane_id { + self.os_api.set_terminal_size_using_fd( + *pid, + pane.get_content_columns() as u16, + pane.get_content_rows() as u16, + ); + } + } + } pub fn render(&mut self) { if self.active_terminal.is_none() || *self.session_state.read().unwrap() != SessionState::Attached @@ -744,10 +1020,7 @@ impl Tab { return; } let mut output = String::new(); - let mut boundaries = Boundaries::new( - self.full_screen_ws.cols as u16, - self.full_screen_ws.rows as u16, - ); + let mut boundaries = Boundaries::new(&self.viewport); let hide_cursor = "\u{1b}[?25l"; output.push_str(hide_cursor); if self.should_clear_display_before_rendering { @@ -755,21 +1028,35 @@ impl Tab { output.push_str(clear_display); self.should_clear_display_before_rendering = false; } - for (kind, pane) in self.panes.iter_mut() { + for (_kind, pane) in self.panes.iter_mut() { if !self.panes_to_hide.contains(&pane.pid()) { match self.active_terminal.unwrap() == pane.pid() { true => { pane.set_active_at(Instant::now()); - boundaries.add_rect(pane.as_ref(), self.mode_info.mode, Some(self.colors)) + match self.mode_info.mode { + InputMode::Normal | InputMode::Locked => { + pane.set_boundary_color(Some(self.colors.green)); + } + _ => { + pane.set_boundary_color(Some(self.colors.orange)); + } + } + if !self.draw_pane_frames { + boundaries.add_rect( + pane.as_ref(), + self.mode_info.mode, + Some(self.colors), + ) + } + } + false => { + pane.set_boundary_color(None); + if !pane.invisible_borders() && !self.draw_pane_frames { + boundaries.add_rect(pane.as_ref(), self.mode_info.mode, None); + } } - false => boundaries.add_rect(pane.as_ref(), self.mode_info.mode, None), } if let Some(vte_output) = pane.render() { - let vte_output = if let PaneId::Terminal(_) = kind { - vte_output - } else { - adjust_to_size(&vte_output, pane.rows(), pane.columns()) - }; // FIXME: Use Termion for cursor and style clearing? output.push_str(&format!( "\u{1b}[{};{}H\u{1b}[m{}", @@ -781,8 +1068,9 @@ impl Tab { } } - // TODO: only render (and calculate) boundaries if there was a resize - output.push_str(&boundaries.vte_output()); + if !self.draw_pane_frames { + output.push_str(&boundaries.vte_output()); + } match self.get_active_terminal_cursor_position() { Some((cursor_position_x, cursor_position_y)) => { @@ -814,6 +1102,28 @@ impl Tab { fn get_selectable_panes(&self) -> impl Iterator)> { self.panes.iter().filter(|(_, p)| p.selectable()) } + fn get_selectable_pane_count(&self) -> usize { + self.get_selectable_panes().count() + } + fn get_next_selectable_pane_position(&self) -> usize { + self.panes + .iter() + .filter(|(k, _)| match k { + PaneId::Plugin(_) => false, + PaneId::Terminal(_) => true, + }) + .count() + + 1 + } + fn is_the_only_selectable_pane(&self, pane_id: &PaneId) -> bool { + let selectable_panes = self.get_selectable_panes(); + if selectable_panes.count() == 1 { + let pane = self.panes.get(pane_id); + pane.map(|pane| pane.selectable()).unwrap_or(false) + } else { + false + } + } fn has_panes(&self) -> bool { let mut all_terminals = self.get_panes(); all_terminals.next().is_some() @@ -822,11 +1132,12 @@ impl Tab { let mut all_terminals = self.get_selectable_panes(); all_terminals.next().is_some() } - fn next_active_pane(&self, panes: Vec) -> Option { + fn next_active_pane(&self, panes: &[PaneId]) -> Option { panes - .into_iter() + .iter() .rev() .find(|pid| self.panes.get(pid).unwrap().selectable()) + .copied() } fn pane_ids_directly_left_of(&self, id: &PaneId) -> Option> { let mut ids = vec![]; @@ -835,7 +1146,7 @@ impl Tab { return None; } for (&pid, terminal) in self.get_panes() { - if terminal.x() + terminal.columns() == terminal_to_check.x() - 1 { + if terminal.x() + terminal.columns() == terminal_to_check.x() { ids.push(pid); } } @@ -849,7 +1160,7 @@ impl Tab { let mut ids = vec![]; let terminal_to_check = self.panes.get(id).unwrap(); for (&pid, terminal) in self.get_panes() { - if terminal.x() == terminal_to_check.x() + terminal_to_check.columns() + 1 { + if terminal.x() == terminal_to_check.x() + terminal_to_check.columns() { ids.push(pid); } } @@ -863,7 +1174,7 @@ impl Tab { let mut ids = vec![]; let terminal_to_check = self.panes.get(id).unwrap(); for (&pid, terminal) in self.get_panes() { - if terminal.y() == terminal_to_check.y() + terminal_to_check.rows() + 1 { + if terminal.y() == terminal_to_check.y() + terminal_to_check.rows() { ids.push(pid); } } @@ -877,7 +1188,7 @@ impl Tab { let mut ids = vec![]; let terminal_to_check = self.panes.get(id).unwrap(); for (&pid, terminal) in self.get_panes() { - if terminal.y() + terminal.rows() + 1 == terminal_to_check.y() { + if terminal.y() + terminal.rows() == terminal_to_check.y() { ids.push(pid); } } @@ -937,7 +1248,7 @@ impl Tab { right_aligned_terminals.sort_by_key(|a| Reverse(a.y())); for terminal in right_aligned_terminals { let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check); - if terminal.y() + terminal.rows() + 1 == terminal_to_check.y() { + if terminal.y() + terminal.rows() == terminal_to_check.y() { terminals.push(terminal); } } @@ -946,11 +1257,11 @@ impl Tab { for terminal in &terminals { let bottom_terminal_boundary = terminal.y() + terminal.rows(); if terminal_borders_to_the_right - .get(&(bottom_terminal_boundary + 1)) + .get(&bottom_terminal_boundary) .is_some() && top_resize_border < bottom_terminal_boundary { - top_resize_border = bottom_terminal_boundary + 1; + top_resize_border = bottom_terminal_boundary; } } terminals.retain(|terminal| terminal.y() >= top_resize_border); @@ -980,12 +1291,12 @@ impl Tab { right_aligned_terminals.sort_by_key(|a| a.y()); for terminal in right_aligned_terminals { let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check); - if terminal.y() == terminal_to_check.y() + terminal_to_check.rows() + 1 { + if terminal.y() == terminal_to_check.y() + terminal_to_check.rows() { terminals.push(terminal); } } // bottom-most border aligned with a pane border to the right - let mut bottom_resize_border = self.full_screen_ws.rows; + let mut bottom_resize_border = self.viewport.y + self.viewport.rows; for terminal in &terminals { let top_terminal_boundary = terminal.y(); if terminal_borders_to_the_right @@ -1023,7 +1334,7 @@ impl Tab { left_aligned_terminals.sort_by_key(|a| Reverse(a.y())); for terminal in left_aligned_terminals { let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check); - if terminal.y() + terminal.rows() + 1 == terminal_to_check.y() { + if terminal.y() + terminal.rows() == terminal_to_check.y() { terminals.push(terminal); } } @@ -1032,11 +1343,11 @@ impl Tab { for terminal in &terminals { let bottom_terminal_boundary = terminal.y() + terminal.rows(); if terminal_borders_to_the_left - .get(&(bottom_terminal_boundary + 1)) + .get(&bottom_terminal_boundary) .is_some() && top_resize_border < bottom_terminal_boundary { - top_resize_border = bottom_terminal_boundary + 1; + top_resize_border = bottom_terminal_boundary; } } terminals.retain(|terminal| terminal.y() >= top_resize_border); @@ -1066,12 +1377,12 @@ impl Tab { left_aligned_terminals.sort_by_key(|a| a.y()); for terminal in left_aligned_terminals { let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check); - if terminal.y() == terminal_to_check.y() + terminal_to_check.rows() + 1 { + if terminal.y() == terminal_to_check.y() + terminal_to_check.rows() { terminals.push(terminal); } } // bottom-most border aligned with a pane border to the left - let mut bottom_resize_border = self.full_screen_ws.rows; + let mut bottom_resize_border = self.viewport.y + self.viewport.rows; for terminal in &terminals { let top_terminal_boundary = terminal.y(); if terminal_borders_to_the_left @@ -1112,7 +1423,7 @@ impl Tab { top_aligned_terminals.sort_by_key(|a| Reverse(a.x())); for terminal in top_aligned_terminals { let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check); - if terminal.x() + terminal.columns() + 1 == terminal_to_check.x() { + if terminal.x() + terminal.columns() == terminal_to_check.x() { terminals.push(terminal); } } @@ -1121,11 +1432,11 @@ impl Tab { for terminal in &terminals { let right_terminal_boundary = terminal.x() + terminal.columns(); if terminal_borders_above - .get(&(right_terminal_boundary + 1)) + .get(&right_terminal_boundary) .is_some() && left_resize_border < right_terminal_boundary { - left_resize_border = right_terminal_boundary + 1; + left_resize_border = right_terminal_boundary; } } terminals.retain(|terminal| terminal.x() >= left_resize_border); @@ -1151,12 +1462,12 @@ impl Tab { top_aligned_terminals.sort_by_key(|a| a.x()); for terminal in top_aligned_terminals { let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check); - if terminal.x() == terminal_to_check.x() + terminal_to_check.columns() + 1 { + if terminal.x() == terminal_to_check.x() + terminal_to_check.columns() { terminals.push(terminal); } } // rightmost border aligned with a pane border above - let mut right_resize_border = self.full_screen_ws.cols; + let mut right_resize_border = self.viewport.x + self.viewport.cols; for terminal in &terminals { let left_terminal_boundary = terminal.x(); if terminal_borders_above @@ -1190,7 +1501,7 @@ impl Tab { // terminals that are next to each other up to current for terminal in bottom_aligned_terminals { let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check); - if terminal.x() + terminal.columns() + 1 == terminal_to_check.x() { + if terminal.x() + terminal.columns() == terminal_to_check.x() { terminals.push(terminal); } } @@ -1199,11 +1510,11 @@ impl Tab { for terminal in &terminals { let right_terminal_boundary = terminal.x() + terminal.columns(); if terminal_borders_below - .get(&(right_terminal_boundary + 1)) + .get(&right_terminal_boundary) .is_some() && left_resize_border < right_terminal_boundary { - left_resize_border = right_terminal_boundary + 1; + left_resize_border = right_terminal_boundary; } } terminals.retain(|terminal| terminal.x() >= left_resize_border); @@ -1229,12 +1540,12 @@ impl Tab { // terminals that are next to each other up to current for terminal in bottom_aligned_terminals { let terminal_to_check = terminals.last().unwrap_or(&terminal_to_check); - if terminal.x() == terminal_to_check.x() + terminal_to_check.columns() + 1 { + if terminal.x() == terminal_to_check.x() + terminal_to_check.columns() { terminals.push(terminal); } } // leftmost border aligned with a pane border above - let mut right_resize_border = self.full_screen_ws.cols; + let mut right_resize_border = self.viewport.x + self.viewport.cols; for terminal in &terminals { let left_terminal_boundary = terminal.x(); if terminal_borders_below @@ -1246,6 +1557,7 @@ impl Tab { } } terminals.retain(|terminal| terminal.x() + terminal.columns() <= right_resize_border); + let right_resize_border = if terminals.is_empty() { terminal_to_check.x() + terminal_to_check.columns() } else { @@ -1257,88 +1569,145 @@ impl Tab { fn reduce_pane_height_down(&mut self, id: &PaneId, count: usize) { let terminal = self.panes.get_mut(id).unwrap(); terminal.reduce_height_down(count); + let position_and_size = terminal.position_and_size(); + + if !self.draw_pane_frames { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&position_and_size, &self.viewport); + terminal.offset_content_columns(pane_columns_offset); + terminal.offset_content_rows(pane_rows_offset); + } if let PaneId::Terminal(pid) = id { self.os_api.set_terminal_size_using_fd( *pid, - terminal.columns() as u16, - terminal.rows() as u16, + terminal.get_content_columns() as u16, + terminal.get_content_rows() as u16, ); } } fn reduce_pane_height_up(&mut self, id: &PaneId, count: usize) { let terminal = self.panes.get_mut(id).unwrap(); terminal.reduce_height_up(count); + let position_and_size = terminal.position_and_size(); + if !self.draw_pane_frames { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&position_and_size, &self.viewport); + terminal.offset_content_columns(pane_columns_offset); + terminal.offset_content_rows(pane_rows_offset); + } if let PaneId::Terminal(pid) = id { self.os_api.set_terminal_size_using_fd( *pid, - terminal.columns() as u16, - terminal.rows() as u16, + terminal.get_content_columns() as u16, + terminal.get_content_rows() as u16, ); } } fn increase_pane_height_down(&mut self, id: &PaneId, count: usize) { let terminal = self.panes.get_mut(id).unwrap(); terminal.increase_height_down(count); + let position_and_size = terminal.position_and_size(); + if !self.draw_pane_frames { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&position_and_size, &self.viewport); + terminal.offset_content_columns(pane_columns_offset); + terminal.offset_content_rows(pane_rows_offset); + } if let PaneId::Terminal(pid) = terminal.pid() { self.os_api.set_terminal_size_using_fd( pid, - terminal.columns() as u16, - terminal.rows() as u16, + terminal.get_content_columns() as u16, + terminal.get_content_rows() as u16, ); } } fn increase_pane_height_up(&mut self, id: &PaneId, count: usize) { let terminal = self.panes.get_mut(id).unwrap(); terminal.increase_height_up(count); + let position_and_size = terminal.position_and_size(); + if !self.draw_pane_frames { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&position_and_size, &self.viewport); + terminal.offset_content_columns(pane_columns_offset); + terminal.offset_content_rows(pane_rows_offset); + } if let PaneId::Terminal(pid) = terminal.pid() { self.os_api.set_terminal_size_using_fd( pid, - terminal.columns() as u16, - terminal.rows() as u16, + terminal.get_content_columns() as u16, + terminal.get_content_rows() as u16, ); } } fn increase_pane_width_right(&mut self, id: &PaneId, count: usize) { let terminal = self.panes.get_mut(id).unwrap(); terminal.increase_width_right(count); + let position_and_size = terminal.position_and_size(); + if !self.draw_pane_frames { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&position_and_size, &self.viewport); + terminal.offset_content_columns(pane_columns_offset); + terminal.offset_content_rows(pane_rows_offset); + } if let PaneId::Terminal(pid) = terminal.pid() { self.os_api.set_terminal_size_using_fd( pid, - terminal.columns() as u16, - terminal.rows() as u16, + terminal.get_content_columns() as u16, + terminal.get_content_rows() as u16, ); } } fn increase_pane_width_left(&mut self, id: &PaneId, count: usize) { let terminal = self.panes.get_mut(id).unwrap(); terminal.increase_width_left(count); + let position_and_size = terminal.position_and_size(); + if !self.draw_pane_frames { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&position_and_size, &self.viewport); + terminal.offset_content_columns(pane_columns_offset); + terminal.offset_content_rows(pane_rows_offset); + } if let PaneId::Terminal(pid) = terminal.pid() { self.os_api.set_terminal_size_using_fd( pid, - terminal.columns() as u16, - terminal.rows() as u16, + terminal.get_content_columns() as u16, + terminal.get_content_rows() as u16, ); } } fn reduce_pane_width_right(&mut self, id: &PaneId, count: usize) { let terminal = self.panes.get_mut(id).unwrap(); terminal.reduce_width_right(count); + let position_and_size = terminal.position_and_size(); + if !self.draw_pane_frames { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&position_and_size, &self.viewport); + terminal.offset_content_columns(pane_columns_offset); + terminal.offset_content_rows(pane_rows_offset); + } if let PaneId::Terminal(pid) = terminal.pid() { self.os_api.set_terminal_size_using_fd( pid, - terminal.columns() as u16, - terminal.rows() as u16, + terminal.get_content_columns() as u16, + terminal.get_content_rows() as u16, ); } } fn reduce_pane_width_left(&mut self, id: &PaneId, count: usize) { let terminal = self.panes.get_mut(id).unwrap(); terminal.reduce_width_left(count); + let position_and_size = terminal.position_and_size(); + if !self.draw_pane_frames { + let (pane_columns_offset, pane_rows_offset) = + pane_content_offset(&position_and_size, &self.viewport); + terminal.offset_content_columns(pane_columns_offset); + terminal.offset_content_rows(pane_rows_offset); + } if let PaneId::Terminal(pid) = terminal.pid() { self.os_api.set_terminal_size_using_fd( pid, - terminal.columns() as u16, - terminal.rows() as u16, + terminal.get_content_columns() as u16, + terminal.get_content_rows() as u16, ); } } @@ -1381,6 +1750,18 @@ impl Tab { terminals_below.retain(|t| { self.pane_is_between_vertical_borders(t, left_resize_border, right_resize_border) }); + + for terminal_id in terminals_to_the_left + .iter() + .chain(terminals_to_the_right.iter()) + { + let pane = self.panes.get(terminal_id).unwrap(); + if (pane.rows() as isize) - (count as isize) < pane.min_height() as isize { + // dirty, dirty hack - should be fixed by the resizing overhaul + return; + } + } + self.reduce_pane_height_up(id, count); for terminal_id in terminals_below { self.increase_pane_height_up(&terminal_id, count); @@ -1407,6 +1788,18 @@ impl Tab { terminals_above.retain(|t| { self.pane_is_between_vertical_borders(t, left_resize_border, right_resize_border) }); + + for terminal_id in terminals_to_the_left + .iter() + .chain(terminals_to_the_right.iter()) + { + let pane = self.panes.get(terminal_id).unwrap(); + if (pane.rows() as isize) - (count as isize) < pane.min_height() as isize { + // dirty, dirty hack - should be fixed by the resizing overhaul + return; + } + } + self.reduce_pane_height_down(id, count); for terminal_id in terminals_above { self.increase_pane_height_down(&terminal_id, count); @@ -1433,6 +1826,15 @@ impl Tab { terminals_to_the_left.retain(|t| { self.pane_is_between_horizontal_borders(t, top_resize_border, bottom_resize_border) }); + + for terminal_id in terminals_above.iter().chain(terminals_below.iter()) { + let pane = self.panes.get(terminal_id).unwrap(); + if (pane.columns() as isize) - (count as isize) < pane.min_width() as isize { + // dirty, dirty hack - should be fixed by the resizing overhaul + return; + } + } + self.reduce_pane_width_right(id, count); for terminal_id in terminals_to_the_left { self.increase_pane_width_right(&terminal_id, count); @@ -1456,6 +1858,15 @@ impl Tab { terminals_to_the_right.retain(|t| { self.pane_is_between_horizontal_borders(t, top_resize_border, bottom_resize_border) }); + + for terminal_id in terminals_above.iter().chain(terminals_below.iter()) { + let pane = self.panes.get(terminal_id).unwrap(); + if (pane.columns() as isize) - (count as isize) < pane.min_width() as isize { + // dirty, dirty hack - should be fixed by the resizing overhaul + return; + } + } + self.reduce_pane_width_left(id, count); for terminal_id in terminals_to_the_right { self.increase_pane_width_left(&terminal_id, count); @@ -1522,7 +1933,9 @@ impl Tab { .expect("can't increase pane size right if there are no terminals to the right"); let terminal_borders_to_the_right: HashSet = terminals_to_the_right .iter() - .map(|t| self.panes.get(t).unwrap().y()) + .map(|t| { + return self.panes.get(t).unwrap().y(); + }) .collect(); let (top_resize_border, terminals_above) = self.right_aligned_contiguous_panes_above(id, &terminal_borders_to_the_right); @@ -1741,13 +2154,14 @@ impl Tab { } if let Some((column_difference, row_difference)) = PaneResizer::new(&mut self.panes, &mut self.os_api) - .resize(self.full_screen_ws, new_screen_size) + .resize(self.display_area, new_screen_size) { self.should_clear_display_before_rendering = true; - self.full_screen_ws.cols = - (self.full_screen_ws.cols as isize + column_difference) as usize; - self.full_screen_ws.rows = - (self.full_screen_ws.rows as isize + row_difference) as usize; + + self.viewport.cols = (self.viewport.cols as isize + column_difference) as usize; + self.viewport.rows = (self.viewport.rows as isize + row_difference) as usize; + self.display_area.cols = (self.display_area.cols as isize + column_difference) as usize; + self.display_area.rows = (self.display_area.rows as isize + row_difference) as usize; }; } pub fn resize_left(&mut self) { @@ -1895,6 +2309,14 @@ impl Tab { .map(|(_, (pid, _))| pid); match next_index { Some(&p) => { + // render previously active pane so that its frame does not remain actively + // colored + let previously_active_pane = + self.panes.get_mut(&self.active_terminal.unwrap()).unwrap(); + previously_active_pane.set_should_render(true); + let next_active_pane = self.panes.get_mut(&p).unwrap(); + next_active_pane.set_should_render(true); + self.active_terminal = Some(p); self.render(); return true; @@ -1927,6 +2349,14 @@ impl Tab { .map(|(_, (pid, _))| pid); match next_index { Some(&p) => { + // render previously active pane so that its frame does not remain actively + // colored + let previously_active_pane = + self.panes.get_mut(&self.active_terminal.unwrap()).unwrap(); + previously_active_pane.set_should_render(true); + let next_active_pane = self.panes.get_mut(&p).unwrap(); + next_active_pane.set_should_render(true); + self.active_terminal = Some(p); } None => { @@ -1957,6 +2387,14 @@ impl Tab { .map(|(_, (pid, _))| pid); match next_index { Some(&p) => { + // render previously active pane so that its frame does not remain actively + // colored + let previously_active_pane = + self.panes.get_mut(&self.active_terminal.unwrap()).unwrap(); + previously_active_pane.set_should_render(true); + let next_active_pane = self.panes.get_mut(&p).unwrap(); + next_active_pane.set_should_render(true); + self.active_terminal = Some(p); } None => { @@ -1988,6 +2426,14 @@ impl Tab { .map(|(_, (pid, _))| pid); match next_index { Some(&p) => { + // render previously active pane so that its frame does not remain actively + // colored + let previously_active_pane = + self.panes.get_mut(&self.active_terminal.unwrap()).unwrap(); + previously_active_pane.set_should_render(true); + let next_active_pane = self.panes.get_mut(&p).unwrap(); + next_active_pane.set_should_render(true); + self.active_terminal = Some(p); self.render(); return true; @@ -2128,7 +2574,7 @@ impl Tab { if let Some(pane) = self.panes.get_mut(&id) { pane.set_selectable(selectable); if self.get_active_pane_id() == Some(id) && !selectable { - self.active_terminal = self.next_active_pane(self.get_pane_ids()) + self.active_terminal = self.next_active_pane(&self.get_pane_ids()) } } } @@ -2162,15 +2608,26 @@ impl Tab { if let Some(panes) = self.panes_to_the_left_between_aligning_borders(id) { if panes.iter().all(|p| { let pane = self.panes.get(p).unwrap(); - pane.can_increase_width_by(pane_to_close_width + 1) + pane.can_increase_width_by(pane_to_close_width) }) { - for pane_id in panes.iter() { - self.increase_pane_width_right(pane_id, pane_to_close_width + 1); - // 1 for the border - } self.panes.remove(&id); if self.active_terminal == Some(id) { - self.active_terminal = self.next_active_pane(panes); + let next_active_pane = self.next_active_pane(&panes); + self.active_terminal = next_active_pane; + if let Some(next_active_pane) = next_active_pane { + if self.is_the_only_selectable_pane(&next_active_pane) + && self.draw_pane_frames + { + let should_render_only_title = true; + self.panes + .get_mut(&next_active_pane) + .unwrap() + .show_boundaries_frame(should_render_only_title); + } + } + } + for pane_id in panes.iter() { + self.increase_pane_width_right(pane_id, pane_to_close_width); } return; } @@ -2178,15 +2635,26 @@ impl Tab { if let Some(panes) = self.panes_to_the_right_between_aligning_borders(id) { if panes.iter().all(|p| { let pane = self.panes.get(p).unwrap(); - pane.can_increase_width_by(pane_to_close_width + 1) + pane.can_increase_width_by(pane_to_close_width) }) { - for pane_id in panes.iter() { - self.increase_pane_width_left(pane_id, pane_to_close_width + 1); - // 1 for the border - } self.panes.remove(&id); if self.active_terminal == Some(id) { - self.active_terminal = self.next_active_pane(panes); + let next_active_pane = self.next_active_pane(&panes); + self.active_terminal = next_active_pane; + if let Some(next_active_pane) = next_active_pane { + if self.is_the_only_selectable_pane(&next_active_pane) + && self.draw_pane_frames + { + let should_render_only_title = true; + self.panes + .get_mut(&next_active_pane) + .unwrap() + .show_boundaries_frame(should_render_only_title); + } + } + } + for pane_id in panes.iter() { + self.increase_pane_width_left(pane_id, pane_to_close_width); } return; } @@ -2194,15 +2662,26 @@ impl Tab { if let Some(panes) = self.panes_above_between_aligning_borders(id) { if panes.iter().all(|p| { let pane = self.panes.get(p).unwrap(); - pane.can_increase_height_by(pane_to_close_height + 1) + pane.can_increase_height_by(pane_to_close_height) }) { - for pane_id in panes.iter() { - self.increase_pane_height_down(pane_id, pane_to_close_height + 1); - // 1 for the border - } self.panes.remove(&id); if self.active_terminal == Some(id) { - self.active_terminal = self.next_active_pane(panes); + let next_active_pane = self.next_active_pane(&panes); + self.active_terminal = next_active_pane; + if let Some(next_active_pane) = next_active_pane { + if self.is_the_only_selectable_pane(&next_active_pane) + && self.draw_pane_frames + { + let should_render_only_title = true; + self.panes + .get_mut(&next_active_pane) + .unwrap() + .show_boundaries_frame(should_render_only_title); + } + } + } + for pane_id in panes.iter() { + self.increase_pane_height_down(pane_id, pane_to_close_height); } return; } @@ -2210,15 +2689,26 @@ impl Tab { if let Some(panes) = self.panes_below_between_aligning_borders(id) { if panes.iter().all(|p| { let pane = self.panes.get(p).unwrap(); - pane.can_increase_height_by(pane_to_close_height + 1) + pane.can_increase_height_by(pane_to_close_height) }) { - for pane_id in panes.iter() { - self.increase_pane_height_up(pane_id, pane_to_close_height + 1); - // 1 for the border - } self.panes.remove(&id); if self.active_terminal == Some(id) { - self.active_terminal = self.next_active_pane(panes); + let next_active_pane = self.next_active_pane(&panes); + self.active_terminal = next_active_pane; + if let Some(next_active_pane) = next_active_pane { + if self.is_the_only_selectable_pane(&next_active_pane) + && self.draw_pane_frames + { + let should_render_only_title = true; + self.panes + .get_mut(&next_active_pane) + .unwrap() + .show_boundaries_frame(should_render_only_title); + } + } + } + for pane_id in panes.iter() { + self.increase_pane_height_up(pane_id, pane_to_close_height); } return; } @@ -2367,10 +2857,10 @@ impl Tab { self.write_selection_to_clipboard(&selected_text); } } - pub fn handle_mouse_hold(&mut self, position: &Position) { + pub fn handle_mouse_hold(&mut self, position_on_screen: &Position) { if let Some(active_pane_id) = self.get_active_pane_id() { if let Some(active_pane) = self.panes.get_mut(&active_pane_id) { - let relative_position = active_pane.relative_position(position); + let relative_position = active_pane.relative_position(position_on_screen); active_pane.update_selection(&relative_position); } } @@ -2390,6 +2880,38 @@ impl Tab { .send_to_server(ServerInstruction::Render(Some(output))) .unwrap(); } + fn is_inside_viewport(&self, pane_id: &PaneId) -> bool { + let pane_position_and_size = self.panes.get(pane_id).unwrap().position_and_size(); + pane_position_and_size.y >= self.viewport.y + && pane_position_and_size.y + pane_position_and_size.rows + <= self.viewport.y + self.viewport.rows + } + fn offset_viewport(&mut self, position_and_size: &PositionAndSize) { + if position_and_size.x == self.viewport.x + && position_and_size.x + position_and_size.cols == self.viewport.x + self.viewport.cols + { + if position_and_size.y == self.viewport.y { + self.viewport.y += position_and_size.rows; + self.viewport.rows -= position_and_size.rows; + } else if position_and_size.y + position_and_size.rows + == self.viewport.y + self.viewport.rows + { + self.viewport.rows -= position_and_size.rows; + } + } + if position_and_size.y == self.viewport.y + && position_and_size.y + position_and_size.rows == self.viewport.y + self.viewport.rows + { + if position_and_size.x == self.viewport.x { + self.viewport.x += position_and_size.cols; + self.viewport.cols -= position_and_size.cols; + } else if position_and_size.x + position_and_size.cols + == self.viewport.x + self.viewport.cols + { + self.viewport.cols -= position_and_size.cols; + } + } + } } #[cfg(test)] diff --git a/zellij-server/src/ui/boundaries.rs b/zellij-server/src/ui/boundaries.rs index 42a80ace1..b25f1cc08 100644 --- a/zellij-server/src/ui/boundaries.rs +++ b/zellij-server/src/ui/boundaries.rs @@ -1,3 +1,4 @@ +use zellij_utils::pane_size::PositionAndSize; use zellij_utils::zellij_tile; use crate::tab::Pane; @@ -405,73 +406,22 @@ impl Coordinates { } } -pub(crate) trait Rect { - fn x(&self) -> usize; - fn y(&self) -> usize; - fn rows(&self) -> usize; - fn columns(&self) -> usize; - fn right_boundary_x_coords(&self) -> usize { - self.x() + self.columns() - } - fn bottom_boundary_y_coords(&self) -> usize { - self.y() + self.rows() - } - fn is_directly_right_of(&self, other: &Self) -> bool { - self.x() == other.x() + other.columns() + 1 - } - fn is_directly_left_of(&self, other: &Self) -> bool { - self.x() + self.columns() + 1 == other.x() - } - fn is_directly_below(&self, other: &Self) -> bool { - self.y() == other.y() + other.rows() + 1 - } - fn is_directly_above(&self, other: &Self) -> bool { - self.y() + self.rows() + 1 == other.y() - } - fn horizontally_overlaps_with(&self, other: &Self) -> bool { - (self.y() >= other.y() && self.y() <= (other.y() + other.rows())) - || ((self.y() + self.rows()) <= (other.y() + other.rows()) - && (self.y() + self.rows()) > other.y()) - || (self.y() <= other.y() && (self.y() + self.rows() >= (other.y() + other.rows()))) - || (other.y() <= self.y() && (other.y() + other.rows() >= (self.y() + self.rows()))) - } - fn get_horizontal_overlap_with(&self, other: &Self) -> usize { - std::cmp::min(self.y() + self.rows(), other.y() + other.rows()) - - std::cmp::max(self.y(), other.y()) - } - fn vertically_overlaps_with(&self, other: &Self) -> bool { - (self.x() >= other.x() && self.x() <= (other.x() + other.columns())) - || ((self.x() + self.columns()) <= (other.x() + other.columns()) - && (self.x() + self.columns()) > other.x()) - || (self.x() <= other.x() - && (self.x() + self.columns() >= (other.x() + other.columns()))) - || (other.x() <= self.x() - && (other.x() + other.columns() >= (self.x() + self.columns()))) - } - fn get_vertical_overlap_with(&self, other: &Self) -> usize { - std::cmp::min(self.x() + self.columns(), other.x() + other.columns()) - - std::cmp::max(self.x(), other.x()) - } -} - pub struct Boundaries { - columns: usize, - rows: usize, - // boundary_characters: HashMap, + position_and_size: PositionAndSize, boundary_characters: HashMap, } impl Boundaries { - pub fn new(columns: u16, rows: u16) -> Self { - let columns = columns as usize; - let rows = rows as usize; + pub fn new(position_and_size: &PositionAndSize) -> Self { Boundaries { - columns, - rows, + position_and_size: *position_and_size, boundary_characters: HashMap::new(), } } pub fn add_rect(&mut self, rect: &dyn Pane, input_mode: InputMode, palette: Option) { + if !self.is_fully_inside_screen(rect) { + return; + } let color = match palette.is_some() { true => match input_mode { InputMode::Normal | InputMode::Locked => Some(palette.unwrap().green), @@ -479,19 +429,23 @@ impl Boundaries { }, false => None, }; - if rect.x() > 0 { + if rect.x() > self.position_and_size.x { + // left boundary let boundary_x_coords = rect.x() - 1; let first_row_coordinates = self.rect_right_boundary_row_start(rect); let last_row_coordinates = self.rect_right_boundary_row_end(rect); for row in first_row_coordinates..last_row_coordinates { let coordinates = Coordinates::new(boundary_x_coords, row); - let mut symbol_to_add = if row == first_row_coordinates && row != 0 { - BoundarySymbol::new(boundary_type::TOP_LEFT).color(color) - } else if row == last_row_coordinates - 1 && row != self.rows - 1 { - BoundarySymbol::new(boundary_type::BOTTOM_LEFT).color(color) - } else { - BoundarySymbol::new(boundary_type::VERTICAL).color(color) - }; + let mut symbol_to_add = + if row == first_row_coordinates && row != self.position_and_size.y { + BoundarySymbol::new(boundary_type::TOP_LEFT).color(color) + } else if row == last_row_coordinates - 1 + && row != self.position_and_size.y + self.position_and_size.rows - 1 + { + BoundarySymbol::new(boundary_type::BOTTOM_LEFT).color(color) + } else { + BoundarySymbol::new(boundary_type::VERTICAL).color(color) + }; if rect.invisible_borders() { symbol_to_add = symbol_to_add.invisible(); } @@ -503,15 +457,19 @@ impl Boundaries { self.boundary_characters.insert(coordinates, next_symbol); } } - if rect.y() > 0 { + if rect.y() > self.position_and_size.y { + // top boundary let boundary_y_coords = rect.y() - 1; let first_col_coordinates = self.rect_bottom_boundary_col_start(rect); let last_col_coordinates = self.rect_bottom_boundary_col_end(rect); for col in first_col_coordinates..last_col_coordinates { let coordinates = Coordinates::new(col, boundary_y_coords); - let mut symbol_to_add = if col == first_col_coordinates && col != 0 { + let mut symbol_to_add = if col == first_col_coordinates + && col != self.position_and_size.x + { BoundarySymbol::new(boundary_type::TOP_LEFT).color(color) - } else if col == last_col_coordinates - 1 && col != self.columns - 1 { + } else if col == last_col_coordinates - 1 && col != self.position_and_size.cols - 1 + { BoundarySymbol::new(boundary_type::TOP_RIGHT).color(color) } else { BoundarySymbol::new(boundary_type::HORIZONTAL).color(color) @@ -528,19 +486,22 @@ impl Boundaries { } } if self.rect_right_boundary_is_before_screen_edge(rect) { - // let boundary_x_coords = self.rect_right_boundary_x_coords(rect); - let boundary_x_coords = rect.right_boundary_x_coords(); + // right boundary + let boundary_x_coords = rect.right_boundary_x_coords() - 1; let first_row_coordinates = self.rect_right_boundary_row_start(rect); let last_row_coordinates = self.rect_right_boundary_row_end(rect); for row in first_row_coordinates..last_row_coordinates { let coordinates = Coordinates::new(boundary_x_coords, row); - let mut symbol_to_add = if row == first_row_coordinates && row != 0 { - BoundarySymbol::new(boundary_type::TOP_RIGHT).color(color) - } else if row == last_row_coordinates - 1 && row != self.rows - 1 { - BoundarySymbol::new(boundary_type::BOTTOM_RIGHT).color(color) - } else { - BoundarySymbol::new(boundary_type::VERTICAL).color(color) - }; + let mut symbol_to_add = + if row == first_row_coordinates && row != self.position_and_size.y { + BoundarySymbol::new(boundary_type::TOP_RIGHT).color(color) + } else if row == last_row_coordinates - 1 + && row != self.position_and_size.y + self.position_and_size.rows - 1 + { + BoundarySymbol::new(boundary_type::BOTTOM_RIGHT).color(color) + } else { + BoundarySymbol::new(boundary_type::VERTICAL).color(color) + }; if rect.invisible_borders() { symbol_to_add = symbol_to_add.invisible(); } @@ -553,14 +514,18 @@ impl Boundaries { } } if self.rect_bottom_boundary_is_before_screen_edge(rect) { - let boundary_y_coords = rect.bottom_boundary_y_coords(); + // bottom boundary + let boundary_y_coords = rect.bottom_boundary_y_coords() - 1; let first_col_coordinates = self.rect_bottom_boundary_col_start(rect); let last_col_coordinates = self.rect_bottom_boundary_col_end(rect); for col in first_col_coordinates..last_col_coordinates { let coordinates = Coordinates::new(col, boundary_y_coords); - let mut symbol_to_add = if col == first_col_coordinates && col != 0 { + let mut symbol_to_add = if col == first_col_coordinates + && col != self.position_and_size.x + { BoundarySymbol::new(boundary_type::BOTTOM_LEFT).color(color) - } else if col == last_col_coordinates - 1 && col != self.columns - 1 { + } else if col == last_col_coordinates - 1 && col != self.position_and_size.cols - 1 + { BoundarySymbol::new(boundary_type::BOTTOM_RIGHT).color(color) } else { BoundarySymbol::new(boundary_type::HORIZONTAL).color(color) @@ -590,27 +555,20 @@ impl Boundaries { vte_output } fn rect_right_boundary_is_before_screen_edge(&self, rect: &dyn Pane) -> bool { - rect.x() + rect.columns() < self.columns + rect.x() + rect.columns() < self.position_and_size.cols } fn rect_bottom_boundary_is_before_screen_edge(&self, rect: &dyn Pane) -> bool { - rect.y() + rect.rows() < self.rows + rect.y() + rect.rows() < self.position_and_size.y + self.position_and_size.rows } fn rect_right_boundary_row_start(&self, rect: &dyn Pane) -> usize { - if rect.y() == 0 { - 0 - } else { + if rect.y() > self.position_and_size.y { rect.y() - 1 + } else { + self.position_and_size.y } } fn rect_right_boundary_row_end(&self, rect: &dyn Pane) -> usize { - let rect_bottom_row = rect.y() + rect.rows(); - // we do this because unless we're on the screen edge, we'd like to go one extra row to - // connect to whatever boundary is beneath us - if rect_bottom_row == self.rows { - rect_bottom_row - } else { - rect_bottom_row + 1 - } + rect.y() + rect.rows() } fn rect_bottom_boundary_col_start(&self, rect: &dyn Pane) -> usize { if rect.x() == 0 { @@ -620,13 +578,12 @@ impl Boundaries { } } fn rect_bottom_boundary_col_end(&self, rect: &dyn Pane) -> usize { - let rect_right_col = rect.x() + rect.columns(); - // we do this because unless we're on the screen edge, we'd like to go one extra column to - // connect to whatever boundary is right of us - if rect_right_col == self.columns { - rect_right_col - } else { - rect_right_col + 1 - } + rect.x() + rect.columns() + } + fn is_fully_inside_screen(&self, rect: &dyn Pane) -> bool { + rect.x() >= self.position_and_size.x + && rect.x() + rect.columns() <= self.position_and_size.x + self.position_and_size.cols + && rect.y() >= self.position_and_size.y + && rect.y() + rect.rows() <= self.position_and_size.y + self.position_and_size.rows } } diff --git a/zellij-server/src/ui/mod.rs b/zellij-server/src/ui/mod.rs index 0087e54e8..beb70bf04 100644 --- a/zellij-server/src/ui/mod.rs +++ b/zellij-server/src/ui/mod.rs @@ -1,3 +1,4 @@ pub mod boundaries; +pub mod pane_boundaries_frame; pub mod pane_resizer; pub mod pane_resizer_beta; diff --git a/zellij-server/src/ui/pane_boundaries_frame.rs b/zellij-server/src/ui/pane_boundaries_frame.rs new file mode 100644 index 000000000..0ae454d96 --- /dev/null +++ b/zellij-server/src/ui/pane_boundaries_frame.rs @@ -0,0 +1,277 @@ +use crate::ui::boundaries::boundary_type; +use ansi_term::Colour::{Fixed, RGB}; +use ansi_term::Style; +use zellij_utils::pane_size::PositionAndSize; +use zellij_utils::zellij_tile::prelude::PaletteColor; + +fn color_string(character: &str, color: Option) -> String { + match color { + Some(color) => match color { + PaletteColor::Rgb((r, g, b)) => { + format!("{}", RGB(r, g, b).bold().paint(character)) + } + PaletteColor::EightBit(color) => { + format!("{}", Fixed(color).bold().paint(character)) + } + }, + None => format!("{}", Style::new().bold().paint(character)), + } +} + +pub struct PaneBoundariesFrame { + pub position_and_size: PositionAndSize, + base_title: String, + title: String, + scroll_position: (usize, usize), // (position, length) + pub color: Option, + draw_title_only: bool, + should_render: bool, +} + +impl PaneBoundariesFrame { + pub fn new(position_and_size: PositionAndSize, title: String) -> Self { + PaneBoundariesFrame { + position_and_size, + color: None, + base_title: title.clone(), + title, + scroll_position: (0, 0), + draw_title_only: false, + should_render: true, + } + } + pub fn frame_title_only(mut self) -> Self { + // TODO: remove this? + self.draw_title_only = true; + self.should_render = true; + self + } + pub fn render_only_title(&mut self, should_render_only_title: bool) { + if should_render_only_title != self.draw_title_only { + self.should_render = true; + self.draw_title_only = should_render_only_title; + } + } + pub fn change_pos_and_size(&mut self, position_and_size: PositionAndSize) { + if position_and_size != self.position_and_size { + self.position_and_size = position_and_size; + self.should_render = true; + } + } + pub fn set_color(&mut self, color: Option) { + if color != self.color { + self.color = color; + self.should_render = true; + } + } + pub fn update_scroll(&mut self, scroll_position: (usize, usize)) { + if scroll_position != self.scroll_position { + self.scroll_position = scroll_position; + self.should_render = true; + } + } + pub fn update_title(&mut self, title: Option<&String>) { + match title { + Some(title) => { + if title != &self.title { + self.title = title.clone(); + self.should_render = true; + } + } + None => { + self.title = self.base_title.clone(); + self.should_render = true; + } + } + } + pub fn content_position_and_size(&self) -> PositionAndSize { + if self.draw_title_only { + self.position_and_size.reduce_top_line() + } else { + self.position_and_size.reduce_outer_frame(1) + } + } + pub fn content_offset(&self) -> (usize, usize) { + // (column_difference, row_difference) + let content_position_and_size = self.content_position_and_size(); + let column_difference = content_position_and_size + .x + .saturating_sub(self.position_and_size.x); + let row_difference = content_position_and_size + .y + .saturating_sub(self.position_and_size.y); + (column_difference, row_difference) + } + pub fn set_should_render(&mut self, should_render: bool) { + self.should_render = should_render; + } + fn render_title_right_side(&self, max_length: usize) -> Option { + if self.scroll_position.0 > 0 || self.scroll_position.1 > 0 { + let prefix = " SCROLL: "; + let full_indication = + format!(" {}/{} ", self.scroll_position.0, self.scroll_position.1); + let short_indication = format!(" {} ", self.scroll_position.0); + if prefix.chars().count() + full_indication.chars().count() <= max_length { + Some(format!("{}{}", prefix, full_indication)) + } else if full_indication.chars().count() <= max_length { + Some(full_indication) + } else if short_indication.chars().count() <= max_length { + Some(short_indication) + } else { + None + } + } else { + None + } + } + fn render_title_left_side(&self, max_length: usize) -> Option { + let middle_truncated_sign = "[..]"; + let middle_truncated_sign_long = "[...]"; + let full_text = format!(" {} ", &self.title); + if max_length <= 6 { + None + } else if full_text.chars().count() <= max_length { + Some(full_text) + } else { + let length_of_each_half = (max_length - middle_truncated_sign.chars().count()) / 2; + let first_part: String = full_text.chars().take(length_of_each_half).collect(); + let second_part: String = full_text + .chars() + .skip(full_text.chars().count() - length_of_each_half) + .collect(); + let title_left_side = if first_part.chars().count() + + middle_truncated_sign.chars().count() + + second_part.chars().count() + < max_length + { + // this means we lost 1 character when dividing the total length into halves + format!( + "{}{}{}", + first_part, middle_truncated_sign_long, second_part + ) + } else { + format!("{}{}{}", first_part, middle_truncated_sign, second_part) + }; + Some(title_left_side) + } + } + fn render_title(&self, vte_output: &mut String) { + let total_title_length = self.position_and_size.cols - 2; // 2 for the left and right corners + let left_boundary = if self.draw_title_only { + boundary_type::HORIZONTAL + } else { + boundary_type::TOP_LEFT + }; + let right_boundary = if self.draw_title_only { + boundary_type::HORIZONTAL + } else { + boundary_type::TOP_RIGHT + }; + let left_side = self.render_title_left_side(total_title_length); + let right_side = left_side.as_ref().and_then(|left_side| { + let space_left = total_title_length.saturating_sub(left_side.chars().count() + 1); // 1 for a middle separator + self.render_title_right_side(space_left) + }); + let title_text = match (left_side, right_side) { + (Some(left_side), Some(right_side)) => { + let mut middle = String::new(); + for _ in + (left_side.chars().count() + right_side.chars().count())..total_title_length + { + middle.push_str(boundary_type::HORIZONTAL); + } + format!( + "{}{}{}{}{}", + left_boundary, left_side, middle, right_side, right_boundary + ) + } + (Some(left_side), None) => { + let mut middle_padding = String::new(); + for _ in left_side.chars().count()..total_title_length { + middle_padding.push_str(boundary_type::HORIZONTAL); + } + format!( + "{}{}{}{}", + left_boundary, left_side, middle_padding, right_boundary + ) + } + _ => { + let mut middle_padding = String::new(); + for _ in 0..total_title_length { + middle_padding.push_str(boundary_type::HORIZONTAL); + } + format!("{}{}{}", left_boundary, middle_padding, right_boundary) + } + }; + vte_output.push_str(&format!( + "\u{1b}[{};{}H\u{1b}[m{}", + self.position_and_size.y + 1, // +1 because goto is 1 indexed + self.position_and_size.x + 1, // +1 because goto is 1 indexed + color_string(&title_text, self.color), + )); // goto row/col + boundary character + } + pub fn render(&mut self) -> Option { + if !self.should_render { + return None; + } + let mut vte_output = String::new(); + if self.draw_title_only { + self.render_title(&mut vte_output); + } else { + for row in + self.position_and_size.y..(self.position_and_size.y + self.position_and_size.rows) + { + if row == self.position_and_size.y { + // top row + self.render_title(&mut vte_output); + } else if row == self.position_and_size.y + self.position_and_size.rows - 1 { + // bottom row + for col in self.position_and_size.x + ..(self.position_and_size.x + self.position_and_size.cols) + { + if col == self.position_and_size.x { + // bottom left corner + vte_output.push_str(&format!( + "\u{1b}[{};{}H\u{1b}[m{}", + row + 1, // +1 because goto is 1 indexed + col + 1, + color_string(boundary_type::BOTTOM_LEFT, self.color), + )); // goto row/col + boundary character + } else if col == self.position_and_size.x + self.position_and_size.cols - 1 + { + // bottom right corner + vte_output.push_str(&format!( + "\u{1b}[{};{}H\u{1b}[m{}", + row + 1, // +1 because goto is 1 indexed + col + 1, + color_string(boundary_type::BOTTOM_RIGHT, self.color), + )); // goto row/col + boundary character + } else { + vte_output.push_str(&format!( + "\u{1b}[{};{}H\u{1b}[m{}", + row + 1, // +1 because goto is 1 indexed + col + 1, + color_string(boundary_type::HORIZONTAL, self.color), + )); // goto row/col + boundary character + } + } + } else { + vte_output.push_str(&format!( + "\u{1b}[{};{}H\u{1b}[m{}", + row + 1, // +1 because goto is 1 indexed + self.position_and_size.x + 1, + color_string(boundary_type::VERTICAL, self.color), + )); // goto row/col + boundary character + vte_output.push_str(&format!( + "\u{1b}[{};{}H\u{1b}[m{}", + row + 1, // +1 because goto is 1 indexed + self.position_and_size.x + self.position_and_size.cols, + color_string(boundary_type::VERTICAL, self.color), + )); // goto row/col + boundary character + } + } + } + self.should_render = false; + Some(vte_output) + } +} diff --git a/zellij-server/src/ui/pane_resizer.rs b/zellij-server/src/ui/pane_resizer.rs index 39f2d40c6..1b5ddabf3 100644 --- a/zellij-server/src/ui/pane_resizer.rs +++ b/zellij-server/src/ui/pane_resizer.rs @@ -112,7 +112,7 @@ impl<'a> PaneResizer<'a> { (pane.x(), pane.y(), pane.columns(), pane.rows()) }; let panes_to_pull = self.panes.values_mut().filter(|p| { - p.x() > pane_x + pane_columns + p.x() >= pane_x + pane_columns && (p.y() <= pane_y && p.y() + p.rows() >= pane_y || p.y() >= pane_y && p.y() + p.rows() <= pane_y + pane_rows) }); @@ -137,7 +137,7 @@ impl<'a> PaneResizer<'a> { (pane.x(), pane.y(), pane.columns(), pane.rows()) }; let panes_to_pull = self.panes.values_mut().filter(|p| { - p.y() > pane_y + pane_rows + p.y() >= pane_y + pane_rows && (p.x() <= pane_x && p.x() + p.columns() >= pane_x || p.x() >= pane_x && p.x() + p.columns() <= pane_x + pane_columns) }); @@ -162,7 +162,7 @@ impl<'a> PaneResizer<'a> { (pane.x(), pane.y(), pane.columns(), pane.rows()) }; let panes_to_push = self.panes.values_mut().filter(|p| { - p.y() > pane_y + pane_rows + p.y() >= pane_y + pane_rows && (p.x() <= pane_x && p.x() + p.columns() >= pane_x || p.x() >= pane_x && p.x() + p.columns() <= pane_x + pane_columns) }); @@ -187,7 +187,7 @@ impl<'a> PaneResizer<'a> { (pane.x(), pane.y(), pane.columns(), pane.rows()) }; let panes_to_push = self.panes.values_mut().filter(|p| { - p.x() > pane_x + pane_columns + p.x() >= pane_x + pane_columns && (p.y() <= pane_y && p.y() + p.rows() >= pane_y || p.y() >= pane_y && p.y() + p.rows() <= pane_y + pane_rows) }); @@ -204,32 +204,44 @@ impl<'a> PaneResizer<'a> { let pane = self.panes.get_mut(id).unwrap(); pane.reduce_height_up(count); if let PaneId::Terminal(pid) = id { - self.os_api - .set_terminal_size_using_fd(*pid, pane.columns() as u16, pane.rows() as u16); + self.os_api.set_terminal_size_using_fd( + *pid, + pane.get_content_columns() as u16, + pane.get_content_rows() as u16, + ); } } fn increase_pane_height_down(&mut self, id: &PaneId, count: usize) { let pane = self.panes.get_mut(id).unwrap(); pane.increase_height_down(count); if let PaneId::Terminal(pid) = pane.pid() { - self.os_api - .set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16); + self.os_api.set_terminal_size_using_fd( + pid, + pane.get_content_columns() as u16, + pane.get_content_rows() as u16, + ); } } fn increase_pane_width_right(&mut self, id: &PaneId, count: usize) { let pane = self.panes.get_mut(id).unwrap(); pane.increase_width_right(count); if let PaneId::Terminal(pid) = pane.pid() { - self.os_api - .set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16); + self.os_api.set_terminal_size_using_fd( + pid, + pane.get_content_columns() as u16, + pane.get_content_rows() as u16, + ); } } fn reduce_pane_width_left(&mut self, id: &PaneId, count: usize) { let pane = self.panes.get_mut(id).unwrap(); pane.reduce_width_left(count); if let PaneId::Terminal(pid) = pane.pid() { - self.os_api - .set_terminal_size_using_fd(pid, pane.columns() as u16, pane.rows() as u16); + self.os_api.set_terminal_size_using_fd( + pid, + pane.get_content_columns() as u16, + pane.get_content_rows() as u16, + ); } } } @@ -240,9 +252,7 @@ fn find_next_increasable_horizontal_pane( increase_by: usize, ) -> Option { let next_pane_candidates = panes.values().filter( - |p| { - p.x() == right_of.x() + right_of.columns() + 1 && p.horizontally_overlaps_with(right_of) - }, // TODO: the name here is wrong, it should be vertically_overlaps_with + |p| p.x() == right_of.x() + right_of.columns() && p.horizontally_overlaps_with(right_of), // TODO: the name here is wrong, it should be vertically_overlaps_with ); let resizable_candidates = next_pane_candidates.filter(|p| p.can_increase_height_by(increase_by)); @@ -265,7 +275,7 @@ fn find_next_increasable_vertical_pane( increase_by: usize, ) -> Option { let next_pane_candidates = panes.values().filter( - |p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below), // TODO: the name here is wrong, it should be horizontally_overlaps_with + |p| p.y() == below.y() + below.rows() && p.vertically_overlaps_with(below), // TODO: the name here is wrong, it should be horizontally_overlaps_with ); let resizable_candidates = next_pane_candidates.filter(|p| p.can_increase_width_by(increase_by)); @@ -288,7 +298,7 @@ fn find_next_reducible_vertical_pane( reduce_by: usize, ) -> Option { let next_pane_candidates = panes.values().filter( - |p| p.y() == below.y() + below.rows() + 1 && p.vertically_overlaps_with(below), // TODO: the name here is wrong, it should be horizontally_overlaps_with + |p| p.y() == below.y() + below.rows() && p.vertically_overlaps_with(below), // TODO: the name here is wrong, it should be horizontally_overlaps_with ); let resizable_candidates = next_pane_candidates.filter(|p| p.can_reduce_width_by(reduce_by)); resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id { @@ -310,9 +320,7 @@ fn find_next_reducible_horizontal_pane( reduce_by: usize, ) -> Option { let next_pane_candidates = panes.values().filter( - |p| { - p.x() == right_of.x() + right_of.columns() + 1 && p.horizontally_overlaps_with(right_of) - }, // TODO: the name here is wrong, it should be vertically_overlaps_with + |p| p.x() == right_of.x() + right_of.columns() && p.horizontally_overlaps_with(right_of), // TODO: the name here is wrong, it should be vertically_overlaps_with ); let resizable_candidates = next_pane_candidates.filter(|p| p.can_reduce_height_by(reduce_by)); resizable_candidates.fold(None, |next_pane_id, p| match next_pane_id { @@ -346,7 +354,7 @@ fn find_increasable_horizontal_chain( { Some(leftmost_pane) => { if !leftmost_pane.can_increase_height_by(increase_by) { - horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1; + horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows(); continue; } let mut panes_to_resize = vec![]; @@ -365,7 +373,7 @@ fn find_increasable_horizontal_chain( current_pane = panes.get(&next_pane_id).unwrap(); } None => { - horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1; + horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows(); break; } }; @@ -396,7 +404,7 @@ fn find_increasable_vertical_chain( { Some(topmost_pane) => { if !topmost_pane.can_increase_width_by(increase_by) { - vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1; + vertical_coordinate = topmost_pane.x() + topmost_pane.columns(); continue; } let mut panes_to_resize = vec![]; @@ -415,7 +423,7 @@ fn find_increasable_vertical_chain( current_pane = panes.get(&next_pane_id).unwrap(); } None => { - vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1; + vertical_coordinate = topmost_pane.x() + topmost_pane.columns(); break; } }; @@ -446,7 +454,7 @@ fn find_reducible_horizontal_chain( { Some(leftmost_pane) => { if !leftmost_pane.can_reduce_height_by(reduce_by) { - horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1; + horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows(); continue; } let mut panes_to_resize = vec![]; @@ -465,7 +473,7 @@ fn find_reducible_horizontal_chain( current_pane = panes.get(&next_pane_id).unwrap(); } None => { - horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows() + 1; + horizontal_coordinate = leftmost_pane.y() + leftmost_pane.rows(); break; } }; @@ -496,7 +504,7 @@ fn find_reducible_vertical_chain( { Some(topmost_pane) => { if !topmost_pane.can_reduce_width_by(increase_by) { - vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1; + vertical_coordinate = topmost_pane.x() + topmost_pane.columns(); continue; } let mut panes_to_resize = vec![]; @@ -515,7 +523,7 @@ fn find_reducible_vertical_chain( current_pane = panes.get(&next_pane_id).unwrap(); } None => { - vertical_coordinate = topmost_pane.x() + topmost_pane.columns() + 1; + vertical_coordinate = topmost_pane.x() + topmost_pane.columns(); break; } }; diff --git a/zellij-server/src/ui/title_telescope.rs b/zellij-server/src/ui/title_telescope.rs new file mode 100644 index 000000000..e69de29bb diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index df159dde0..0ce5cff81 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -82,7 +82,14 @@ fn create_new_screen(position_and_size: PositionAndSize) -> Screen { let max_panes = None; let mode_info = ModeInfo::default(); let session_state = Arc::new(RwLock::new(SessionState::Attached)); - Screen::new(bus, &client_attributes, max_panes, mode_info, session_state) + Screen::new( + bus, + &client_attributes, + max_panes, + mode_info, + session_state, + false, // draw_pane_frames + ) } #[test] diff --git a/zellij-server/src/unit/tab_tests.rs b/zellij-server/src/unit/tab_tests.rs index cc08a5b16..085943976 100644 --- a/zellij-server/src/unit/tab_tests.rs +++ b/zellij-server/src/unit/tab_tests.rs @@ -96,6 +96,7 @@ fn create_new_tab(position_and_size: PositionAndSize) -> Tab { mode_info, colors, session_state, + true, // draw pane frames ) } @@ -136,7 +137,7 @@ fn split_panes_vertically() { .unwrap() .position_and_size() .cols, - 60, + 61, "first pane column count" ); assert_eq!( @@ -252,7 +253,7 @@ fn split_panes_horizontally() { .unwrap() .position_and_size() .y, - 11, + 10, "second pane y position" ); assert_eq!( @@ -270,7 +271,7 @@ fn split_panes_horizontally() { .unwrap() .position_and_size() .rows, - 9, + 10, "second pane row count" ); } @@ -315,7 +316,7 @@ fn split_largest_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "first pane column count" ); assert_eq!( @@ -380,7 +381,7 @@ fn split_largest_pane() { .unwrap() .position_and_size() .y, - 11, + 10, "third pane y position" ); assert_eq!( @@ -389,7 +390,7 @@ fn split_largest_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "third pane column count" ); assert_eq!( @@ -398,7 +399,7 @@ fn split_largest_pane() { .unwrap() .position_and_size() .rows, - 9, + 10, "third pane row count" ); @@ -417,7 +418,7 @@ fn split_largest_pane() { .unwrap() .position_and_size() .y, - 11, + 10, "fourth pane y position" ); assert_eq!( @@ -435,25 +436,11 @@ fn split_largest_pane() { .unwrap() .position_and_size() .rows, - 9, + 10, "fourth pane row count" ); } -#[test] -pub fn cannot_split_panes_vertically_when_active_terminal_is_too_small() { - let position_and_size = PositionAndSize { - cols: 8, - rows: 20, - x: 0, - y: 0, - ..Default::default() - }; - let mut tab = create_new_tab(position_and_size); - tab.vertical_split(PaneId::Terminal(2)); - assert_eq!(tab.panes.len(), 1, "Tab still has only one pane"); -} - #[test] pub fn cannot_split_panes_vertically_when_active_pane_is_too_small() { let position_and_size = PositionAndSize { @@ -539,7 +526,7 @@ pub fn toggle_focused_pane_fullscreen() { ); assert_eq!( tab.panes.get(&PaneId::Terminal(4)).unwrap().y(), - 11, + 10, "Pane y is on screen edge" ); assert_eq!( @@ -549,7 +536,7 @@ pub fn toggle_focused_pane_fullscreen() { ); assert_eq!( tab.panes.get(&PaneId::Terminal(4)).unwrap().rows(), - 9, + 10, "Pane rows match fullscreen rows" ); // we don't test if all other panes are hidden because this logic is done in the render @@ -889,7 +876,7 @@ pub fn close_pane_with_multiple_panes_above_it() { .unwrap() .position_and_size() .cols, - 60, + 61, "first remaining pane column count" ); assert_eq!( @@ -990,7 +977,7 @@ pub fn close_pane_with_multiple_panes_below_it() { .unwrap() .position_and_size() .cols, - 60, + 61, "first remaining pane column count" ); assert_eq!( @@ -1120,7 +1107,7 @@ pub fn close_pane_with_multiple_panes_to_the_left() { .unwrap() .position_and_size() .y, - 11, + 10, "second remaining pane y position" ); assert_eq!( @@ -1138,7 +1125,7 @@ pub fn close_pane_with_multiple_panes_to_the_left() { .unwrap() .position_and_size() .rows, - 9, + 10, "second remaining pane row count" ); } @@ -1221,7 +1208,7 @@ pub fn close_pane_with_multiple_panes_to_the_right() { .unwrap() .position_and_size() .y, - 11, + 10, "second remaining pane y position" ); assert_eq!( @@ -1239,7 +1226,7 @@ pub fn close_pane_with_multiple_panes_to_the_right() { .unwrap() .position_and_size() .rows, - 9, + 10, "second remaining pane row count" ); } @@ -1311,7 +1298,7 @@ pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 60, + 61, "first remaining pane column count" ); assert_eq!( @@ -1367,7 +1354,7 @@ pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() { .unwrap() .position_and_size() .x, - 92, + 91, "third remaining pane x position" ); assert_eq!( @@ -1385,7 +1372,7 @@ pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 29, + 30, "third remaining pane column count" ); assert_eq!( @@ -1413,7 +1400,7 @@ pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() { .unwrap() .position_and_size() .y, - 11, + 10, "fourth remaining pane y position" ); assert_eq!( @@ -1422,7 +1409,7 @@ pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 60, + 61, "fourth remaining pane column count" ); assert_eq!( @@ -1431,7 +1418,7 @@ pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 9, + 10, "fourth remaining pane row count" ); @@ -1441,7 +1428,7 @@ pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() { .unwrap() .position_and_size() .x, - 92, + 91, "sixths remaining pane x position" ); assert_eq!( @@ -1450,7 +1437,7 @@ pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() { .unwrap() .position_and_size() .y, - 11, + 10, "sixths remaining pane y position" ); assert_eq!( @@ -1459,7 +1446,7 @@ pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 29, + 30, "sixths remaining pane column count" ); assert_eq!( @@ -1468,7 +1455,7 @@ pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 9, + 10, "sixths remaining pane row count" ); @@ -1478,7 +1465,7 @@ pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() { .unwrap() .position_and_size() .x, - 77, + 76, "seventh remaining pane x position" ); assert_eq!( @@ -1496,7 +1483,7 @@ pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 14, + 15, "seventh remaining pane column count" ); assert_eq!( @@ -1577,7 +1564,7 @@ pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 60, + 61, "first remaining pane column count" ); assert_eq!( @@ -1596,7 +1583,7 @@ pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() { .unwrap() .position_and_size() .x, - 92, + 91, "third remaining pane x position" ); assert_eq!( @@ -1614,7 +1601,7 @@ pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 29, + 30, "third remaining pane column count" ); assert_eq!( @@ -1642,7 +1629,7 @@ pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() { .unwrap() .position_and_size() .y, - 11, + 10, "fourth remaining pane y position" ); assert_eq!( @@ -1651,7 +1638,7 @@ pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 60, + 61, "fourth remaining pane column count" ); assert_eq!( @@ -1660,7 +1647,7 @@ pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 9, + 10, "fourth remaining pane row count" ); @@ -1707,7 +1694,7 @@ pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() { .unwrap() .position_and_size() .x, - 92, + 91, "sixths remaining pane x position" ); assert_eq!( @@ -1716,7 +1703,7 @@ pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() { .unwrap() .position_and_size() .y, - 11, + 10, "sixths remaining pane y position" ); assert_eq!( @@ -1725,7 +1712,7 @@ pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 29, + 30, "sixths remaining pane column count" ); assert_eq!( @@ -1734,7 +1721,7 @@ pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 9, + 10, "sixths remaining pane row count" ); @@ -1744,7 +1731,7 @@ pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() { .unwrap() .position_and_size() .x, - 77, + 76, "seventh remaining pane x position" ); assert_eq!( @@ -1762,7 +1749,7 @@ pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 14, + 15, "seventh remaining pane column count" ); assert_eq!( @@ -1816,6 +1803,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { tab.move_focus_up(); tab.move_focus_left(); tab.resize_right(); + tab.resize_up(); tab.horizontal_split(new_pane_id_6); tab.move_focus_right(); tab.close_focused_pane(); @@ -1846,7 +1834,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 60, + 61, "first remaining pane column count" ); assert_eq!( @@ -1855,7 +1843,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 15, + 13, "first remaining pane row count" ); @@ -1874,7 +1862,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { .unwrap() .position_and_size() .y, - 16, + 13, "third remaining pane y position" ); assert_eq!( @@ -1892,7 +1880,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 3, + 5, "third remaining pane row count" ); @@ -1911,7 +1899,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { .unwrap() .position_and_size() .y, - 24, + 23, "fourth remaining pane y position" ); assert_eq!( @@ -1920,7 +1908,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 60, + 61, "fourth remaining pane column count" ); assert_eq!( @@ -1929,7 +1917,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 6, + 7, "fourth remaining pane row count" ); @@ -1966,7 +1954,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 15, + 13, "second remaining pane row count" ); @@ -1985,7 +1973,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { .unwrap() .position_and_size() .y, - 24, + 23, "sixths remaining pane y position" ); assert_eq!( @@ -2003,7 +1991,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 6, + 7, "sixths remaining pane row count" ); @@ -2022,7 +2010,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { .unwrap() .position_and_size() .y, - 20, + 18, "seventh remaining pane y position" ); assert_eq!( @@ -2040,7 +2028,7 @@ pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 3, + 5, "seventh remaining pane row count" ); } @@ -2084,6 +2072,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { tab.vertical_split(new_pane_id_5); tab.move_focus_up(); tab.resize_left(); + tab.resize_up(); tab.horizontal_split(new_pane_id_6); tab.move_focus_left(); tab.close_focused_pane(); @@ -2114,7 +2103,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 60, + 61, "first remaining pane column count" ); assert_eq!( @@ -2123,7 +2112,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 15, + 13, "first remaining pane row count" ); @@ -2142,7 +2131,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { .unwrap() .position_and_size() .y, - 24, + 23, "fourth remaining pane y position" ); assert_eq!( @@ -2151,7 +2140,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { .unwrap() .position_and_size() .cols, - 60, + 61, "fourth remaining pane column count" ); assert_eq!( @@ -2160,7 +2149,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 6, + 7, "fourth remaining pane row count" ); @@ -2197,7 +2186,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 15, + 13, "second remaining pane row count" ); @@ -2216,7 +2205,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { .unwrap() .position_and_size() .y, - 16, + 13, "third remaining pane y position" ); assert_eq!( @@ -2234,7 +2223,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 3, + 5, "third remaining pane row count" ); @@ -2253,7 +2242,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { .unwrap() .position_and_size() .y, - 24, + 23, "sixths remaining pane y position" ); assert_eq!( @@ -2271,7 +2260,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 6, + 7, "sixths remaining pane row count" ); @@ -2290,7 +2279,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { .unwrap() .position_and_size() .y, - 20, + 18, "seventh remaining pane y position" ); assert_eq!( @@ -2308,7 +2297,7 @@ pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() { .unwrap() .position_and_size() .rows, - 3, + 5, "seventh remaining pane row count" ); } @@ -2331,7 +2320,7 @@ pub fn move_focus_down() { assert_eq!( tab.get_active_pane().unwrap().y(), - 11, + 10, "Active pane is the bottom one" ); } @@ -2358,12 +2347,12 @@ pub fn move_focus_down_to_the_most_recently_used_pane() { assert_eq!( tab.get_active_pane().unwrap().y(), - 11, + 10, "Active pane y position" ); assert_eq!( tab.get_active_pane().unwrap().x(), - 92, + 91, "Active pane x position" ); } @@ -2418,7 +2407,7 @@ pub fn move_focus_up_to_the_most_recently_used_pane() { ); assert_eq!( tab.get_active_pane().unwrap().x(), - 92, + 91, "Active pane x position" ); } @@ -2468,7 +2457,7 @@ pub fn move_focus_left_to_the_most_recently_used_pane() { assert_eq!( tab.get_active_pane().unwrap().y(), - 16, + 15, "Active pane y position" ); assert_eq!( @@ -2523,7 +2512,7 @@ pub fn move_focus_right_to_the_most_recently_used_pane() { assert_eq!( tab.get_active_pane().unwrap().y(), - 16, + 15, "Active pane y position" ); assert_eq!( @@ -2563,7 +2552,7 @@ pub fn resize_down_with_pane_above() { ); assert_eq!( tab.panes.get(&new_pane_id).unwrap().position_and_size().y, - 13, + 12, "focused pane y position" ); assert_eq!( @@ -2581,7 +2570,7 @@ pub fn resize_down_with_pane_above() { .unwrap() .position_and_size() .rows, - 7, + 8, "focused pane row count" ); @@ -2653,7 +2642,7 @@ pub fn resize_down_with_pane_below() { ); assert_eq!( tab.panes.get(&new_pane_id).unwrap().position_and_size().y, - 13, + 12, "pane below y position" ); assert_eq!( @@ -2671,7 +2660,7 @@ pub fn resize_down_with_pane_below() { .unwrap() .position_and_size() .rows, - 7, + 8, "pane below row count" ); @@ -2750,7 +2739,7 @@ pub fn resize_down_with_panes_above_and_below() { ); assert_eq!( tab.panes.get(&new_pane_id_1).unwrap().position_and_size().y, - 16, + 15, "focused pane y position" ); assert_eq!( @@ -2768,7 +2757,7 @@ pub fn resize_down_with_panes_above_and_below() { .unwrap() .position_and_size() .rows, - 9, + 10, "focused pane row count" ); @@ -2779,7 +2768,7 @@ pub fn resize_down_with_panes_above_and_below() { ); assert_eq!( tab.panes.get(&new_pane_id_2).unwrap().position_and_size().y, - 26, + 25, "pane below y position" ); assert_eq!( @@ -2797,7 +2786,7 @@ pub fn resize_down_with_panes_above_and_below() { .unwrap() .position_and_size() .rows, - 4, + 5, "pane below row count" ); @@ -2865,7 +2854,7 @@ pub fn resize_down_with_multiple_panes_above() { ); assert_eq!( tab.panes.get(&new_pane_id_1).unwrap().position_and_size().y, - 18, + 17, "focused pane y position" ); assert_eq!( @@ -2883,7 +2872,7 @@ pub fn resize_down_with_multiple_panes_above() { .unwrap() .position_and_size() .rows, - 12, + 13, "focused pane row count" ); @@ -2932,7 +2921,7 @@ pub fn resize_down_with_multiple_panes_above() { .unwrap() .position_and_size() .cols, - 60, + 61, "second pane above column count" ); assert_eq!( @@ -2982,7 +2971,7 @@ pub fn resize_down_with_panes_above_aligned_left_with_current_pane() { ); assert_eq!( tab.panes.get(&focused_pane).unwrap().position_and_size().y, - 18, + 17, "focused pane y position" ); assert_eq!( @@ -3000,7 +2989,7 @@ pub fn resize_down_with_panes_above_aligned_left_with_current_pane() { .unwrap() .position_and_size() .rows, - 12, + 13, "focused pane row count" ); @@ -3028,7 +3017,7 @@ pub fn resize_down_with_panes_above_aligned_left_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane above and to the left column count" ); assert_eq!( @@ -3077,7 +3066,7 @@ pub fn resize_down_with_panes_above_aligned_left_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane to the left y position" ); assert_eq!( @@ -3086,7 +3075,7 @@ pub fn resize_down_with_panes_above_aligned_left_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane to the left column count" ); assert_eq!( @@ -3095,7 +3084,7 @@ pub fn resize_down_with_panes_above_aligned_left_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane to the left row count" ); } @@ -3182,7 +3171,7 @@ pub fn resize_down_with_panes_below_aligned_left_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane above and to the left column count" ); assert_eq!( @@ -3202,7 +3191,7 @@ pub fn resize_down_with_panes_below_aligned_left_with_current_pane() { ); assert_eq!( tab.panes.get(&pane_below).unwrap().position_and_size().y, - 18, + 17, "pane above y position" ); assert_eq!( @@ -3212,7 +3201,7 @@ pub fn resize_down_with_panes_below_aligned_left_with_current_pane() { ); assert_eq!( tab.panes.get(&pane_below).unwrap().position_and_size().rows, - 12, + 13, "pane above row count" ); @@ -3231,7 +3220,7 @@ pub fn resize_down_with_panes_below_aligned_left_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane to the left y position" ); assert_eq!( @@ -3240,7 +3229,7 @@ pub fn resize_down_with_panes_below_aligned_left_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane to the left column count" ); assert_eq!( @@ -3249,7 +3238,7 @@ pub fn resize_down_with_panes_below_aligned_left_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane to the left row count" ); } @@ -3292,7 +3281,7 @@ pub fn resize_down_with_panes_above_aligned_right_with_current_pane() { ); assert_eq!( tab.panes.get(&focused_pane).unwrap().position_and_size().y, - 18, + 17, "focused pane y position" ); assert_eq!( @@ -3301,7 +3290,7 @@ pub fn resize_down_with_panes_above_aligned_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "focused pane column count" ); assert_eq!( @@ -3310,7 +3299,7 @@ pub fn resize_down_with_panes_above_aligned_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 12, + 13, "focused pane row count" ); @@ -3326,7 +3315,7 @@ pub fn resize_down_with_panes_above_aligned_right_with_current_pane() { ); assert_eq!( tab.panes.get(&pane_above).unwrap().position_and_size().cols, - 60, + 61, "pane above column count" ); assert_eq!( @@ -3350,7 +3339,7 @@ pub fn resize_down_with_panes_above_aligned_right_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane to the right y position" ); assert_eq!( @@ -3368,7 +3357,7 @@ pub fn resize_down_with_panes_above_aligned_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane to the right row count" ); @@ -3456,7 +3445,7 @@ pub fn resize_down_with_panes_below_aligned_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "focused pane column count" ); assert_eq!( @@ -3476,17 +3465,17 @@ pub fn resize_down_with_panes_below_aligned_right_with_current_pane() { ); assert_eq!( tab.panes.get(&pane_below).unwrap().position_and_size().y, - 18, + 17, "pane below y position" ); assert_eq!( tab.panes.get(&pane_below).unwrap().position_and_size().cols, - 60, + 61, "pane below column count" ); assert_eq!( tab.panes.get(&pane_below).unwrap().position_and_size().rows, - 12, + 13, "pane below row count" ); @@ -3505,7 +3494,7 @@ pub fn resize_down_with_panes_below_aligned_right_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane below and to the right y position" ); assert_eq!( @@ -3523,7 +3512,7 @@ pub fn resize_down_with_panes_below_aligned_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane below and to the right row count" ); @@ -3618,7 +3607,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -3646,7 +3635,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -3655,7 +3644,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -3664,7 +3653,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -3683,7 +3672,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .y, - 18, + 17, "pane 3 y position" ); assert_eq!( @@ -3701,7 +3690,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 12, + 13, "pane 3 row count" ); @@ -3711,7 +3700,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .x, - 92, + 91, "pane 4 x position" ); assert_eq!( @@ -3720,7 +3709,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 4 y position" ); assert_eq!( @@ -3729,7 +3718,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 29, + 30, "pane 4 column count" ); assert_eq!( @@ -3738,7 +3727,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 4 row count" ); @@ -3785,7 +3774,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .x, - 92, + 91, "pane 6 x position" ); assert_eq!( @@ -3803,7 +3792,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 29, + 30, "pane 6 column count" ); assert_eq!( @@ -3869,7 +3858,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -3897,7 +3886,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -3906,7 +3895,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -3915,7 +3904,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -3934,7 +3923,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .y, - 18, + 17, "pane 3 y position" ); assert_eq!( @@ -3952,7 +3941,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 12, + 13, "pane 3 row count" ); @@ -3962,7 +3951,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .x, - 92, + 91, "pane 4 x position" ); assert_eq!( @@ -3971,7 +3960,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 4 y position" ); assert_eq!( @@ -3980,7 +3969,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 29, + 30, "pane 4 column count" ); assert_eq!( @@ -3989,7 +3978,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 4 row count" ); @@ -4036,7 +4025,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .x, - 92, + 91, "pane 6 x position" ); assert_eq!( @@ -4054,7 +4043,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 29, + 30, "pane 6 column count" ); assert_eq!( @@ -4124,7 +4113,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -4152,7 +4141,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -4161,7 +4150,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -4170,7 +4159,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -4217,7 +4206,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .x, - 92, + 91, "pane 4 x position" ); assert_eq!( @@ -4235,7 +4224,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .cols, - 29, + 30, "pane 4 column count" ); assert_eq!( @@ -4263,7 +4252,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .y, - 18, + 17, "pane 5 y position" ); assert_eq!( @@ -4281,7 +4270,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .rows, - 12, + 13, "pane 5 row count" ); @@ -4291,7 +4280,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .x, - 92, + 91, "pane 6 x position" ); assert_eq!( @@ -4300,7 +4289,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .y, - 16, + 15, "pane 6 y position" ); assert_eq!( @@ -4309,7 +4298,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .cols, - 29, + 30, "pane 6 column count" ); assert_eq!( @@ -4318,7 +4307,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .rows, - 14, + 15, "pane 6 row count" ); @@ -4328,7 +4317,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .x, - 77, + 76, "pane 7 x position" ); assert_eq!( @@ -4337,7 +4326,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .y, - 18, + 17, "pane 7 y position" ); assert_eq!( @@ -4346,7 +4335,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .cols, - 7, + 8, "pane 7 column count" ); assert_eq!( @@ -4355,7 +4344,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .rows, - 12, + 13, "pane 7 row count" ); @@ -4365,7 +4354,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .x, - 85, + 84, "pane 8 x position" ); assert_eq!( @@ -4374,7 +4363,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .y, - 18, + 17, "pane 8 y position" ); assert_eq!( @@ -4383,7 +4372,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .cols, - 6, + 7, "pane 8 column count" ); assert_eq!( @@ -4392,7 +4381,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef .unwrap() .position_and_size() .rows, - 12, + 13, "pane 8 row count" ); } @@ -4455,7 +4444,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -4483,7 +4472,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -4492,7 +4481,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -4501,7 +4490,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -4548,7 +4537,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .x, - 92, + 91, "pane 4 x position" ); assert_eq!( @@ -4566,7 +4555,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .cols, - 29, + 30, "pane 4 column count" ); assert_eq!( @@ -4585,7 +4574,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .x, - 77, + 76, "pane 5 x position" ); assert_eq!( @@ -4603,7 +4592,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .cols, - 7, + 8, "pane 5 column count" ); assert_eq!( @@ -4622,7 +4611,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .x, - 85, + 84, "pane 6 x position" ); assert_eq!( @@ -4640,7 +4629,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .cols, - 6, + 7, "pane 6 column count" ); assert_eq!( @@ -4668,7 +4657,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .y, - 18, + 17, "pane 7 y position" ); assert_eq!( @@ -4686,7 +4675,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .rows, - 12, + 13, "pane 7 row count" ); @@ -4696,7 +4685,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .x, - 92, + 91, "pane 8 x position" ); assert_eq!( @@ -4705,7 +4694,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .y, - 16, + 15, "pane 8 y position" ); assert_eq!( @@ -4714,7 +4703,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .cols, - 29, + 30, "pane 8 column count" ); assert_eq!( @@ -4723,7 +4712,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ .unwrap() .position_and_size() .rows, - 14, + 15, "pane 8 row count" ); } @@ -4739,7 +4728,7 @@ pub fn cannot_resize_down_when_pane_below_is_at_minimum_height() { let position_and_size = PositionAndSize { cols: 121, - rows: 7, + rows: 10, x: 0, y: 0, ..Default::default() @@ -4755,7 +4744,7 @@ pub fn cannot_resize_down_when_pane_below_is_at_minimum_height() { .unwrap() .position_and_size() .rows, - 3, + 5, "pane 1 height stayed the same" ); assert_eq!( @@ -4764,7 +4753,7 @@ pub fn cannot_resize_down_when_pane_below_is_at_minimum_height() { .unwrap() .position_and_size() .rows, - 3, + 5, "pane 2 height stayed the same" ); } @@ -4813,7 +4802,7 @@ pub fn resize_left_with_pane_to_the_left() { .unwrap() .position_and_size() .cols, - 50, + 51, "pane 1 column count" ); assert_eq!( @@ -4908,7 +4897,7 @@ pub fn resize_left_with_pane_to_the_right() { .unwrap() .position_and_size() .cols, - 50, + 51, "pane 1 column count" ); assert_eq!( @@ -5005,7 +4994,7 @@ pub fn resize_left_with_panes_to_the_left_and_right() { .unwrap() .position_and_size() .cols, - 50, + 51, "pane 1 column count" ); assert_eq!( @@ -5061,7 +5050,7 @@ pub fn resize_left_with_panes_to_the_left_and_right() { .unwrap() .position_and_size() .x, - 92, + 91, "pane 2 x position" ); assert_eq!( @@ -5079,7 +5068,7 @@ pub fn resize_left_with_panes_to_the_left_and_right() { .unwrap() .position_and_size() .cols, - 29, + 30, "pane 2 column count" ); assert_eq!( @@ -5139,7 +5128,7 @@ pub fn resize_left_with_multiple_panes_to_the_left() { .unwrap() .position_and_size() .cols, - 50, + 51, "pane 1 column count" ); assert_eq!( @@ -5204,7 +5193,7 @@ pub fn resize_left_with_multiple_panes_to_the_left() { .unwrap() .position_and_size() .y, - 11, + 10, "pane 2 y position" ); assert_eq!( @@ -5213,7 +5202,7 @@ pub fn resize_left_with_multiple_panes_to_the_left() { .unwrap() .position_and_size() .cols, - 50, + 51, "pane 2 column count" ); assert_eq!( @@ -5222,7 +5211,7 @@ pub fn resize_left_with_multiple_panes_to_the_left() { .unwrap() .position_and_size() .rows, - 9, + 10, "pane 2 row count" ); } @@ -5275,7 +5264,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -5303,7 +5292,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -5312,7 +5301,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_with_current_pane() { .unwrap() .position_and_size() .cols, - 50, + 51, "pane 2 column count" ); assert_eq!( @@ -5321,7 +5310,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -5340,7 +5329,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 3 y position" ); assert_eq!( @@ -5358,7 +5347,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 3 row count" ); @@ -5449,7 +5438,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -5477,7 +5466,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -5486,7 +5475,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_with_current_pane() { .unwrap() .position_and_size() .cols, - 50, + 51, "pane 2 column count" ); assert_eq!( @@ -5495,7 +5484,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -5514,7 +5503,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 3 y position" ); assert_eq!( @@ -5532,7 +5521,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 3 row count" ); @@ -5621,7 +5610,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .cols, - 50, + 51, "pane 1 column count" ); assert_eq!( @@ -5649,7 +5638,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -5658,7 +5647,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -5667,7 +5656,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -5686,7 +5675,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 3 y position" ); assert_eq!( @@ -5704,7 +5693,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 3 row count" ); @@ -5794,7 +5783,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .cols, - 50, + 51, "pane 1 column count" ); assert_eq!( @@ -5822,7 +5811,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -5831,7 +5820,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -5840,7 +5829,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -5859,7 +5848,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 3 y position" ); assert_eq!( @@ -5877,7 +5866,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 3 row count" ); @@ -5972,7 +5961,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -6000,7 +5989,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -6009,7 +5998,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa .unwrap() .position_and_size() .cols, - 50, + 51, "pane 2 column count" ); assert_eq!( @@ -6018,7 +6007,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa .unwrap() .position_and_size() .rows, - 7, + 8, "pane 2 row count" ); @@ -6037,7 +6026,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa .unwrap() .position_and_size() .y, - 24, + 23, "pane 3 y position" ); assert_eq!( @@ -6046,7 +6035,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa .unwrap() .position_and_size() .cols, - 60, + 61, "pane 3 column count" ); assert_eq!( @@ -6055,7 +6044,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa .unwrap() .position_and_size() .rows, - 6, + 7, "pane 3 row count" ); @@ -6074,7 +6063,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa .unwrap() .position_and_size() .y, - 24, + 23, "pane 4 y position" ); assert_eq!( @@ -6092,7 +6081,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa .unwrap() .position_and_size() .rows, - 6, + 7, "pane 4 row count" ); @@ -6111,7 +6100,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa .unwrap() .position_and_size() .y, - 16, + 15, "pane 5 y position" ); assert_eq!( @@ -6129,7 +6118,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa .unwrap() .position_and_size() .rows, - 7, + 8, "pane 5 row count" ); @@ -6225,7 +6214,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -6253,7 +6242,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -6262,7 +6251,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .cols, - 50, + 51, "pane 2 column count" ); assert_eq!( @@ -6271,7 +6260,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .rows, - 7, + 8, "pane 2 row count" ); @@ -6290,7 +6279,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .y, - 24, + 23, "pane 3 y position" ); assert_eq!( @@ -6299,7 +6288,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .cols, - 60, + 61, "pane 3 column count" ); assert_eq!( @@ -6308,7 +6297,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .rows, - 6, + 7, "pane 3 row count" ); @@ -6327,7 +6316,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .y, - 24, + 23, "pane 4 y position" ); assert_eq!( @@ -6345,7 +6334,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .rows, - 6, + 7, "pane 4 row count" ); @@ -6364,7 +6353,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .y, - 16, + 15, "pane 5 y position" ); assert_eq!( @@ -6382,7 +6371,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .rows, - 7, + 8, "pane 5 row count" ); @@ -6450,6 +6439,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov tab.move_focus_up(); tab.vertical_split(PaneId::Terminal(5)); tab.move_focus_down(); + tab.resize_down(); tab.vertical_split(PaneId::Terminal(6)); tab.horizontal_split(PaneId::Terminal(7)); tab.horizontal_split(PaneId::Terminal(8)); @@ -6480,7 +6470,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -6508,7 +6498,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .y, - 36, + 35, "pane 2 y position" ); assert_eq!( @@ -6517,7 +6507,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .cols, - 50, + 51, "pane 2 column count" ); assert_eq!( @@ -6526,7 +6516,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .rows, - 17, + 20, "pane 2 row count" ); @@ -6545,7 +6535,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .y, - 54, + 55, "pane 3 y position" ); assert_eq!( @@ -6554,7 +6544,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .cols, - 60, + 61, "pane 3 column count" ); assert_eq!( @@ -6563,7 +6553,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .rows, - 16, + 15, "pane 3 row count" ); @@ -6582,7 +6572,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .y, - 54, + 55, "pane 4 y position" ); assert_eq!( @@ -6600,7 +6590,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .rows, - 16, + 15, "pane 4 row count" ); @@ -6656,7 +6646,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .y, - 36, + 35, "pane 6 y position" ); assert_eq!( @@ -6674,7 +6664,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .rows, - 8, + 10, "pane 6 row count" ); @@ -6711,7 +6701,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .rows, - 4, + 5, "pane 7 row count" ); @@ -6748,7 +6738,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov .unwrap() .position_and_size() .rows, - 3, + 5, "pane 8 row count" ); } @@ -6779,6 +6769,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo tab.move_focus_up(); tab.vertical_split(PaneId::Terminal(5)); tab.move_focus_down(); + tab.resize_down(); tab.vertical_split(PaneId::Terminal(6)); tab.move_focus_left(); tab.horizontal_split(PaneId::Terminal(7)); @@ -6810,7 +6801,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -6838,7 +6829,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .y, - 36, + 35, "pane 2 y position" ); assert_eq!( @@ -6847,7 +6838,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .cols, - 50, + 51, "pane 2 column count" ); assert_eq!( @@ -6856,7 +6847,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 8, + 10, "pane 2 row count" ); @@ -6875,7 +6866,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .y, - 54, + 55, "pane 3 y position" ); assert_eq!( @@ -6884,7 +6875,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .cols, - 60, + 61, "pane 3 column count" ); assert_eq!( @@ -6893,7 +6884,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 16, + 15, "pane 3 row count" ); @@ -6912,7 +6903,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .y, - 54, + 55, "pane 4 y position" ); assert_eq!( @@ -6930,7 +6921,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 16, + 15, "pane 4 row count" ); @@ -6986,7 +6977,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .y, - 36, + 35, "pane 6 y position" ); assert_eq!( @@ -7004,7 +6995,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 17, + 20, "pane 6 row count" ); @@ -7032,7 +7023,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .cols, - 50, + 51, "pane 7 column count" ); assert_eq!( @@ -7041,7 +7032,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 4, + 5, "pane 7 row count" ); @@ -7069,7 +7060,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .cols, - 50, + 51, "pane 8 column count" ); assert_eq!( @@ -7078,7 +7069,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 3, + 5, "pane 8 row count" ); } @@ -7093,7 +7084,7 @@ pub fn cannot_resize_left_when_pane_to_the_left_is_at_minimum_width() { // █ == focused pane let position_and_size = PositionAndSize { - cols: 9, + cols: 10, rows: 20, x: 0, y: 0, @@ -7109,7 +7100,7 @@ pub fn cannot_resize_left_when_pane_to_the_left_is_at_minimum_width() { .unwrap() .position_and_size() .cols, - 4, + 5, "pane 1 columns stayed the same" ); assert_eq!( @@ -7118,7 +7109,7 @@ pub fn cannot_resize_left_when_pane_to_the_left_is_at_minimum_width() { .unwrap() .position_and_size() .cols, - 4, + 5, "pane 2 columns stayed the same" ); } @@ -7167,7 +7158,7 @@ pub fn resize_right_with_pane_to_the_left() { .unwrap() .position_and_size() .cols, - 70, + 71, "pane 1 column count" ); assert_eq!( @@ -7263,7 +7254,7 @@ pub fn resize_right_with_pane_to_the_right() { .unwrap() .position_and_size() .cols, - 70, + 71, "pane 1 column count" ); assert_eq!( @@ -7360,7 +7351,7 @@ pub fn resize_right_with_panes_to_the_left_and_right() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -7416,7 +7407,7 @@ pub fn resize_right_with_panes_to_the_left_and_right() { .unwrap() .position_and_size() .x, - 102, + 101, "pane 2 x position" ); assert_eq!( @@ -7434,7 +7425,7 @@ pub fn resize_right_with_panes_to_the_left_and_right() { .unwrap() .position_and_size() .cols, - 19, + 20, "pane 2 column count" ); assert_eq!( @@ -7495,7 +7486,7 @@ pub fn resize_right_with_multiple_panes_to_the_left() { .unwrap() .position_and_size() .cols, - 70, + 71, "pane 1 column count" ); assert_eq!( @@ -7560,7 +7551,7 @@ pub fn resize_right_with_multiple_panes_to_the_left() { .unwrap() .position_and_size() .y, - 11, + 10, "pane 3 y position" ); assert_eq!( @@ -7569,7 +7560,7 @@ pub fn resize_right_with_multiple_panes_to_the_left() { .unwrap() .position_and_size() .cols, - 70, + 71, "pane 3 column count" ); assert_eq!( @@ -7578,7 +7569,7 @@ pub fn resize_right_with_multiple_panes_to_the_left() { .unwrap() .position_and_size() .rows, - 9, + 10, "pane 3 row count" ); } @@ -7631,7 +7622,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -7696,7 +7687,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_with_current_pane() { .unwrap() .position_and_size() .y, - 11, + 10, "pane 3 y position" ); assert_eq!( @@ -7705,7 +7696,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_with_current_pane() { .unwrap() .position_and_size() .cols, - 70, + 71, "pane 3 column count" ); assert_eq!( @@ -7714,7 +7705,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_with_current_pane() { .unwrap() .position_and_size() .rows, - 9, + 10, "pane 3 row count" ); @@ -7733,7 +7724,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_with_current_pane() { .unwrap() .position_and_size() .y, - 11, + 10, "pane 4 y position" ); assert_eq!( @@ -7751,7 +7742,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_with_current_pane() { .unwrap() .position_and_size() .rows, - 9, + 10, "pane 4 row count" ); } @@ -7804,7 +7795,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -7869,7 +7860,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_with_current_pane() { .unwrap() .position_and_size() .y, - 11, + 10, "pane 3 y position" ); assert_eq!( @@ -7878,7 +7869,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_with_current_pane() { .unwrap() .position_and_size() .cols, - 70, + 71, "pane 3 column count" ); assert_eq!( @@ -7887,7 +7878,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_with_current_pane() { .unwrap() .position_and_size() .rows, - 9, + 10, "pane 3 row count" ); @@ -7906,7 +7897,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_with_current_pane() { .unwrap() .position_and_size() .y, - 11, + 10, "pane 4 y position" ); assert_eq!( @@ -7924,7 +7915,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_with_current_pane() { .unwrap() .position_and_size() .rows, - 9, + 10, "pane 4 row count" ); } @@ -7978,7 +7969,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .cols, - 70, + 71, "pane 1 column count" ); assert_eq!( @@ -8043,7 +8034,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .y, - 11, + 10, "pane 3 y position" ); assert_eq!( @@ -8052,7 +8043,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 3 column count" ); assert_eq!( @@ -8061,7 +8052,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .rows, - 9, + 10, "pane 3 row count" ); @@ -8080,7 +8071,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .y, - 11, + 10, "pane 4 y position" ); assert_eq!( @@ -8098,7 +8089,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .rows, - 9, + 10, "pane 4 row count" ); } @@ -8153,7 +8144,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .cols, - 70, + 71, "pane 1 column count" ); assert_eq!( @@ -8218,7 +8209,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .y, - 11, + 10, "pane 3 y position" ); assert_eq!( @@ -8227,7 +8218,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 3 column count" ); assert_eq!( @@ -8236,7 +8227,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .rows, - 9, + 10, "pane 3 row count" ); @@ -8255,7 +8246,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .y, - 11, + 10, "pane 4 y position" ); assert_eq!( @@ -8273,7 +8264,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_bottom_with_current_pane() { .unwrap() .position_and_size() .rows, - 9, + 10, "pane 4 row count" ); } @@ -8331,7 +8322,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -8359,7 +8350,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .y, - 11, + 10, "pane 2 y position" ); assert_eq!( @@ -8368,7 +8359,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .cols, - 70, + 71, "pane 2 column count" ); assert_eq!( @@ -8377,7 +8368,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .rows, - 4, + 5, "pane 2 row count" ); @@ -8396,7 +8387,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .y, - 16, + 15, "pane 3 y position" ); assert_eq!( @@ -8405,7 +8396,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .cols, - 60, + 61, "pane 3 column count" ); assert_eq!( @@ -8414,7 +8405,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .rows, - 4, + 5, "pane 3 row count" ); @@ -8433,7 +8424,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .y, - 16, + 15, "pane 4 y position" ); assert_eq!( @@ -8451,7 +8442,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .rows, - 4, + 5, "pane 4 row count" ); @@ -8470,7 +8461,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .y, - 11, + 10, "pane 5 y position" ); assert_eq!( @@ -8488,7 +8479,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p .unwrap() .position_and_size() .rows, - 4, + 5, "pane 5 row count" ); @@ -8583,7 +8574,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_ .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -8611,7 +8602,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_ .unwrap() .position_and_size() .y, - 11, + 10, "pane 2 y position" ); assert_eq!( @@ -8620,7 +8611,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_ .unwrap() .position_and_size() .cols, - 70, + 71, "pane 2 column count" ); assert_eq!( @@ -8629,7 +8620,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_ .unwrap() .position_and_size() .rows, - 4, + 5, "pane 2 row count" ); @@ -8648,7 +8639,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_ .unwrap() .position_and_size() .y, - 16, + 15, "pane 3 y position" ); assert_eq!( @@ -8657,7 +8648,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_ .unwrap() .position_and_size() .cols, - 60, + 61, "pane 3 column count" ); assert_eq!( @@ -8666,7 +8657,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_ .unwrap() .position_and_size() .rows, - 4, + 5, "pane 3 row count" ); @@ -8685,7 +8676,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_ .unwrap() .position_and_size() .y, - 16, + 15, "pane 4 y position" ); assert_eq!( @@ -8703,7 +8694,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_ .unwrap() .position_and_size() .rows, - 4, + 5, "pane 4 row count" ); @@ -8722,7 +8713,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_ .unwrap() .position_and_size() .y, - 11, + 10, "pane 5 y position" ); assert_eq!( @@ -8740,7 +8731,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_ .unwrap() .position_and_size() .rows, - 4, + 5, "pane 5 row count" ); @@ -8807,6 +8798,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo tab.move_focus_up(); tab.vertical_split(PaneId::Terminal(5)); tab.move_focus_down(); + tab.resize_up(); tab.vertical_split(PaneId::Terminal(6)); tab.horizontal_split(PaneId::Terminal(7)); tab.horizontal_split(PaneId::Terminal(8)); @@ -8837,7 +8829,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -8846,7 +8838,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 35, + 33, "pane 1 row count" ); @@ -8865,7 +8857,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .y, - 36, + 33, "pane 2 y position" ); assert_eq!( @@ -8874,7 +8866,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .cols, - 70, + 71, "pane 2 column count" ); assert_eq!( @@ -8883,7 +8875,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 17, + 20, "pane 2 row count" ); @@ -8902,7 +8894,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .y, - 54, + 53, "pane 3 y position" ); assert_eq!( @@ -8911,7 +8903,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .cols, - 60, + 61, "pane 3 column count" ); assert_eq!( @@ -8920,7 +8912,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 16, + 17, "pane 3 row count" ); @@ -8939,7 +8931,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .y, - 54, + 53, "pane 4 y position" ); assert_eq!( @@ -8957,7 +8949,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 16, + 17, "pane 4 row count" ); @@ -8994,7 +8986,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 35, + 33, "pane 5 row count" ); @@ -9013,7 +9005,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .y, - 36, + 33, "pane 6 y position" ); assert_eq!( @@ -9031,7 +9023,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 8, + 10, "pane 6 row count" ); @@ -9050,7 +9042,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .y, - 45, + 43, "pane 7 y position" ); assert_eq!( @@ -9068,7 +9060,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 4, + 5, "pane 7 row count" ); @@ -9087,7 +9079,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .y, - 50, + 48, "pane 8 y position" ); assert_eq!( @@ -9105,7 +9097,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo .unwrap() .position_and_size() .rows, - 3, + 5, "pane 8 row count" ); } @@ -9135,6 +9127,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab tab.move_focus_up(); tab.vertical_split(PaneId::Terminal(5)); tab.move_focus_down(); + tab.resize_up(); tab.vertical_split(PaneId::Terminal(6)); tab.move_focus_left(); tab.horizontal_split(PaneId::Terminal(7)); @@ -9166,7 +9159,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -9175,7 +9168,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .rows, - 35, + 33, "pane 1 row count" ); @@ -9194,7 +9187,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .y, - 36, + 33, "pane 2 y position" ); assert_eq!( @@ -9203,7 +9196,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .cols, - 70, + 71, "pane 2 column count" ); assert_eq!( @@ -9212,7 +9205,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .rows, - 8, + 10, "pane 2 row count" ); @@ -9231,7 +9224,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .y, - 54, + 53, "pane 3 y position" ); assert_eq!( @@ -9240,7 +9233,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .cols, - 60, + 61, "pane 3 column count" ); assert_eq!( @@ -9249,7 +9242,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .rows, - 16, + 17, "pane 3 row count" ); @@ -9268,7 +9261,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .y, - 54, + 53, "pane 4 y position" ); assert_eq!( @@ -9286,7 +9279,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .rows, - 16, + 17, "pane 4 row count" ); @@ -9323,7 +9316,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .rows, - 35, + 33, "pane 5 row count" ); @@ -9342,7 +9335,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .y, - 36, + 33, "pane 6 y position" ); assert_eq!( @@ -9360,7 +9353,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .rows, - 17, + 20, "pane 6 row count" ); @@ -9379,7 +9372,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .y, - 45, + 43, "pane 7 y position" ); assert_eq!( @@ -9388,7 +9381,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .cols, - 70, + 71, "pane 7 column count" ); assert_eq!( @@ -9397,7 +9390,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .rows, - 4, + 5, "pane 7 row count" ); @@ -9416,7 +9409,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .y, - 50, + 48, "pane 8 y position" ); assert_eq!( @@ -9425,7 +9418,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .cols, - 70, + 71, "pane 8 column count" ); assert_eq!( @@ -9434,7 +9427,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab .unwrap() .position_and_size() .rows, - 3, + 5, "pane 8 row count" ); } @@ -9448,7 +9441,7 @@ pub fn cannot_resize_right_when_pane_to_the_left_is_at_minimum_width() { // └─┴─┘ └─┴─┘ // █ == focused pane let position_and_size = PositionAndSize { - cols: 9, + cols: 10, rows: 20, x: 0, y: 0, @@ -9464,7 +9457,7 @@ pub fn cannot_resize_right_when_pane_to_the_left_is_at_minimum_width() { .unwrap() .position_and_size() .cols, - 4, + 5, "pane 1 columns stayed the same" ); assert_eq!( @@ -9473,7 +9466,7 @@ pub fn cannot_resize_right_when_pane_to_the_left_is_at_minimum_width() { .unwrap() .position_and_size() .cols, - 4, + 5, "pane 2 columns stayed the same" ); } @@ -9551,7 +9544,7 @@ pub fn resize_up_with_pane_above() { .unwrap() .position_and_size() .y, - 9, + 8, "pane 2 y position" ); assert_eq!( @@ -9569,7 +9562,7 @@ pub fn resize_up_with_pane_above() { .unwrap() .position_and_size() .rows, - 11, + 12, "pane 2 row count" ); } @@ -9648,7 +9641,7 @@ pub fn resize_up_with_pane_below() { .unwrap() .position_and_size() .y, - 9, + 8, "pane 2 y position" ); assert_eq!( @@ -9666,7 +9659,7 @@ pub fn resize_up_with_pane_below() { .unwrap() .position_and_size() .rows, - 11, + 12, "pane 2 row count" ); } @@ -9749,7 +9742,7 @@ pub fn resize_up_with_panes_above_and_below() { .unwrap() .position_and_size() .y, - 14, + 13, "pane 2 y position" ); assert_eq!( @@ -9767,7 +9760,7 @@ pub fn resize_up_with_panes_above_and_below() { .unwrap() .position_and_size() .rows, - 9, + 10, "pane 2 row count" ); @@ -9786,7 +9779,7 @@ pub fn resize_up_with_panes_above_and_below() { .unwrap() .position_and_size() .y, - 24, + 23, "pane 3 y position" ); assert_eq!( @@ -9804,7 +9797,7 @@ pub fn resize_up_with_panes_above_and_below() { .unwrap() .position_and_size() .rows, - 6, + 7, "pane 3 row count" ); } @@ -9856,7 +9849,7 @@ pub fn resize_up_with_multiple_panes_above() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -9884,7 +9877,7 @@ pub fn resize_up_with_multiple_panes_above() { .unwrap() .position_and_size() .y, - 14, + 13, "pane 2 y position" ); assert_eq!( @@ -9902,7 +9895,7 @@ pub fn resize_up_with_multiple_panes_above() { .unwrap() .position_and_size() .rows, - 16, + 17, "pane 2 row count" ); @@ -9991,7 +9984,7 @@ pub fn resize_up_with_panes_above_aligned_left_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -10019,7 +10012,7 @@ pub fn resize_up_with_panes_above_aligned_left_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -10028,7 +10021,7 @@ pub fn resize_up_with_panes_above_aligned_left_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -10037,7 +10030,7 @@ pub fn resize_up_with_panes_above_aligned_left_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -10093,7 +10086,7 @@ pub fn resize_up_with_panes_above_aligned_left_with_current_pane() { .unwrap() .position_and_size() .y, - 14, + 13, "pane 4 y position" ); assert_eq!( @@ -10111,7 +10104,7 @@ pub fn resize_up_with_panes_above_aligned_left_with_current_pane() { .unwrap() .position_and_size() .rows, - 16, + 17, "pane 4 row count" ); } @@ -10166,7 +10159,7 @@ pub fn resize_up_with_panes_below_aligned_left_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -10194,7 +10187,7 @@ pub fn resize_up_with_panes_below_aligned_left_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -10203,7 +10196,7 @@ pub fn resize_up_with_panes_below_aligned_left_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -10212,7 +10205,7 @@ pub fn resize_up_with_panes_below_aligned_left_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -10268,7 +10261,7 @@ pub fn resize_up_with_panes_below_aligned_left_with_current_pane() { .unwrap() .position_and_size() .y, - 14, + 13, "pane 4 y position" ); assert_eq!( @@ -10286,7 +10279,7 @@ pub fn resize_up_with_panes_below_aligned_left_with_current_pane() { .unwrap() .position_and_size() .rows, - 16, + 17, "pane 4 row count" ); } @@ -10341,7 +10334,7 @@ pub fn resize_up_with_panes_above_aligned_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -10369,7 +10362,7 @@ pub fn resize_up_with_panes_above_aligned_right_with_current_pane() { .unwrap() .position_and_size() .y, - 14, + 13, "pane 2 y position" ); assert_eq!( @@ -10378,7 +10371,7 @@ pub fn resize_up_with_panes_above_aligned_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -10387,7 +10380,7 @@ pub fn resize_up_with_panes_above_aligned_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 16, + 17, "pane 2 row count" ); @@ -10443,7 +10436,7 @@ pub fn resize_up_with_panes_above_aligned_right_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 4 y position" ); assert_eq!( @@ -10461,7 +10454,7 @@ pub fn resize_up_with_panes_above_aligned_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 4 row count" ); } @@ -10517,7 +10510,7 @@ pub fn resize_up_with_panes_below_aligned_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -10545,7 +10538,7 @@ pub fn resize_up_with_panes_below_aligned_right_with_current_pane() { .unwrap() .position_and_size() .y, - 14, + 13, "pane 2 y position" ); assert_eq!( @@ -10554,7 +10547,7 @@ pub fn resize_up_with_panes_below_aligned_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -10563,7 +10556,7 @@ pub fn resize_up_with_panes_below_aligned_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 16, + 17, "pane 2 row count" ); @@ -10619,7 +10612,7 @@ pub fn resize_up_with_panes_below_aligned_right_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 4 y position" ); assert_eq!( @@ -10637,7 +10630,7 @@ pub fn resize_up_with_panes_below_aligned_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 4 row count" ); } @@ -10693,7 +10686,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -10721,7 +10714,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -10730,7 +10723,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -10739,7 +10732,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -10758,7 +10751,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .y, - 14, + 13, "pane 3 y position" ); assert_eq!( @@ -10776,7 +10769,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 16, + 17, "pane 3 row count" ); @@ -10786,7 +10779,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .x, - 92, + 91, "pane 4 x position" ); assert_eq!( @@ -10795,7 +10788,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 4 y position" ); assert_eq!( @@ -10804,7 +10797,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 29, + 30, "pane 4 column count" ); assert_eq!( @@ -10813,7 +10806,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 4 row count" ); @@ -10860,7 +10853,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .x, - 92, + 91, "pane 6 x position" ); assert_eq!( @@ -10878,7 +10871,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 29, + 30, "pane 6 column count" ); assert_eq!( @@ -10944,7 +10937,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -10972,7 +10965,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -10981,7 +10974,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -10990,7 +10983,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -11009,7 +11002,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .y, - 14, + 13, "pane 3 y position" ); assert_eq!( @@ -11027,7 +11020,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 16, + 17, "pane 3 row count" ); @@ -11037,7 +11030,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .x, - 92, + 91, "pane 4 x position" ); assert_eq!( @@ -11046,7 +11039,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .y, - 16, + 15, "pane 4 y position" ); assert_eq!( @@ -11055,7 +11048,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 29, + 30, "pane 4 column count" ); assert_eq!( @@ -11064,7 +11057,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .rows, - 14, + 15, "pane 4 row count" ); @@ -11111,7 +11104,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .x, - 92, + 91, "pane 6 x position" ); assert_eq!( @@ -11129,7 +11122,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { .unwrap() .position_and_size() .cols, - 29, + 30, "pane 6 column count" ); assert_eq!( @@ -11198,7 +11191,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -11226,7 +11219,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -11235,7 +11228,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -11244,7 +11237,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -11291,7 +11284,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .x, - 92, + 91, "pane 4 x position" ); assert_eq!( @@ -11309,7 +11302,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .cols, - 29, + 30, "pane 4 column count" ); assert_eq!( @@ -11337,7 +11330,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .y, - 14, + 13, "pane 5 y position" ); assert_eq!( @@ -11355,7 +11348,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .rows, - 16, + 17, "pane 5 row count" ); @@ -11365,7 +11358,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .x, - 92, + 91, "pane 6 x position" ); assert_eq!( @@ -11374,7 +11367,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .y, - 16, + 15, "pane 6 y position" ); assert_eq!( @@ -11383,7 +11376,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .cols, - 29, + 30, "pane 6 column count" ); assert_eq!( @@ -11392,7 +11385,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .rows, - 14, + 15, "pane 6 row count" ); @@ -11402,7 +11395,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .x, - 77, + 76, "pane 7 x position" ); assert_eq!( @@ -11411,7 +11404,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .y, - 14, + 13, "pane 7 y position" ); assert_eq!( @@ -11420,7 +11413,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .cols, - 7, + 8, "pane 7 column count" ); assert_eq!( @@ -11429,7 +11422,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .rows, - 16, + 17, "pane 7 row count" ); @@ -11439,7 +11432,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .x, - 85, + 84, "pane 8 x position" ); assert_eq!( @@ -11448,7 +11441,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .y, - 14, + 13, "pane 8 y position" ); assert_eq!( @@ -11457,7 +11450,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .cols, - 6, + 7, "pane 8 column count" ); assert_eq!( @@ -11466,7 +11459,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ .unwrap() .position_and_size() .rows, - 16, + 17, "pane 8 row count" ); } @@ -11527,7 +11520,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .cols, - 60, + 61, "pane 1 column count" ); assert_eq!( @@ -11555,7 +11548,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .y, - 16, + 15, "pane 2 y position" ); assert_eq!( @@ -11564,7 +11557,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .cols, - 60, + 61, "pane 2 column count" ); assert_eq!( @@ -11573,7 +11566,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .rows, - 14, + 15, "pane 2 row count" ); @@ -11620,7 +11613,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .x, - 92, + 91, "pane 4 x position" ); assert_eq!( @@ -11638,7 +11631,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .cols, - 29, + 30, "pane 4 column count" ); assert_eq!( @@ -11666,7 +11659,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .y, - 14, + 13, "pane 5 y position" ); assert_eq!( @@ -11684,7 +11677,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .rows, - 16, + 17, "pane 5 row count" ); @@ -11694,7 +11687,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .x, - 92, + 91, "pane 6 x position" ); assert_eq!( @@ -11703,7 +11696,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .y, - 16, + 15, "pane 6 y position" ); assert_eq!( @@ -11712,7 +11705,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .cols, - 29, + 30, "pane 6 column count" ); assert_eq!( @@ -11721,7 +11714,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .rows, - 14, + 15, "pane 6 row count" ); @@ -11731,7 +11724,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .x, - 77, + 76, "pane 7 x position" ); assert_eq!( @@ -11749,7 +11742,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .cols, - 7, + 8, "pane 7 column count" ); assert_eq!( @@ -11768,7 +11761,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .x, - 85, + 84, "pane 8 x position" ); assert_eq!( @@ -11786,7 +11779,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri .unwrap() .position_and_size() .cols, - 6, + 7, "pane 8 column count" ); assert_eq!( @@ -11811,7 +11804,7 @@ pub fn cannot_resize_up_when_pane_above_is_at_minimum_height() { let position_and_size = PositionAndSize { cols: 121, - rows: 7, + rows: 10, x: 0, y: 0, ..Default::default() @@ -11826,7 +11819,7 @@ pub fn cannot_resize_up_when_pane_above_is_at_minimum_height() { .unwrap() .position_and_size() .rows, - 3, + 5, "pane 1 height stayed the same" ); assert_eq!( @@ -11835,7 +11828,7 @@ pub fn cannot_resize_up_when_pane_above_is_at_minimum_height() { .unwrap() .position_and_size() .rows, - 3, + 5, "pane 2 height stayed the same" ); } diff --git a/zellij-server/src/wasm_vm.rs b/zellij-server/src/wasm_vm.rs index 41a468ee2..0f6b721e2 100644 --- a/zellij-server/src/wasm_vm.rs +++ b/zellij-server/src/wasm_vm.rs @@ -133,15 +133,19 @@ pub(crate) fn wasm_thread_main(bus: Bus, store: Store, data_d drop(bus.senders.send_to_screen(ScreenInstruction::Render)); } PluginInstruction::Render(buf_tx, pid, rows, cols) => { - let (instance, plugin_env) = plugin_map.get(&pid).unwrap(); + if rows == 0 || cols == 0 { + buf_tx.send(String::new()).unwrap(); + } else { + let (instance, plugin_env) = plugin_map.get(&pid).unwrap(); - let render = instance.exports.get_function("render").unwrap(); + let render = instance.exports.get_function("render").unwrap(); - render - .call(&[Value::I32(rows as i32), Value::I32(cols as i32)]) - .unwrap(); + render + .call(&[Value::I32(rows as i32), Value::I32(cols as i32)]) + .unwrap(); - buf_tx.send(wasi_read_string(&plugin_env.wasi_env)).unwrap(); + buf_tx.send(wasi_read_string(&plugin_env.wasi_env)).unwrap(); + } } PluginInstruction::Unload(pid) => drop(plugin_map.remove(&pid)), PluginInstruction::Exit => break, diff --git a/zellij-utils/assets/config/default.yaml b/zellij-utils/assets/config/default.yaml index 24ee95f59..4654cee90 100644 --- a/zellij-utils/assets/config/default.yaml +++ b/zellij-utils/assets/config/default.yaml @@ -105,6 +105,8 @@ keybinds: key: [Char: 'x',] - action: [ToggleFocusFullscreen,] key: [Char: 'f',] + - action: [TogglePaneFrames,] + key: [Char: 'z',] - action: [FocusPreviousPane,] key: [ Alt: '[',] - action: [FocusNextPane,] diff --git a/zellij-utils/assets/layouts/default.yaml b/zellij-utils/assets/layouts/default.yaml index 96bf1809c..b163821de 100644 --- a/zellij-utils/assets/layouts/default.yaml +++ b/zellij-utils/assets/layouts/default.yaml @@ -2,12 +2,14 @@ direction: Horizontal parts: - direction: Vertical + borderless: true split_size: Fixed: 1 run: plugin: tab-bar - direction: Vertical - direction: Vertical + borderless: true split_size: Fixed: 2 run: diff --git a/zellij-utils/assets/layouts/disable-status-bar.yaml b/zellij-utils/assets/layouts/disable-status-bar.yaml index b990ba500..a03c71c3a 100644 --- a/zellij-utils/assets/layouts/disable-status-bar.yaml +++ b/zellij-utils/assets/layouts/disable-status-bar.yaml @@ -2,6 +2,7 @@ direction: Horizontal parts: - direction: Vertical + borderless: true split_size: Fixed: 1 run: diff --git a/zellij-utils/assets/layouts/strider.yaml b/zellij-utils/assets/layouts/strider.yaml index 9bbe5772f..288143894 100644 --- a/zellij-utils/assets/layouts/strider.yaml +++ b/zellij-utils/assets/layouts/strider.yaml @@ -2,6 +2,7 @@ direction: Horizontal parts: - direction: Vertical + borderless: true split_size: Fixed: 1 run: @@ -15,6 +16,7 @@ parts: plugin: strider - direction: Horizontal - direction: Vertical + borderless: true split_size: Fixed: 2 run: diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index 6a053038a..c0891d52d 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -209,6 +209,7 @@ pub enum ScreenContext { CloseFocusedPane, ToggleActiveSyncTab, ToggleActiveTerminalFullscreen, + TogglePaneFrames, SetSelectable, SetInvisibleBorders, SetFixedHeight, diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index 431a09bf7..3e86409bc 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -56,6 +56,8 @@ pub enum Action { PageScrollDown, /// Toggle between fullscreen focus pane and normal layout. ToggleFocusFullscreen, + /// Toggle frames around panes in the UI + TogglePaneFrames, /// Toggle between sending text commands to all panes on the current tab and normal mode. ToggleActiveSyncTab, /// Open a new pane in the specified direction (relative to focus). diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index 090ccb13f..33e08bfdb 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -50,6 +50,8 @@ pub struct Layout { pub parts: Vec, pub split_size: Option, pub run: Option, + #[serde(default)] + pub borderless: bool, } type LayoutResult = Result; @@ -141,6 +143,14 @@ impl Layout { total_panes } + pub fn total_borderless_panes(&self) -> usize { + let mut total_borderless_panes = 0; + total_borderless_panes += self.parts.iter().filter(|p| p.borderless).count(); + for part in self.parts.iter() { + total_borderless_panes += part.total_borderless_panes(); + } + total_borderless_panes + } pub fn extract_run_instructions(&self) -> Vec> { let mut run_instructions = vec![]; if self.parts.is_empty() { @@ -168,7 +178,7 @@ fn split_space_to_parts_vertically( let mut split_parts = Vec::new(); let mut current_x_position = space_to_split.x; let mut current_width = 0; - let max_width = space_to_split.cols - (sizes.len() - 1); // minus space for gaps + let max_width = space_to_split.cols; let mut parts_to_grow = Vec::new(); @@ -192,7 +202,7 @@ fn split_space_to_parts_vertically( ..Default::default() }); current_width += columns; - current_x_position += columns + 1; // 1 for gap + current_x_position += columns; } if current_width > max_width { @@ -210,7 +220,7 @@ fn split_space_to_parts_vertically( last_flexible_index = idx; } current_width += part.cols; - current_x_position += part.cols + 1; // 1 for gap + current_x_position += part.cols; } } @@ -233,7 +243,7 @@ fn split_space_to_parts_horizontally( let mut split_parts = Vec::new(); let mut current_y_position = space_to_split.y; let mut current_height = 0; - let max_height = space_to_split.rows - (sizes.len() - 1); // minus space for gaps + let max_height = space_to_split.rows; let mut parts_to_grow = Vec::new(); @@ -256,7 +266,7 @@ fn split_space_to_parts_horizontally( ..Default::default() }); current_height += rows; - current_y_position += rows + 1; // 1 for gap + current_y_position += rows; } if current_height > max_height { @@ -275,7 +285,7 @@ fn split_space_to_parts_horizontally( last_flexible_index = idx; } current_height += part.rows; - current_y_position += part.rows + 1; // 1 for gap + current_y_position += part.rows; } } diff --git a/zellij-utils/src/input/mod.rs b/zellij-utils/src/input/mod.rs index 746d58619..87d72db8a 100644 --- a/zellij-utils/src/input/mod.rs +++ b/zellij-utils/src/input/mod.rs @@ -30,6 +30,7 @@ pub fn get_mode_info( ("r".to_string(), "Right split".to_string()), ("x".to_string(), "Close".to_string()), ("f".to_string(), "Fullscreen".to_string()), + ("z".to_string(), "Frames".to_string()), ], InputMode::Tab => vec![ ("←↓↑→".to_string(), "Move focus".to_string()), diff --git a/zellij-utils/src/input/options.rs b/zellij-utils/src/input/options.rs index a2f9231cd..94994e1e3 100644 --- a/zellij-utils/src/input/options.rs +++ b/zellij-utils/src/input/options.rs @@ -58,6 +58,9 @@ pub struct Options { #[serde(default)] /// Disable handling of mouse events pub disable_mouse_mode: bool, + #[structopt(long)] + #[serde(default)] + pub no_pane_frames: bool, /// Set behaviour on force close (quit or detach) #[structopt(long)] pub on_force_close: Option, @@ -80,6 +83,7 @@ impl Options { let simplified_ui = merge_bool(other.simplified_ui, self.simplified_ui); let disable_mouse_mode = merge_bool(other.disable_mouse_mode, self.disable_mouse_mode); + let no_pane_frames = merge_bool(other.no_pane_frames, self.no_pane_frames); let default_mode = other.default_mode.or(self.default_mode); let default_shell = other.default_shell.or_else(|| self.default_shell.clone()); @@ -94,6 +98,7 @@ impl Options { default_shell, layout_dir, disable_mouse_mode, + no_pane_frames, on_force_close, } } diff --git a/zellij-utils/src/pane_size.rs b/zellij-utils/src/pane_size.rs index da165d4e6..db439b612 100644 --- a/zellij-utils/src/pane_size.rs +++ b/zellij-utils/src/pane_size.rs @@ -5,7 +5,7 @@ use crate::position::Position; /// Contains the position and size of a [`Pane`], or more generally of any terminal, measured /// in character rows and columns. -#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq)] pub struct PositionAndSize { pub x: usize, pub y: usize, @@ -34,4 +34,16 @@ impl PositionAndSize { let row = point.line.0 as usize; self.x <= col && col < self.x + self.cols && self.y <= row && row < self.y + self.rows } + pub fn reduce_outer_frame(mut self, frame_width: usize) -> Self { + self.x += frame_width; + self.rows -= frame_width * 2; + self.y += frame_width; + self.cols -= frame_width * 2; + self + } + pub fn reduce_top_line(mut self) -> Self { + self.y += 1; + self.rows -= 1; + self + } } diff --git a/zellij-utils/src/shared.rs b/zellij-utils/src/shared.rs index a741cc10b..b1edb97fd 100644 --- a/zellij-utils/src/shared.rs +++ b/zellij-utils/src/shared.rs @@ -18,7 +18,7 @@ pub fn set_permissions(path: &Path) -> io::Result<()> { fs::set_permissions(path, permissions) } -fn ansi_len(s: &str) -> usize { +pub fn ansi_len(s: &str) -> usize { from_utf8(&strip(s.as_bytes()).unwrap()) .unwrap() .chars()