Skip to content

Commit

Permalink
feat: add moving tab to other position (#3047)
Browse files Browse the repository at this point in the history
* feat: add moving tab to other position

* docs(changelog): revert changes

* test: update config snapshots

* refactor: get rid of HorizontalDirection enum

* refactor: cleanup code order

* refactor: use debug! instead of info!

* refactor: use more defensive way to switch tabs

* refactor: revert tip changes

* refactor: code formatting

* refactor: improve invalid input notification

* refactor: inline fns for calculating target index

---------

Co-authored-by: Jae-Heon Ji <atx6419@gmail.com>
  • Loading branch information
devzbysiu and jaeheonji authored Feb 18, 2024
1 parent b677ffe commit dd5ea26
Show file tree
Hide file tree
Showing 31 changed files with 2,007 additions and 7 deletions.
9 changes: 9 additions & 0 deletions default-plugins/status-bar/src/tip/data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod compact_layout;
mod edit_scrollbuffer;
mod floating_panes_mouse;
mod move_focus_hjkl_tab_switch;
mod move_tabs;
mod quicknav;
mod send_mouse_click_to_terminal;
mod sync_tab;
Expand Down Expand Up @@ -88,5 +89,13 @@ lazy_static! {
full: compact_layout::compact_layout_full,
}
),
(
"move_tabs",
TipBody {
short: move_tabs::move_tabs_short,
medium: move_tabs::move_tabs_medium,
full: move_tabs::move_tabs_full,
}
)
]);
}
69 changes: 69 additions & 0 deletions default-plugins/status-bar/src/tip/data/move_tabs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use ansi_term::{
unstyled_len, ANSIString, ANSIStrings,
Color::{Fixed, RGB},
Style,
};

use zellij_tile::prelude::*;
use zellij_tile_utils::palette_match;

use crate::LinePart;

macro_rules! strings {
($ANSIStrings:expr) => {{
let strings: &[ANSIString] = $ANSIStrings;

let ansi_strings = ANSIStrings(strings);

LinePart {
part: format!("{}", ansi_strings),
len: unstyled_len(&ansi_strings),
}
}};
}

pub fn move_tabs_full(help: &ModeInfo) -> LinePart {
// Tip: Wrong order of tabs? You can move them to left and right with:
// Alt + i (left) and Alt + o (right)
let green_color = palette_match!(help.style.colors.green);

let bits = vec![
Style::new().paint(" Tip: "),
Style::new().paint("Wrong order of tabs? You can move them to left and right with: "),
Style::new().fg(green_color).bold().paint("Alt + i"),
Style::new().paint(" (left) and "),
Style::new().fg(green_color).bold().paint("Alt + o"),
Style::new().paint(" (right)"),
];
strings!(&bits)
}

pub fn move_tabs_medium(help: &ModeInfo) -> LinePart {
// Tip: You can move tabs to left and right with:
// Alt + i (left) and Alt + o (right)
let green_color = palette_match!(help.style.colors.green);

let bits = vec![
Style::new().paint(" Tip: "),
Style::new().paint("You can move tabs to left and right with: "),
Style::new().fg(green_color).bold().paint("Alt + i"),
Style::new().paint(" (left) and "),
Style::new().fg(green_color).bold().paint("Alt + o"),
Style::new().paint(" (right)"),
];
strings!(&bits)
}

pub fn move_tabs_short(help: &ModeInfo) -> LinePart {
// Move tabs with: Alt + i (left) and Alt + o (right)
let green_color = palette_match!(help.style.colors.green);

let bits = vec![
Style::new().paint(" Move tabs with: "),
Style::new().fg(green_color).bold().paint("Alt + i"),
Style::new().paint(" (left) and "),
Style::new().fg(green_color).bold().paint("Alt + o"),
Style::new().paint(" (right)"),
];
strings!(&bits)
}
123 changes: 123 additions & 0 deletions src/tests/e2e/cases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ use regex::Regex;
use std::fmt::Write;
use std::path::Path;

use crate::tests::e2e::steps::{
check_focus_on_second_tab, check_second_tab_opened, check_third_tab_is_left_wrapped,
check_third_tab_is_right_wrapped, check_third_tab_moved_left,
check_third_tab_moved_to_beginning, check_third_tab_opened, move_tab_left, move_tab_right,
new_tab, switch_focus_to_left_tab, type_second_tab_content,
};

use super::remote_runner::{RemoteRunner, RemoteTerminal, Step};

pub const QUIT: [u8; 1] = [17]; // ctrl-q
Expand Down Expand Up @@ -56,13 +63,19 @@ pub const SWITCH_PREV_TAB_IN_TAB_MODE: [u8; 1] = [104]; // h
pub const CLOSE_TAB_IN_TAB_MODE: [u8; 1] = [120]; // x
pub const RENAME_TAB_MODE: [u8; 1] = [114]; // r

pub const MOVE_TAB_LEFT: [u8; 2] = [27, 105]; // Alt + i
pub const MOVE_TAB_RIGHT: [u8; 2] = [27, 111]; // Alt + o

pub const SESSION_MODE: [u8; 1] = [15]; // ctrl-o
pub const DETACH_IN_SESSION_MODE: [u8; 1] = [100]; // d

pub const BRACKETED_PASTE_START: [u8; 6] = [27, 91, 50, 48, 48, 126]; // \u{1b}[200~
pub const BRACKETED_PASTE_END: [u8; 6] = [27, 91, 50, 48, 49, 126]; // \u{1b}[201
pub const SLEEP: [u8; 0] = [];

pub const SECOND_TAB_CONTENT: [u8; 14] =
[84, 97, 98, 32, 35, 50, 32, 99, 111, 110, 116, 101, 110, 116]; // Tab #2 content

pub fn sgr_mouse_report(position: Position, button: u8) -> Vec<u8> {
// button: (release is with lower case m, not supported here yet)
// 0 => left click
Expand Down Expand Up @@ -511,6 +524,116 @@ pub fn close_tab() {
assert!(!last_snapshot.contains("Tab #2"));
}

#[test]
#[ignore]
pub fn move_tab_to_left() {
let mut test_attempts = 10;
let last_snapshot = loop {
RemoteRunner::kill_running_sessions(fake_win_size());
let mut runner = RemoteRunner::new(fake_win_size())
.add_step(new_tab())
.add_step(check_second_tab_opened())
.add_step(new_tab())
.add_step(check_third_tab_opened()) // should have Tab#1 >> Tab#2 >> Tab#3 (focused on Tab#3)
.add_step(move_tab_left()); // now, it should be Tab#1 >> Tab#3 >> Tab#2

runner.run_all_steps();

let last_snapshot = runner.take_snapshot_after(check_third_tab_moved_left());
if !runner.test_timed_out || test_attempts == 0 {
break last_snapshot;
}
test_attempts -= 1;
};
assert_snapshot!(account_for_races_in_snapshot(last_snapshot));
}

fn fake_win_size() -> Size {
Size {
cols: 120,
rows: 24,
}
}

#[test]
#[ignore]
pub fn move_tab_to_right() {
let mut test_attempts = 10;
let last_snapshot = loop {
RemoteRunner::kill_running_sessions(fake_win_size());
let mut runner = RemoteRunner::new(fake_win_size())
.add_step(new_tab())
.add_step(check_second_tab_opened())
.add_step(type_second_tab_content()) // allows verifying the focus later
.add_step(new_tab())
.add_step(check_third_tab_opened())
.add_step(switch_focus_to_left_tab())
.add_step(check_focus_on_second_tab()) // should have Tab#1 >> Tab#2 >> Tab#3 (focused on Tab#2)
.add_step(move_tab_right()); // now, it should be Tab#1 >> Tab#3 >> Tab#2

runner.run_all_steps();

let last_snapshot = runner.take_snapshot_after(check_third_tab_moved_left());
if !runner.test_timed_out || test_attempts == 0 {
break last_snapshot;
}
test_attempts -= 1;
};
assert_snapshot!(account_for_races_in_snapshot(last_snapshot));
}

#[test]
#[ignore]
pub fn move_tab_to_left_until_it_wraps_around() {
let mut test_attempts = 10;
let last_snapshot = loop {
RemoteRunner::kill_running_sessions(fake_win_size());
let mut runner = RemoteRunner::new(fake_win_size())
.add_step(new_tab())
.add_step(check_second_tab_opened())
.add_step(new_tab())
.add_step(check_third_tab_opened())
.add_step(move_tab_left())
.add_step(check_third_tab_moved_left())
.add_step(move_tab_left())
.add_step(check_third_tab_moved_to_beginning()) // should have Tab#3 >> Tab#1 >> Tab#2 (focused on Tab#3)
.add_step(move_tab_left()); // now, it should be Tab#2 >> Tab#1 >> Tab#3

runner.run_all_steps();

let last_snapshot = runner.take_snapshot_after(check_third_tab_is_left_wrapped());
if !runner.test_timed_out || test_attempts == 0 {
break last_snapshot;
}
test_attempts -= 1;
};
assert_snapshot!(account_for_races_in_snapshot(last_snapshot));
}

#[test]
#[ignore]
pub fn move_tab_to_right_until_it_wraps_around() {
let mut test_attempts = 10;
let last_snapshot = loop {
RemoteRunner::kill_running_sessions(fake_win_size());
let mut runner = RemoteRunner::new(fake_win_size())
.add_step(new_tab())
.add_step(check_second_tab_opened())
.add_step(new_tab())
.add_step(check_third_tab_opened()) // should have Tab#1 >> Tab#2 >> Tab#3 (focused on Tab#3)
.add_step(move_tab_right()); // now, it should be Tab#3 >> Tab#2 >> Tab#1

runner.run_all_steps();

let last_snapshot = runner.take_snapshot_after(check_third_tab_is_right_wrapped());
if !runner.test_timed_out || test_attempts == 0 {
break last_snapshot;
}
test_attempts -= 1;
};
assert_snapshot!(account_for_races_in_snapshot(last_snapshot));
}

#[test]
#[ignore]
pub fn close_pane() {
Expand Down
1 change: 1 addition & 0 deletions src/tests/e2e/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod cases;
mod remote_runner;
mod steps;
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
source: src/tests/e2e/cases.rs
assertion_line: 531
expression: account_for_races_in_snapshot(last_snapshot)
---
Zellij (e2e-test)  Tab #1  Tab #3  Tab #2
Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
$ █ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
source: src/tests/e2e/cases.rs
expression: account_for_races_in_snapshot(last_snapshot)
---
Zellij (e2e-test)  Tab #2  Tab #1  Tab #3
Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
$ █ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
source: src/tests/e2e/cases.rs
assertion_line: 624
expression: account_for_races_in_snapshot(last_snapshot)
---
Zellij (e2e-test)  Tab #1  Tab #3  Tab #2
Pane #1 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
$ Tab #2 content█ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
Loading

0 comments on commit dd5ea26

Please sign in to comment.