Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ux): tmux mode #1073

Merged
merged 4 commits into from
Feb 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified assets/plugins/status-bar.wasm
Binary file not shown.
Binary file modified assets/plugins/strider.wasm
Binary file not shown.
Binary file modified assets/plugins/tab-bar.wasm
Binary file not shown.
15 changes: 15 additions & 0 deletions default-plugins/status-bar/src/first_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,5 +369,20 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
colored_elements,
separator,
),
InputMode::Tmux => key_indicators(
max_len,
&[
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Lock),
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Pane),
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Tab),
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Resize),
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Move),
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Scroll),
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Session),
CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit),
],
colored_elements,
separator,
),
}
}
103 changes: 103 additions & 0 deletions default-plugins/status-bar/src/second_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ fn full_shortcut_list(help: &ModeInfo, tip: TipFn) -> LinePart {
match help.mode {
InputMode::Normal => tip(help.palette),
InputMode::Locked => locked_interface_indication(help.palette),
InputMode::Tmux => full_tmux_mode_indication(help),
InputMode::RenamePane => full_shortcut_list_nonstandard_mode(select_pane_shortcut)(help),
_ => full_shortcut_list_nonstandard_mode(confirm_pane_selection)(help),
}
Expand All @@ -234,6 +235,7 @@ fn shortened_shortcut_list(help: &ModeInfo, tip: TipFn) -> LinePart {
match help.mode {
InputMode::Normal => tip(help.palette),
InputMode::Locked => locked_interface_indication(help.palette),
InputMode::Tmux => short_tmux_mode_indication(help),
InputMode::RenamePane => {
shortened_shortcut_list_nonstandard_mode(select_pane_shortcut)(help)
}
Expand Down Expand Up @@ -266,6 +268,22 @@ fn best_effort_shortcut_list_nonstandard_mode(
}
}

fn best_effort_tmux_shortcut_list(help: &ModeInfo, max_len: usize) -> LinePart {
let mut line_part = tmux_mode_indication(help);
for (i, (letter, description)) in help.keybinds.iter().enumerate() {
let shortcut = first_word_shortcut(i == 0, letter, description, help.palette);
if line_part.len + shortcut.len + MORE_MSG.chars().count() > max_len {
// TODO: better
line_part.part = format!("{}{}", line_part.part, MORE_MSG);
line_part.len += MORE_MSG.chars().count();
break;
}
line_part.len += shortcut.len;
line_part.part = format!("{}{}", line_part.part, shortcut);
}
line_part
}

fn best_effort_shortcut_list(help: &ModeInfo, tip: TipFn, max_len: usize) -> LinePart {
match help.mode {
InputMode::Normal => {
Expand All @@ -284,6 +302,7 @@ fn best_effort_shortcut_list(help: &ModeInfo, tip: TipFn, max_len: usize) -> Lin
LinePart::default()
}
}
InputMode::Tmux => best_effort_tmux_shortcut_list(help, max_len),
InputMode::RenamePane => {
best_effort_shortcut_list_nonstandard_mode(select_pane_shortcut)(help, max_len)
}
Expand Down Expand Up @@ -377,6 +396,90 @@ pub fn fullscreen_panes_to_hide(palette: &Palette, panes_to_hide: usize) -> Line
}
}

pub fn tmux_mode_indication(help: &ModeInfo) -> LinePart {
let white_color = match help.palette.white {
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
PaletteColor::EightBit(color) => Fixed(color),
};
let orange_color = match help.palette.orange {
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
PaletteColor::EightBit(color) => Fixed(color),
};

let shortcut_left_separator = Style::new().fg(white_color).bold().paint(" (");
let shortcut_right_separator = Style::new().fg(white_color).bold().paint("): ");
let tmux_mode_text = "TMUX MODE";
let tmux_mode_indicator = Style::new().fg(orange_color).bold().paint(tmux_mode_text);
let line_part = LinePart {
part: format!(
"{}{}{}",
shortcut_left_separator, tmux_mode_indicator, shortcut_right_separator
),
len: tmux_mode_text.chars().count() + 5, // 2 for the separators, 3 for the colon and following space
};
line_part
}

pub fn full_tmux_mode_indication(help: &ModeInfo) -> LinePart {
let white_color = match help.palette.white {
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
PaletteColor::EightBit(color) => Fixed(color),
};
let orange_color = match help.palette.orange {
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
PaletteColor::EightBit(color) => Fixed(color),
};

let shortcut_left_separator = Style::new().fg(white_color).bold().paint(" (");
let shortcut_right_separator = Style::new().fg(white_color).bold().paint("): ");
let tmux_mode_text = "TMUX MODE";
let tmux_mode_indicator = Style::new().fg(orange_color).bold().paint(tmux_mode_text);
let mut line_part = LinePart {
part: format!(
"{}{}{}",
shortcut_left_separator, tmux_mode_indicator, shortcut_right_separator
),
len: tmux_mode_text.chars().count() + 5, // 2 for the separators, 3 for the colon and following space
};

for (i, (letter, description)) in help.keybinds.iter().enumerate() {
let shortcut = full_length_shortcut(i == 0, letter, description, help.palette);
line_part.len += shortcut.len;
line_part.part = format!("{}{}", line_part.part, shortcut,);
}
line_part
}

pub fn short_tmux_mode_indication(help: &ModeInfo) -> LinePart {
let white_color = match help.palette.white {
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
PaletteColor::EightBit(color) => Fixed(color),
};
let orange_color = match help.palette.orange {
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
PaletteColor::EightBit(color) => Fixed(color),
};

let shortcut_left_separator = Style::new().fg(white_color).bold().paint(" (");
let shortcut_right_separator = Style::new().fg(white_color).bold().paint("): ");
let tmux_mode_text = "TMUX MODE";
let tmux_mode_indicator = Style::new().fg(orange_color).bold().paint(tmux_mode_text);
let mut line_part = LinePart {
part: format!(
"{}{}{}",
shortcut_left_separator, tmux_mode_indicator, shortcut_right_separator
),
len: tmux_mode_text.chars().count() + 5, // 2 for the separators, 3 for the colon and following space
};

for (i, (letter, description)) in help.keybinds.iter().enumerate() {
let shortcut = first_word_shortcut(i == 0, letter, description, help.palette);
line_part.len += shortcut.len;
line_part.part = format!("{}{}", line_part.part, shortcut);
}
line_part
}

pub fn locked_fullscreen_panes_to_hide(palette: &Palette, panes_to_hide: usize) -> LinePart {
let white_color = match palette.white {
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
Expand Down
49 changes: 49 additions & 0 deletions src/tests/e2e/cases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ pub const MOVE_FOCUS_LEFT_IN_NORMAL_MODE: [u8; 2] = [27, 104]; // alt-h
pub const MOVE_FOCUS_RIGHT_IN_NORMAL_MODE: [u8; 2] = [27, 108]; // alt-l

pub const PANE_MODE: [u8; 1] = [16]; // ctrl-p
pub const TMUX_MODE: [u8; 1] = [2]; // ctrl-b
pub const SPAWN_TERMINAL_IN_PANE_MODE: [u8; 1] = [110]; // n
pub const MOVE_FOCUS_IN_PANE_MODE: [u8; 1] = [112]; // p
pub const SPLIT_DOWN_IN_PANE_MODE: [u8; 1] = [100]; // d
pub const SPLIT_RIGHT_IN_PANE_MODE: [u8; 1] = [114]; // r
pub const SPLIT_RIGHT_IN_TMUX_MODE: [u8; 1] = [37]; // %
pub const TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE: [u8; 1] = [102]; // f
pub const TOGGLE_FLOATING_PANES: [u8; 1] = [119]; // w
pub const CLOSE_PANE_IN_PANE_MODE: [u8; 1] = [120]; // x
Expand Down Expand Up @@ -1748,3 +1750,50 @@ pub fn focus_tab_with_layout() {
};
assert_snapshot!(last_snapshot);
}

#[test]
#[ignore]
pub fn tmux_mode() {
let fake_win_size = Size {
cols: 120,
rows: 24,
};

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(Step {
name: "Split pane to the right",
instruction: |mut remote_terminal: RemoteTerminal| -> bool {
let mut step_is_complete = false;
if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2)
{
remote_terminal.send_key(&TMUX_MODE);
remote_terminal.send_key(&SPLIT_RIGHT_IN_TMUX_MODE);
// back to normal mode after split
step_is_complete = true;
}
step_is_complete
},
});
runner.run_all_steps();
let last_snapshot = runner.take_snapshot_after(Step {
name: "Wait for new pane to appear",
instruction: |remote_terminal: RemoteTerminal| -> bool {
let mut step_is_complete = false;
if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() {
// cursor is in the newly opened second pane
step_is_complete = true;
}
step_is_complete
},
});
if runner.test_timed_out && test_attempts > 0 {
test_attempts -= 1;
continue;
} else {
break last_snapshot;
}
};
assert_snapshot!(last_snapshot);
}
29 changes: 29 additions & 0 deletions src/tests/e2e/snapshots/zellij__tests__e2e__cases__tmux_mode.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
source: src/tests/e2e/cases.rs
expression: last_snapshot

---
Zellij (e2e-test)  Tab #1 
┌ Pane #1 ─────────────────────────────────────────────────┐┌ Pane #2 ─────────────────────────────────────────────────┐
│$ ││$ █ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SCROLL  <o> SESSION  <q> QUIT 
Tip: Alt + <n> => new pane. Alt + <[] or hjkl> => navigate. Alt + <+-> => resize pane.
2 changes: 1 addition & 1 deletion zellij-server/src/panes/plugin_pane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ impl Pane for PluginPane {
.unwrap();
}
fn clear_scroll(&mut self) {
unimplemented!();
// noop
}
fn start_selection(&mut self, start: &Position, client_id: ClientId) {
self.send_plugin_instructions
Expand Down
4 changes: 4 additions & 0 deletions zellij-tile/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ pub enum InputMode {
/// `Prompt` mode allows interacting with active prompts.
#[serde(alias = "prompt")]
Prompt,
/// `Tmux` mode allows for basic tmux keybindings functionality
#[serde(alias = "tmux")]
Tmux,
}

impl Default for InputMode {
Expand Down Expand Up @@ -164,6 +167,7 @@ impl FromStr for InputMode {
"renametab" => Ok(InputMode::RenameTab),
"session" => Ok(InputMode::Session),
"move" => Ok(InputMode::Move),
"tmux" => Ok(InputMode::Tmux),
"prompt" => Ok(InputMode::Prompt),
"renamepane" => Ok(InputMode::RenamePane),
e => Err(e.to_string().into()),
Expand Down
71 changes: 71 additions & 0 deletions zellij-utils/assets/config/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ keybinds:
key: [Ctrl: 'o',]
- action: [SwitchToMode: Move,]
key: [Ctrl: 'h',]
- action: [SwitchToMode: Tmux,]
key: [Ctrl: 'b',]
- action: [Quit,]
key: [Ctrl: 'q',]
- action: [NewPane: ]
Expand Down Expand Up @@ -62,6 +64,8 @@ keybinds:
key: [Ctrl: 'o',]
- action: [SwitchToMode: Move,]
key: [Ctrl: 'h',]
- action: [SwitchToMode: Tmux,]
key: [Ctrl: 'b',]
- action: [Quit]
key: [Ctrl: 'q']
- action: [Resize: Left,]
Expand Down Expand Up @@ -113,6 +117,8 @@ keybinds:
key: [Ctrl: 'o',]
- action: [SwitchToMode: Move,]
key: [Ctrl: 'h',]
- action: [SwitchToMode: Tmux,]
key: [Ctrl: 'b',]
- action: [Quit,]
key: [Ctrl: 'q',]
- action: [MoveFocus: Left,]
Expand Down Expand Up @@ -223,6 +229,8 @@ keybinds:
key: [Ctrl: 's']
- action: [SwitchToMode: Move,]
key: [Ctrl: 'h',]
- action: [SwitchToMode: Tmux,]
key: [Ctrl: 'b',]
- action: [SwitchToMode: Session,]
key: [Ctrl: 'o',]
- action: [SwitchToMode: RenameTab, TabNameInput: [0],]
Expand Down Expand Up @@ -290,6 +298,8 @@ keybinds:
key: [Ctrl: 'p',]
- action: [SwitchToMode: Move,]
key: [Ctrl: 'h',]
- action: [SwitchToMode: Tmux,]
key: [Ctrl: 'b',]
- action: [SwitchToMode: Session,]
key: [Ctrl: 'o',]
- action: [SwitchToMode: Resize,]
Expand Down Expand Up @@ -389,6 +399,8 @@ keybinds:
key: [Ctrl: 'p',]
- action: [SwitchToMode: Move,]
key: [Ctrl: 'h',]
- action: [SwitchToMode: Tmux,]
key: [Ctrl: 'b',]
- action: [SwitchToMode: Tab,]
key: [Ctrl: 't',]
- action: [SwitchToMode: Normal,]
Expand Down Expand Up @@ -419,6 +431,65 @@ keybinds:
key: [ Alt: '+']
- action: [Resize: Decrease,]
key: [ Alt: '-']
tmux:
- action: [SwitchToMode: Locked,]
key: [Ctrl: 'g']
- action: [SwitchToMode: Resize,]
key: [Ctrl: 'n',]
- action: [SwitchToMode: Pane,]
key: [Ctrl: 'p',]
- action: [SwitchToMode: Move,]
key: [Ctrl: 'h',]
- action: [SwitchToMode: Tab,]
key: [Ctrl: 't',]
- action: [SwitchToMode: Normal,]
key: [Ctrl: 'o', Char: "\n", Char: ' ', Esc]
- action: [SwitchToMode: Scroll,]
key: [Ctrl: 's']
- action: [Quit,]
key: [Ctrl: 'q',]
- action: [NewPane: Down, SwitchToMode: Normal,]
key: [Char: "\"",]
- action: [NewPane: Right, SwitchToMode: Normal,]
key: [Char: '%',]
- action: [ToggleFocusFullscreen, SwitchToMode: Normal,]
key: [Char: 'z',]
- action: [NewTab: , SwitchToMode: Normal,]
key: [ Char: 'c',]
- action: [SwitchToMode: RenameTab, TabNameInput: [0],]
key: [Char: ',']
- action: [GoToPreviousTab, SwitchToMode: Normal,]
key: [ Char: 'p']
- action: [GoToNextTab, SwitchToMode: Normal,]
key: [ Char: 'n']
- action: [MoveFocus: Left, SwitchToMode: Normal,]
key: [ Left,]
- action: [MoveFocus: Right, SwitchToMode: Normal,]
key: [ Right,]
- action: [MoveFocus: Down, SwitchToMode: Normal,]
key: [ Down,]
- action: [MoveFocus: Up, SwitchToMode: Normal,]
key: [ Up,]
- action: [NewPane: ,]
key: [ Alt: 'n',]
- action: [MoveFocus: Left,]
key: [ Alt: 'h',]
- action: [MoveFocus: Right,]
key: [ Alt: 'l',]
- action: [MoveFocus: Down,]
key: [ Alt: 'j',]
- action: [MoveFocus: Up,]
key: [ Alt: 'k',]
- action: [FocusPreviousPane,]
key: [ Alt: '[',]
- action: [FocusNextPane,]
key: [ Alt: ']',]
- action: [Resize: Increase,]
key: [ Alt: '=']
- action: [Resize: Increase,]
key: [ Alt: '+']
- action: [Resize: Decrease,]
key: [ Alt: '-']
plugins:
- path: tab-bar
tag: tab-bar
Expand Down
Loading