diff options
| author | a-kenji <aks.kenji@protonmail.com> | 2021-03-26 23:33:36 +0100 |
|---|---|---|
| committer | a-kenji <aks.kenji@protonmail.com> | 2021-03-26 23:33:36 +0100 |
| commit | 84488a35aa2cef3505e9b40f7f0345cff73d62c8 (patch) | |
| tree | 880d5019c40675177ea0402a186f6826d2bffa6f /src | |
| parent | Config: Fix README (diff) | |
| parent | feat(plugin): refactored to a new and more general plugin API (diff) | |
| download | sl0ppij-84488a35aa2cef3505e9b40f7f0345cff73d62c8.tar.gz sl0ppij-84488a35aa2cef3505e9b40f7f0345cff73d62c8.tar.xz sl0ppij-84488a35aa2cef3505e9b40f7f0345cff73d62c8.zip | |
Merge branch 'main' of https://github.com/zellij-org/zellij into config-file
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/boundaries.rs | 128 | ||||
| -rw-r--r-- | src/client/layout.rs | 8 | ||||
| -rw-r--r-- | src/client/panes/plugin_pane.rs | 2 | ||||
| -rw-r--r-- | src/client/panes/terminal_character.rs | 10 | ||||
| -rw-r--r-- | src/client/panes/terminal_pane.rs | 36 | ||||
| -rw-r--r-- | src/client/tab.rs | 193 | ||||
| -rw-r--r-- | src/common/errors.rs | 24 | ||||
| -rw-r--r-- | src/common/input/actions.rs | 6 | ||||
| -rw-r--r-- | src/common/input/handler.rs | 137 | ||||
| -rw-r--r-- | src/common/input/keybinds.rs | 8 | ||||
| -rw-r--r-- | src/common/input/unit/keybinds_test.rs | 2 | ||||
| -rw-r--r-- | src/common/ipc.rs | 8 | ||||
| -rw-r--r-- | src/common/mod.rs | 197 | ||||
| -rw-r--r-- | src/common/os_input_output.rs | 13 | ||||
| -rw-r--r-- | src/common/screen.rs | 50 | ||||
| -rw-r--r-- | src/common/utils/consts.rs | 2 | ||||
| -rw-r--r-- | src/common/wasm_vm.rs | 62 | ||||
| -rw-r--r-- | src/tests/fakes.rs | 11 | ||||
| -rw-r--r-- | src/tests/integration/expansion_boundary.rs | 11 | ||||
| -rw-r--r-- | src/tests/integration/resize_down.rs | 16 | ||||
| -rw-r--r-- | src/tests/integration/resize_left.rs | 15 | ||||
| -rw-r--r-- | src/tests/integration/resize_right.rs | 15 | ||||
| -rw-r--r-- | src/tests/integration/resize_up.rs | 15 | ||||
| -rw-r--r-- | src/tests/utils.rs | 1 |
24 files changed, 469 insertions, 501 deletions
diff --git a/src/client/boundaries.rs b/src/client/boundaries.rs index 67733c12..e498da89 100644 --- a/src/client/boundaries.rs +++ b/src/client/boundaries.rs @@ -1,5 +1,7 @@ use crate::tab::Pane; +use ansi_term::Colour; use std::collections::HashMap; +use zellij_tile::data::InputMode; use std::fmt::{Display, Error, Formatter}; @@ -17,12 +19,20 @@ pub mod boundary_type { pub const CROSS: &str = "┼"; } +pub mod colors { + use ansi_term::Colour::{self, Fixed}; + pub const WHITE: Colour = Fixed(255); + pub const GREEN: Colour = Fixed(154); + pub const GRAY: Colour = Fixed(238); +} + pub type BoundaryType = &'static str; // easy way to refer to boundary_type above #[derive(Clone, Copy, Debug)] pub struct BoundarySymbol { boundary_type: BoundaryType, invisible: bool, + color: Option<Colour>, } impl BoundarySymbol { @@ -30,20 +40,27 @@ impl BoundarySymbol { BoundarySymbol { boundary_type, invisible: false, + color: Some(colors::GRAY), } } pub fn invisible(mut self) -> Self { self.invisible = true; self } + pub fn color(&mut self, color: Option<Colour>) -> Self { + self.color = color; + *self + } } impl Display for BoundarySymbol { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - if self.invisible { - write!(f, " ") - } else { - write!(f, "{}", self.boundary_type) + match self.invisible { + true => write!(f, " "), + false => match self.color { + Some(color) => write!(f, "{}", color.paint(self.boundary_type)), + None => write!(f, "{}", self.boundary_type), + }, } } } @@ -53,6 +70,10 @@ fn combine_symbols( next_symbol: BoundarySymbol, ) -> Option<BoundarySymbol> { let invisible = current_symbol.invisible || next_symbol.invisible; + let color = match (current_symbol.color.is_some(), next_symbol.color.is_some()) { + (true, _) => current_symbol.color, + _ => next_symbol.color, + }; let current_symbol = current_symbol.boundary_type; let next_symbol = next_symbol.boundary_type; match (current_symbol, next_symbol) { @@ -62,6 +83,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_RIGHT, boundary_type::VERTICAL) => { @@ -70,6 +92,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_RIGHT, boundary_type::HORIZONTAL) => { @@ -78,6 +101,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_RIGHT, boundary_type::TOP_LEFT) => { @@ -86,6 +110,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_RIGHT, boundary_type::BOTTOM_RIGHT) => { @@ -94,6 +119,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_RIGHT, boundary_type::BOTTOM_LEFT) => { @@ -102,6 +128,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_RIGHT, boundary_type::VERTICAL_LEFT) => { @@ -110,6 +137,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_RIGHT, boundary_type::VERTICAL_RIGHT) => { @@ -118,6 +146,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_RIGHT, boundary_type::HORIZONTAL_DOWN) => { @@ -126,6 +155,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_RIGHT, boundary_type::HORIZONTAL_UP) => { @@ -134,6 +164,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_RIGHT, boundary_type::CROSS) => { @@ -142,6 +173,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL, boundary_type::HORIZONTAL) => { @@ -150,6 +182,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL, boundary_type::VERTICAL) => { @@ -158,6 +191,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL, boundary_type::TOP_LEFT) => { @@ -166,6 +200,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL, boundary_type::BOTTOM_RIGHT) => { @@ -174,6 +209,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL, boundary_type::BOTTOM_LEFT) => { @@ -182,6 +218,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL, boundary_type::VERTICAL_LEFT) => { @@ -190,6 +227,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL, boundary_type::VERTICAL_RIGHT) => { @@ -198,6 +236,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL, boundary_type::HORIZONTAL_DOWN) => { @@ -206,6 +245,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL, boundary_type::HORIZONTAL_UP) => { @@ -214,6 +254,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL, boundary_type::CROSS) => { @@ -222,6 +263,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL, boundary_type::VERTICAL) => { @@ -230,6 +272,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL, boundary_type::TOP_LEFT) => { @@ -238,6 +281,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL, boundary_type::BOTTOM_RIGHT) => { @@ -246,6 +290,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL, boundary_type::BOTTOM_LEFT) => { @@ -254,6 +299,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL, boundary_type::VERTICAL_LEFT) => { @@ -262,6 +308,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL, boundary_type::VERTICAL_RIGHT) => { @@ -270,6 +317,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL, boundary_type::HORIZONTAL_DOWN) => { @@ -278,6 +326,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL, boundary_type::HORIZONTAL_UP) => { @@ -286,6 +335,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL, boundary_type::CROSS) => { @@ -294,6 +344,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_LEFT, boundary_type::TOP_LEFT) => { @@ -302,6 +353,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_LEFT, boundary_type::BOTTOM_RIGHT) => { @@ -310,6 +362,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_LEFT, boundary_type::BOTTOM_LEFT) => { @@ -318,6 +371,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_LEFT, boundary_type::VERTICAL_LEFT) => { @@ -326,6 +380,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_LEFT, boundary_type::VERTICAL_RIGHT) => { @@ -334,6 +389,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_LEFT, boundary_type::HORIZONTAL_DOWN) => { @@ -342,6 +398,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_LEFT, boundary_type::HORIZONTAL_UP) => { @@ -350,6 +407,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::TOP_LEFT, boundary_type::CROSS) => { @@ -358,6 +416,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_RIGHT, boundary_type::BOTTOM_RIGHT) => { @@ -366,6 +425,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_RIGHT, boundary_type::BOTTOM_LEFT) => { @@ -374,6 +434,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_RIGHT, boundary_type::VERTICAL_LEFT) => { @@ -382,6 +443,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_RIGHT, boundary_type::VERTICAL_RIGHT) => { @@ -390,6 +452,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_RIGHT, boundary_type::HORIZONTAL_DOWN) => { @@ -398,6 +461,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_RIGHT, boundary_type::HORIZONTAL_UP) => { @@ -406,6 +470,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_RIGHT, boundary_type::CROSS) => { @@ -414,6 +479,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_LEFT, boundary_type::BOTTOM_LEFT) => { @@ -422,6 +488,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_LEFT, boundary_type::VERTICAL_LEFT) => { @@ -430,6 +497,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_LEFT, boundary_type::VERTICAL_RIGHT) => { @@ -438,6 +506,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_LEFT, boundary_type::HORIZONTAL_DOWN) => { @@ -446,6 +515,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_LEFT, boundary_type::HORIZONTAL_UP) => { @@ -454,6 +524,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::BOTTOM_LEFT, boundary_type::CROSS) => { @@ -462,6 +533,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL_LEFT, boundary_type::VERTICAL_LEFT) => { @@ -470,6 +542,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL_LEFT, boundary_type::VERTICAL_RIGHT) => { @@ -478,6 +551,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL_LEFT, boundary_type::HORIZONTAL_DOWN) => { @@ -486,6 +560,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL_LEFT, boundary_type::HORIZONTAL_UP) => { @@ -494,6 +569,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL_LEFT, boundary_type::CROSS) => { @@ -502,6 +578,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL_RIGHT, boundary_type::VERTICAL_RIGHT) => { @@ -510,6 +587,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL_RIGHT, boundary_type::HORIZONTAL_DOWN) => { @@ -518,6 +596,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL_RIGHT, boundary_type::HORIZONTAL_UP) => { @@ -526,6 +605,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::VERTICAL_RIGHT, boundary_type::CROSS) => { @@ -534,6 +614,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL_DOWN, boundary_type::HORIZONTAL_DOWN) => { @@ -542,6 +623,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL_DOWN, boundary_type::HORIZONTAL_UP) => { @@ -550,6 +632,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL_DOWN, boundary_type::CROSS) => { @@ -558,6 +641,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL_UP, boundary_type::HORIZONTAL_UP) => { @@ -566,6 +650,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::HORIZONTAL_UP, boundary_type::CROSS) => { @@ -574,6 +659,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (boundary_type::CROSS, boundary_type::CROSS) => { @@ -582,6 +668,7 @@ fn combine_symbols( Some(BoundarySymbol { boundary_type, invisible, + color, }) } (_, _) => None, @@ -677,7 +764,14 @@ impl Boundaries { boundary_characters: HashMap::new(), } } - pub fn add_rect(&mut self, rect: &dyn Pane) { + pub fn add_rect(&mut self, rect: &dyn Pane, input_mode: InputMode, color: Option<Colour>) { + let color = match color.is_some() { + true => match input_mode { + InputMode::Normal | InputMode::Locked => Some(colors::GREEN), + _ => Some(colors::WHITE), + }, + false => None, + }; if rect.x() > 0 { let boundary_x_coords = rect.x() - 1; let first_row_coordinates = self.rect_right_boundary_row_start(rect); @@ -685,11 +779,11 @@ impl Boundaries { for row in first_row_coordinates..last_row_coordinates { let coordinates = Coordinates::new(boundary_x_coords, row); let mut symbol_to_add = if row == first_row_coordinates && row != 0 { - BoundarySymbol::new(boundary_type::TOP_LEFT) + BoundarySymbol::new(boundary_type::TOP_LEFT).color(color) } else if row == last_row_coordinates - 1 && row != self.rows - 1 { - BoundarySymbol::new(boundary_type::BOTTOM_LEFT) + BoundarySymbol::new(boundary_type::BOTTOM_LEFT).color(color) } else { - BoundarySymbol::new(boundary_type::VERTICAL) + BoundarySymbol::new(boundary_type::VERTICAL).color(color) }; if rect.invisible_borders() { symbol_to_add = symbol_to_add.invisible(); @@ -709,11 +803,11 @@ impl Boundaries { for col in first_col_coordinates..last_col_coordinates { let coordinates = Coordinates::new(col, boundary_y_coords); let mut symbol_to_add = if col == first_col_coordinates && col != 0 { - BoundarySymbol::new(boundary_type::TOP_LEFT) + BoundarySymbol::new(boundary_type::TOP_LEFT).color(color) } else if col == last_col_coordinates - 1 && col != self.columns - 1 { - BoundarySymbol::new(boundary_type::TOP_RIGHT) + BoundarySymbol::new(boundary_type::TOP_RIGHT).color(color) } else { - BoundarySymbol::new(boundary_type::HORIZONTAL) + BoundarySymbol::new(boundary_type::HORIZONTAL).color(color) }; if rect.invisible_borders() { symbol_to_add = symbol_to_add.invisible(); @@ -734,11 +828,11 @@ impl Boundaries { for row in first_row_coordinates..last_row_coordinates { let coordinates = Coordinates::new(boundary_x_coords, row); let mut symbol_to_add = if row == first_row_coordinates && row != 0 { - BoundarySymbol::new(boundary_type::TOP_RIGHT) + BoundarySymbol::new(boundary_type::TOP_RIGHT).color(color) } else if row == last_row_coordinates - 1 && row != self.rows - 1 { - BoundarySymbol::new(boundary_type::BOTTOM_RIGHT) + BoundarySymbol::new(boundary_type::BOTTOM_RIGHT).color(color) } else { - BoundarySymbol::new(boundary_type::VERTICAL) + BoundarySymbol::new(boundary_type::VERTICAL).color(color) }; if rect.invisible_borders() { symbol_to_add = symbol_to_add.invisible(); @@ -758,11 +852,11 @@ impl Boundaries { for col in first_col_coordinates..last_col_coordinates { let coordinates = Coordinates::new(col, boundary_y_coords); let mut symbol_to_add = if col == first_col_coordinates && col != 0 { - BoundarySymbol::new(boundary_type::BOTTOM_LEFT) + BoundarySymbol::new(boundary_type::BOTTOM_LEFT).color(color) } else if col == last_col_coordinates - 1 && col != self.columns - 1 { - BoundarySymbol::new(boundary_type::BOTTOM_RIGHT) + BoundarySymbol::new(boundary_type::BOTTOM_RIGHT).color(color) } else { - BoundarySymbol::new(boundary_type::HORIZONTAL) + BoundarySymbol::new(boundary_type::HORIZONTAL).color(color) }; if rect.invisible_borders() { symbol_to_add = symbol_to_add.invisible(); diff --git a/src/client/layout.rs b/src/client/layout.rs index 1b383540..2d1daaf4 100644 --- a/src/client/layout.rs +++ b/src/client/layout.rs @@ -1,10 +1,8 @@ -use crate::utils::consts::ZELLIJ_ROOT_LAYOUT_DIR; use directories_next::ProjectDirs; use serde::{Deserialize, Serialize}; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::{fs::File, io::prelude::*}; -use crate::common::wasm_vm::EventType; use crate::panes::PositionAndSize; fn split_space_to_parts_vertically( @@ -181,19 +179,15 @@ pub struct Layout { pub plugin: Option<PathBuf>, #[serde(default)] pub expansion_boundary: bool, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub events: Vec<EventType>, } impl Layout { pub fn new(layout_path: PathBuf) -> Self { let project_dirs = ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap(); let layout_dir = project_dirs.data_dir().join("layouts/"); - let root_layout_dir = Path::new(ZELLIJ_ROOT_LAYOUT_DIR); let mut layout_file = File::open(&layout_path) .or_else(|_| File::open(&layout_path.with_extension("yaml"))) .or_else(|_| File::open(&layout_dir.join(&layout_path).with_extension("yaml"))) - .or_else(|_| File::open(root_layout_dir.join(&layout_path).with_extension("yaml"))) .unwrap_or_else(|_| panic!("cannot find layout {}", &layout_path.display())); let mut layout = String::new(); diff --git a/src/client/panes/plugin_pane.rs b/src/client/panes/plugin_pane.rs index 588cffd6..4cffff5f 100644 --- a/src/client/panes/plugin_pane.rs +++ b/src/client/panes/plugin_pane.rs @@ -120,7 +120,7 @@ impl Pane for PluginPane { let (buf_tx, buf_rx) = channel(); self.send_plugin_instructions - .send(PluginInstruction::Draw( + .send(PluginInstruction::Render( buf_tx, self.pid, self.rows(), diff --git a/src/client/panes/terminal_character.rs b/src/client/panes/terminal_character.rs index 80c3162b..053ebd3f 100644 --- a/src/client/panes/terminal_character.rs +++ b/src/client/panes/terminal_character.rs @@ -23,7 +23,7 @@ pub enum AnsiCode { On, Reset, NamedColor(NamedColor), - RGBCode((u8, u8, u8)), + RgbCode((u8, u8, u8)), ColorIndex(u8), } @@ -336,7 +336,7 @@ impl CharacterStyles { [36, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::Cyan))), [37, ..] => *self = self.foreground(Some(AnsiCode::NamedColor(NamedColor::White))), [38, 2, ..] => { - let ansi_code = AnsiCode::RGBCode(( + let ansi_code = AnsiCode::RgbCode(( *ansi_params.get(2).unwrap() as u8, *ansi_params.get(3).unwrap() as u8, *ansi_params.get(4).unwrap() as u8, @@ -364,7 +364,7 @@ impl CharacterStyles { [46, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::Cyan))), [47, ..] => *self = self.background(Some(AnsiCode::NamedColor(NamedColor::White))), [48, 2, ..] => { - let ansi_code = AnsiCode::RGBCode(( + let ansi_code = AnsiCode::RgbCode(( *ansi_params.get(2).unwrap() as u8, *ansi_params.get(3).unwrap() as u8, *ansi_params.get(4).unwrap() as u8, @@ -416,7 +416,7 @@ impl Display for CharacterStyles { } if let Some(ansi_code) = self.foreground { match ansi_code { - AnsiCode::RGBCode((r, g, b)) => { + AnsiCode::RgbCode((r, g, b)) => { write!(f, "\u{1b}[38;2;{};{};{}m", r, g, b)?; } AnsiCode::ColorIndex(color_index) => { @@ -433,7 +433,7 @@ impl Display for CharacterStyles { }; if let Some(ansi_code) = self.background { match ansi_code { - AnsiCode::RGBCode((r, g, b)) => { + AnsiCode::RgbCode((r, g, b)) => { write!(f, "\u{1b}[48;2;{};{};{}m", r, g, b)?; } AnsiCode::ColorIndex(color_index) => { diff --git a/src/client/panes/terminal_pane.rs b/src/client/panes/terminal_pane.rs index fd83d571..f0b15e50 100644 --- a/src/client/panes/terminal_pane.rs +++ b/src/client/panes/terminal_pane.rs @@ -70,13 +70,11 @@ impl Pane for TerminalPane { fn reset_size_and_position_override(&mut self) { self.position_and_size_override = None; self.reflow_lines(); - self.mark_for_rerender(); } fn change_pos_and_size(&mut self, position_and_size: &PositionAndSize) { self.position_and_size.columns = position_and_size.columns; self.position_and_size.rows = position_and_size.rows; self.reflow_lines(); - self.mark_for_rerender(); } fn override_size_and_position(&mut self, x: usize, y: usize, size: &PositionAndSize) { let position_and_size_override = PositionAndSize { @@ -87,7 +85,6 @@ impl Pane for TerminalPane { }; self.position_and_size_override = Some(position_and_size_override); self.reflow_lines(); - self.mark_for_rerender(); } fn handle_event(&mut self, event: VteEvent) { match event { @@ -191,12 +188,14 @@ impl Pane for TerminalPane { self.max_height } fn render(&mut self) -> Option<String> { - // if self.should_render { + // FIXME: + // the below conditional is commented out because it causes several bugs: + // 1. When panes are resized or tabs are switched the previous contents of the screen stick + // around + // 2. When there are wide characters in a pane, since we don't yet handle them properly, + // the spill over to the pane to the right + // if self.should_render || cfg!(test) { if true { - // while checking should_render rather than rendering each pane every time - // is more performant, it causes some problems when the pane to the left should be - // rendered and has wide characters (eg. Chinese characters or emoji) - // as a (hopefully) temporary hack, we render all panes until we find a better solution let mut vte_output = String::new(); let buffer_lines = &self.read_buffer_as_lines(); let display_cols = self.get_columns(); @@ -205,12 +204,11 @@ impl Pane for TerminalPane { for line_index in 0..self.grid.height { let x = self.get_x(); let y = self.get_y(); - vte_output = format!( - "{}\u{1b}[{};{}H\u{1b}[m", - vte_output, + vte_output.push_str(&format!( + "\u{1b}[{};{}H\u{1b}[m", y + line_index + 1, x + 1 - ); // goto row/col and reset styles + )); // goto row/col and reset styles for _col_index in 0..self.grid.width { vte_output.push(EMPTY_TERMINAL_CHARACTER.character); } @@ -220,7 +218,7 @@ impl Pane for TerminalPane { for (row, line) in buffer_lines.iter().enumerate() { let x = self.get_x(); let y = self.get_y(); - vte_output = format!("{}\u{1b}[{};{}H\u{1b}[m", vte_output, y + row + 1, x + 1); // goto row/col and reset styles + vte_output.push_str(&format!("\u{1b}[{};{}H\u{1b}[m", y + row + 1, x + 1)); // goto row/col and reset styles for (col, t_character) in line.iter().enumerate() { if col < display_cols { // in some cases (eg. while resizing) some characters will spill over @@ -232,14 +230,14 @@ impl Pane for TerminalPane { // the terminal keeps the previous styles as long as we're in the same // line, so we only want to update the new styles here (this also // includes resetting previous styles as needed) - vte_output = format!("{}{}", vte_output, new_styles); + vte_output.push_str(&new_styles.to_string()); } vte_output.push(t_character.character); } } character_styles.clear(); } - self.mark_for_rerender(); + self.should_render = false; Some(vte_output) } else { None @@ -252,45 +250,37 @@ impl Pane for TerminalPane { self.position_and_size.y += count; self.position_and_size.rows -= count; self.reflow_lines(); - self.mark_for_rerender(); } fn increase_height_down(&mut self, count: usize) { self.position_and_size.rows += count; self.reflow_lines(); - self.mark_for_rerender(); } fn increase_height_up(&mut self, count: usize) { self.position_and_size.y -= count; self.position_and_size.rows += count; self.reflow_lines(); - self.mark_for_rerender(); } fn reduce_height_up(&mut self, count: usize) { self.position_and_size.rows -= count; self.reflow_lines(); - self.mark_for_rerender(); } fn reduce_width_right(&mut self, count: usize) { self.position_and_size.x += count; self.position_and_size.columns -= count; self.reflow_lines(); - self.mark_for_rerender(); } fn reduce_width_left(&mut self, count: usize) { self.position_and_size.columns -= count; self.reflow_lines(); - self.mark_for_rerender(); } fn increase_width_left(&mut self, count: usize) { self.position_and_size.x -= count; self.position_and_size.columns += count; self.reflow_lines(); - self.mark_for_rerender(); } fn increase_width_right(&mut self, count: usize) { self.position_and_size.columns += count; self.reflow_lines(); - self.mark_for_rerender(); } fn scroll_up(&mut self, count: usize) { self.grid.move_viewport_up(count); diff --git a/src/client/tab.rs b/src/client/tab.rs index 1ef0b720..1e56fd8b 100644 --- a/src/client/tab.rs +++ b/src/client/tab.rs @@ -1,20 +1,21 @@ //! `Tab`s holds multiple panes. It tracks their coordinates (x/y) and size, //! as well as how they should be resized -use crate::common::{AppInstruction, SenderWithContext}; +use crate::boundaries::colors; +use crate::common::{input::handler::parse_keys, AppInstruction, SenderWithContext}; use crate::layout::Layout; use crate::panes::{PaneId, PositionAndSize, TerminalPane}; use crate::pty_bus::{PtyInstruction, VteEvent}; -use crate::wasm_vm::{PluginInputType, PluginInstruction}; +use crate::wasm_vm::PluginInstruction; use crate::{boundaries::Boundaries, panes::PluginPane}; use crate::{os_input_output::OsApi, utils::shared::pad_to_size}; -use serde::{Deserialize, Serialize}; use std::os::unix::io::RawFd; use std::{ cmp::Reverse, collections::{BTreeMap, HashSet}, }; use std::{io::Write, sync::mpsc::channel}; +use zellij_tile::data::{Event, InputMode}; const CURSOR_HEIGHT_WIDTH_RATIO: usize = 4; // this is not accurate and kind of a magic number, TODO: look into this const MIN_TERMINAL_HEIGHT: usize = 2; @@ -65,14 +66,7 @@ pub struct Tab { pub send_plugin_instructions: SenderWithContext<PluginInstruction>, pub send_app_instructions: SenderWithContext<AppInstruction>, expansion_boundary: Option<PositionAndSize>, -} - -#[derive(Clone, Debug, Default, Serialize, Deserialize)] -pub struct TabData { - /* subset of fields to publish to plugins */ - pub position: usize, - pub name: String, - pub active: bool, + pub input_mode: InputMode, } // FIXME: Use a struct that has a pane_type enum, to reduce all of the duplication @@ -189,6 +183,7 @@ impl Tab { send_app_instructions: SenderWithContext<AppInstruction>, max_panes: Option<usize>, pane_id: Option<PaneId>, + input_mode: InputMode, ) -> Self { let panes = if let Some(PaneId::Terminal(pid)) = pane_id { let new_terminal = TerminalPane::new(pid, *full_screen_ws); @@ -218,6 +213,7 @@ impl Tab { send_pty_instructions, send_plugin_instructions, expansion_boundary: None, + input_mode, } } @@ -262,11 +258,7 @@ impl Tab { if let Some(plugin) = &layout.plugin { let (pid_tx, pid_rx) = channel(); self.send_plugin_instructions - .send(PluginInstruction::Load( - pid_tx, - plugin.clone(), - layout.events.clone(), - )) + .send(PluginInstruction::Load(pid_tx, plugin.clone())) .unwrap(); let pid = pid_rx.recv().unwrap(); let new_plugin = PluginPane::new( @@ -305,7 +297,6 @@ impl Tab { self.toggle_active_pane_fullscreen(); } if !self.has_panes() { - // FIXME: This could use a second look if let PaneId::Terminal(term_pid) = pid { let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws); self.os_api.set_terminal_size_using_fd( @@ -356,7 +347,6 @@ impl Tab { if terminal_to_split.rows() * CURSOR_HEIGHT_WIDTH_RATIO > terminal_to_split.columns() && terminal_to_split.rows() > terminal_to_split.min_height() * 2 { - // FIXME: This could use a second look if let PaneId::Terminal(term_pid) = pid { let (top_winsize, bottom_winsize) = split_horizontally_with_gap(&terminal_ws); let new_terminal = TerminalPane::new(term_pid, bottom_winsize); @@ -377,7 +367,6 @@ impl Tab { self.active_terminal = Some(pid); } } else if terminal_to_split.columns() > terminal_to_split.min_width() * 2 { - // FIXME: This could use a second look if let PaneId::Terminal(term_pid) = pid { let (left_winsize, right_winsize) = split_vertically_with_gap(&terminal_ws); let new_terminal = TerminalPane::new(term_pid, right_winsize); @@ -407,7 +396,6 @@ impl Tab { self.toggle_active_pane_fullscreen(); } if !self.has_panes() { - // FIXME: This could use a second look if let PaneId::Terminal(term_pid) = pid { let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws); self.os_api.set_terminal_size_using_fd( @@ -418,47 +406,44 @@ impl Tab { self.panes.insert(pid, Box::new(new_terminal)); self.active_terminal = Some(pid); } - } else { - // FIXME: This could use a second look - if let PaneId::Terminal(term_pid) = pid { - // TODO: check minimum size of active terminal - let active_pane_id = &self.get_active_pane_id().unwrap(); - let active_pane = self.panes.get_mut(active_pane_id).unwrap(); - if active_pane.rows() < MIN_TERMINAL_HEIGHT * 2 + 1 { - self.send_pty_instructions - .send(PtyInstruction::ClosePane(pid)) // we can't open this pane, close the pty - .unwrap(); - return; - } - let terminal_ws = PositionAndSize { - x: active_pane.x(), - y: active_pane.y(), - rows: active_pane.rows(), - columns: active_pane.columns(), - }; - let (top_winsize, bottom_winsize) = split_horizontally_with_gap(&terminal_ws); + } else if let PaneId::Terminal(term_pid) = pid { + // TODO: check minimum size of active terminal + let active_pane_id = &self.get_active_pane_id().unwrap(); + let active_pane = self.panes.get_mut(active_pane_id).unwrap(); + if active_pane.rows() < MIN_TERMINAL_HEIGHT * 2 + 1 { + self.send_pty_instructions + .send(PtyInstruction::ClosePane(pid)) // we can't open this pane, close the pty + .unwrap(); + return; + } + let terminal_ws = PositionAndSize { + x: active_pane.x(), + y: active_pane.y(), + rows: active_pane.rows(), + columns: active_pane.columns(), + }; + let (top_winsize, bottom_winsize) = split_horizontally_with_gap(&terminal_ws); + + active_pane.change_pos_and_size(&top_winsize); - active_pane.change_pos_and_size(&top_winsize); + let new_terminal = TerminalPane::new(term_pid, bottom_winsize); + self.os_api.set_terminal_size_using_fd( + new_terminal.pid, + bottom_winsize.columns as u16, + bottom_winsize.rows as u16, + ); + self.panes.insert(pid, Box::new(new_terminal)); - let new_terminal = TerminalPane::new(term_pid, bottom_winsize); + if let PaneId::Terminal(active_terminal_pid) = active_pane_id { self.os_api.set_terminal_size_using_fd( - new_terminal.pid, - bottom_winsize.columns as u16, - bottom_winsize.rows as u16, + *active_terminal_pid, + top_winsize.columns as u16, + top_winsize.rows as u16, ); - self.panes.insert(pid, Box::new(new_terminal)); - - if let PaneId::Terminal(active_terminal_pid) = active_pane_id { - self.os_api.set_terminal_size_using_fd( - *active_terminal_pid, - top_winsize.columns as u16, - top_winsize.rows as u16, - ); - } - - self.active_terminal = Some(pid); - self.render(); } + + self.active_terminal = Some(pid); + self.render(); } } pub fn vertical_split(&mut self, pid: PaneId) { @@ -467,7 +452,6 @@ impl Tab { self.toggle_active_pane_fullscreen(); } if !self.has_panes() { - // FIXME: This could use a second look if let PaneId::Terminal(term_pid) = pid { let new_terminal = TerminalPane::new(term_pid, self.full_screen_ws); self.os_api.set_terminal_size_using_fd( @@ -478,47 +462,44 @@ impl Tab { self.panes.insert(pid, Box::new(new_terminal)); self.active_terminal = Some(pid); } - } else { - // FIXME: This could use a second look - if let PaneId::Terminal(term_pid) = pid { - // TODO: check minimum size of active terminal - let active_pane_id = &self.get_active_pane_id().unwrap(); - let active_pane = self.panes.get_mut(active_pane_id).unwrap(); - if active_pane.columns() < MIN_TERMINAL_WIDTH * 2 + 1 { - self.send_pty_instructions - .send(PtyInstruction::ClosePane(pid)) // we can't open this pane, close the pty - .unwrap(); - return; - } - let terminal_ws = PositionAndSize { - x: active_pane.x(), - y: active_pane.y(), - rows: active_pane.rows(), - columns: active_pane.columns(), - }; - let (left_winsize, right_winsize) = split_vertically_with_gap(&terminal_ws); + } else if let PaneId::Terminal(term_pid) = pid { + // TODO: check minimum size of active terminal + let active_pane_id = &self.get_active_pane_id().unwrap(); + let active_pane = self.panes.get_mut(active_pane_id).unwrap(); + if active_pane.columns() < MIN_TERMINAL_WIDTH * 2 + 1 { + self.send_pty_instructions + .send(PtyInstruction::ClosePane(pid)) // we can't open this pane, close the pty + .unwrap(); + return; + } + let terminal_ws = PositionAndSize { + x: active_pane.x(), + y: active_pane.y(), + rows: active_pane.rows(), + columns: active_pane.columns(), + }; + let (left_winsize, right_winsize) = split_vertically_with_gap(&terminal_ws); - active_pane.change_pos_and_size(&left_winsize); + active_pane.change_pos_and_size(&left_winsize); + + let new_terminal = TerminalPane::new(term_pid, right_winsize); + self.os_api.set_terminal_size_using_fd( + new_terminal.pid, + right_winsize.columns as u16, + right_winsize.rows as u16, + ); + self.panes.insert(pid, Box::new(new_terminal)); - let new_terminal = TerminalPane::new(term_pid, right_winsize); + if let PaneId::Terminal(active_terminal_pid) = active_pane_id { self.os_api.set_terminal_size_using_fd( - new_terminal.pid, - right_winsize.columns as u16, - right_winsize.rows as u16, + *active_terminal_pid, + left_winsize.columns as u16, + left_winsize.rows as u16, ); - self.panes.insert(pid, Box::new(new_terminal)); - - if let PaneId::Terminal(active_terminal_pid) = active_pane_id { - self.os_api.set_terminal_size_using_fd( - *active_terminal_pid, - left_winsize.columns as u16, - left_winsize.rows as u16, - ); - } - - self.active_terminal = Some(pid); - self.render(); } + + self.active_terminal = Some(pid); + self.render(); } } pub fn get_active_pane(&self) -> Option<&dyn Pane> { @@ -562,12 +543,11 @@ impl Tab { .expect("failed to drain terminal"); } Some(PaneId::Plugin(pid)) => { - self.send_plugin_instructions - .send(PluginInstruction::Input( - PluginInputType::Normal(pid), - input_bytes, - )) - .unwrap(); + for key in parse_keys(&input_bytes) { + self.send_plugin_instructions + .send(PluginInstruction::Update(Some(pid), Event::KeyPress(key))) + .unwrap() + } } _ => {} } @@ -645,7 +625,12 @@ impl Tab { .expect("cannot write to stdout"); for (kind, terminal) in self.panes.iter_mut() { if !self.panes_to_hide.contains(&terminal.pid()) { - boundaries.add_rect(terminal.as_ref()); + match self.active_terminal.unwrap() == terminal.pid() { + true => { + boundaries.add_rect(terminal.as_ref(), self.input_mode, Some(colors::GREEN)) + } + false => boundaries.add_rect(terminal.as_ref(), self.input_mode, None), + } if let Some(vte_output) = terminal.render() { let vte_output = if let PaneId::Terminal(_) = kind { vte_output @@ -1679,8 +1664,8 @@ impl Tab { } else if self.can_reduce_pane_and_surroundings_right(&active_pane_id, count) { self.reduce_pane_and_surroundings_right(&active_pane_id, count); } - self.render(); } + self.render(); } pub fn resize_left(&mut self) { // TODO: find out by how much we actually reduced and only reduce by that much @@ -1691,8 +1676,8 @@ impl Tab { } else if self.can_reduce_pane_and_surroundings_left(&active_pane_id, count) { self.reduce_pane_and_surroundings_left(&active_pane_id, count); } - self.render(); } + self.render(); } pub fn resize_down(&mut self) { // TODO: find out by how much we actually reduced and only reduce by that much @@ -1703,8 +1688,8 @@ impl Tab { } else if self.can_reduce_pane_and_surroundings_down(&active_pane_id, count) { self.reduce_pane_and_surroundings_down(&active_pane_id, count); } - self.render(); } + self.render(); } pub fn resize_up(&mut self) { // TODO: find out by how much we actually reduced and only reduce by that much @@ -1715,8 +1700,8 @@ impl Tab { } else if self.can_reduce_pane_and_surroundings_up(&active_pane_id, count) { self.reduce_pane_and_surroundings_up(&active_pane_id, count); } - self.render(); } + self.render(); } pub fn move_focus(&mut self) { if !self.has_selectable_panes() { diff --git a/src/common/errors.rs b/src/common/errors.rs index df741629..f5aeae85 100644 --- a/src/common/errors.rs +++ b/src/common/errors.rs @@ -133,7 +133,7 @@ pub enum ContextType { Plugin(PluginContext), /// An app-related call. App(AppContext), - IPCServer, + IpcServer, StdinHandler, AsyncTask, /// An empty, placeholder call. This should be thought of as representing no call at all. @@ -152,7 +152,7 @@ impl Display for ContextType { ContextType::Plugin(c) => write!(f, "{}plugin_thread: {}{:?}", purple, green, c), ContextType::App(c) => write!(f, "{}main_thread: {}{:?}", purple, green, c), - ContextType::IPCServer => write!(f, "{}ipc_server: {}AcceptInput", purple, green), + ContextType::IpcServer => write!(f, "{}ipc_server: {}AcceptInput", purple, green), ContextType::StdinHandler => { write!(f, "{}stdin_handler_thread: {}AcceptInput", purple, green) } @@ -164,6 +164,7 @@ impl Display for ContextType { } } +// FIXME: Just deriving EnumDiscriminants from strum will remove the need for any of this!!! /// Stack call representations corresponding to the different types of [`ScreenInstruction`]s. #[derive(Debug, Clone, Copy, PartialEq)] pub enum ScreenContext { @@ -199,8 +200,10 @@ pub enum ScreenContext { CloseTab, GoToTab, UpdateTabName, + ChangeInputMode, } +// FIXME: Just deriving EnumDiscriminants from strum will remove the need for any of this!!! impl From<&ScreenInstruction> for ScreenContext { fn from(screen_instruction: &ScreenInstruction) -> Self { match *screen_instruction { @@ -238,6 +241,7 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenInstruction::CloseTab => ScreenContext::CloseTab, ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab, ScreenInstruction::UpdateTabName(_) => ScreenContext::UpdateTabName, + ScreenInstruction::ChangeInputMode(_) => ScreenContext::ChangeInputMode, } } } @@ -276,24 +280,20 @@ use crate::wasm_vm::PluginInstruction; #[derive(Debug, Clone, Copy, PartialEq)] pub enum PluginContext { Load, - Draw, - Input, - GlobalInput, + Update, + Render, Unload, Quit, - Tabs, } impl From<&PluginInstruction> for PluginContext { fn from(plugin_instruction: &PluginInstruction) -> Self { match *plugin_instruction { PluginInstruction::Load(..) => PluginContext::Load, - PluginInstruction::Draw(..) => PluginContext::Draw, - PluginInstruction::Input(..) => PluginContext::Input, - PluginInstruction::GlobalInput(_) => PluginContext::GlobalInput, + PluginInstruction::Update(..) => PluginContext::Update, + PluginInstruction::Render(..) => PluginContext::Render, PluginInstruction::Unload(_) => PluginContext::Unload, PluginInstruction::Quit => PluginContext::Quit, - PluginInstruction::UpdateTabs(..) => PluginContext::Tabs, } } } @@ -301,8 +301,6 @@ impl From<&PluginInstruction> for PluginContext { /// Stack call representations corresponding to the different types of [`AppInstruction`]s. #[derive(Debug, Clone, Copy, PartialEq)] pub enum AppContext { - GetState, - SetState, Exit, Error, } @@ -310,8 +308,6 @@ pub enum AppContext { impl From<&AppInstruction> for AppContext { fn from(app_instruction: &AppInstruction) -> Self { match *app_instruction { - AppInstruction::GetState(_) => AppContext::GetState, - AppInstruction::SetState(_) => AppContext::SetState, AppInstruction::Exit => AppContext::Exit, AppInstruction::Error(_) => AppContext::Error, } diff --git a/src/common/input/actions.rs b/src/common/input/actions.rs index a8a3d600..ac923f7d 100644 --- a/src/common/input/actions.rs +++ b/src/common/input/actions.rs @@ -1,8 +1,7 @@ //! Definition of the actions that can be bound to keys. -use super::handler; -//use super::macros; use serde::{Deserialize, Serialize}; +use zellij_tile::data::InputMode; /// The four directions (left, right, up, down). #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] @@ -21,7 +20,7 @@ pub enum Action { /// Write to the terminal. Write(Vec<u8>), /// Switch to the specified input mode. - SwitchToMode(handler::InputMode), + SwitchToMode(InputMode), /// Resize focus pane in specified direction. Resize(Direction), /// Switch focus to next pane in specified direction. @@ -51,5 +50,4 @@ pub enum Action { CloseTab, GoToTab(u32), TabNameInput(Vec<u8>), - SaveTabName, } diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs index 49d87124..0d30530a 100644 --- a/src/common/input/handler.rs +++ b/src/common/input/handler.rs @@ -3,17 +3,16 @@ use super::actions::Action; use super::keybinds::Keybinds; use crate::common::input::config::Config; -use crate::common::{update_state, AppInstruction, AppState, SenderWithContext, OPENCALLS}; +use crate::common::{AppInstruction, SenderWithContext, OPENCALLS}; use crate::errors::ContextType; use crate::os_input_output::OsApi; use crate::pty_bus::PtyInstruction; use crate::screen::ScreenInstruction; -use crate::wasm_vm::{EventType, PluginInputType, PluginInstruction}; +use crate::wasm_vm::PluginInstruction; use crate::CommandIsExecuting; -use serde::{Deserialize, Serialize}; -use strum_macros::EnumIter; -use termion::input::TermReadEventsAndRaw; +use termion::input::{TermRead, TermReadEventsAndRaw}; +use zellij_tile::data::{Event, InputMode, Key, ModeInfo}; /// Handles the dispatching of [`Action`]s according to the current /// [`InputMode`], and keep tracks of the current [`InputMode`]. @@ -64,27 +63,22 @@ impl InputHandler { 'input_loop: loop { //@@@ I think this should actually just iterate over stdin directly let stdin_buffer = self.os_input.read_from_stdin(); - drop( - self.send_plugin_instructions - .send(PluginInstruction::GlobalInput(stdin_buffer.clone())), - ); for key_result in stdin_buffer.events_and_raw() { match key_result { Ok((event, raw_bytes)) => match event { termion::event::Event::Key(key) => { + let key = cast_termion_key(key); // FIXME this explicit break is needed because the current test // framework relies on it to not create dead threads that loop // and eat up CPUs. Do not remove until the test framework has // been revised. Sorry about this (@categorille) - if { - let mut should_break = false; - for action in - Keybinds::key_to_actions(&key, raw_bytes, &self.mode, &keybinds) - { - should_break |= self.dispatch_action(action); - } - should_break - } { + let mut should_break = false; + for action in + Keybinds::key_to_actions(&key, raw_bytes, &self.mode, &keybinds) + { + should_break |= self.dispatch_action(action); + } + if should_break { break 'input_loop; } } @@ -127,9 +121,15 @@ impl InputHandler { } Action::SwitchToMode(mode) => { self.mode = mode; - update_state(&self.send_app_instructions, |_| AppState { - input_mode: self.mode, - }); + self.send_plugin_instructions + .send(PluginInstruction::Update( + None, + Event::ModeUpdate(get_mode_info(mode)), + )) + .unwrap(); + self.send_screen_instructions + .send(ScreenInstruction::ChangeInputMode(mode)) + .unwrap(); self.send_screen_instructions .send(ScreenInstruction::Render) .unwrap(); @@ -230,27 +230,10 @@ impl InputHandler { .unwrap(); } Action::TabNameInput(c) => { - self.send_plugin_instructions - .send(PluginInstruction::Input( - PluginInputType::Event(EventType::Tab), - c.clone(), - )) - .unwrap(); self.send_screen_instructions .send(ScreenInstruction::UpdateTabName(c)) .unwrap(); } - Action::SaveTabName => { - self.send_plugin_instructions - .send(PluginInstruction::Input( - PluginInputType::Event(EventType::Tab), - vec![b'\n'], - )) - .unwrap(); - self.send_screen_instructions - .send(ScreenInstruction::UpdateTabName(vec![b'\n'])) - .unwrap(); - } Action::NoOp => {} } @@ -266,52 +249,10 @@ impl InputHandler { } } -/// Describes the different input modes, which change the way that keystrokes will be interpreted. -#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, EnumIter, Serialize, Deserialize)] -pub enum InputMode { - /// In `Normal` mode, input is always written to the terminal, except for the shortcuts leading - /// to other modes - #[serde(alias = "normal")] - Normal, - /// In `Locked` mode, input is always written to the terminal and all shortcuts are disabled - /// except the one leading back to normal mode - #[serde(alias = "locked")] - Locked, - /// `Resize` mode allows resizing the different existing panes. - #[serde(alias = "resize")] - Resize, - /// `Pane` mode allows creating and closing panes, as well as moving between them. - #[serde(alias = "pane")] - Pane, - /// `Tab` mode allows creating and closing tabs, as well as moving between them. - #[serde(alias = "tab")] - Tab, - /// `Scroll` mode allows scrolling up and down within a pane. - #[serde(alias = "scroll")] - Scroll, - #[serde(alias = "renametab")] - RenameTab, -} - -/// Represents the contents of the help message that is printed in the status bar, -/// which indicates the current [`InputMode`] and what the keybinds for that mode -/// are. Related to the default `status-bar` plugin. -#[derive(Default, Debug, Clone, Serialize, Deserialize)] -pub struct Help { - pub mode: InputMode, - pub keybinds: Vec<(String, String)>, // <shortcut> => <shortcut description> -} - -impl Default for InputMode { - fn default() -> InputMode { - InputMode::Normal - } -} - /// Creates a [`Help`] struct indicating the current [`InputMode`] and its keybinds /// (as pairs of [`String`]s). // TODO this should probably be automatically generated in some way -pub fn get_help(mode: InputMode) -> Help { +pub fn get_mode_info(mode: InputMode) -> ModeInfo { let mut keybinds: Vec<(String, String)> = vec![]; match mode { InputMode::Normal | InputMode::Locked => {} @@ -340,7 +281,7 @@ pub fn get_help(mode: InputMode) -> Help { keybinds.push(("Enter".to_string(), "when done".to_string())); } } - Help { mode, keybinds } + ModeInfo { mode, keybinds } } /// Entry point to the module. Instantiates an [`InputHandler`] and starts @@ -365,3 +306,35 @@ pub fn input_loop( ) .handle_input(); } + +pub fn parse_keys(input_bytes: &[u8]) -> Vec<Key> { + input_bytes.keys().flatten().map(cast_termion_key).collect() +} + +// FIXME: This is an absolutely cursed function that should be destroyed as soon +// as an alternative that doesn't touch zellij-tile can be developed... +fn cast_termion_key(event: termion::event::Key) -> Key { + match event { + termion::event::Key::Backspace => Key::Backspace, + termion::event::Key::Left => Key::Left, + termion::event::Key::Right => Key::Right, + termion::event::Key::Up => Key::Up, + termion::event::Key::Down => Key::Down, + termion::event::Key::Home => Key::Home, + termion::event::Key::End => Key::End, + termion::event::Key::PageUp => Key::PageUp, + termion::event::Key::PageDown => Key::PageDown, + termion::event::Key::BackTab => Key::BackTab, + termion::event::Key::Delete => Key::Delete, + termion::event::Key::Insert => Key::Insert, + termion::event::Key::F(n) => Key::F(n), + termion::event::Key::Char(c) => Key::Char(c), + termion::event::Key::Alt(c) => Key::Alt(c), + termion::event::Key::Ctrl(c) => Key::Ctrl(c), + termion::event::Key::Null => Key::Null, + termion::event::Key::Esc => Key::Esc, + _ => { + unimplemented!("Encountered an unknown key!") + } + } +} diff --git a/src/common/input/keybinds.rs b/src/common/input/keybinds.rs index c70123b6..6a14a182 100644 --- a/src/common/input/keybinds.rs +++ b/src/common/input/keybinds.rs @@ -2,11 +2,10 @@ use std::collections::HashMap; use super::actions::{Action, Direction}; -use super::handler::InputMode; use serde::Deserialize; use strum::IntoEnumIterator; -use termion::event::Key; +use zellij_tile::data::*; #[derive(Clone, Debug, PartialEq)] pub struct Keybinds(HashMap<InputMode, ModeKeybinds>); @@ -275,10 +274,7 @@ impl Keybinds { defaults.insert(Key::Up, vec![Action::ScrollUp]); } InputMode::RenameTab => { - defaults.insert( - Key::Char('\n'), - vec![Action::SaveTabName, Action::SwitchToMode(InputMode::Tab)], - ); + defaults.insert(Key::Char('\n'), vec![Action::SwitchToMode(InputMode::Tab)]); defaults.insert( Key::Ctrl('g'), vec![Action::SwitchToMode(InputMode::Normal)], diff --git a/src/common/input/unit/keybinds_test.rs b/src/common/input/unit/keybinds_test.rs index 2b306bc3..6411d017 100644 --- a/src/common/input/unit/keybinds_test.rs +++ b/src/common/input/unit/keybinds_test.rs @@ -1,6 +1,6 @@ use super::super::actions::*; use super::super::keybinds::*; -use termion::event::Key; +use zellij_tile::data::Key; #[test] fn merge_keybinds_merges_different_keys() { diff --git a/src/common/ipc.rs b/src/common/ipc.rs index 77d57df3..81576b86 100644 --- a/src/common/ipc.rs +++ b/src/common/ipc.rs @@ -3,12 +3,12 @@ use serde::{Deserialize, Serialize}; use std::collections::HashSet; -type SessionID = u64; +type SessionId = u64; #[derive(PartialEq, Eq, Serialize, Deserialize, Hash)] pub struct Session { // Unique ID for this session - id: SessionID, + id: SessionId, // Identifier for the underlying IPC primitive (socket, pipe) conn_name: String, // User configured alias for the session @@ -30,9 +30,9 @@ pub enum ClientToServerMsg { // Create a new session CreateSession, // Attach to a running session - AttachToSession(SessionID, ClientType), + AttachToSession(SessionId, ClientType), // Force detach - DetachSession(SessionID), + DetachSession(SessionId), // Disconnect from the session we're connected to DisconnectFromSession, } diff --git a/src/common/mod.rs b/src/common/mod.rs index 777b615f..57c21155 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -9,35 +9,36 @@ pub mod screen; pub mod utils; pub mod wasm_vm; -use std::io::Write; -use std::path::{Path, PathBuf}; +use std::cell::RefCell; +use std::path::PathBuf; use std::sync::mpsc; use std::thread; -use std::{cell::RefCell, sync::mpsc::TrySendError}; use std::{collections::HashMap, fs}; - -use crate::panes::PaneId; -use directories_next::ProjectDirs; -use input::handler::InputMode; -use serde::{Deserialize, Serialize}; -use termion::input::TermRead; -use wasm_vm::PluginEnv; -use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value}; -use wasmer_wasi::{Pipe, WasiState}; +use std::{ + collections::HashSet, + io::Write, + str::FromStr, + sync::{Arc, Mutex}, +}; use crate::cli::CliArgs; use crate::common::input::config::Config; use crate::layout::Layout; +use crate::panes::PaneId; use command_is_executing::CommandIsExecuting; +use directories_next::ProjectDirs; use errors::{AppContext, ContextType, ErrorContext, PluginContext, PtyContext, ScreenContext}; use input::handler::input_loop; use os_input_output::OsApi; use pty_bus::{PtyBus, PtyInstruction}; use screen::{Screen, ScreenInstruction}; -use utils::consts::{ZELLIJ_IPC_PIPE, ZELLIJ_ROOT_PLUGIN_DIR}; -use wasm_vm::{ - wasi_stdout, wasi_write_string, zellij_imports, EventType, PluginInputType, PluginInstruction, -}; +use serde::{Deserialize, Serialize}; +use utils::consts::ZELLIJ_IPC_PIPE; +use wasm_vm::PluginEnv; +use wasm_vm::{wasi_stdout, wasi_write_string, zellij_imports, PluginInstruction}; +use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value}; +use wasmer_wasi::{Pipe, WasiState}; +use zellij_tile::data::{EventType, InputMode}; #[derive(Serialize, Deserialize, Debug)] pub enum ApiCommand { @@ -46,33 +47,6 @@ pub enum ApiCommand { SplitVertically, MoveFocus, } -// FIXME: It would be good to add some more things to this over time -#[derive(Debug, Clone)] -pub struct AppState { - pub input_mode: InputMode, -} - -impl Default for AppState { - fn default() -> Self { - AppState { - input_mode: InputMode::default(), - } - } -} - -// FIXME: Make this a method on the big `Communication` struct, so that app_tx can be extracted -// from self instead of being explicitly passed here -pub fn update_state( - app_tx: &SenderWithContext<AppInstruction>, - update_fn: impl FnOnce(AppState) -> AppState, -) { - let (state_tx, state_rx) = mpsc::channel(); - - drop(app_tx.send(AppInstruction::GetState(state_tx))); - let state = state_rx.recv().unwrap(); - - drop(app_tx.send(AppInstruction::SetState(update_fn(state)))) -} /// An [MPSC](mpsc) asynchronous channel with added error context. pub type ChannelWithContext<T> = ( @@ -116,19 +90,6 @@ impl<T: Clone> SenderWithContext<T> { } } - /// Attempts to send an event on this sender's channel, terminating instead of blocking - /// if the event could not be sent (buffer full or connection closed). - /// - /// This can only be called on [`SyncSender`](SenderType::SyncSender)s, and will - /// panic if called on an asynchronous [`Sender`](SenderType::Sender). - pub fn try_send(&self, event: T) -> Result<(), TrySendError<(T, ErrorContext)>> { - if let SenderType::SyncSender(ref s) = self.sender { - s.try_send((event, self.err_ctx)) - } else { - panic!("try_send can only be called on SyncSenders!") - } - } - /// Updates this [`SenderWithContext`]'s [`ErrorContext`]. This is the way one adds /// a call to the error context. /// @@ -151,8 +112,6 @@ thread_local!( /// Instructions related to the entire application. #[derive(Clone)] pub enum AppInstruction { - GetState(mpsc::Sender<AppState>), - SetState(AppState), Exit, Error(String), } @@ -167,8 +126,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { .write(take_snapshot.as_bytes()) .unwrap(); - let mut app_state = AppState::default(); - let config = Config::from_cli_config(opts.config) .map_err(|e| { eprintln!("There was an error in the config file:\n{}", e); @@ -307,6 +264,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { &full_screen_ws, os_input, max_panes, + InputMode::Normal, ); loop { let (event, mut err_ctx) = screen @@ -398,8 +356,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { .get_active_tab_mut() .unwrap() .set_pane_selectable(id, selectable); - // FIXME: Is this needed? - screen.render(); } ScreenInstruction::SetMaxHeight(id, max_height) => { screen @@ -441,6 +397,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { ScreenInstruction::UpdateTabName(c) => { screen.update_active_tab_name(c); } + ScreenInstruction::ChangeInputMode(input_mode) => { + screen.change_input_mode(input_mode); + } ScreenInstruction::Quit => { break; } @@ -460,12 +419,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { let store = Store::default(); let mut plugin_id = 0; let mut plugin_map = HashMap::new(); - let handler_map: HashMap<EventType, String> = - [(EventType::Tab, "handle_tab_rename_keypress".to_string())] - .iter() - .cloned() - .collect(); - move || loop { let (event, mut err_ctx) = receive_plugin_instructions .recv() @@ -475,18 +428,13 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { send_pty_instructions.update(err_ctx); send_app_instructions.update(err_ctx); match event { - PluginInstruction::Load(pid_tx, path, events) => { + PluginInstruction::Load(pid_tx, path) => { let project_dirs = ProjectDirs::from("org", "Zellij Contributors", "Zellij").unwrap(); let plugin_dir = project_dirs.data_dir().join("plugins/"); - // FIXME: This really shouldn't need to exist anymore, let's get rid of it! - let root_plugin_dir = Path::new(ZELLIJ_ROOT_PLUGIN_DIR); let wasm_bytes = fs::read(&path) .or_else(|_| fs::read(&path.with_extension("wasm"))) .or_else(|_| fs::read(&plugin_dir.join(&path).with_extension("wasm"))) - .or_else(|_| { - fs::read(&root_plugin_dir.join(&path).with_extension("wasm")) - }) .unwrap_or_else(|_| panic!("cannot find plugin {}", &path.display())); // FIXME: Cache this compiled module on disk. I could use `(de)serialize_to_file()` for that @@ -517,7 +465,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { send_screen_instructions: send_screen_instructions.clone(), send_app_instructions: send_app_instructions.clone(), wasi_env, - events, + subscriptions: Arc::new(Mutex::new(HashSet::new())), }; let zellij = zellij_imports(&store, &plugin_env); @@ -532,88 +480,33 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { pid_tx.send(plugin_id).unwrap(); plugin_id += 1; } - PluginInstruction::Draw(buf_tx, pid, rows, cols) => { + PluginInstruction::Update(pid, event) => { + for (&i, (instance, plugin_env)) in &plugin_map { + let subs = plugin_env.subscriptions.lock().unwrap(); + // FIXME: This is very janky... Maybe I should write my own macro for Event -> EventType? + let event_type = EventType::from_str(&event.to_string()).unwrap(); + if (pid.is_none() || pid == Some(i)) && subs.contains(&event_type) { + let update = instance.exports.get_function("update").unwrap(); + wasi_write_string( + &plugin_env.wasi_env, + &serde_json::to_string(&event).unwrap(), + ); + update.call(&[]).unwrap(); + } + } + drop(send_screen_instructions.send(ScreenInstruction::Render)); + } + PluginInstruction::Render(buf_tx, pid, rows, cols) => { let (instance, plugin_env) = plugin_map.get(&pid).unwrap(); - let draw = instance.exports.get_function("draw").unwrap(); + let render = instance.exports.get_function("render").unwrap(); - draw.call(&[Value::I32(rows as i32), Value::I32(cols as i32)]) + render + .call(&[Value::I32(rows as i32), Value::I32(cols as i32)]) .unwrap(); buf_tx.send(wasi_stdout(&plugin_env.wasi_env)).unwrap(); } - PluginInstruction::UpdateTabs(mut tabs) => { - for (instance, plugin_env) in plugin_map.values() { - if !plugin_env.events.contains(&EventType::Tab) { - continue; - } - let handler = instance.exports.get_function("update_tabs").unwrap(); - tabs.sort_by(|a, b| a.position.cmp(&b.position)); - wasi_write_string( - &plugin_env.wasi_env, - &serde_json::to_string(&tabs).unwrap(), - ); - handler.call(&[]).unwrap(); - } - } - // FIXME: Deduplicate this with the callback below! - PluginInstruction::Input(input_type, input_bytes) => { - match input_type { - PluginInputType::Normal(pid) => { - let (instance, plugin_env) = plugin_map.get(&pid).unwrap(); - let handle_key = - instance.exports.get_function("handle_key").unwrap(); - for key in input_bytes.keys() { - if let Ok(key) = key { - wasi_write_string( - &plugin_env.wasi_env, - &serde_json::to_string(&key).unwrap(), - ); - handle_key.call(&[]).unwrap(); - } - } - } - PluginInputType::Event(event) => { - for (instance, plugin_env) in plugin_map.values() { - if !plugin_env.events.contains(&event) { - continue; - } - let handle_key = instance - .exports - .get_function(handler_map.get(&event).unwrap()) - .unwrap(); - for key in input_bytes.keys() { - if let Ok(key) = key { - wasi_write_string( - &plugin_env.wasi_env, - &serde_json::to_string(&key).unwrap(), - ); - handle_key.call(&[]).unwrap(); - } - } - } - } - } - drop(send_screen_instructions.send(ScreenInstruction::Render)); - } - PluginInstruction::GlobalInput(input_bytes) => { - // FIXME: Set up an event subscription system, and timed callbacks - for (instance, plugin_env) in plugin_map.values() { - let handler = - instance.exports.get_function("handle_global_key").unwrap(); - for key in input_bytes.keys() { - if let Ok(key) = key { - wasi_write_string( - &plugin_env.wasi_env, - &serde_json::to_string(&key).unwrap(), - ); - handler.call(&[]).unwrap(); - } - } - } - - drop(send_screen_instructions.send(ScreenInstruction::Render)); - } PluginInstruction::Unload(pid) => drop(plugin_map.remove(&pid)), PluginInstruction::Quit => break, } @@ -636,7 +529,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { let listener = std::os::unix::net::UnixListener::bind(ZELLIJ_IPC_PIPE) .expect("could not listen on ipc socket"); let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); - err_ctx.add_call(ContextType::IPCServer); + err_ctx.add_call(ContextType::IpcServer); send_pty_instructions.update(err_ctx); send_screen_instructions.update(err_ctx); @@ -713,8 +606,6 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) { send_screen_instructions.update(err_ctx); send_pty_instructions.update(err_ctx); match app_instruction { - AppInstruction::GetState(state_tx) => drop(state_tx.send(app_state.clone())), - AppInstruction::SetState(state) => app_state = state, AppInstruction::Exit => { break; } diff --git a/src/common/os_input_output.rs b/src/common/os_input_output.rs index 26a7d497..043a9aea 100644 --- a/src/common/os_input_output.rs +++ b/src/common/os_input_output.rs @@ -82,15 +82,10 @@ fn handle_command_exit(mut child: Child) { } for signal in signals.pending() { - // FIXME: We need to handle more signals here! - #[allow(clippy::single_match)] - match signal { - signal_hook::SIGINT => { - child.kill().unwrap(); - child.wait().unwrap(); - break 'handle_exit; - } - _ => {} + if signal == signal_hook::SIGINT { + child.kill().unwrap(); + child.wait().unwrap(); + break 'handle_exit; } } } diff --git a/src/common/screen.rs b/src/common/screen.rs index 199a1223..5208834a 100644 --- a/src/common/screen.rs +++ b/src/common/screen.rs @@ -9,10 +9,12 @@ use super::{AppInstruction, SenderWithContext}; use crate::os_input_output::OsApi; use crate::panes::PositionAndSize; use crate::pty_bus::{PtyInstruction, VteEvent}; -use crate::tab::{Tab, TabData}; +use crate::tab::Tab; use crate::{errors::ErrorContext, wasm_vm::PluginInstruction}; use crate::{layout::Layout, panes::PaneId}; +use zellij_tile::data::{Event, InputMode, TabInfo}; + /// Instructions that can be sent to the [`Screen`]. #[derive(Debug, Clone)] pub enum ScreenInstruction { @@ -48,6 +50,7 @@ pub enum ScreenInstruction { CloseTab, GoToTab(u32), UpdateTabName(Vec<u8>), + ChangeInputMode(InputMode), } /// A [`Screen`] holds multiple [`Tab`]s, each one holding multiple [`panes`](crate::client::panes). @@ -71,7 +74,7 @@ pub struct Screen { active_tab_index: Option<usize>, /// The [`OsApi`] this [`Screen`] uses. os_api: Box<dyn OsApi>, - tabname_buf: String, + input_mode: InputMode, } impl Screen { @@ -84,6 +87,7 @@ impl Screen { full_screen_ws: &PositionAndSize, os_api: Box<dyn OsApi>, max_panes: Option<usize>, + input_mode: InputMode, ) -> Self { Screen { receiver: receive_screen_instructions, @@ -95,7 +99,7 @@ impl Screen { active_tab_index: None, tabs: BTreeMap::new(), os_api, - tabname_buf: String::new(), + input_mode, } } @@ -115,6 +119,7 @@ impl Screen { self.send_app_instructions.clone(), self.max_panes, Some(PaneId::Terminal(pane_id)), + self.input_mode, ); self.active_tab_index = Some(tab_index); self.tabs.insert(tab_index, tab); @@ -169,15 +174,12 @@ impl Screen { pub fn go_to_tab(&mut self, mut tab_index: usize) { tab_index -= 1; let active_tab = self.get_active_tab().unwrap(); - match self.tabs.values().find(|t| t.position == tab_index) { - Some(t) => { - if t.index != active_tab.index { - self.active_tab_index = Some(t.index); - self.update_tabs(); - self.render(); - } + if let Some(t) = self.tabs.values().find(|t| t.position == tab_index) { + if t.index != active_tab.index { + self.active_tab_index = Some(t.index); + self.update_tabs(); + self.render(); } - None => {} } } @@ -259,6 +261,7 @@ impl Screen { self.send_app_instructions.clone(), self.max_panes, None, + self.input_mode, ); tab.apply_layout(layout, new_pids); self.active_tab_index = Some(tab_index); @@ -270,33 +273,38 @@ impl Screen { let mut tab_data = vec![]; let active_tab_index = self.active_tab_index.unwrap(); for tab in self.tabs.values() { - tab_data.push(TabData { + tab_data.push(TabInfo { position: tab.position, name: tab.name.clone(), active: active_tab_index == tab.index, }); } self.send_plugin_instructions - .send(PluginInstruction::UpdateTabs(tab_data)) + .send(PluginInstruction::Update(None, Event::TabUpdate(tab_data))) .unwrap(); } pub fn update_active_tab_name(&mut self, buf: Vec<u8>) { let s = str::from_utf8(&buf).unwrap(); + let active_tab = self.get_active_tab_mut().unwrap(); match s { "\0" => { - self.tabname_buf = String::new(); + active_tab.name = String::new(); } - "\n" => { - let new_name = self.tabname_buf.clone(); - let active_tab = self.get_active_tab_mut().unwrap(); - active_tab.name = new_name; - self.update_tabs(); - self.render(); + "\u{007F}" | "\u{0008}" => { + //delete and backspace keys + active_tab.name.pop(); } c => { - self.tabname_buf.push_str(c); + active_tab.name.push_str(c); } } + self.update_tabs(); + } + pub fn change_input_mode(&mut self, input_mode: InputMode) { + self.input_mode = input_mode; + for tab in self.tabs.values_mut() { + tab.input_mode = self.input_mode; + } } } diff --git a/src/common/utils/consts.rs b/src/common/utils/consts.rs index fa9eee0d..663a545d 100644 --- a/src/common/utils/consts.rs +++ b/src/common/utils/consts.rs @@ -4,5 +4,3 @@ pub const ZELLIJ_TMP_DIR: &str = "/tmp/zellij"; pub const ZELLIJ_TMP_LOG_DIR: &str = "/tmp/zellij/zellij-log"; pub const ZELLIJ_TMP_LOG_FILE: &str = "/tmp/zellij/zellij-log/log.txt"; pub const ZELLIJ_IPC_PIPE: &str = "/tmp/zellij/ipc"; -pub const ZELLIJ_ROOT_PLUGIN_DIR: &str = "/usr/share/zellij/plugins"; -pub const ZELLIJ_ROOT_LAYOUT_DIR: &str = "/usr/share/zellij/layouts"; diff --git a/src/common/wasm_vm.rs b/src/common/wasm_vm.rs index 15b920ad..29b110ae 100644 --- a/src/common/wasm_vm.rs +++ b/src/common/wasm_vm.rs @@ -1,36 +1,22 @@ -use crate::tab::TabData; -use serde::{Deserialize, Serialize}; use std::{ + collections::HashSet, path::PathBuf, - sync::mpsc::{channel, Sender}, + sync::{mpsc::Sender, Arc, Mutex}, }; use wasmer::{imports, Function, ImportObject, Store, WasmerEnv}; use wasmer_wasi::WasiEnv; +use zellij_tile::data::{Event, EventType}; use super::{ - input::handler::get_help, pty_bus::PtyInstruction, screen::ScreenInstruction, AppInstruction, - PaneId, SenderWithContext, + pty_bus::PtyInstruction, screen::ScreenInstruction, AppInstruction, PaneId, SenderWithContext, }; -#[derive(Clone, Debug, PartialEq, Hash, Eq, Serialize, Deserialize)] -pub enum EventType { - Tab, -} - -#[derive(Clone, Debug)] -pub enum PluginInputType { - Normal(u32), - Event(EventType), -} - #[derive(Clone, Debug)] pub enum PluginInstruction { - Load(Sender<u32>, PathBuf, Vec<EventType>), - Draw(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols - Input(PluginInputType, Vec<u8>), // plugin id, input bytes - GlobalInput(Vec<u8>), // input bytes + Load(Sender<u32>, PathBuf), + Update(Option<u32>, Event), // Focused plugin / broadcast, event data + Render(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols Unload(u32), - UpdateTabs(Vec<TabData>), // num tabs, active tab Quit, } @@ -41,7 +27,7 @@ pub struct PluginEnv { pub send_app_instructions: SenderWithContext<AppInstruction>, pub send_pty_instructions: SenderWithContext<PtyInstruction>, // FIXME: This should be a big bundle of all of the channels pub wasi_env: WasiEnv, - pub events: Vec<EventType>, + pub subscriptions: Arc<Mutex<HashSet<EventType>>>, } // Plugin API --------------------------------------------------------------------------------------------------------- @@ -49,16 +35,28 @@ pub struct PluginEnv { pub fn zellij_imports(store: &Store, plugin_env: &PluginEnv) -> ImportObject { imports! { "zellij" => { + "host_subscribe" => Function::new_native_with_env(store, plugin_env.clone(), host_subscribe), + "host_unsubscribe" => Function::new_native_with_env(store, plugin_env.clone(), host_unsubscribe), "host_open_file" => Function::new_native_with_env(store, plugin_env.clone(), host_open_file), "host_set_invisible_borders" => Function::new_native_with_env(store, plugin_env.clone(), host_set_invisible_borders), "host_set_max_height" => Function::new_native_with_env(store, plugin_env.clone(), host_set_max_height), "host_set_selectable" => Function::new_native_with_env(store, plugin_env.clone(), host_set_selectable), - "host_get_help" => Function::new_native_with_env(store, plugin_env.clone(), host_get_help), } } } -// FIXME: Bundle up all of the channels! Pair that with WasiEnv? +fn host_subscribe(plugin_env: &PluginEnv) { + let mut subscriptions = plugin_env.subscriptions.lock().unwrap(); + let new: HashSet<EventType> = serde_json::from_str(&wasi_stdout(&plugin_env.wasi_env)).unwrap(); + subscriptions.extend(new); +} + +fn host_unsubscribe(plugin_env: &PluginEnv) { + let mut subscriptions = plugin_env.subscriptions.lock().unwrap(); + let old: HashSet<EventType> = serde_json::from_str(&wasi_stdout(&plugin_env.wasi_env)).unwrap(); + subscriptions.retain(|k| !old.contains(k)); +} + fn host_open_file(plugin_env: &PluginEnv) { let path = PathBuf::from(wasi_stdout(&plugin_env.wasi_env).lines().next().unwrap()); plugin_env @@ -67,7 +65,6 @@ fn host_open_file(plugin_env: &PluginEnv) { .unwrap(); } -// FIXME: Think about these naming conventions – should everything be prefixed by 'host'? fn host_set_selectable(plugin_env: &PluginEnv, selectable: i32) { let selectable = selectable != 0; plugin_env @@ -101,21 +98,6 @@ fn host_set_invisible_borders(plugin_env: &PluginEnv, invisible_borders: i32) { .unwrap() } -fn host_get_help(plugin_env: &PluginEnv) { - let (state_tx, state_rx) = channel(); - // FIXME: If I changed the application so that threads were sent the termination - // signal and joined one at a time, there would be an order to shutdown, so I - // could get rid of this .is_ok() check and the .try_send() - if plugin_env - .send_app_instructions - .try_send(AppInstruction::GetState(state_tx)) - .is_ok() - { - let help = get_help(state_rx.recv().unwrap().input_mode); - wasi_write_string(&plugin_env.wasi_env, &serde_json::to_string(&help).unwrap()); - } -} - // Helper Functions --------------------------------------------------------------------------------------------------- // FIXME: Unwrap city diff --git a/src/tests/fakes.rs b/src/tests/fakes.rs index fa9c6f0e..c800de97 100644 --- a/src/tests/fakes.rs +++ b/src/tests/fakes.rs @@ -10,6 +10,8 @@ use std::time::{Duration, Instant}; use crate::os_input_output::OsApi; use crate::tests::possible_tty_inputs::{get_possible_tty_inputs, Bytes}; +use crate::tests::utils::commands::SLEEP; + const MIN_TIME_BETWEEN_SNAPSHOTS: Duration = Duration::from_millis(50); #[derive(Clone)] @@ -189,11 +191,16 @@ impl OsApi for FakeInputOutput { ::std::thread::sleep(MIN_TIME_BETWEEN_SNAPSHOTS - last_snapshot_time.elapsed()); } } - self.stdin_commands + let command = self + .stdin_commands .lock() .unwrap() .pop_front() - .unwrap_or(vec![]) + .unwrap_or(vec![]); + if command == SLEEP { + std::thread::sleep(std::time::Duration::from_millis(200)); + } + command } fn get_stdout_writer(&self) -> Box<dyn Write> { Box::new(self.stdout_writer.clone()) diff --git a/src/tests/integration/expansion_boundary.rs b/src/tests/integration/expansion_boundary.rs index 7cb0b0f7..c68c1d5a 100644 --- a/src/tests/integration/expansion_boundary.rs +++ b/src/tests/integration/expansion_boundary.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use crate::panes::PositionAndSize; use crate::tests::fakes::FakeInputOutput; use crate::tests::utils::commands::{ - PANE_MODE, QUIT, RESIZE_DOWN_IN_RESIZE_MODE, RESIZE_MODE, SPAWN_TERMINAL_IN_PANE_MODE, + PANE_MODE, QUIT, RESIZE_DOWN_IN_RESIZE_MODE, RESIZE_MODE, SLEEP, SPAWN_TERMINAL_IN_PANE_MODE, TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE, }; use crate::tests::utils::{get_next_to_last_snapshot, get_output_frame_snapshots}; @@ -23,7 +23,12 @@ pub fn new_panes_are_open_inside_expansion_border() { y: 0, }; let mut fake_input_output = get_fake_os_input(&fake_win_size); - fake_input_output.add_terminal_input(&[&PANE_MODE, &SPAWN_TERMINAL_IN_PANE_MODE, &QUIT]); + fake_input_output.add_terminal_input(&[ + &PANE_MODE, + &SPAWN_TERMINAL_IN_PANE_MODE, + &SLEEP, + &QUIT, + ]); let mut opts = CliArgs::default(); opts.layout = Some(PathBuf::from( "src/tests/fixtures/layouts/expansion-boundary-in-the-middle.yaml", @@ -55,6 +60,7 @@ pub fn resize_pane_inside_expansion_border() { &SPAWN_TERMINAL_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); let mut opts = CliArgs::default(); @@ -87,6 +93,7 @@ pub fn toggling_fullcsreen_in_expansion_border_expands_only_until_border() { &PANE_MODE, &SPAWN_TERMINAL_IN_PANE_MODE, &TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE, + &SLEEP, &QUIT, ]); let mut opts = CliArgs::default(); diff --git a/src/tests/integration/resize_down.rs b/src/tests/integration/resize_down.rs index 0171cea2..4957b33e 100644 --- a/src/tests/integration/resize_down.rs +++ b/src/tests/integration/resize_down.rs @@ -7,7 +7,8 @@ use crate::{start, CliArgs}; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_DOWN_IN_RESIZE_MODE, - RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, + RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, + SPLIT_RIGHT_IN_PANE_MODE, }; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { @@ -37,6 +38,7 @@ pub fn resize_down_with_pane_above() { &SPLIT_DOWN_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); @@ -75,6 +77,7 @@ pub fn resize_down_with_pane_below() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); @@ -118,6 +121,7 @@ pub fn resize_down_with_panes_above_and_below() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); @@ -160,6 +164,7 @@ pub fn resize_down_with_multiple_panes_above() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -205,6 +210,7 @@ pub fn resize_down_with_panes_above_aligned_left_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -249,6 +255,7 @@ pub fn resize_down_with_panes_below_aligned_left_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -291,6 +298,7 @@ pub fn resize_down_with_panes_above_aligned_right_with_current_pane() { &SPLIT_DOWN_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -334,6 +342,7 @@ pub fn resize_down_with_panes_below_aligned_right_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -380,6 +389,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_current_pane() { &SPLIT_DOWN_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -428,6 +438,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -493,6 +504,7 @@ pub fn resize_down_with_panes_above_aligned_left_and_right_with_panes_to_the_lef &RESIZE_LEFT_IN_RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -560,6 +572,7 @@ pub fn resize_down_with_panes_below_aligned_left_and_right_with_to_the_left_and_ &RESIZE_LEFT_IN_RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -596,6 +609,7 @@ pub fn cannot_resize_down_when_pane_below_is_at_minimum_height() { &SPLIT_DOWN_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_DOWN_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); diff --git a/src/tests/integration/resize_left.rs b/src/tests/integration/resize_left.rs index 0d0d61a5..a9d229d9 100644 --- a/src/tests/integration/resize_left.rs +++ b/src/tests/integration/resize_left.rs @@ -7,7 +7,7 @@ use crate::{start, CliArgs}; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, - RESIZE_UP_IN_RESIZE_MODE, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, + RESIZE_UP_IN_RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { @@ -34,6 +34,7 @@ pub fn resize_left_with_pane_to_the_left() { &SPLIT_RIGHT_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); @@ -70,6 +71,7 @@ pub fn resize_left_with_pane_to_the_right() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); @@ -108,6 +110,7 @@ pub fn resize_left_with_panes_to_the_left_and_right() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); @@ -148,6 +151,7 @@ pub fn resize_left_with_multiple_panes_to_the_left() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -191,6 +195,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -231,6 +236,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_with_current_pane() { &SPLIT_DOWN_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -273,6 +279,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_bottom_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -314,6 +321,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_bottom_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -360,6 +368,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_current_pa &SPLIT_RIGHT_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -408,6 +417,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_current_p &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -473,6 +483,7 @@ pub fn resize_left_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abov &RESIZE_UP_IN_RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -541,6 +552,7 @@ pub fn resize_left_with_panes_to_the_right_aligned_top_and_bottom_with_panes_abo &RESIZE_UP_IN_RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -577,6 +589,7 @@ pub fn cannot_resize_left_when_pane_to_the_left_is_at_minimum_width() { &SPLIT_RIGHT_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); diff --git a/src/tests/integration/resize_right.rs b/src/tests/integration/resize_right.rs index 8f1928ee..fef33e84 100644 --- a/src/tests/integration/resize_right.rs +++ b/src/tests/integration/resize_right.rs @@ -7,7 +7,7 @@ use crate::{start, CliArgs}; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_MODE, RESIZE_RIGHT_IN_RESIZE_MODE, - RESIZE_UP_IN_RESIZE_MODE, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, + RESIZE_UP_IN_RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { @@ -34,6 +34,7 @@ pub fn resize_right_with_pane_to_the_left() { &SPLIT_RIGHT_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); @@ -70,6 +71,7 @@ pub fn resize_right_with_pane_to_the_right() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); @@ -108,6 +110,7 @@ pub fn resize_right_with_panes_to_the_left_and_right() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); @@ -148,6 +151,7 @@ pub fn resize_right_with_multiple_panes_to_the_left() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -191,6 +195,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -231,6 +236,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_with_current_pane() { &SPLIT_DOWN_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -273,6 +279,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_bottom_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -314,6 +321,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_bottom_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -360,6 +368,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_current_p &SPLIT_RIGHT_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -408,6 +417,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_current_ &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -473,6 +483,7 @@ pub fn resize_right_with_panes_to_the_left_aligned_top_and_bottom_with_panes_abo &RESIZE_UP_IN_RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -540,6 +551,7 @@ pub fn resize_right_with_panes_to_the_right_aligned_top_and_bottom_with_panes_ab &RESIZE_UP_IN_RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -576,6 +588,7 @@ pub fn cannot_resize_right_when_pane_to_the_left_is_at_minimum_width() { &SPLIT_RIGHT_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_RIGHT_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); diff --git a/src/tests/integration/resize_up.rs b/src/tests/integration/resize_up.rs index 2df6dfa7..9d4dd05a 100644 --- a/src/tests/integration/resize_up.rs +++ b/src/tests/integration/resize_up.rs @@ -7,7 +7,7 @@ use crate::{start, CliArgs}; use crate::tests::utils::commands::{ MOVE_FOCUS_IN_PANE_MODE, PANE_MODE, QUIT, RESIZE_LEFT_IN_RESIZE_MODE, RESIZE_MODE, - RESIZE_UP_IN_RESIZE_MODE, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, + RESIZE_UP_IN_RESIZE_MODE, SLEEP, SPLIT_DOWN_IN_PANE_MODE, SPLIT_RIGHT_IN_PANE_MODE, }; fn get_fake_os_input(fake_win_size: &PositionAndSize) -> FakeInputOutput { @@ -36,6 +36,7 @@ pub fn resize_up_with_pane_above() { &SPLIT_DOWN_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); @@ -74,6 +75,7 @@ pub fn resize_up_with_pane_below() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); @@ -117,6 +119,7 @@ pub fn resize_up_with_panes_above_and_below() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); @@ -158,6 +161,7 @@ pub fn resize_up_with_multiple_panes_above() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -201,6 +205,7 @@ pub fn resize_up_with_panes_above_aligned_left_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -245,6 +250,7 @@ pub fn resize_up_with_panes_below_aligned_left_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -287,6 +293,7 @@ pub fn resize_up_with_panes_above_aligned_right_with_current_pane() { &SPLIT_DOWN_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -330,6 +337,7 @@ pub fn resize_up_with_panes_below_aligned_right_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -376,6 +384,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_current_pane() { &SPLIT_DOWN_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -424,6 +433,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_current_pane() { &MOVE_FOCUS_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -489,6 +499,7 @@ pub fn resize_up_with_panes_above_aligned_left_and_right_with_panes_to_the_left_ &RESIZE_LEFT_IN_RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -556,6 +567,7 @@ pub fn resize_up_with_panes_below_aligned_left_and_right_with_to_the_left_and_ri &RESIZE_LEFT_IN_RESIZE_MODE, &RESIZE_LEFT_IN_RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); @@ -592,6 +604,7 @@ pub fn cannot_resize_up_when_pane_above_is_at_minimum_height() { &SPLIT_DOWN_IN_PANE_MODE, &RESIZE_MODE, &RESIZE_UP_IN_RESIZE_MODE, + &SLEEP, &QUIT, ]); start(Box::new(fake_input_output.clone()), CliArgs::default()); diff --git a/src/tests/utils.rs b/src/tests/utils.rs index 86973d74..14f4cfa0 100644 --- a/src/tests/utils.rs +++ b/src/tests/utils.rs @@ -76,4 +76,5 @@ pub mod commands { pub const SWITCH_NEXT_TAB_IN_TAB_MODE: [u8; 1] = [108]; // l 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 SLEEP: [u8; 0] = []; } |
