aboutsummaryrefslogtreecommitdiffstats
path: root/zellij-server/src
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2021-06-30 11:27:35 +0200
committerGitHub <noreply@github.com>2021-06-30 11:27:35 +0200
commited4fd2a8e77df304539ca7f445a78039028eaa8a (patch)
treeae48b03370b11f3f0987676584724463ac83460d /zellij-server/src
parentMerge pull request #590 from a-kenji/clippy-fixes (diff)
downloadsl0ppij-ed4fd2a8e77df304539ca7f445a78039028eaa8a.tar.gz
sl0ppij-ed4fd2a8e77df304539ca7f445a78039028eaa8a.tar.xz
sl0ppij-ed4fd2a8e77df304539ca7f445a78039028eaa8a.zip
chore(tests): move all integration tests to be either unit or e2e tests - remove old testing infra (#589)
* tests(integration): move basic integration tests to be unit tests * fix(tests): silently fail threadbus for tests * tests(unit): move compatibility tests to become unit tests for grid * tests(unit): move close_pane tests to become unit tests for grid * tests(e2e): move basic layout test to e2e * tests(unit): move move_focus tests to be unit tests * tests(unit): move resize_down tests to be unit tests * tests(unit): move resize_left tests to be unit tests * tests(unit): move resize_right tests to be unit tests * tests(unit): move resize_up tests to be unit tests * tests(infra): remove unused infra * style(fmt): make rustfmt happy * debug * debug * debug * debug * chore(test): shift volume mounting around because github actions is a special child
Diffstat (limited to 'zellij-server/src')
-rw-r--r--zellij-server/src/lib.rs1
-rw-r--r--zellij-server/src/panes/terminal_pane.rs4
-rw-r--r--zellij-server/src/panes/unit/grid_tests.rs290
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_cursor_linewrap.snap10
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__clear_scroll_region.snap9
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__display_tab_characters_properly.snap21
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__emacs_longbuf.snap10
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__exa_plus_omf_theme.snap62
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_paste_multiline.snap27
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_select_tab_completion_options.snap11
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_tab_completion_options.snap11
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__git_diff_scrollup.snap34
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__git_log.snap34
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__htop.snap34
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__htop_right_scrolling.snap34
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__htop_scrolling.snap34
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__neovim_insert_mode.snap34
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__run_bandwhich_from_fish_shell.snap34
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__top_and_quit.snap62
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_ctrl_d.snap34
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_ctrl_u.snap34
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_overwrite.snap34
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_scroll_region_down.snap34
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_inside_a_pane-2.snap26
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_inside_a_pane-3.snap26
-rw-r--r--zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_inside_a_pane.snap26
-rw-r--r--zellij-server/src/panes/unit/terminal_pane_tests.rs30
-rw-r--r--zellij-server/src/screen.rs22
-rw-r--r--zellij-server/src/tab.rs4
-rw-r--r--zellij-server/src/thread_bus.rs72
-rw-r--r--zellij-server/src/unit/screen_tests.rs255
-rw-r--r--zellij-server/src/unit/tab_tests.rs11840
32 files changed, 13182 insertions, 11 deletions
diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs
index 27872b64..5322e6a6 100644
--- a/zellij-server/src/lib.rs
+++ b/zellij-server/src/lib.rs
@@ -390,6 +390,7 @@ fn init_session(
to_pty: Some(to_pty),
to_plugin: Some(to_plugin),
to_server: None,
+ should_silently_fail: false,
},
capabilities,
palette: client_attributes.palette,
diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs
index 734007ea..0abc7a5a 100644
--- a/zellij-server/src/panes/terminal_pane.rs
+++ b/zellij-server/src/panes/terminal_pane.rs
@@ -340,3 +340,7 @@ impl TerminalPane {
self.grid.cursor_coordinates()
}
}
+
+#[cfg(test)]
+#[path = "./unit/terminal_pane_tests.rs"]
+mod grid_tests;
diff --git a/zellij-server/src/panes/unit/grid_tests.rs b/zellij-server/src/panes/unit/grid_tests.rs
index bce67e06..048d3d0a 100644
--- a/zellij-server/src/panes/unit/grid_tests.rs
+++ b/zellij-server/src/panes/unit/grid_tests.rs
@@ -555,3 +555,293 @@ fn wrap_wide_characters_at_the_end_of_the_line() {
}
assert_snapshot!(format!("{:?}", grid));
}
+
+/*
+ * These tests below are general compatibility tests for non-trivial scenarios running in the terminal.
+ * They use fake TTY input replicated from these scenarios.
+ *
+ */
+
+#[test]
+fn run_bandwhich_from_fish_shell() {
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "fish_and_bandwhich";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+fn fish_tab_completion_options() {
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "fish_tab_completion_options";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn fish_select_tab_completion_options() {
+ // the difference between this and the previous test is that here we press <TAB>
+ // twice, meaning the selection moves between the options and the command line
+ // changes.
+ // this is not clearly seen in the snapshot because it does not include styles,
+ // but we can see the command line change and the cursor staying in place
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "fish_select_tab_completion_options";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn vim_scroll_region_down() {
+ // here we test a case where vim defines the scroll region as lesser than the screen row count
+ // and then scrolls down
+ // the region is defined here by vim as 1-26 (there are 28 rows)
+ // then the cursor is moved to line 26 and a new line is added
+ // what should happen is that the first line in the scroll region (1) is deleted
+ // and an empty line is inserted in the last scroll region line (26)
+ // this tests also has other steps afterwards that fills the line with the next line in the
+ // file
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "vim_scroll_region_down";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn vim_ctrl_d() {
+ // in vim ctrl-d moves down half a page
+ // in this case, it sends the terminal the csi 'M' directive, which tells it to delete X (13 in
+ // this case) lines inside the scroll region and push the other lines up
+ // what happens here is that 13 lines are deleted and instead 13 empty lines are added at the
+ // end of the scroll region
+ // vim makes sure to fill these empty lines with the rest of the file
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "vim_ctrl_d";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn vim_ctrl_u() {
+ // in vim ctrl-u moves up half a page
+ // in this case, it sends the terminal the csi 'L' directive, which tells it to insert X (13 in
+ // this case) lines at the cursor, pushing away (deleting) the last line in the scroll region
+ // this causes the effect of scrolling up X lines (vim replaces the lines with the ones in the
+ // file above the current content)
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "vim_ctrl_u";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn htop() {
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "htop";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn htop_scrolling() {
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "htop_scrolling";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn htop_right_scrolling() {
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "htop_right_scrolling";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn vim_overwrite() {
+ // this tests the vim overwrite message
+ // to recreate:
+ // * open a file in vim
+ // * open the same file in another window
+ // * change the file in the other window and save
+ // * change the file in the original vim window and save
+ // * confirm you would like to change the file by pressing 'y' and then ENTER
+ // * if everything looks fine, this test passed :)
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "vim_overwrite";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn clear_scroll_region() {
+ // this is actually a test of 1049h/l (alternative buffer)
+ // @imsnif - the name is a monument to the time I didn't fully understand this mechanism :)
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "clear_scroll_region";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn display_tab_characters_properly() {
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "tab_characters";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn neovim_insert_mode() {
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "nvim_insert";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn bash_cursor_linewrap() {
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 116, Palette::default());
+ let fixture_name = "bash_cursor_linewrap";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn fish_paste_multiline() {
+ // here we paste a multiline command in fish shell, making sure we support it
+ // going up and changing the colors of our line-wrapped pasted text
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 149, Palette::default());
+ let fixture_name = "fish_paste_multiline";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn git_log() {
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 149, Palette::default());
+ let fixture_name = "git_log";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn git_diff_scrollup() {
+ // this tests makes sure that when we have a git diff that exceeds the screen size
+ // we are able to scroll up
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(28, 149, Palette::default());
+ let fixture_name = "git_diff_scrollup";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn emacs_longbuf() {
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(60, 284, Palette::default());
+ let fixture_name = "emacs_longbuf_tutorial";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn top_and_quit() {
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(56, 235, Palette::default());
+ let fixture_name = "top_and_quit";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
+
+#[test]
+pub fn exa_plus_omf_theme() {
+ // this tests that we handle a tab delimited table properly
+ // without overriding the previous content
+ // this is a potential bug because the \t character is a goto
+ // if we forwarded it as is to the terminal, we would be skipping
+ // over existing on-screen content without deleting it, so we must
+ // convert it to spaces
+ let mut vte_parser = vte::Parser::new();
+ let mut grid = Grid::new(56, 235, Palette::default());
+ let fixture_name = "exa_plus_omf_theme";
+ let content = read_fixture(fixture_name);
+ for byte in content {
+ vte_parser.advance(&mut grid, byte);
+ }
+ assert_snapshot!(format!("{:?}", grid));
+}
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_cursor_linewrap.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_cursor_linewrap.snap
new file mode 100644
index 00000000..93634316
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__bash_cursor_linewrap.snap
@@ -0,0 +1,10 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): Welcome to fish, the friendly interactive shell
+01 (C): ⋊> ~/c/mosaic on main ⨯ bash 16:00:06
+02 (C): [aram@green mosaic]$ 12345678912345678912345678912345678912345678912345678912345678912345678912345678912345678912345
+03 (W):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__clear_scroll_region.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__clear_scroll_region.snap
new file mode 100644
index 00000000..b53826df
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__clear_scroll_region.snap
@@ -0,0 +1,9 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): Welcome to fish, the friendly interactive shell
+01 (C): ⋊> ~/c/mosaic on main ⨯ vim some-file 15:07:22
+02 (C): ⋊> ~/c/mosaic on main ⨯ 15:07:29
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__display_tab_characters_properly.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__display_tab_characters_properly.snap
new file mode 100644
index 00000000..48c75d6c
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__display_tab_characters_properly.snap
@@ -0,0 +1,21 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C):
+01 (C): OS: 5.9.13-arch1-1 GNU/Linux
+02 (C): Uptime: 10 hours, 42 minutes
+03 (C): Hostname: kingdom
+04 (C): Disk usage:
+05 (C):
+06 (C): df: /run/user/1000/doc: Operation not permitted
+07 (C): / 321G / 514G 66%
+08 (C): /efi 27M / 96M 28%
+09 (C):
+10 (C): Network:
+11 (C):
+12 (C): wlp2s0 192.168.0.3
+13 (C):
+14 (C): [I] [20:07] kingdom:mosaic (main) |
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__emacs_longbuf.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__emacs_longbuf.snap
new file mode 100644
index 00000000..5c08c323
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__emacs_longbuf.snap
@@ -0,0 +1,10 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): ➜ mosaic git:(mosaic#130) emacs
+01 (C): ➜ mosaic git:(mosaic#130) emacs -nw
+02 (C): ➜ mosaic git:(mosaic#130) exit
+03 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__exa_plus_omf_theme.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__exa_plus_omf_theme.snap
new file mode 100644
index 00000000..eba80043
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__exa_plus_omf_theme.snap
@@ -0,0 +1,62 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): .rw-r--r-- 3.3k aram 11 Jan 16:09 CODE_OF_CONDUCT.md
+01 (C): .rw-r--r-- 3.5k aram 17 Feb 16:06 CONTRIBUTING.md
+02 (C): drwxr-xr-x - aram 10 Feb 11:53 default-tiles
+03 (C): drwxr-xr-x - aram 10 Feb 11:53 docs
+04 (C): .rw-r--r-- 2.1k aram 10 Feb 11:53 GOVERNANCE.md
+05 (C): .rw-r--r-- 1.1k aram 10 Feb 11:53 LICENSE.md
+06 (C): .rw-r--r-- 4.7k aram 17 Feb 16:06 README.md
+07 (C): drwxr-xr-x - aram 17 Feb 16:06 src
+08 (C): drwxr-xr-x - aram 17 Feb 16:08 target
+09 (C): drwxr-xr-x - aram 17 Feb 16:06 zellij-tile
+10 (C): ⋊> ~/c/zellij on main ⨯ ll 10:27:45
+11 (C): Permissions Size User Date Modified Name
+12 (C): drwxr-xr-x - aram 11 Feb 14:04 assets
+13 (C): .rwxr-xr-x 596 aram 17 Feb 16:06 build-all.sh
+14 (C): .rw-r--r-- 1.4k aram 17 Feb 16:06 build.rs
+15 (C): .rw-r--r-- 56k aram 17 Feb 16:07 Cargo.lock
+16 (C): .rw-r--r-- 2.1k aram 17 Feb 16:06 Cargo.toml
+17 (C): .rw-r--r-- 3.3k aram 11 Jan 16:09 CODE_OF_CONDUCT.md
+18 (C): .rw-r--r-- 3.5k aram 17 Feb 16:06 CONTRIBUTING.md
+19 (C): drwxr-xr-x - aram 10 Feb 11:53 default-tiles
+20 (C): drwxr-xr-x - aram 10 Feb 11:53 docs
+21 (C): .rw-r--r-- 2.1k aram 10 Feb 11:53 GOVERNANCE.md
+22 (C): .rw-r--r-- 1.1k aram 10 Feb 11:53 LICENSE.md
+23 (C): .rw-r--r-- 4.7k aram 17 Feb 16:06 README.md
+24 (C): drwxr-xr-x - aram 17 Feb 16:06 src
+25 (C): drwxr-xr-x - aram 17 Feb 16:08 target
+26 (C): drwxr-xr-x - aram 17 Feb 16:06 zellij-tile
+27 (C): ⋊> ~/c/zellij on main ⨯ omf theme 10:27:45
+28 (C): Installed:
+29 (C): agnoster chain default plain
+30 (C):
+31 (C): Available:
+32 (C): agnoster eden lavender scorphish
+33 (C): aight emoji-powerline lolfish separation
+34 (C): ays es mars shellder
+35 (C): batman fishbone mish simple-ass-prompt
+36 (C): beloglazov fishface mokou simplevi
+37 (C): bira fishy-drupal mtahmed slavic-cat
+38 (C): bobthefish fisk nai spacefish
+39 (C): bongnoster fox nelsonjchen sushi
+40 (C): boxfish gentoo neolambda syl20bnr
+41 (C): budspencer gianu numist taktoa
+42 (C): cbjohnson gitstatus ocean technopagan
+43 (C): chain gnuykeaj one toaster
+44 (C): clearance godfather pastfish tomita
+45 (C): cmorrell graystatus perryh trout
+46 (C): coffeeandcode harleen plain tweetjay
+47 (C): cor idan pure uggedal
+48 (C): cyan integral pygmalion will
+49 (C): dangerous jacaetevha random wolf-theme
+50 (C): default johanson randomrussel yimmy
+51 (C): dmorrell kawasaki redfish zeit
+52 (C): doughsay krisleech red-snapper zephyr
+53 (C): eclm l robbyrussell zish
+54 (C): edan lambda sashimi
+55 (C): ⋊> ~/c/zellij on main ⨯ 10:27:46
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_paste_multiline.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_paste_multiline.snap
new file mode 100644
index 00000000..faf24017
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_paste_multiline.snap
@@ -0,0 +1,27 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C):
+01 (C): OS: 5.9.14-arch1-1 GNU/Linux
+02 (C): Uptime: 12 hours, 21 minutes
+03 (C): Hostname: kingdom
+04 (C): Disk usage:
+05 (C):
+06 (C): df: /run/user/1000/doc: Operation not permitted
+07 (C): / 295G / 514G 61%
+08 (C): /efi 27M / 96M 28%
+09 (C):
+10 (C): Network:
+11 (C):
+12 (C): wlp2s0 192.168.0.3
+13 (C):
+14 (C): [I] [21:58] kingdom:mosaic (main) | echo -ne (\
+15 (C): df -l -h | grep -E 'dev/(xvda|sd|mapper)' | \
+16 (C): awk '{printf "\\\\t%s\\\\t%4s / %4s %s\\\\n\n", $6, $3, $2, $5}' | \
+17 (C): sed -e 's/^\(.*\([8][5-9]\|[9][0-9]\)%.*\)$/\\\\e[0;31m\1\\\\e[0m/' -e 's/^\(.*\([7][5-9]\|[8][0-4]\)%.*\
+18 (W): )$/\\\\e[0;33m\1\\\\e[0m/' | \
+19 (C): paste -sd ''\
+20 (C): )
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_select_tab_completion_options.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_select_tab_completion_options.snap
new file mode 100644
index 00000000..88addebb
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_select_tab_completion_options.snap
@@ -0,0 +1,11 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): Welcome to fish, the friendly interactive shell
+01 (C): ⋊> ~/c/mosaic on main ⨯ sudo badblocks 11:32:23
+02 (C): badblocks (Executable, 33kB) base64 (Executable, 42kB) bash (Executable, 906kB)
+03 (C): bandwhich (Executable, 3.0MB) basename (Executable, 38kB) bashbug (Executable, 6.8kB)
+04 (C): base32 (Executable, 42kB) basenc (Executable, 50kB) bass
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_tab_completion_options.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_tab_completion_options.snap
new file mode 100644
index 00000000..a093e708
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__fish_tab_completion_options.snap
@@ -0,0 +1,11 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): Welcome to fish, the friendly interactive shell
+01 (C): ⋊> ~/c/mosaic on main ⨯ sudo bandwhich 11:18:26
+02 (C): badblocks (Executable, 33kB) base64 (Executable, 42kB) bash (Executable, 906kB)
+03 (C): bandwhich (Executable, 3.0MB) basename (Executable, 38kB) bashbug (Executable, 6.8kB)
+04 (C): base32 (Executable, 42kB) basenc (Executable, 50kB) bass
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__git_diff_scrollup.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__git_diff_scrollup.snap
new file mode 100644
index 00000000..e4c5e29f
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__git_diff_scrollup.snap
@@ -0,0 +1,34 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (W):
+01 (W): src/terminal_pane/scroll.rs
+02 (W): ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────
+03 (C):
+04 (C): ────────────────────────────────────────────────┐
+05 (C): use crate::terminal_pane::terminal_character::{ │
+06 (C): ────────────────────────────────────────────────┘
+07 (C): 5
+08 (C): CharacterStyles, TerminalCharacter, EMPTY_TERMINAL_CHARACTER,
+09 (C): };
+10 (C):
+11 (C): use crate::utils::logging::debug_log_to_file;
+12 (C):
+13 (C): /*
+14 (C): * Scroll
+15 (C): *
+16 (C):
+17 (C): ──────────────┐
+18 (C): impl Scroll { │
+19 (C): ──────────────┘
+20 (C): 663
+21 (C): pub fn move_current_buffer_to_alternative_buffer(&mut self) {
+22 (C): self.alternative_buffer = Some(self.canonical_lines.drain(..).collect());
+23 (C): self.alternative_cursor_position = Some(self.cursor_position);
+24 (C): self.cursor_position.reset();
+25 (C): self.clear_all();
+26 (C): }
+27 (C): :
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__git_log.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__git_log.snap
new file mode 100644
index 00000000..6f0225ba
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__git_log.snap
@@ -0,0 +1,34 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C):
+01 (C): * wip: doesn't render when new tab is created?
+02 (C):
+03 (C): * wip: doesnt re-render when a new tab is spawned for now
+04 (C):
+05 (C): * wip: tabs now are a BTreeMap and we can switch between them in both directions
+06 (C):
+07 (C): * wip: I think that should also be here
+08 (C):
+09 (C): * wip: cleanup
+10 (C):
+11 (C): * Spawn a new terminal simultaneously with a new tab
+12 (C):
+13 (C): * Ensure proper Opening and Closing of tabs
+14 (C):
+15 (C): * cleanup
+16 (C):
+17 (C): * more cleanup
+18 (C):
+19 (C): * tests(snapshots): add 'loading' snapshot to each scenario
+20 (C):
+21 (C): * fix(tests): update snapshots
+22 (C):
+23 (C): * Add tests for tabs implementation
+24 (C):
+25 (C): * wip: added tests, moved tab related stuff to a separate file
+26 (C):
+27 (C): :
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__htop.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__htop.snap
new file mode 100644
index 00000000..a692b163
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__htop.snap
@@ -0,0 +1,34 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C):
+01 (C): 1 [||||| 10.1%] Tasks: 73, 413 thr; 1 running
+02 (C): 2 [||||||| 13.5%] Load average: 1.03 1.07 1.30
+03 (C): 3 [|||||| 10.8%] Uptime: 22:41:15
+04 (C): 4 [|||||| 10.6%]
+05 (C): Mem[|||||||||||||||||||||||||||||||||||||3.28G/15.3G]
+06 (C): Swp[ 0K/16.0G]
+07 (C):
+08 (C): PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
+09 (C): 1352 aram 20 0 3776M 581M 238M S 8.7 3.7 2h01:10 /usr/lib/firefox/firefox
+10 (C): 98777 aram 20 0 537M 6184 4240 S 8.1 0.0 0:00.80 target/debug/mosaic --debug
+11 (C): 1669 aram 20 0 2944M 318M 130M S 8.1 2.0 1h01:33 /usr/lib/firefox/firefox -contentproc -childID 6 -i
+12 (C): 826 aram 9 -11 1581M 15092 11244 S 6.1 0.1 42:21.83 /usr/bin/pulseaudio --daemonize=no
+13 (C): 9419 aram 20 0 533M 7392 3344 S 4.7 0.0 22:01.92 /usr/local/bin/mosaic --max-panes 4
+14 (C): 98913 aram 20 0 537M 6184 4240 S 3.4 0.0 0:00.31 target/debug/mosaic --debug
+15 (C): 1505 aram 20 0 3187M 329M 206M S 3.4 2.1 23:35.90 /usr/lib/firefox/firefox -contentproc -childID 2 -i
+16 (C): 98912 aram 20 0 537M 6184 4240 S 2.7 0.0 0:00.22 target/debug/mosaic --debug
+17 (C): 1164 aram -6 0 1581M 15092 11244 S 2.7 0.1 21:39.80 /usr/bin/pulseaudio --daemonize=no
+18 (C): 1247 aram 20 0 1184M 292M 84828 S 2.7 1.9 38:01.54 /usr/lib/Xorg -nolisten tcp :0 vt1 -keeptty -auth /
+19 (C): 1475 aram -11 0 3776M 581M 238M S 2.0 3.7 14:27.94 /usr/lib/firefox/firefox
+20 (C): 8574 aram 20 0 2944M 318M 130M S 2.0 2.0 14:36.50 /usr/lib/firefox/firefox -contentproc -childID 6 -i
+21 (C): 1364 aram 20 0 3776M 581M 238M S 2.0 3.7 18:01.89 /usr/lib/firefox/firefox
+22 (C): 1870 aram 20 0 3776M 581M 238M S 2.0 3.7 13:27.06 /usr/lib/firefox/firefox
+23 (C): 9427 aram 20 0 533M 7392 3344 S 2.0 0.0 6:53.47 /usr/local/bin/mosaic --max-panes 4
+24 (C): 98905 aram 20 0 537M 6184 4240 S 2.0 0.0 0:00.17 target/debug/mosaic --debug
+25 (C): 99272 aram 20 0 8456 4348 3320 R 1.3 0.0 0:00.13 htop
+26 (C): 8611 aram 20 0 2944M 318M 130M S 1.3 2.0 8:17.90 /usr/lib/firefox/firefox -contentproc -childID 6 -i
+27 (C): F1Help F2Setup F3SearchF4FilterF5Tree F6SortByF7Nice -F8Nice +F9Kill F10Quit
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__htop_right_scrolling.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__htop_right_scrolling.snap
new file mode 100644
index 00000000..aca29e3e
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__htop_right_scrolling.snap
@@ -0,0 +1,34 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C):
+01 (C): 1 [|||||||||| 16.9%] Tasks: 110, 512 thr; 1 running
+02 (C): 2 [|||||||||| 17.1%] Load average: 1.04 1.30 1.29
+03 (C): 3 [||||||| 13.9%] Uptime: 6 days, 07:01:39
+04 (C): 4 [||||||||| 14.9%]
+05 (C): Mem[|||||||||||||||||||||||||||||||||||||8.80G/15.3G]
+06 (C): Swp[| 2.82M/16.0G]
+07 (C):
+08 (C): PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
+09 (C): 20 0 8576 4508 3356 R 1.3 0.0 0:00.11 htop
+10 (C): 20 0 171M 10868 7804 S 0.0 0.1 2:08.38 /sbin/init
+11 (C): 20 0 107M 29364 28092 S 0.0 0.2 0:03.42 /usr/lib/systemd/systemd-journald
+12 (C): 20 0 32648 9568 6616 S 0.0 0.1 0:01.87 /usr/lib/systemd/systemd-udevd
+13 (C): 20 0 78060 992 856 S 0.0 0.0 0:00.00 /usr/bin/lvmetad -f
+14 (C): 20 0 6952 4356 3492 S 0.0 0.0 0:57.67 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidf
+15 (C): 20 0 14824 7552 5984 S 0.0 0.0 0:12.93 /usr/bin/connmand -n --nodnsproxy
+16 (C): 20 0 17696 7940 6696 S 0.0 0.0 0:01.25 /usr/lib/systemd/systemd-logind
+17 (C): 20 0 1635M 56148 20460 S 0.0 0.3 1:27.24 /usr/bin/dockerd -H fd://
+18 (C): 20 0 1635M 56148 20460 S 0.0 0.3 0:38.37 /usr/bin/dockerd -H fd://
+19 (C): 20 0 1635M 56148 20460 S 0.0 0.3 0:00.01 /usr/bin/dockerd -H fd://
+20 (C): 20 0 1635M 56148 20460 S 0.0 0.3 0:00.00 /usr/bin/dockerd -H fd://
+21 (C): 20 0 1635M 56148 20460 S 0.0 0.3 0:00.00 /usr/bin/dockerd -H fd://
+22 (C): 20 0 1635M 56148 20460 S 0.0 0.3 0:00.00 /usr/bin/dockerd -H fd://
+23 (C): 20 0 1635M 56148 20460 S 0.0 0.3 1:47.55 /usr/bin/dockerd -H fd://
+24 (C): 20 0 1635M 56148 20460 S 0.0 0.3 1:26.19 /usr/bin/dockerd -H fd://
+25 (C): 20 0 1635M 56148 20460 S 0.0 0.3 1:40.77 /usr/bin/dockerd -H fd://
+26 (C): 20 0 1635M 56148 20460 S 0.0 0.3 1:47.26 /usr/bin/dockerd -H fd://
+27 (C): F1Help F2Setup F3SearchF4FilterF5Tree F6SortByF7Nice -F8Nice +F9Kill F10Quit
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__htop_scrolling.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__htop_scrolling.snap
new file mode 100644
index 00000000..5f6c323d
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__htop_scrolling.snap
@@ -0,0 +1,34 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C):
+01 (C): 1 [||||||||||||||||||||||||||||||||||||||||||100.0%] Tasks: 79, 382 thr; 1 running
+02 (C): 2 [ 0.0%] Load average: 1.40 1.43 1.38
+03 (C): 3 [ 0.0%] Uptime: 2 days, 07:33:50
+04 (C): 4 [ 0.0%]
+05 (C): Mem[|||||||||||||||||||||||||||||||||||||3.64G/15.3G]
+06 (C): Swp[ 0K/16.0G]
+07 (C):
+08 (C): PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
+09 (W): 123934 aram 20 0 8444 4384 3364 R 66.7 0.0 0:00.05 htop --delay=100000000000
+10 (C): 1 root 20 0 171M 11616 8608 S 0.0 0.1 0:56.91 /sbin/init
+11 (C): 268 root 20 0 93324 34340 33072 S 0.0 0.2 0:01.05 /usr/lib/systemd/systemd-journald
+12 (C): 276 root 20 0 32648 10192 7240 S 0.0 0.1 0:01.13 /usr/lib/systemd/systemd-udevd
+13 (C): 286 root 20 0 78060 1132 996 S 0.0 0.0 0:00.00 /usr/bin/lvmetad -f
+14 (C): 343 dbus 20 0 6952 4384 3520 S 0.0 0.0 0:13.85 /usr/bin/dbus-daemon --system --address=systemd: --
+15 (C): 344 root 20 0 14588 7512 6176 S 0.0 0.0 0:03.21 /usr/bin/connmand -n --nodnsproxy
+16 (C): 345 root 20 0 17696 8372 7128 S 0.0 0.1 0:00.67 /usr/lib/systemd/systemd-logind
+17 (C): 395 root 20 0 1635M 83324 44976 S 0.0 0.5 0:32.43 /usr/bin/dockerd -H fd://
+18 (C): 396 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.01 /usr/bin/dockerd -H fd://
+19 (C): 397 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.01 /usr/bin/dockerd -H fd://
+20 (C): 398 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.00 /usr/bin/dockerd -H fd://
+21 (C): 399 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.00 /usr/bin/dockerd -H fd://
+22 (C): 412 root 20 0 1635M 83324 44976 S 0.0 0.5 0:00.00 /usr/bin/dockerd -H fd://
+23 (C): 441 root 20 0 1635M 83324 44976 S 0.0 0.5 0:41.35 /usr/bin/dockerd -H fd://
+24 (C): 442 root 20 0 1635M 83324 44976 S 0.0 0.5 0:33.61 /usr/bin/dockerd -H fd://
+25 (C): 444 root 20 0 1635M 83324 44976 S 0.0 0.5 0:33.13 /usr/bin/dockerd -H fd://
+26 (C): 449 root 20 0 1635M 83324 44976 S 0.0 0.5 0:41.39 /usr/bin/dockerd -H fd://
+27 (C): F1Help F2Setup F3SearchF4FilterF5Tree F6SortByF7Nice -F8Nice +F9Kill F10Quit
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__neovim_insert_mode.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__neovim_insert_mode.snap
new file mode 100644
index 00000000..9c2536d4
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__neovim_insert_mode.snap
@@ -0,0 +1,34 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): line 1
+01 (C): line 2
+02 (C): line 3
+03 (C): line 4
+04 (C): line 5
+05 (C): line 6
+06 (C): line 7
+07 (C): line 8
+08 (C): line 9
+09 (C): line 10
+10 (C): line 11
+11 (C): line 12
+12 (C): line 13
+13 (C): line 14
+14 (C): line 15
+15 (C): line 16
+16 (C): line 17
+17 (C): line 18
+18 (C): line 19
+19 (C): line 20
+20 (C): line 21
+21 (C): line 22
+22 (C): line 23
+23 (C): line 24
+24 (C): line 25
+25 (C): line 26
+26 (C): some-file 10,1 Top
+27 (C): -- INSERT --
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__run_bandwhich_from_fish_shell.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__run_bandwhich_from_fish_shell.snap
new file mode 100644
index 00000000..257fd889
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__run_bandwhich_from_fish_shell.snap
@@ -0,0 +1,34 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): Total Up / Down: 46Bps / 57Bps
+01 (C): ┌Utilization by process name───────────────────────────────────────────────────────────────────────────────────────┐
+02 (C): │Process Connections Up / Down │
+03 (C): │ │
+04 (C): │firefox 3 46Bps / 57Bps │
+05 (C): │ │
+06 (C): │ │
+07 (C): │ │
+08 (C): │ │
+09 (C): │ │
+10 (C): │ │
+11 (C): │ │
+12 (C): │ │
+13 (C): │ │
+14 (C): │ │
+15 (C): │ │
+16 (C): │ │
+17 (C): │ │
+18 (C): │ │
+19 (C): │ │
+20 (C): │ │
+21 (C): │ │
+22 (C): │ │
+23 (C): │ │
+24 (C): │ │
+25 (C): │ │
+26 (C): └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
+27 (C): Press <SPACE> to pause. Use <TAB> to rearrange tables. (DNS queries hidden).
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__top_and_quit.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__top_and_quit.snap
new file mode 100644
index 00000000..250e5b45
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__top_and_quit.snap
@@ -0,0 +1,62 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): Tasks: 158 total, 1 running, 157 sleeping, 0 stopped, 0 zombie
+01 (C): %Cpu(s): 24.2 us, 1.6 sy, 0.0 ni, 74.2 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
+02 (C): MiB Mem : 15715.1 total, 7001.4 free, 2163.7 used, 6549.9 buff/cache
+03 (C): MiB Swap: 16384.0 total, 16384.0 free, 0.0 used. 12809.8 avail Mem
+04 (C):
+05 (C): PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
+06 (C): 15838 aram 20 0 7275240 56912 18964 S 73.3 0.4 0:17.79 zellij
+07 (C): 12653 aram 20 0 39032 22164 14372 S 20.0 0.1 0:00.63 urxvt
+08 (C): 1477 aram 20 0 3178660 301992 203236 S 6.7 1.9 3:49.82 Web Content
+09 (C): 1 root 20 0 175360 11532 8596 S 0.0 0.1 0:05.90 systemd
+10 (C): 2 root 20 0 0 0 0 S 0.0 0.0 0:00.01 kthreadd
+11 (C): 3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_gp
+12 (C): 4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_par_gp
+13 (C): 6 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H-kblockd
+14 (C): 8 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 mm_percpu_wq
+15 (C): 9 root 20 0 0 0 0 S 0.0 0.0 0:01.24 ksoftirqd/0
+16 (C): 10 root -2 0 0 0 0 S 0.0 0.0 0:00.00 rcuc/0
+17 (C): 11 root -2 0 0 0 0 I 0.0 0.0 0:06.12 rcu_preempt
+18 (C): 12 root -2 0 0 0 0 S 0.0 0.0 0:00.00 rcub/0
+19 (C): 13 root rt 0 0 0 0 S 0.0 0.0 0:00.01 migration/0
+20 (C): 14 root -51 0 0 0 0 S 0.0 0.0 0:00.00 idle_inject/0
+21 (C): 16 root 20 0 0 0 0 S 0.0 0.0 0:00.00 cpuhp/0
+22 (C): 17 root 20 0 0 0 0 S 0.0 0.0 0:00.00 cpuhp/1
+23 (C): 18 root -51 0 0 0 0 S 0.0 0.0 0:00.00 idle_inject/1
+24 (C): 19 root rt 0 0 0 0 S 0.0 0.0 0:00.35 migration/1
+25 (C): 20 root -2 0 0 0 0 S 0.0 0.0 0:00.00 rcuc/1
+26 (C): 21 root 20 0 0 0 0 S 0.0 0.0 0:00.49 ksoftirqd/1
+27 (C): 23 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/1:0H-kblockd
+28 (C): 24 root 20 0 0 0 0 S 0.0 0.0 0:00.00 cpuhp/2
+29 (C): 25 root -51 0 0 0 0 S 0.0 0.0 0:00.00 idle_inject/2
+30 (C): 26 root rt 0 0 0 0 S 0.0 0.0 0:00.39 migration/2
+31 (C): 27 root -2 0 0 0 0 S 0.0 0.0 0:00.00 rcuc/2
+32 (C): 28 root 20 0 0 0 0 S 0.0 0.0 0:00.99 ksoftirqd/2
+33 (C): 30 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/2:0H-kblockd
+34 (C): 31 root 20 0 0 0 0 S 0.0 0.0 0:00.00 cpuhp/3
+35 (C): 32 root -51 0 0 0 0 S 0.0 0.0 0:00.00 idle_inject/3
+36 (C): 33 root rt 0 0 0 0 S 0.0 0.0 0:00.43 migration/3
+37 (C): 34 root -2 0 0 0 0 S 0.0 0.0 0:00.00 rcuc/3
+38 (C): 35 root 20 0 0 0 0 S 0.0 0.0 0:00.90 ksoftirqd/3
+39 (C): 37 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/3:0H-kblockd
+40 (C): 38 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kdevtmpfs
+41 (C): 39 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 netns
+42 (C): 40 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_tasks_kthre
+43 (C): 41 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kauditd
+44 (C): 44 root 20 0 0 0 0 S 0.0 0.0 0:00.00 khungtaskd
+45 (C): 45 root 20 0 0 0 0 S 0.0 0.0 0:00.00 oom_reaper
+46 (C): 46 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 writeback
+47 (C): 47 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kcompactd0
+48 (C): 48 root 25 5 0 0 0 S 0.0 0.0 0:00.00 ksmd
+49 (C): 49 root 39 19 0 0 0 S 0.0 0.0 0:00.00 khugepaged
+50 (C): 137 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kintegrityd
+51 (C): 138 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kblockd
+52 (C): 139 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 blkcg_punt_bio
+53 (C): 140 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 ata_sff
+54 (C): 141 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 edac-poller
+55 (C): ⋊> ~/c/zellij on fix-top ⨯ 13:00:53
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_ctrl_d.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_ctrl_d.snap
new file mode 100644
index 00000000..e9b83504
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_ctrl_d.snap
@@ -0,0 +1,34 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): 3 line14
+01 (C): 2 line15
+02 (C): 1 line16
+03 (C): 17 line17
+04 (C): 1 line18
+05 (C): 2 line19
+06 (C): 3 line20
+07 (C): 4 line21
+08 (C): 5 line22
+09 (C): 6 line23
+10 (C): 7 line24
+11 (C): 8 line25
+12 (C): 9 line26
+13 (C): 10 line27
+14 (C): 11 line28
+15 (C): 12 line29
+16 (C): 13 line30
+17 (C): 14 line31
+18 (C): 15 line32
+19 (C): 16 line33
+20 (C): 17 line34
+21 (C): 18 line35
+22 (C): 19 line36
+23 (C): 20 line37
+24 (C): 21 line38
+25 (C): 22 line39
+26 (C): NORMAL testfile.rs unix | utf-8 | rust 40% 17:1
+27 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_ctrl_u.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_ctrl_u.snap
new file mode 100644
index 00000000..f886a2eb
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_ctrl_u.snap
@@ -0,0 +1,34 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): 22 line4
+01 (C): 21 line5
+02 (C): 20 line6
+03 (C): 19 line7
+04 (C): 18 line8
+05 (C): 17 line9
+06 (C): 16 line10
+07 (C): 15 line11
+08 (C): 14 line12
+09 (C): 13 line13
+10 (C): 12 line14
+11 (C): 11 line15
+12 (C): 10 line16
+13 (C): 9 line17
+14 (C): 8 line18
+15 (C): 7 line19
+16 (C): 6 line20
+17 (C): 5 line21
+18 (C): 4 line22
+19 (C): 3 line23
+20 (C): 2 line24
+21 (C): 1 line25
+22 (C): 26 line26
+23 (C): 1 line27
+24 (C): 2 line28
+25 (C): 3 line29
+26 (C): NORMAL testfile.rs unix | utf-8 | rust 61% 26:1
+27 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_overwrite.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_overwrite.snap
new file mode 100644
index 00000000..f8066d6a
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_overwrite.snap
@@ -0,0 +1,34 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): 1
+01 (C): 1 line 1
+02 (C): 2 line 2
+03 (C): 3 line 3
+04 (C): 4 line 4
+05 (C): 5 line 5
+06 (C): 6 line 6
+07 (C): 7 line 7
+08 (C): 8 line 8
+09 (C): 9 line 9
+10 (C): 10 line 10
+11 (C): 11 line 11
+12 (C): 12 line 12
+13 (C): 13 line 13
+14 (C): 14 line 14
+15 (C): 15 line 15
+16 (C): 16 line 16
+17 (C): 17 line 17
+18 (C): 18 line 18
+19 (C): 19 line 19
+20 (C): 20 line 20
+21 (C): 21 line 21
+22 (C): 22 line 22
+23 (C): 23 line 23
+24 (C): 24 line 24
+25 (C): 25 line 25
+26 (C): NORMAL some-file unix | utf-8 | no ft 1% 1:1
+27 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_scroll_region_down.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_scroll_region_down.snap
new file mode 100644
index 00000000..17a18220
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__grid__grid_tests__vim_scroll_region_down.snap
@@ -0,0 +1,34 @@
+---
+source: zellij-server/src/panes/./unit/grid_tests.rs
+expression: "format!(\"{:?}\", grid)"
+
+---
+00 (C): 22 line2
+01 (C): 21 line3
+02 (C): 20 line4
+03 (C): 19 line5
+04 (C): 18 line6
+05 (C): 17 line7
+06 (C): 16 line8
+07 (C): 15 line9
+08 (C): 14 line10
+09 (C): 13 line11
+10 (C): 12 line12
+11 (C): 11 line13
+12 (C): 10 line14
+13 (C): 9 line15
+14 (C): 8 line16
+15 (C): 7 line17
+16 (C): 6 line18
+17 (C): 5 line19
+18 (C): 4 line20
+19 (C): 3 line21
+20 (C): 2 line22
+21 (C): 1 line23
+22 (C): 24 line24
+23 (C): 1 line25
+24 (C): 2 line26
+25 (C): 3 line27
+26 (C): NORMAL testfile.rs unix | utf-8 | rust 57% 24:1
+27 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_inside_a_pane-2.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_inside_a_pane-2.snap
new file mode 100644
index 00000000..cd74ae8f
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_inside_a_pane-2.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+expression: "format!(\"{:?}\", terminal_pane . grid)"
+
+---
+00 (C): line 5
+01 (C): line 6
+02 (C): line 7
+03 (C): line 8
+04 (C): line 9
+05 (C): line 10
+06 (C): line 11
+07 (C): line 12
+08 (C): line 13
+09 (C): line 14
+10 (C): line 15
+11 (C): line 16
+12 (C): line 17
+13 (C): line 18
+14 (C): line 19
+15 (C): line 20
+16 (C): line 21
+17 (C): line 22
+18 (C): line 23
+19 (C): line 24
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_inside_a_pane-3.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_inside_a_pane-3.snap
new file mode 100644
index 00000000..4c1776c0
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_inside_a_pane-3.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+expression: "format!(\"{:?}\", terminal_pane . grid)"
+
+---
+00 (C): line 12
+01 (C): line 13
+02 (C): line 14
+03 (C): line 15
+04 (C): line 16
+05 (C): line 17
+06 (C): line 18
+07 (C): line 19
+08 (C): line 20
+09 (C): line 21
+10 (C): line 22
+11 (C): line 23
+12 (C): line 24
+13 (C): line 25
+14 (C): line 26
+15 (C): line 27
+16 (C): line 28
+17 (C): line 29
+18 (C): line 30
+19 (C):
+
diff --git a/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_inside_a_pane.snap b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_inside_a_pane.snap
new file mode 100644
index 00000000..0d852f68
--- /dev/null
+++ b/zellij-server/src/panes/unit/snapshots/zellij_server__panes__terminal_pane__grid_tests__scrolling_inside_a_pane.snap
@@ -0,0 +1,26 @@
+---
+source: zellij-server/src/panes/./unit/terminal_pane_tests.rs
+expression: "format!(\"{:?}\", terminal_pane . grid)"
+
+---
+00 (C): line 2
+01 (C): line 3
+02 (C): line 4
+03 (C): line 5
+04 (C): line 6
+05 (C): line 7
+06 (C): line 8
+07 (C): line 9
+08 (C): line 10
+09 (C): line 11
+10 (C): line 12
+11 (C): line 13
+12 (C): line 14
+13 (C): line 15
+14 (C): line 16
+15 (C): line 17
+16 (C): line 18
+17 (C): line 19
+18 (C): line 20
+19 (C): line 21
+
diff --git a/zellij-server/src/panes/unit/terminal_pane_tests.rs b/zellij-server/src/panes/unit/terminal_pane_tests.rs
new file mode 100644
index 00000000..f3abf91a
--- /dev/null
+++ b/zellij-server/src/panes/unit/terminal_pane_tests.rs
@@ -0,0 +1,30 @@
+use super::super::TerminalPane;
+use crate::tab::Pane;
+use ::insta::assert_snapshot;
+use zellij_utils::pane_size::PositionAndSize;
+use zellij_utils::zellij_tile::data::Palette;
+
+#[test]
+pub fn scrolling_inside_a_pane() {
+ let fake_win_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let pid = 1;
+ let palette = Palette::default();
+ let mut terminal_pane = TerminalPane::new(pid, fake_win_size, palette);
+ let mut text_to_fill_pane = String::new();
+ for i in 0..30 {
+ text_to_fill_pane.push_str(&format!("\rline {}\n", i + 1));
+ }
+ terminal_pane.handle_pty_bytes(text_to_fill_pane.as_bytes().to_vec());
+ terminal_pane.scroll_up(10);
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+ terminal_pane.scroll_down(3);
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+ terminal_pane.clear_scroll();
+ assert_snapshot!(format!("{:?}", terminal_pane.grid));
+}
diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs
index 009a3a92..88fb7848 100644
--- a/zellij-server/src/screen.rs
+++ b/zellij-server/src/screen.rs
@@ -393,6 +393,16 @@ impl Screen {
tab.mode_info = self.mode_info.clone();
}
}
+ pub fn move_focus_left_or_previous_tab(&mut self) {
+ if !self.get_active_tab_mut().unwrap().move_focus_left() {
+ self.switch_tab_prev();
+ }
+ }
+ pub fn move_focus_right_or_next_tab(&mut self) {
+ if !self.get_active_tab_mut().unwrap().move_focus_right() {
+ self.switch_tab_next();
+ }
+ }
}
// The box is here in order to make the
@@ -507,9 +517,7 @@ pub(crate) fn screen_thread_main(
screen.get_active_tab_mut().unwrap().move_focus_left();
}
ScreenInstruction::MoveFocusLeftOrPreviousTab => {
- if !screen.get_active_tab_mut().unwrap().move_focus_left() {
- screen.switch_tab_prev();
- }
+ screen.move_focus_left_or_previous_tab();
screen
.bus
.senders
@@ -523,9 +531,7 @@ pub(crate) fn screen_thread_main(
screen.get_active_tab_mut().unwrap().move_focus_right();
}
ScreenInstruction::MoveFocusRightOrNextTab => {
- if !screen.get_active_tab_mut().unwrap().move_focus_right() {
- screen.switch_tab_next();
- }
+ screen.move_focus_right_or_next_tab();
screen
.bus
.senders
@@ -674,3 +680,7 @@ pub(crate) fn screen_thread_main(
}
}
}
+
+#[cfg(test)]
+#[path = "./unit/screen_tests.rs"]
+mod screen_tests;
diff --git a/zellij-server/src/tab.rs b/zellij-server/src/tab.rs
index fbcb5ada..523f65df 100644
--- a/zellij-server/src/tab.rs
+++ b/zellij-server/src/tab.rs
@@ -2272,3 +2272,7 @@ impl Tab {
}
}
}
+
+#[cfg(test)]
+#[path = "./unit/tab_tests.rs"]
+mod tab_tests;
diff --git a/zellij-server/src/thread_bus.rs b/zellij-server/src/thread_bus.rs
index f7c1c1eb..c7262993 100644
--- a/zellij-server/src/thread_bus.rs
+++ b/zellij-server/src/thread_bus.rs
@@ -7,12 +7,15 @@ use crate::{
use zellij_utils::{channels, channels::SenderWithContext, errors::ErrorContext};
/// A container for senders to the different threads in zellij on the server side
-#[derive(Clone)]
+#[derive(Default, Clone)]
pub(crate) struct ThreadSenders {
pub to_screen: Option<SenderWithContext<ScreenInstruction>>,
pub to_pty: Option<SenderWithContext<PtyInstruction>>,
pub to_plugin: Option<SenderWithContext<PluginInstruction>>,
pub to_server: Option<SenderWithContext<ServerInstruction>>,
+ // this is a convenience for the unit tests
+ // it's not advisable to set it to true in production code
+ pub should_silently_fail: bool,
}
impl ThreadSenders {
@@ -20,32 +23,75 @@ impl ThreadSenders {
&self,
instruction: ScreenInstruction,
) -> Result<(), channels::SendError<(ScreenInstruction, ErrorContext)>> {
- self.to_screen.as_ref().unwrap().send(instruction)
+ if self.should_silently_fail {
+ let _ = self
+ .to_screen
+ .as_ref()
+ .map(|sender| sender.send(instruction))
+ .unwrap_or_else(|| Ok(()));
+ Ok(())
+ } else {
+ self.to_screen.as_ref().unwrap().send(instruction)
+ }
}
pub fn send_to_pty(
&self,
instruction: PtyInstruction,
) -> Result<(), channels::SendError<(PtyInstruction, ErrorContext)>> {
- self.to_pty.as_ref().unwrap().send(instruction)
+ if self.should_silently_fail {
+ let _ = self
+ .to_pty
+ .as_ref()
+ .map(|sender| sender.send(instruction))
+ .unwrap_or_else(|| Ok(()));
+ Ok(())
+ } else {
+ self.to_pty.as_ref().unwrap().send(instruction)
+ }
}
pub fn send_to_plugin(
&self,
instruction: PluginInstruction,
) -> Result<(), channels::SendError<(PluginInstruction, ErrorContext)>> {
- self.to_plugin.as_ref().unwrap().send(instruction)
+ if self.should_silently_fail {
+ let _ = self
+ .to_plugin
+ .as_ref()
+ .map(|sender| sender.send(instruction))
+ .unwrap_or_else(|| Ok(()));
+ Ok(())
+ } else {
+ self.to_plugin.as_ref().unwrap().send(instruction)
+ }
}
pub fn send_to_server(
&self,
instruction: ServerInstruction,
) -> Result<(), channels::SendError<(ServerInstruction, ErrorContext)>> {
- self.to_server.as_ref().unwrap().send(instruction)
+ if self.should_silently_fail {
+ let _ = self
+ .to_server
+ .as_ref()
+ .map(|sender| sender.send(instruction))
+ .unwrap_or_else(|| Ok(()));
+ Ok(())
+ } else {
+ self.to_server.as_ref().unwrap().send(instruction)
+ }
+ }
+ #[allow(unused)]
+ pub fn silently_fail_on_send(mut self) -> Self {
+ // this is mostly used for the tests, see struct
+ self.should_silently_fail = true;
+ self
}
}
/// A container for a receiver, OS input and the senders to a given thread
+#[derive(Default)]
pub(crate) struct Bus<T> {
receivers: Vec<channels::Receiver<(T, ErrorContext)>>,
pub senders: ThreadSenders,
@@ -68,10 +114,26 @@ impl<T> Bus<T> {
to_pty: to_pty.cloned(),
to_plugin: to_plugin.cloned(),
to_server: to_server.cloned(),
+ should_silently_fail: false,
},
os_input: os_input.clone(),
}
}
+ #[allow(unused)]
+ pub fn empty() -> Self {
+ // this is mostly used for the tests
+ Bus {
+ receivers: vec![],
+ senders: ThreadSenders {
+ to_screen: None,
+ to_pty: None,
+ to_plugin: None,
+ to_server: None,
+ should_silently_fail: true,
+ },
+ os_input: None,
+ }
+ }
pub fn recv(&self) -> Result<(T, ErrorContext), channels::RecvError> {
let mut selector = channels::Select::new();
diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs
new file mode 100644
index 00000000..da52c585
--- /dev/null
+++ b/zellij-server/src/unit/screen_tests.rs
@@ -0,0 +1,255 @@
+use super::{Screen, ScreenInstruction};
+use crate::zellij_tile::data::{InputMode, ModeInfo, Palette};
+use crate::{
+ os_input_output::{AsyncReader, Pid, ServerOsApi},
+ thread_bus::Bus,
+ SessionState,
+};
+use std::sync::{Arc, RwLock};
+use zellij_utils::pane_size::PositionAndSize;
+
+use std::os::unix::io::RawFd;
+use std::path::PathBuf;
+
+use zellij_utils::ipc::ClientAttributes;
+use zellij_utils::nix;
+
+use zellij_utils::{
+ errors::ErrorContext,
+ interprocess::local_socket::LocalSocketStream,
+ ipc::{ClientToServerMsg, ServerToClientMsg},
+};
+
+#[derive(Clone)]
+struct FakeInputOutput {}
+
+impl ServerOsApi for FakeInputOutput {
+ fn set_terminal_size_using_fd(&self, _fd: RawFd, _cols: u16, _rows: u16) {
+ // noop
+ }
+ fn spawn_terminal(&self, _file_to_open: Option<PathBuf>) -> (RawFd, Pid) {
+ unimplemented!()
+ }
+ fn read_from_tty_stdout(&self, _fd: RawFd, _buf: &mut [u8]) -> Result<usize, nix::Error> {
+ unimplemented!()
+ }
+ fn async_file_reader(&self, _fd: RawFd) -> Box<dyn AsyncReader> {
+ unimplemented!()
+ }
+ fn write_to_tty_stdin(&self, _fd: RawFd, _buf: &[u8]) -> Result<usize, nix::Error> {
+ unimplemented!()
+ }
+ fn tcdrain(&self, _fd: RawFd) -> Result<(), nix::Error> {
+ unimplemented!()
+ }
+ fn box_clone(&self) -> Box<dyn ServerOsApi> {
+ Box::new((*self).clone())
+ }
+ fn kill(&self, _pid: Pid) -> Result<(), nix::Error> {
+ unimplemented!()
+ }
+ fn recv_from_client(&self) -> (ClientToServerMsg, ErrorContext) {
+ unimplemented!()
+ }
+ fn send_to_client(&self, _msg: ServerToClientMsg) {
+ unimplemented!()
+ }
+ fn add_client_sender(&self) {
+ unimplemented!()
+ }
+ fn send_to_temp_client(&self, _msg: ServerToClientMsg) {
+ unimplemented!()
+ }
+ fn remove_client_sender(&self) {
+ unimplemented!()
+ }
+ fn update_receiver(&mut self, _stream: LocalSocketStream) {
+ unimplemented!()
+ }
+ fn load_palette(&self) -> Palette {
+ unimplemented!()
+ }
+}
+
+fn create_new_screen(position_and_size: PositionAndSize) -> Screen {
+ let mut bus: Bus<ScreenInstruction> = Bus::empty();
+ let fake_os_input = FakeInputOutput {};
+ bus.os_input = Some(Box::new(fake_os_input));
+ let mut client_attributes = ClientAttributes::default();
+ client_attributes.position_and_size = position_and_size;
+ let max_panes = None;
+ let mode_info = ModeInfo::default();
+ let input_mode = InputMode::Normal;
+ let session_state = Arc::new(RwLock::new(SessionState::Attached));
+ Screen::new(
+ bus,
+ &client_attributes,
+ max_panes,
+ mode_info,
+ input_mode,
+ session_state,
+ )
+}
+
+#[test]
+fn open_new_tab() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut screen = create_new_screen(position_and_size);
+
+ screen.new_tab(1);
+ screen.new_tab(2);
+
+ assert_eq!(screen.tabs.len(), 2, "Screen now has two tabs");
+ assert_eq!(
+ screen.get_active_tab().unwrap().position,
+ 1,
+ "Active tab switched to new tab"
+ );
+}
+
+#[test]
+pub fn switch_to_prev_tab() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut screen = create_new_screen(position_and_size);
+
+ screen.new_tab(1);
+ screen.new_tab(2);
+ screen.switch_tab_prev();
+
+ assert_eq!(
+ screen.get_active_tab().unwrap().position,
+ 0,
+ "Active tab switched to previous tab"
+ );
+}
+
+#[test]
+pub fn switch_to_next_tab() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut screen = create_new_screen(position_and_size);
+
+ screen.new_tab(1);
+ screen.new_tab(2);
+ screen.switch_tab_prev();
+ screen.switch_tab_next();
+
+ assert_eq!(
+ screen.get_active_tab().unwrap().position,
+ 1,
+ "Active tab switched to next tab"
+ );
+}
+
+#[test]
+pub fn close_tab() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut screen = create_new_screen(position_and_size);
+
+ screen.new_tab(1);
+ screen.new_tab(2);
+ screen.close_tab();
+
+ assert_eq!(screen.tabs.len(), 1, "Only one tab left");
+ assert_eq!(
+ screen.get_active_tab().unwrap().position,
+ 0,
+ "Active tab switched to previous tab"
+ );
+}
+
+#[test]
+pub fn close_the_middle_tab() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut screen = create_new_screen(position_and_size);
+
+ screen.new_tab(1);
+ screen.new_tab(2);
+ screen.new_tab(3);
+ screen.switch_tab_prev();
+ screen.close_tab();
+
+ assert_eq!(screen.tabs.len(), 2, "Two tabs left");
+ assert_eq!(
+ screen.get_active_tab().unwrap().position,
+ 0,
+ "Active tab switched to previous tab"
+ );
+}
+
+#[test]
+fn move_focus_left_at_left_screen_edge_changes_tab() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut screen = create_new_screen(position_and_size);
+
+ screen.new_tab(1);
+ screen.new_tab(2);
+ screen.new_tab(3);
+ screen.switch_tab_prev();
+ screen.move_focus_left_or_previous_tab();
+
+ assert_eq!(
+ screen.get_active_tab().unwrap().position,
+ 0,
+ "Active tab switched to previous"
+ );
+}
+
+#[test]
+fn move_focus_right_at_right_screen_edge_changes_tab() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut screen = create_new_screen(position_and_size);
+
+ screen.new_tab(1);
+ screen.new_tab(2);
+ screen.new_tab(3);
+ screen.switch_tab_prev();
+ screen.move_focus_right_or_next_tab();
+
+ assert_eq!(
+ screen.get_active_tab().unwrap().position,
+ 2,
+ "Active tab switched to next"
+ );
+}
diff --git a/zellij-server/src/unit/tab_tests.rs b/zellij-server/src/unit/tab_tests.rs
new file mode 100644
index 00000000..87c3be71
--- /dev/null
+++ b/zellij-server/src/unit/tab_tests.rs
@@ -0,0 +1,11840 @@
+use super::Tab;
+use crate::zellij_tile::data::{InputMode, ModeInfo, Palette};
+use crate::{
+ os_input_output::{AsyncReader, Pid, ServerOsApi},
+ panes::PaneId,
+ thread_bus::ThreadSenders,
+ SessionState,
+};
+use std::sync::{Arc, RwLock};
+use zellij_utils::pane_size::PositionAndSize;
+
+use std::os::unix::io::RawFd;
+use std::path::PathBuf;
+
+use zellij_utils::nix;
+
+use zellij_utils::{
+ errors::ErrorContext,
+ interprocess::local_socket::LocalSocketStream,
+ ipc::{ClientToServerMsg, ServerToClientMsg},
+};
+
+struct FakeInputOutput {}
+
+impl ServerOsApi for FakeInputOutput {
+ fn set_terminal_size_using_fd(&self, _fd: RawFd, _cols: u16, _rows: u16) {
+ // noop
+ }
+ fn spawn_terminal(&self, _file_to_open: Option<PathBuf>) -> (RawFd, Pid) {
+ unimplemented!()
+ }
+ fn read_from_tty_stdout(&self, _fd: RawFd, _buf: &mut [u8]) -> Result<usize, nix::Error> {
+ unimplemented!()
+ }
+ fn async_file_reader(&self, _fd: RawFd) -> Box<dyn AsyncReader> {
+ unimplemented!()
+ }
+ fn write_to_tty_stdin(&self, _fd: RawFd, _buf: &[u8]) -> Result<usize, nix::Error> {
+ unimplemented!()
+ }
+ fn tcdrain(&self, _fd: RawFd) -> Result<(), nix::Error> {
+ unimplemented!()
+ }
+ fn box_clone(&self) -> Box<dyn ServerOsApi> {
+ unimplemented!()
+ }
+ fn kill(&self, _pid: Pid) -> Result<(), nix::Error> {
+ unimplemented!()
+ }
+ fn recv_from_client(&self) -> (ClientToServerMsg, ErrorContext) {
+ unimplemented!()
+ }
+ fn send_to_client(&self, _msg: ServerToClientMsg) {
+ unimplemented!()
+ }
+ fn add_client_sender(&self) {
+ unimplemented!()
+ }
+ fn send_to_temp_client(&self, _msg: ServerToClientMsg) {
+ unimplemented!()
+ }
+ fn remove_client_sender(&self) {
+ unimplemented!()
+ }
+ fn update_receiver(&mut self, _stream: LocalSocketStream) {
+ unimplemented!()
+ }
+ fn load_palette(&self) -> Palette {
+ unimplemented!()
+ }
+}
+
+fn create_new_tab(position_and_size: PositionAndSize) -> Tab {
+ let index = 0;
+ let position = 0;
+ let name = String::new();
+ let os_api = Box::new(FakeInputOutput {});
+ let senders = ThreadSenders::default().silently_fail_on_send();
+ let max_panes = None;
+ let first_pane_id = Some(PaneId::Terminal(1));
+ let mode_info = ModeInfo::default();
+ let input_mode = InputMode::Normal;
+ let colors = Palette::default();
+ let session_state = Arc::new(RwLock::new(SessionState::Attached));
+ Tab::new(
+ index,
+ position,
+ name,
+ &position_and_size,
+ os_api,
+ senders,
+ max_panes,
+ first_pane_id,
+ mode_info,
+ input_mode,
+ colors,
+ session_state,
+ )
+}
+
+#[test]
+fn split_panes_vertically() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.vertical_split(new_pane_id);
+ assert_eq!(tab.panes.len(), 2, "The tab has two panes");
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "first pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "first pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "first pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "first pane row count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "second pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "second pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "second pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "second pane row count"
+ );
+}
+
+#[test]
+fn split_panes_horizontally() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.horizontal_split(new_pane_id);
+ assert_eq!(tab.panes.len(), 2, "The tab has two panes");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "first pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "first pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "first pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "first pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "second pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "second pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "second pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "second pane row count"
+ );
+}
+
+#[test]
+fn split_largest_pane() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ for i in 2..5 {
+ let new_pane_id = PaneId::Terminal(i);
+ tab.new_pane(new_pane_id);
+ }
+ assert_eq!(tab.panes.len(), 4, "The tab has four panes");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "first pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "first pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "first pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "first pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "second pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "second pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "second pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "second pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "third pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "third pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "third pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "third pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "fourth pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "fourth pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "fourth pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "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 {
+ 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_horizontally_when_active_pane_is_too_small() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 4,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ assert_eq!(tab.panes.len(), 1, "Tab still has only one pane");
+}
+
+#[test]
+pub fn cannot_split_largest_pane_when_there_is_no_room() {
+ let position_and_size = PositionAndSize {
+ cols: 8,
+ rows: 4,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.new_pane(PaneId::Terminal(2));
+ assert_eq!(tab.panes.len(), 1, "Tab still has only one pane");
+}
+
+#[test]
+pub fn toggle_focused_pane_fullscreen() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ for i in 2..5 {
+ let new_pane_id = PaneId::Terminal(i);
+ tab.new_pane(new_pane_id);
+ }
+ tab.toggle_active_pane_fullscreen();
+ assert_eq!(
+ tab.panes.get(&PaneId::Terminal(4)).unwrap().x(),
+ 0,
+ "Pane x is on screen edge"
+ );
+ assert_eq!(
+ tab.panes.get(&PaneId::Terminal(4)).unwrap().y(),
+ 0,
+ "Pane y is on screen edge"
+ );
+ assert_eq!(
+ tab.panes.get(&PaneId::Terminal(4)).unwrap().columns(),
+ 121,
+ "Pane cols match fullscreen cols"
+ );
+ assert_eq!(
+ tab.panes.get(&PaneId::Terminal(4)).unwrap().rows(),
+ 20,
+ "Pane rows match fullscreen rows"
+ );
+ tab.toggle_active_pane_fullscreen();
+ assert_eq!(
+ tab.panes.get(&PaneId::Terminal(4)).unwrap().x(),
+ 61,
+ "Pane x is on screen edge"
+ );
+ assert_eq!(
+ tab.panes.get(&PaneId::Terminal(4)).unwrap().y(),
+ 11,
+ "Pane y is on screen edge"
+ );
+ assert_eq!(
+ tab.panes.get(&PaneId::Terminal(4)).unwrap().columns(),
+ 60,
+ "Pane cols match fullscreen cols"
+ );
+ assert_eq!(
+ tab.panes.get(&PaneId::Terminal(4)).unwrap().rows(),
+ 9,
+ "Pane rows match fullscreen rows"
+ );
+ // we don't test if all other panes are hidden because this logic is done in the render
+ // function and we already test that in the e2e tests
+}
+
+#[test]
+pub fn move_focus_is_disabled_in_fullscreen() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ for i in 2..5 {
+ let new_pane_id = PaneId::Terminal(i);
+ tab.new_pane(new_pane_id);
+ }
+ tab.toggle_active_pane_fullscreen();
+ tab.move_focus_left();
+ assert_eq!(
+ tab.panes.get(&PaneId::Terminal(4)).unwrap().x(),
+ 0,
+ "Pane x is on screen edge"
+ );
+ assert_eq!(
+ tab.panes.get(&PaneId::Terminal(4)).unwrap().y(),
+ 0,
+ "Pane y is on screen edge"
+ );
+ assert_eq!(
+ tab.panes.get(&PaneId::Terminal(4)).unwrap().columns(),
+ 121,
+ "Pane cols match fullscreen cols"
+ );
+ assert_eq!(
+ tab.panes.get(&PaneId::Terminal(4)).unwrap().rows(),
+ 20,
+ "Pane rows match fullscreen rows"
+ );
+}
+
+#[test]
+pub fn close_pane_with_another_pane_above_it() {
+ // ┌───────────┐ ┌───────────┐
+ // │xxxxxxxxxxx│ │xxxxxxxxxxx│
+ // │xxxxxxxxxxx│ │xxxxxxxxxxx│
+ // ├───────────┤ ==close==> │xxxxxxxxxxx│
+ // │███████████│ │xxxxxxxxxxx│
+ // │███████████│ │xxxxxxxxxxx│
+ // └───────────┘ └───────────┘
+ // █ == pane being closed
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.horizontal_split(new_pane_id);
+ tab.close_focused_pane();
+ assert_eq!(tab.panes.len(), 1, "One pane left in tab");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "remaining pane row count"
+ );
+}
+
+#[test]
+pub fn close_pane_with_another_pane_below_it() {
+ // ┌───────────┐ ┌───────────┐
+ // │███████████│ │xxxxxxxxxxx│
+ // │███████████│ │xxxxxxxxxxx│
+ // ├───────────┤ ==close==> │xxxxxxxxxxx│
+ // │xxxxxxxxxxx│ │xxxxxxxxxxx│
+ // │xxxxxxxxxxx│ │xxxxxxxxxxx│
+ // └───────────┘ └───────────┘
+ // █ == pane being closed
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.horizontal_split(new_pane_id);
+ tab.move_focus_up();
+ tab.close_focused_pane();
+ assert_eq!(tab.panes.len(), 1, "One pane left in tab");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "remaining pane row count"
+ );
+}
+
+#[test]
+pub fn close_pane_with_another_pane_to_the_left() {
+ // ┌─────┬─────┐ ┌──────────┐
+ // │xxxxx│█████│ │xxxxxxxxxx│
+ // │xxxxx│█████│ ==close==> │xxxxxxxxxx│
+ // │xxxxx│█████│ │xxxxxxxxxx│
+ // └─────┴─────┘ └──────────┘
+ // █ == pane being closed
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.vertical_split(new_pane_id);
+ tab.close_focused_pane();
+ assert_eq!(tab.panes.len(), 1, "One pane left in tab");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "remaining pane row count"
+ );
+}
+
+#[test]
+pub fn close_pane_with_another_pane_to_the_right() {
+ // ┌─────┬─────┐ ┌──────────┐
+ // │█████│xxxxx│ │xxxxxxxxxx│
+ // │█████│xxxxx│ ==close==> │xxxxxxxxxx│
+ // │█████│xxxxx│ │xxxxxxxxxx│
+ // └─────┴─────┘ └──────────┘
+ // █ == pane being closed
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.vertical_split(new_pane_id);
+ tab.move_focus_left();
+ tab.close_focused_pane();
+ assert_eq!(tab.panes.len(), 1, "One pane left in tab");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "remaining pane row count"
+ );
+}
+
+#[test]
+pub fn close_pane_with_multiple_panes_above_it() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │xxxxx│xxxxx│ │xxxxx│xxxxx│
+ // │xxxxx│xxxxx│ │xxxxx│xxxxx│
+ // ├─────┴─────┤ ==close==> │xxxxx│xxxxx│
+ // │███████████│ │xxxxx│xxxxx│
+ // │███████████│ │xxxxx│xxxxx│
+ // └───────────┘ └─────┴─────┘
+ // █ == pane being closed
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ tab.horizontal_split(new_pane_id_1);
+ tab.move_focus_up();
+ tab.vertical_split(new_pane_id_2);
+ tab.move_focus_down();
+ tab.close_focused_pane();
+ assert_eq!(tab.panes.len(), 2, "Two panes left in tab");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "first remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "first remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "first remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "first remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "second remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "second remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "second remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "second remaining pane row count"
+ );
+}
+
+#[test]
+pub fn close_pane_with_multiple_panes_below_it() {
+ // ┌───────────┐ ┌─────┬─────┐
+ // │███████████│ │xxxxx│xxxxx│
+ // │███████████│ │xxxxx│xxxxx│
+ // ├─────┬─────┤ ==close==> │xxxxx│xxxxx│
+ // │xxxxx│xxxxx│ │xxxxx│xxxxx│
+ // │xxxxx│xxxxx│ │xxxxx│xxxxx│
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == pane being closed
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ tab.horizontal_split(new_pane_id_1);
+ tab.vertical_split(new_pane_id_2);
+ tab.move_focus_up();
+ tab.close_focused_pane();
+ assert_eq!(tab.panes.len(), 2, "Two panes left in tab");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "first remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "first remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "first remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "first remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "second remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "second remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "second remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "second remaining pane row count"
+ );
+}
+
+#[test]
+pub fn close_pane_with_multiple_panes_to_the_left() {
+ // ┌─────┬─────┐ ┌──────────┐
+ // │xxxxx│█████│ │xxxxxxxxxx│
+ // │xxxxx│█████│ │xxxxxxxxxx│
+ // ├─────┤█████│ ==close==> ├──────────┤
+ // │xxxxx│█████│ │xxxxxxxxxx│
+ // │xxxxx│█████│ │xxxxxxxxxx│
+ // └─────┴─────┘ └──────────┘
+ // █ == pane being closed
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ tab.vertical_split(new_pane_id_1);
+ tab.move_focus_left();
+ tab.horizontal_split(new_pane_id_2);
+ tab.move_focus_right();
+ tab.close_focused_pane();
+ assert_eq!(tab.panes.len(), 2, "Two panes left in tab");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "first remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "first remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "first remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "first remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "second remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "second remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "second remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "second remaining pane row count"
+ );
+}
+
+#[test]
+pub fn close_pane_with_multiple_panes_to_the_right() {
+ // ┌─────┬─────┐ ┌──────────┐
+ // │█████│xxxxx│ │xxxxxxxxxx│
+ // │█████│xxxxx│ │xxxxxxxxxx│
+ // │█████├─────┤ ==close==> ├──────────┤
+ // │█████│xxxxx│ │xxxxxxxxxx│
+ // │█████│xxxxx│ │xxxxxxxxxx│
+ // └─────┴─────┘ └──────────┘
+ // █ == pane being closed
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ tab.vertical_split(new_pane_id_1);
+ tab.horizontal_split(new_pane_id_2);
+ tab.move_focus_left();
+ tab.close_focused_pane();
+ assert_eq!(tab.panes.len(), 2, "Two panes left in tab");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "first remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "first remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "first remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "first remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "second remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "second remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "second remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "second remaining pane row count"
+ );
+}
+
+#[test]
+pub fn close_pane_with_multiple_panes_above_it_away_from_screen_edges() {
+ // ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐
+ // │xxx│xxx│xxx│xxx│ │xxx│xxx│xxx│xxx│
+ // ├───┤xxx│xxx├───┤ ├───┤xxx│xxx├───┤
+ // │xxx├───┴───┤xxx│ ==close==> │xxx│xxx│xxx│xxx│
+ // │xxx│███████│xxx│ │xxx│xxx│xxx│xxx│
+ // │xxx│███████│xxx│ │xxx│xxx│xxx│xxx│
+ // └───┴───────┴───┘ └───┴───┴───┴───┘
+ // █ == pane being closed
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+ let new_pane_id_6 = PaneId::Terminal(7);
+
+ tab.vertical_split(new_pane_id_1);
+ tab.vertical_split(new_pane_id_2);
+ tab.move_focus_left();
+ tab.move_focus_left();
+ tab.horizontal_split(new_pane_id_3);
+ tab.move_focus_right();
+ tab.horizontal_split(new_pane_id_4);
+ tab.move_focus_right();
+ tab.horizontal_split(new_pane_id_5);
+ tab.move_focus_left();
+ tab.move_focus_up();
+ tab.resize_down();
+ tab.vertical_split(new_pane_id_6);
+ tab.move_focus_down();
+ tab.close_focused_pane();
+
+ assert_eq!(tab.panes.len(), 6, "Six panes left in tab");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "first remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "first remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "first remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "first remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "second remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "second remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 15,
+ "second remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "second remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "third remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "third remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "third remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "third remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "fourth remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "fourth remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "fourth remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "fourth remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "sixths remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "sixths remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "sixths remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "sixths remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 77,
+ "seventh remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "seventh remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 14,
+ "seventh remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "seventh remaining pane row count"
+ );
+}
+
+#[test]
+pub fn close_pane_with_multiple_panes_below_it_away_from_screen_edges() {
+ // ┌───┬───────┬───┐ ┌───┬───┬───┬───┐
+ // │xxx│███████│xxx│ │xxx│xxx│xxx│xxx│
+ // │xxx│███████│xxx│ │xxx│xxx│xxx│xxx│
+ // │xxx├───┬───┤xxx│ ==close==> │xxx│xxx│xxx│xxx│
+ // ├───┤xxx│xxx├───┤ ├───┤xxx│xxx├───┤
+ // │xxx│xxx│xxx│xxx│ │xxx│xxx│xxx│xxx│
+ // └───┴───┴───┴───┘ └───┴───┴───┴───┘
+ // █ == pane being closed
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+ let new_pane_id_6 = PaneId::Terminal(7);
+
+ tab.vertical_split(new_pane_id_1);
+ tab.vertical_split(new_pane_id_2);
+ tab.move_focus_left();
+ tab.move_focus_left();
+ tab.horizontal_split(new_pane_id_3);
+ tab.move_focus_right();
+ tab.horizontal_split(new_pane_id_4);
+ tab.move_focus_right();
+ tab.horizontal_split(new_pane_id_5);
+ tab.move_focus_left();
+ tab.resize_up();
+ tab.vertical_split(new_pane_id_6);
+ tab.move_focus_up();
+ tab.close_focused_pane();
+
+ assert_eq!(tab.panes.len(), 6, "Six panes left in tab");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "first remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "first remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "first remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "first remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "third remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "third remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "third remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "third remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "fourth remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "fourth remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "fourth remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "fourth remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "second remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "second remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 15,
+ "second remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "second remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "sixths remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "sixths remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "sixths remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "sixths remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 77,
+ "seventh remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "seventh remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 14,
+ "seventh remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "seventh remaining pane row count"
+ );
+}
+
+#[test]
+pub fn close_pane_with_multiple_panes_to_the_left_away_from_screen_edges() {
+ // ┌────┬──────┐ ┌────┬──────┐
+ // │xxxx│xxxxxx│ │xxxx│xxxxxx│
+ // ├────┴┬─────┤ ├────┴──────┤
+ // │xxxxx│█████│ │xxxxxxxxxxx│
+ // ├─────┤█████│ ==close==> ├───────────┤
+ // │xxxxx│█████│ │xxxxxxxxxxx│
+ // ├────┬┴─────┤ ├────┬──────┤
+ // │xxxx│xxxxxx│ │xxxx│xxxxxx│
+ // └────┴──────┘ └────┴──────┘
+ // █ == pane being closed
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+ let new_pane_id_6 = PaneId::Terminal(7);
+
+ tab.horizontal_split(new_pane_id_1);
+ tab.horizontal_split(new_pane_id_2);
+ tab.move_focus_up();
+ tab.move_focus_up();
+ tab.vertical_split(new_pane_id_3);
+ tab.move_focus_down();
+ tab.vertical_split(new_pane_id_4);
+ tab.move_focus_down();
+ tab.vertical_split(new_pane_id_5);
+ tab.move_focus_up();
+ tab.move_focus_left();
+ tab.resize_right();
+ tab.horizontal_split(new_pane_id_6);
+ tab.move_focus_right();
+ tab.close_focused_pane();
+
+ assert_eq!(tab.panes.len(), 6, "Six panes left in tab");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "first remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "first remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "first remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "first remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "third remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "third remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "third remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 3,
+ "third remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "fourth remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 24,
+ "fourth remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "fourth remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 6,
+ "fourth remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "second remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "second remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "second remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "second remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "sixths remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 24,
+ "sixths remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "sixths remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 6,
+ "sixths remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "seventh remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 20,
+ "seventh remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "seventh remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 3,
+ "seventh remaining pane row count"
+ );
+}
+
+#[test]
+pub fn close_pane_with_multiple_panes_to_the_right_away_from_screen_edges() {
+ // ┌────┬──────┐ ┌────┬──────┐
+ // │xxxx│xxxxxx│ │xxxx│xxxxxx│
+ // ├────┴┬─────┤ ├────┴──────┤
+ // │█████│xxxxx│ │xxxxxxxxxxx│
+ // │█████├─────┤ ==close==> ├───────────┤
+ // │█████│xxxxx│ │xxxxxxxxxxx│
+ // ├────┬┴─────┤ ├────┬──────┤
+ // │xxxx│xxxxxx│ │xxxx│xxxxxx│
+ // └────┴──────┘ └────┴──────┘
+ // █ == pane being closed
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+ let new_pane_id_4 = PaneId::Terminal(5);
+ let new_pane_id_5 = PaneId::Terminal(6);
+ let new_pane_id_6 = PaneId::Terminal(7);
+
+ tab.horizontal_split(new_pane_id_1);
+ tab.horizontal_split(new_pane_id_2);
+ tab.move_focus_up();
+ tab.move_focus_up();
+ tab.vertical_split(new_pane_id_3);
+ tab.move_focus_down();
+ tab.vertical_split(new_pane_id_4);
+ tab.move_focus_down();
+ tab.vertical_split(new_pane_id_5);
+ tab.move_focus_up();
+ tab.resize_left();
+ tab.horizontal_split(new_pane_id_6);
+ tab.move_focus_left();
+ tab.close_focused_pane();
+
+ assert_eq!(tab.panes.len(), 6, "Six panes left in tab");
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "first remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "first remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "first remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "first remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "fourth remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 24,
+ "fourth remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "fourth remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 6,
+ "fourth remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "second remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "second remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "second remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "second remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "third remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "third remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "third remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 3,
+ "third remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "sixths remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 24,
+ "sixths remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "sixths remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 6,
+ "sixths remaining pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "seventh remaining pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 20,
+ "seventh remaining pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "seventh remaining pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 3,
+ "seventh remaining pane row count"
+ );
+}
+
+#[test]
+pub fn move_focus_down() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id = PaneId::Terminal(2);
+
+ tab.horizontal_split(new_pane_id);
+ tab.move_focus_up();
+ tab.move_focus_down();
+
+ assert_eq!(
+ tab.get_active_pane().unwrap().y(),
+ 11,
+ "Active pane is the bottom one"
+ );
+}
+
+#[test]
+pub fn move_focus_down_to_the_most_recently_used_pane() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+
+ tab.horizontal_split(new_pane_id_1);
+ tab.vertical_split(new_pane_id_2);
+ tab.vertical_split(new_pane_id_3);
+ tab.move_focus_up();
+ tab.move_focus_down();
+
+ assert_eq!(
+ tab.get_active_pane().unwrap().y(),
+ 11,
+ "Active pane y position"
+ );
+ assert_eq!(
+ tab.get_active_pane().unwrap().x(),
+ 92,
+ "Active pane x position"
+ );
+}
+
+#[test]
+pub fn move_focus_up() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id = PaneId::Terminal(2);
+
+ tab.horizontal_split(new_pane_id);
+ tab.move_focus_up();
+
+ assert_eq!(
+ tab.get_active_pane().unwrap().y(),
+ 0,
+ "Active pane is the top one"
+ );
+}
+
+#[test]
+pub fn move_focus_up_to_the_most_recently_used_pane() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+
+ tab.horizontal_split(new_pane_id_1);
+ tab.move_focus_up();
+ tab.vertical_split(new_pane_id_2);
+ tab.vertical_split(new_pane_id_3);
+ tab.move_focus_down();
+ tab.move_focus_up();
+
+ assert_eq!(
+ tab.get_active_pane().unwrap().y(),
+ 0,
+ "Active pane y position"
+ );
+ assert_eq!(
+ tab.get_active_pane().unwrap().x(),
+ 92,
+ "Active pane x position"
+ );
+}
+
+#[test]
+pub fn move_focus_left() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id = PaneId::Terminal(2);
+
+ tab.vertical_split(new_pane_id);
+ tab.move_focus_left();
+
+ assert_eq!(
+ tab.get_active_pane().unwrap().x(),
+ 0,
+ "Active pane is the left one"
+ );
+}
+
+#[test]
+pub fn move_focus_left_to_the_most_recently_used_pane() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+
+ tab.vertical_split(new_pane_id_1);
+ tab.move_focus_left();
+ tab.horizontal_split(new_pane_id_2);
+ tab.horizontal_split(new_pane_id_3);
+ tab.move_focus_right();
+ tab.move_focus_left();
+
+ assert_eq!(
+ tab.get_active_pane().unwrap().y(),
+ 16,
+ "Active pane y position"
+ );
+ assert_eq!(
+ tab.get_active_pane().unwrap().x(),
+ 0,
+ "Active pane x position"
+ );
+}
+
+#[test]
+pub fn move_focus_right() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id = PaneId::Terminal(2);
+
+ tab.vertical_split(new_pane_id);
+ tab.move_focus_left();
+ tab.move_focus_right();
+
+ assert_eq!(
+ tab.get_active_pane().unwrap().x(),
+ 61,
+ "Active pane is the right one"
+ );
+}
+
+#[test]
+pub fn move_focus_right_to_the_most_recently_used_pane() {
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ let new_pane_id_3 = PaneId::Terminal(4);
+
+ tab.vertical_split(new_pane_id_1);
+ tab.horizontal_split(new_pane_id_2);
+ tab.horizontal_split(new_pane_id_3);
+ tab.move_focus_left();
+ tab.move_focus_right();
+
+ assert_eq!(
+ tab.get_active_pane().unwrap().y(),
+ 16,
+ "Active pane y position"
+ );
+ assert_eq!(
+ tab.get_active_pane().unwrap().x(),
+ 61,
+ "Active pane x position"
+ );
+}
+
+#[test]
+pub fn resize_down_with_pane_above() {
+ // ┌───────────┐ ┌───────────┐
+ // │ │ │ │
+ // │ │ │ │
+ // ├───────────┤ ==resize=down==> │ │
+ // │███████████│ ├───────────┤
+ // │███████████│ │███████████│
+ // │███████████│ │███████████│
+ // └───────────┘ └───────────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.horizontal_split(new_pane_id);
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes.get(&new_pane_id).unwrap().position_and_size().x,
+ 0,
+ "focused pane x position"
+ );
+ assert_eq!(
+ tab.panes.get(&new_pane_id).unwrap().position_and_size().y,
+ 13,
+ "focused pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&new_pane_id)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "focused pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&new_pane_id)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 7,
+ "focused pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane above x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane above y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "pane above column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 12,
+ "pane above row count"
+ );
+}
+
+#[test]
+pub fn resize_down_with_pane_below() {
+ // ┌───────────┐ ┌───────────┐
+ // │███████████│ │███████████│
+ // │███████████│ │███████████│
+ // ├───────────┤ ==resize=down==> │███████████│
+ // │ │ ├───────────┤
+ // │ │ │ │
+ // └───────────┘ └───────────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.horizontal_split(new_pane_id);
+ tab.move_focus_up();
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes.get(&new_pane_id).unwrap().position_and_size().x,
+ 0,
+ "pane below x position"
+ );
+ assert_eq!(
+ tab.panes.get(&new_pane_id).unwrap().position_and_size().y,
+ 13,
+ "pane below y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&new_pane_id)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "pane below column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&new_pane_id)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 7,
+ "pane below row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "focused pane x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "focused pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "focused pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 12,
+ "focused pane row count"
+ );
+}
+
+#[test]
+pub fn resize_down_with_panes_above_and_below() {
+ // ┌───────────┐ ┌───────────┐
+ // │ │ │ │
+ // │ │ │ │
+ // ├───────────┤ ├───────────┤
+ // │███████████│ ==resize=down==> │███████████│
+ // │███████████│ │███████████│
+ // │███████████│ │███████████│
+ // ├───────────┤ │███████████│
+ // │ │ ├───────────┤
+ // │ │ │ │
+ // └───────────┘ └───────────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let first_pane_id = PaneId::Terminal(1);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ tab.horizontal_split(new_pane_id_1);
+ tab.horizontal_split(new_pane_id_2);
+ tab.move_focus_up();
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes.get(&new_pane_id_1).unwrap().position_and_size().x,
+ 0,
+ "focused pane x position"
+ );
+ assert_eq!(
+ tab.panes.get(&new_pane_id_1).unwrap().position_and_size().y,
+ 16,
+ "focused pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&new_pane_id_1)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "focused pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&new_pane_id_1)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "focused pane row count"
+ );
+
+ assert_eq!(
+ tab.panes.get(&new_pane_id_2).unwrap().position_and_size().x,
+ 0,
+ "pane below x position"
+ );
+ assert_eq!(
+ tab.panes.get(&new_pane_id_2).unwrap().position_and_size().y,
+ 26,
+ "pane below y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&new_pane_id_2)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "pane below column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&new_pane_id_2)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane below row count"
+ );
+
+ assert_eq!(
+ tab.panes.get(&first_pane_id).unwrap().position_and_size().x,
+ 0,
+ "pane above x position"
+ );
+ assert_eq!(
+ tab.panes.get(&first_pane_id).unwrap().position_and_size().y,
+ 0,
+ "pane above y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&first_pane_id)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "pane above column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&first_pane_id)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane above row count"
+ );
+}
+
+#[test]
+pub fn resize_down_with_multiple_panes_above() {
+ //
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ │ │
+ // ├─────┴─────┤ ==resize=down==> │ │ │
+ // │███████████│ ├─────┴─────┤
+ // │███████████│ │███████████│
+ // └───────────┘ └───────────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let first_pane_id = PaneId::Terminal(1);
+ let new_pane_id_1 = PaneId::Terminal(2);
+ let new_pane_id_2 = PaneId::Terminal(3);
+ tab.horizontal_split(new_pane_id_1);
+ tab.move_focus_up();
+ tab.vertical_split(new_pane_id_2);
+ tab.move_focus_down();
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes.get(&new_pane_id_1).unwrap().position_and_size().x,
+ 0,
+ "focused pane x position"
+ );
+ assert_eq!(
+ tab.panes.get(&new_pane_id_1).unwrap().position_and_size().y,
+ 18,
+ "focused pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&new_pane_id_1)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "focused pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&new_pane_id_1)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 12,
+ "focused pane row count"
+ );
+
+ assert_eq!(
+ tab.panes.get(&new_pane_id_2).unwrap().position_and_size().x,
+ 61,
+ "first pane above x position"
+ );
+ assert_eq!(
+ tab.panes.get(&new_pane_id_2).unwrap().position_and_size().y,
+ 0,
+ "first pane above y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&new_pane_id_2)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "first pane above column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&new_pane_id_2)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "first pane above row count"
+ );
+
+ assert_eq!(
+ tab.panes.get(&first_pane_id).unwrap().position_and_size().x,
+ 0,
+ "second pane above x position"
+ );
+ assert_eq!(
+ tab.panes.get(&first_pane_id).unwrap().position_and_size().y,
+ 0,
+ "second pane above y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&first_pane_id)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "second pane above column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&first_pane_id)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "second pane above row count"
+ );
+}
+
+#[test]
+pub fn resize_down_with_panes_above_aligned_left_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ │ │
+ // │ │ │ │ │ │
+ // ├─────┼─────┤ ==resize=down==> ├─────┤ │
+ // │ │█████│ │ ├─────┤
+ // │ │█████│ │ │█████│
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let pane_above_and_left = PaneId::Terminal(1);
+ let pane_to_the_left = PaneId::Terminal(2);
+ let focused_pane = PaneId::Terminal(3);
+ let pane_above = PaneId::Terminal(4);
+ tab.horizontal_split(pane_to_the_left);
+ tab.vertical_split(focused_pane);
+ tab.move_focus_up();
+ tab.vertical_split(pane_above);
+ tab.move_focus_down();
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes.get(&focused_pane).unwrap().position_and_size().x,
+ 61,
+ "focused pane x position"
+ );
+ assert_eq!(
+ tab.panes.get(&focused_pane).unwrap().position_and_size().y,
+ 18,
+ "focused pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&focused_pane)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "focused pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&focused_pane)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 12,
+ "focused pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&pane_above_and_left)
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane above and to the left x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_above_and_left)
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane above and to the left y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_above_and_left)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane above and to the left column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_above_and_left)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane above and to the left row count"
+ );
+
+ assert_eq!(
+ tab.panes.get(&pane_above).unwrap().position_and_size().x,
+ 61,
+ "pane above x position"
+ );
+ assert_eq!(
+ tab.panes.get(&pane_above).unwrap().position_and_size().y,
+ 0,
+ "pane above y position"
+ );
+ assert_eq!(
+ tab.panes.get(&pane_above).unwrap().position_and_size().cols,
+ 60,
+ "pane above column count"
+ );
+ assert_eq!(
+ tab.panes.get(&pane_above).unwrap().position_and_size().rows,
+ 17,
+ "pane above row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_left)
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane to the left x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_left)
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane to the left y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_left)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane to the left column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_left)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane to the left row count"
+ );
+}
+
+#[test]
+pub fn resize_down_with_panes_below_aligned_left_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │█████│ │ │█████│
+ // │ │█████│ │ │█████│
+ // ├─────┼─────┤ ==resize=down==> ├─────┤█████│
+ // │ │ │ │ ├─────┤
+ // │ │ │ │ │ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let pane_to_the_left = PaneId::Terminal(1);
+ let pane_below_and_left = PaneId::Terminal(2);
+ let pane_below = PaneId::Terminal(3);
+ let focused_pane = PaneId::Terminal(4);
+ tab.horizontal_split(pane_below_and_left);
+ tab.vertical_split(pane_below);
+ tab.move_focus_up();
+ tab.vertical_split(focused_pane);
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes.get(&focused_pane).unwrap().position_and_size().x,
+ 61,
+ "focused pane x position"
+ );
+ assert_eq!(
+ tab.panes.get(&focused_pane).unwrap().position_and_size().y,
+ 0,
+ "focused pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&focused_pane)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "focused pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&focused_pane)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "focused pane row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_left)
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane above and to the left x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_left)
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane above and to the left y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_left)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane above and to the left column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_left)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane above and to the left row count"
+ );
+
+ assert_eq!(
+ tab.panes.get(&pane_below).unwrap().position_and_size().x,
+ 61,
+ "pane above x position"
+ );
+ assert_eq!(
+ tab.panes.get(&pane_below).unwrap().position_and_size().y,
+ 18,
+ "pane above y position"
+ );
+ assert_eq!(
+ tab.panes.get(&pane_below).unwrap().position_and_size().cols,
+ 60,
+ "pane above column count"
+ );
+ assert_eq!(
+ tab.panes.get(&pane_below).unwrap().position_and_size().rows,
+ 12,
+ "pane above row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&pane_below_and_left)
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane to the left x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_below_and_left)
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane to the left y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_below_and_left)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane to the left column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_below_and_left)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane to the left row count"
+ );
+}
+
+#[test]
+pub fn resize_down_with_panes_above_aligned_right_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ │ │
+ // │ │ │ │ │ │
+ // ├─────┼─────┤ ==resize=down==> │ ├─────┤
+ // │█████│ │ ├─────┤ │
+ // │█████│ │ │█████│ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let pane_above = PaneId::Terminal(1);
+ let focused_pane = PaneId::Terminal(2);
+ let pane_to_the_right = PaneId::Terminal(3);
+ let pane_above_and_right = PaneId::Terminal(4);
+ tab.horizontal_split(focused_pane);
+ tab.vertical_split(pane_to_the_right);
+ tab.move_focus_up();
+ tab.vertical_split(pane_above_and_right);
+ tab.move_focus_down();
+ tab.move_focus_left();
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes.get(&focused_pane).unwrap().position_and_size().x,
+ 0,
+ "focused pane x position"
+ );
+ assert_eq!(
+ tab.panes.get(&focused_pane).unwrap().position_and_size().y,
+ 18,
+ "focused pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&focused_pane)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "focused pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&focused_pane)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 12,
+ "focused pane row count"
+ );
+
+ assert_eq!(
+ tab.panes.get(&pane_above).unwrap().position_and_size().x,
+ 0,
+ "pane above x position"
+ );
+ assert_eq!(
+ tab.panes.get(&pane_above).unwrap().position_and_size().y,
+ 0,
+ "pane above y position"
+ );
+ assert_eq!(
+ tab.panes.get(&pane_above).unwrap().position_and_size().cols,
+ 60,
+ "pane above column count"
+ );
+ assert_eq!(
+ tab.panes.get(&pane_above).unwrap().position_and_size().rows,
+ 17,
+ "pane above row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_right)
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane to the right x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_right)
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane to the right y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_right)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane to the right column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_right)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane to the right row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&pane_above_and_right)
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane above and to the right x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_above_and_right)
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane above and to the right y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_above_and_right)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane above and to the right column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_above_and_right)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane above and to the right row count"
+ );
+}
+
+#[test]
+pub fn resize_down_with_panes_below_aligned_right_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │█████│ │ │█████│ │
+ // │█████│ │ │█████│ │
+ // ├─────┼─────┤ ==resize=down==> │█████├─────┤
+ // │ │ │ ├─────┤ │
+ // │ │ │ │ │ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ let focused_pane = PaneId::Terminal(1);
+ let pane_below = PaneId::Terminal(2);
+ let pane_below_and_right = PaneId::Terminal(3);
+ let pane_to_the_right = PaneId::Terminal(4);
+ tab.horizontal_split(pane_below);
+ tab.vertical_split(pane_below_and_right);
+ tab.move_focus_up();
+ tab.vertical_split(pane_to_the_right);
+ tab.move_focus_left();
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes.get(&focused_pane).unwrap().position_and_size().x,
+ 0,
+ "focused pane x position"
+ );
+ assert_eq!(
+ tab.panes.get(&focused_pane).unwrap().position_and_size().y,
+ 0,
+ "focused pane y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&focused_pane)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "focused pane column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&focused_pane)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "focused pane row count"
+ );
+
+ assert_eq!(
+ tab.panes.get(&pane_below).unwrap().position_and_size().x,
+ 0,
+ "pane below x position"
+ );
+ assert_eq!(
+ tab.panes.get(&pane_below).unwrap().position_and_size().y,
+ 18,
+ "pane below y position"
+ );
+ assert_eq!(
+ tab.panes.get(&pane_below).unwrap().position_and_size().cols,
+ 60,
+ "pane below column count"
+ );
+ assert_eq!(
+ tab.panes.get(&pane_below).unwrap().position_and_size().rows,
+ 12,
+ "pane below row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&pane_below_and_right)
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane below and to the right x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_below_and_right)
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane below and to the right y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_below_and_right)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane below and to the right column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_below_and_right)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane below and to the right row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_right)
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane to the right x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_right)
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane to the right y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_right)
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane to the right column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&pane_to_the_right)
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane to the right row count"
+ );
+}
+
+#[test]
+pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() {
+ // ┌───┬───┬───┐ ┌───┬───┬───┐
+ // │ │ │ │ │ │ │ │
+ // │ │ │ │ │ │ │ │
+ // ├───┼───┼───┤ ==resize=down==> ├───┤ ├───┤
+ // │ │███│ │ │ ├───┤ │
+ // │ │███│ │ │ │███│ │
+ // └───┴───┴───┘ └───┴───┴───┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_left();
+ tab.move_focus_down();
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 18,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 30,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 12,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 30,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 6 row count"
+ );
+}
+
+#[test]
+pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() {
+ // ┌───┬───┬───┐ ┌───┬───┬───┐
+ // │ │███│ │ │ │███│ │
+ // │ │███│ │ │ │███│ │
+ // ├───┼───┼───┤ ==resize=down==> ├───┤███├───┤
+ // │ │ │ │ │ ├───┤ │
+ // │ │ │ │ │ │ │ │
+ // └───┴───┴───┘ └───┴───┴───┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_left();
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 18,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 30,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 12,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 30,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 6 row count"
+ );
+}
+
+#[test]
+pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_left_and_right() {
+ // ┌─┬───────┬─┐ ┌─┬───────┬─┐
+ // │ │ │ │ │ │ │ │
+ // │ │ │ │ │ │ │ │
+ // ├─┼─┬───┬─┼─┤ ==resize=down==> ├─┤ ├─┤
+ // │ │ │███│ │ │ │ ├─┬───┬─┤ │
+ // │ │ │███│ │ │ │ │ │███│ │ │
+ // └─┴─┴───┴─┴─┘ └─┴─┴───┴─┴─┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_down();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_left();
+ tab.vertical_split(PaneId::Terminal(7));
+ tab.vertical_split(PaneId::Terminal(8));
+ tab.move_focus_left();
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 30,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 18,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 15,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 12,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 6 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 77,
+ "pane 7 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 18,
+ "pane 7 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 7,
+ "pane 7 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 12,
+ "pane 7 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 85,
+ "pane 8 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 18,
+ "pane 8 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 6,
+ "pane 8 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 12,
+ "pane 8 row count"
+ );
+}
+
+#[test]
+pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_right() {
+ // ┌─┬─┬───┬─┬─┐ ┌─┬─┬───┬─┬─┐
+ // │ │ │███│ │ │ │ │ │███│ │ │
+ // │ │ │███│ │ │ │ │ │███│ │ │
+ // ├─┼─┴───┴─┼─┤ ==resize=down==> ├─┤ │███│ ├─┤
+ // │ │ │ │ │ ├─┴───┴─┤ │
+ // │ │ │ │ │ │ │ │
+ // └─┴───────┴─┘ └─┴───────┴─┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_left();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_down();
+ tab.vertical_split(PaneId::Terminal(7));
+ tab.vertical_split(PaneId::Terminal(8));
+ tab.move_focus_left();
+ tab.move_focus_up();
+ tab.move_focus_left();
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 15,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 77,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 7,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 85,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 6,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "pane 6 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 7 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 18,
+ "pane 7 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 30,
+ "pane 7 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 12,
+ "pane 7 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 8 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 8 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 8 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 8 row count"
+ );
+}
+
+#[test]
+pub fn cannot_resize_down_when_pane_below_is_at_minimum_height() {
+ // ┌───────────┐ ┌───────────┐
+ // │███████████│ │███████████│
+ // ├───────────┤ ==resize=down==> ├───────────┤
+ // │ │ │ │
+ // └───────────┘ └───────────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 7,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.move_focus_up();
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 3,
+ "pane 1 height stayed the same"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 3,
+ "pane 2 height stayed the same"
+ );
+}
+
+#[test]
+pub fn resize_left_with_pane_to_the_left() {
+ // ┌─────┬─────┐ ┌───┬───────┐
+ // │ │█████│ │ │███████│
+ // │ │█████│ ==resize=left==> │ │███████│
+ // │ │█████│ │ │███████│
+ // └─────┴─────┘ └───┴───────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 2 row count"
+ );
+}
+
+#[test]
+pub fn resize_left_with_pane_to_the_right() {
+ // ┌─────┬─────┐ ┌───┬───────┐
+ // │█████│ │ │███│ │
+ // │█████│ │ ==resize=left==> │███│ │
+ // │█████│ │ │███│ │
+ // └─────┴─────┘ └───┴───────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.move_focus_left();
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 2 row count"
+ );
+}
+
+#[test]
+pub fn resize_left_with_panes_to_the_left_and_right() {
+ // ┌─────┬─────┬─────┐ ┌─────┬───┬───────┐
+ // │ │█████│ │ │ │███│ │
+ // │ │█████│ │ ==resize=left==> │ │███│ │
+ // │ │█████│ │ │ │███│ │
+ // └─────┴─────┴─────┘ └─────┴───┴───────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.move_focus_left();
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 40,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 2 row count"
+ );
+}
+
+#[test]
+pub fn resize_left_with_multiple_panes_to_the_left() {
+ // ┌─────┬─────┐ ┌───┬───────┐
+ // │ │█████│ │ │███████│
+ // ├─────┤█████│ ==resize=left==> ├───┤███████│
+ // │ │█████│ │ │███████│
+ // └─────┴─────┘ └───┴───────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.move_focus_left();
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.move_focus_right();
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "pane 2 row count"
+ );
+}
+
+#[test]
+pub fn resize_left_with_panes_to_the_left_aligned_top_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ │ │
+ // ├─────┼─────┤ ==resize=left==> ├───┬─┴─────┤
+ // │ │█████│ │ │███████│
+ // └─────┴─────┘ └───┴───────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_down();
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 4 row count"
+ );
+}
+
+#[test]
+pub fn resize_left_with_panes_to_the_right_aligned_top_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ │ │
+ // ├─────┼─────┤ ==resize=left==> ├───┬─┴─────┤
+ // │█████│ │ │███│ │
+ // └─────┴─────┘ └───┴───────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_down();
+ tab.move_focus_left();
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 4 row count"
+ );
+}
+
+#[test]
+pub fn resize_left_with_panes_to_the_left_aligned_bottom_with_current_pane() {
+ // ┌─────┬─────┐ ┌───┬───────┐
+ // │ │█████│ │ │███████│
+ // ├─────┼─────┤ ==resize=left==> ├───┴─┬─────┤
+ // │ │ │ │ │ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 4 row count"
+ );
+}
+
+#[test]
+pub fn resize_left_with_panes_to_the_right_aligned_bottom_with_current_pane() {
+ // ┌─────┬─────┐ ┌───┬───────┐
+ // │█████│ │ │███│ │
+ // ├─────┼─────┤ ==resize=left==> ├───┴─┬─────┤
+ // │ │ │ │ │ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_left();
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 4 row count"
+ );
+}
+
+#[test]
+pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ │ │
+ // ├─────┼─────┤ ├───┬─┴─────┤
+ // │ │█████│ ==resize=left==> │ │███████│
+ // ├─────┼─────┤ ├───┴─┬─────┤
+ // │ │ │ │ │ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_down();
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 7,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 24,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 6,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 24,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 6,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 7,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 6 row count"
+ );
+}
+
+#[test]
+pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ │ │
+ // ├─────┼─────┤ ├───┬─┴─────┤
+ // │█████│ │ ==resize=left==> │███│ │
+ // ├─────┼─────┤ ├───┴─┬─────┤
+ // │ │ │ │ │ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_down();
+ tab.move_focus_left();
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 7,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 24,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 6,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 24,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 6,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 7,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 6 row count"
+ );
+}
+
+#[test]
+pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_above_and_below() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // ├─────┼─────┤ ├───┬─┴─────┤
+ // │ ├─────┤ │ ├───────┤
+ // │ │█████│ ==resize=left==> │ │███████│
+ // │ ├─────┤ │ ├───────┤
+ // ├─────┼─────┤ ├───┴─┬─────┤
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 70,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.move_focus_down();
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.horizontal_split(PaneId::Terminal(7));
+ tab.horizontal_split(PaneId::Terminal(8));
+ tab.move_focus_up();
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 35,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 36,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 54,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 54,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 35,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 36,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 8,
+ "pane 6 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 7 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 45,
+ "pane 7 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 7 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane 7 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 8 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 50,
+ "pane 8 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 8 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 3,
+ "pane 8 row count"
+ );
+}
+
+#[test]
+pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_above_and_below() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // ├─────┼─────┤ ├───┬─┴─────┤
+ // ├─────┤ │ ├───┤ │
+ // │█████│ │ ==resize=left==> │███│ │
+ // ├─────┤ │ ├───┤ │
+ // ├─────┼─────┤ ├───┴─┬─────┤
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 70,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.move_focus_down();
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_left();
+ tab.horizontal_split(PaneId::Terminal(7));
+ tab.horizontal_split(PaneId::Terminal(8));
+ tab.move_focus_up();
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 35,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 36,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 8,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 54,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 54,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 35,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 51,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 36,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "pane 6 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 7 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 45,
+ "pane 7 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 7 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane 7 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 8 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 50,
+ "pane 8 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 8 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 3,
+ "pane 8 row count"
+ );
+}
+
+#[test]
+pub fn cannot_resize_left_when_pane_to_the_left_is_at_minimum_width() {
+ // ┌─┬─┐ ┌─┬─┐
+ // │ │█│ │ │█│
+ // │ │█│ ==resize=left==> │ │█│
+ // │ │█│ │ │█│
+ // └─┴─┘ └─┴─┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 9,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.resize_left();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 4,
+ "pane 1 columns stayed the same"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 4,
+ "pane 2 columns stayed the same"
+ );
+}
+
+#[test]
+pub fn resize_right_with_pane_to_the_left() {
+ // ┌─────┬─────┐ ┌───────┬───┐
+ // │ │█████│ │ │███│
+ // │ │█████│ ==resize=right==> │ │███│
+ // │ │█████│ │ │███│
+ // └─────┴─────┘ └───────┴───┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 2 row count"
+ );
+}
+
+#[test]
+pub fn resize_right_with_pane_to_the_right() {
+ // ┌─────┬─────┐ ┌───────┬───┐
+ // │█████│ │ │███████│ │
+ // │█████│ │ ==resize=right==> │███████│ │
+ // │█████│ │ │███████│ │
+ // └─────┴─────┘ └───────┴───┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.move_focus_left();
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 2 row count"
+ );
+}
+
+#[test]
+pub fn resize_right_with_panes_to_the_left_and_right() {
+ // ┌─────┬─────┬─────┐ ┌─────┬───────┬───┐
+ // │ │█████│ │ │ │███████│ │
+ // │ │█████│ │ ==resize=right==> │ │███████│ │
+ // │ │█████│ │ │ │███████│ │
+ // └─────┴─────┴─────┘ └─────┴───────┴───┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.move_focus_left();
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 40,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 102,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 19,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 2 row count"
+ );
+}
+
+#[test]
+pub fn resize_right_with_multiple_panes_to_the_left() {
+ // ┌─────┬─────┐ ┌───────┬───┐
+ // │ │█████│ │ │███│
+ // ├─────┤█████│ ==resize=right==> ├───────┤███│
+ // │ │█████│ │ │███│
+ // └─────┴─────┘ └───────┴───┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.move_focus_left();
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.move_focus_right();
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 20,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "pane 3 row count"
+ );
+}
+
+#[test]
+pub fn resize_right_with_panes_to_the_left_aligned_top_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ │ │
+ // ├─────┼─────┤ ==resize=right==> ├─────┴─┬───┤
+ // │ │█████│ │ │███│
+ // └─────┴─────┘ └───────┴───┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.move_focus_left();
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.move_focus_right();
+ tab.horizontal_split(PaneId::Terminal(4));
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "pane 4 row count"
+ );
+}
+
+#[test]
+pub fn resize_right_with_panes_to_the_right_aligned_top_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ │ │
+ // ├─────┼─────┤ ==resize=right==> ├─────┴─┬───┤
+ // │█████│ │ │███████│ │
+ // └─────┴─────┘ └───────┴───┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.move_focus_left();
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.move_focus_right();
+ tab.horizontal_split(PaneId::Terminal(4));
+ tab.move_focus_left();
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "pane 4 row count"
+ );
+}
+
+#[test]
+pub fn resize_right_with_panes_to_the_left_aligned_bottom_with_current_pane() {
+ // ┌─────┬─────┐ ┌───────┬───┐
+ // │ │█████│ │ │███│
+ // ├─────┼─────┤ ==resize=right==> ├─────┬─┴───┤
+ // │ │ │ │ │ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.move_focus_left();
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.move_focus_right();
+ tab.horizontal_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "pane 4 row count"
+ );
+}
+
+#[test]
+pub fn resize_right_with_panes_to_the_right_aligned_bottom_with_current_pane() {
+ // ┌─────┬─────┐ ┌───────┬───┐
+ // │█████│ │ │███████│ │
+ // ├─────┼─────┤ ==resize=right==> ├─────┬─┴───┤
+ // │ │ │ │ │ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.move_focus_left();
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.move_focus_right();
+ tab.horizontal_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.move_focus_left();
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "pane 4 row count"
+ );
+}
+
+#[test]
+pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ │ │
+ // ├─────┼─────┤ ├─────┴─┬───┤
+ // │ │█████│ ==resize=right==> │ │███│
+ // ├─────┼─────┤ ├─────┬─┴───┤
+ // │ │ │ │ │ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_down();
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 6 row count"
+ );
+}
+
+#[test]
+pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ │ │
+ // ├─────┼─────┤ ├─────┴─┬───┤
+ // │█████│ │ ==resize=right==> │███████│ │
+ // ├─────┼─────┤ ├─────┬─┴───┤
+ // │ │ │ │ │ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_down();
+ tab.move_focus_left();
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 11,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 10,
+ "pane 6 row count"
+ );
+}
+
+#[test]
+pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_above_and_below() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // ├─────┼─────┤ ├─────┴─┬───┤
+ // │ ├─────┤ │ ├───┤
+ // │ │█████│ ==resize=right==> │ │███│
+ // │ ├─────┤ │ ├───┤
+ // ├─────┼─────┤ ├─────┬─┴───┤
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 70,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.move_focus_down();
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.horizontal_split(PaneId::Terminal(7));
+ tab.horizontal_split(PaneId::Terminal(8));
+ tab.move_focus_up();
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 35,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 36,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 54,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 54,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 35,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 36,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 8,
+ "pane 6 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 7 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 45,
+ "pane 7 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 7 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane 7 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 8 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 50,
+ "pane 8 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 8 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 3,
+ "pane 8 row count"
+ );
+}
+
+#[test]
+pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_above_and_below() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // ├─────┼─────┤ ├─────┴─┬───┤
+ // ├─────┤ │ ├───────┤ │
+ // │█████│ │ ==resize=right==> │███████│ │
+ // ├─────┤ │ ├───────┤ │
+ // ├─────┼─────┤ ├─────┬─┴───┤
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 70,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.move_focus_down();
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_left();
+ tab.horizontal_split(PaneId::Terminal(7));
+ tab.horizontal_split(PaneId::Terminal(8));
+ tab.move_focus_up();
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 35,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 36,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 8,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 54,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 54,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 35,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 71,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 36,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 50,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 17,
+ "pane 6 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 7 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 45,
+ "pane 7 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 7 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 4,
+ "pane 7 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 8 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 50,
+ "pane 8 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 70,
+ "pane 8 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 3,
+ "pane 8 row count"
+ );
+}
+
+#[test]
+pub fn cannot_resize_right_when_pane_to_the_left_is_at_minimum_width() {
+ // ┌─┬─┐ ┌─┬─┐
+ // │ │█│ │ │█│
+ // │ │█│ ==resize=right==> │ │█│
+ // │ │█│ │ │█│
+ // └─┴─┘ └─┴─┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 9,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.vertical_split(PaneId::Terminal(2));
+ tab.resize_right();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 4,
+ "pane 1 columns stayed the same"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 4,
+ "pane 2 columns stayed the same"
+ );
+}
+
+#[test]
+pub fn resize_up_with_pane_above() {
+ // ┌───────────┐ ┌───────────┐
+ // │ │ │ │
+ // │ │ ├───────────┤
+ // ├───────────┤ ==resize=up==> │███████████│
+ // │███████████│ │███████████│
+ // │███████████│ │███████████│
+ // └───────────┘ └───────────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.resize_up();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 8,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 9,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 11,
+ "pane 2 row count"
+ );
+}
+
+#[test]
+pub fn resize_up_with_pane_below() {
+ // ┌───────────┐ ┌───────────┐
+ // │███████████│ │███████████│
+ // │███████████│ ├───────────┤
+ // ├───────────┤ ==resize=up==> │ │
+ // │ │ │ │
+ // │ │ │ │
+ // └───────────┘ └───────────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 20,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.move_focus_up();
+ tab.resize_up();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 8,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 9,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 11,
+ "pane 2 row count"
+ );
+}
+
+#[test]
+pub fn resize_up_with_panes_above_and_below() {
+ // ┌───────────┐ ┌───────────┐
+ // │ │ │ │
+ // │ │ ├───────────┤
+ // ├───────────┤ │███████████│
+ // │███████████│ ==resize=up==> │███████████│
+ // │███████████│ │███████████│
+ // ├───────────┤ ├───────────┤
+ // │ │ │ │
+ // │ │ │ │
+ // └───────────┘ └───────────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.horizontal_split(PaneId::Terminal(3));
+ tab.move_focus_up();
+ tab.resize_up();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 14,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 9,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 24,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 6,
+ "pane 3 row count"
+ );
+}
+
+#[test]
+pub fn resize_up_with_multiple_panes_above() {
+ //
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ ├─────┴─────┤
+ // ├─────┴─────┤ ==resize=up==> │███████████│
+ // │███████████│ │███████████│
+ // └───────────┘ └───────────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.move_focus_down();
+ tab.resize_up();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 14,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 121,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 3 row count"
+ );
+}
+
+#[test]
+pub fn resize_up_with_panes_above_aligned_left_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ ├─────┤
+ // ├─────┼─────┤ ==resize=up==> ├─────┤█████│
+ // │ │█████│ │ │█████│
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.move_focus_down();
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.resize_up();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 14,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 4 row count"
+ );
+}
+
+#[test]
+pub fn resize_up_with_panes_below_aligned_left_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │█████│ │ │█████│
+ // │ │█████│ │ ├─────┤
+ // ├─────┼─────┤ ==resize=up==> ├─────┤ │
+ // │ │ │ │ │ │
+ // │ │ │ │ │ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.move_focus_down();
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.resize_up();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 14,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 4 row count"
+ );
+}
+
+#[test]
+pub fn resize_up_with_panes_above_aligned_right_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │ │ │ │ │ │
+ // │ │ │ ├─────┤ │
+ // ├─────┼─────┤ ==resize=up==> │█████├─────┤
+ // │█████│ │ │█████│ │
+ // │█████│ │ │█████│ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.move_focus_down();
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_left();
+ tab.resize_up();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 14,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 4 row count"
+ );
+}
+
+#[test]
+pub fn resize_up_with_panes_below_aligned_right_with_current_pane() {
+ // ┌─────┬─────┐ ┌─────┬─────┐
+ // │█████│ │ │█████│ │
+ // │█████│ │ ├─────┤ │
+ // ├─────┼─────┤ ==resize=up==> │ ├─────┤
+ // │ │ │ │ │ │
+ // │ │ │ │ │ │
+ // └─────┴─────┘ └─────┴─────┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.move_focus_down();
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_left();
+ tab.move_focus_up();
+ tab.resize_up();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 14,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 4 row count"
+ );
+}
+
+#[test]
+pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() {
+ // ┌───┬───┬───┐ ┌───┬───┬───┐
+ // │ │ │ │ │ │ │ │
+ // │ │ │ │ │ ├───┤ │
+ // ├───┼───┼───┤ ==resize=up==> ├───┤███├───┤
+ // │ │███│ │ │ │███│ │
+ // │ │███│ │ │ │███│ │
+ // └───┴───┴───┘ └───┴───┴───┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_left();
+ tab.resize_up();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 14,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 30,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 30,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 6 row count"
+ );
+}
+
+#[test]
+pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() {
+ // ┌───┬───┬───┐ ┌───┬───┬───┐
+ // │ │███│ │ │ │███│ │
+ // │ │███│ │ │ ├───┤ │
+ // ├───┼───┼───┤ ==resize=up==> ├───┤ ├───┤
+ // │ │ │ │ │ │ │ │
+ // │ │ │ │ │ │ │ │
+ // └───┴───┴───┘ └───┴───┴───┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_left();
+ tab.move_focus_up();
+ tab.resize_up();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 14,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 30,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 30,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 6 row count"
+ );
+}
+
+#[test]
+pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_and_right() {
+ // ┌─┬───────┬─┐ ┌─┬───────┬─┐
+ // │ │ │ │ │ │ │ │
+ // │ │ │ │ │ ├─┬───┬─┤ │
+ // ├─┼─┬───┬─┼─┤ ==resize=up==> ├─┤ │███│ ├─┤
+ // │ │ │███│ │ │ │ │ │███│ │ │
+ // │ │ │███│ │ │ │ │ │███│ │ │
+ // └─┴─┴───┴─┴─┘ └─┴─┴───┴─┴─┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_down();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_left();
+ tab.vertical_split(PaneId::Terminal(7));
+ tab.vertical_split(PaneId::Terminal(8));
+ tab.move_focus_left();
+ tab.resize_up();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 30,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 14,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 15,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 6 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 77,
+ "pane 7 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 14,
+ "pane 7 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 7,
+ "pane 7 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 7 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 85,
+ "pane 8 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 14,
+ "pane 8 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 6,
+ "pane 8 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 8 row count"
+ );
+}
+
+#[test]
+pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_right() {
+ // ┌─┬─┬───┬─┬─┐ ┌─┬─┬───┬─┬─┐
+ // │ │ │███│ │ │ │ │ │███│ │ │
+ // │ │ │███│ │ │ │ ├─┴───┴─┤ │
+ // ├─┼─┴───┴─┼─┤ ==resize=up==> ├─┤ ├─┤
+ // │ │ │ │ │ │ │ │
+ // │ │ │ │ │ │ │ │
+ // └─┴───────┴─┘ └─┴───────┴─┘
+ // █ == focused pane
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 30,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.move_focus_up();
+ tab.vertical_split(PaneId::Terminal(3));
+ tab.vertical_split(PaneId::Terminal(4));
+ tab.move_focus_down();
+ tab.vertical_split(PaneId::Terminal(5));
+ tab.vertical_split(PaneId::Terminal(6));
+ tab.move_focus_up();
+ tab.move_focus_left();
+ tab.vertical_split(PaneId::Terminal(7));
+ tab.vertical_split(PaneId::Terminal(8));
+ tab.move_focus_left();
+ tab.resize_up();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 1 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 1 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 1 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 1 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 0,
+ "pane 2 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 2 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 60,
+ "pane 2 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 2 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 3 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 3 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 15,
+ "pane 3 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(3))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 3 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 4 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 4 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 4 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(4))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 15,
+ "pane 4 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 61,
+ "pane 5 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 14,
+ "pane 5 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 30,
+ "pane 5 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(5))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 16,
+ "pane 5 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 92,
+ "pane 6 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 16,
+ "pane 6 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 29,
+ "pane 6 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(6))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 14,
+ "pane 6 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 77,
+ "pane 7 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 7 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 7,
+ "pane 7 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(7))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 7 row count"
+ );
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .x,
+ 85,
+ "pane 8 x position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .y,
+ 0,
+ "pane 8 y position"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .cols,
+ 6,
+ "pane 8 column count"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(8))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 13,
+ "pane 8 row count"
+ );
+}
+
+#[test]
+pub fn cannot_resize_up_when_pane_above_is_at_minimum_height() {
+ // ┌───────────┐ ┌───────────┐
+ // │ │ │ │
+ // ├───────────┤ ==resize=up==> ├───────────┤
+ // │███████████│ │███████████│
+ // └───────────┘ └───────────┘
+ // █ == focused pane
+
+ let position_and_size = PositionAndSize {
+ cols: 121,
+ rows: 7,
+ x: 0,
+ y: 0,
+ ..Default::default()
+ };
+ let mut tab = create_new_tab(position_and_size);
+ tab.horizontal_split(PaneId::Terminal(2));
+ tab.resize_down();
+
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(1))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 3,
+ "pane 1 height stayed the same"
+ );
+ assert_eq!(
+ tab.panes
+ .get(&PaneId::Terminal(2))
+ .unwrap()
+ .position_and_size()
+ .rows,
+ 3,
+ "pane 2 height stayed the same"
+ );
+}