diff --git a/default-plugins/fixture-plugin-for-tests/src/main.rs b/default-plugins/fixture-plugin-for-tests/src/main.rs index f504eec8..b6cac35b 100644 --- a/default-plugins/fixture-plugin-for-tests/src/main.rs +++ b/default-plugins/fixture-plugin-for-tests/src/main.rs @@ -56,6 +56,7 @@ impl ZellijPlugin for State { PermissionType::WebAccess, PermissionType::ReadCliPipes, PermissionType::MessageAndLaunchOtherPlugins, + PermissionType::RebindKeys, ]); self.configuration = configuration; subscribe(&[ @@ -318,6 +319,18 @@ impl ZellijPlugin for State { Some(std::path::PathBuf::from("/tmp")), ); }, + BareKey::Char('0') if key.has_modifiers(&[KeyModifier::Ctrl]) => { + rebind_keys( + " + keybinds { + locked { + bind \"a\" { NewTab; } + } + } + " + .to_owned(), + ); + }, _ => {}, }, Event::CustomMessage(message, payload) => { diff --git a/src/tests/e2e/cases.rs b/src/tests/e2e/cases.rs index 6b1c12c6..9687d53c 100644 --- a/src/tests/e2e/cases.rs +++ b/src/tests/e2e/cases.rs @@ -162,6 +162,7 @@ pub fn split_terminals_vertically() { if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); // back to normal mode after split step_is_complete = true; @@ -205,6 +206,7 @@ pub fn cannot_split_terminals_vertically_when_active_terminal_is_too_small() { let mut step_is_complete = false; if remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); // back to normal mode after split step_is_complete = true; @@ -259,6 +261,7 @@ pub fn scrolling_inside_a_pane() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -286,6 +289,7 @@ pub fn scrolling_inside_a_pane() { { // all lines have been written to the pane remote_terminal.send_key(&SCROLL_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SCROLL_UP_IN_SCROLL_MODE); step_is_complete = true; } @@ -337,6 +341,7 @@ pub fn toggle_pane_fullscreen() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -350,6 +355,7 @@ pub fn toggle_pane_fullscreen() { if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { // cursor is in the newly opened second pane remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE); step_is_complete = true; } @@ -398,6 +404,7 @@ pub fn open_new_tab() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -411,6 +418,7 @@ pub fn open_new_tab() { if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { // cursor is in the newly opened second pane remote_terminal.send_key(&TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); step_is_complete = true; } @@ -463,6 +471,7 @@ pub fn close_tab() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -476,6 +485,7 @@ pub fn close_tab() { if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { // cursor is in the newly opened second pane remote_terminal.send_key(&TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); step_is_complete = true; } @@ -493,6 +503,7 @@ pub fn close_tab() { { // cursor is in the newly opened second tab remote_terminal.send_key(&TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&CLOSE_TAB_IN_TAB_MODE); step_is_complete = true; } @@ -653,6 +664,7 @@ pub fn close_pane() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -666,6 +678,7 @@ pub fn close_pane() { if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { // cursor is in the newly opened second pane remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&CLOSE_PANE_IN_PANE_MODE); step_is_complete = true; } @@ -751,6 +764,7 @@ pub fn closing_last_pane_exits_zellij() { if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&CLOSE_PANE_IN_PANE_MODE); step_is_complete = true; } @@ -795,6 +809,7 @@ pub fn typing_exit_closes_pane() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -807,9 +822,13 @@ pub fn typing_exit_closes_pane() { let mut step_is_complete = false; if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { remote_terminal.send_key("e".as_bytes()); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key("x".as_bytes()); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key("i".as_bytes()); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key("t".as_bytes()); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key("\n".as_bytes()); step_is_complete = true; } @@ -859,6 +878,7 @@ pub fn resize_pane() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -872,6 +892,7 @@ pub fn resize_pane() { if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { // cursor is in the newly opened second pane remote_terminal.send_key(&RESIZE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&RESIZE_LEFT_IN_RESIZE_MODE); // back to normal mode remote_terminal.send_key(&ENTER); @@ -933,7 +954,9 @@ pub fn lock_mode() { let mut step_is_complete = false; if remote_terminal.snapshot_contains("INTERFACE LOCKED") { remote_terminal.send_key(&TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key("abc".as_bytes()); step_is_complete = true; } @@ -983,6 +1006,7 @@ pub fn resize_terminal_window() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -1046,6 +1070,7 @@ pub fn detach_and_attach_session() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -1070,6 +1095,7 @@ pub fn detach_and_attach_session() { let mut step_is_complete = false; if remote_terminal.cursor_position_is(77, 2) { remote_terminal.send_key(&SESSION_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&DETACH_IN_SESSION_MODE); // text has been entered step_is_complete = true; @@ -1286,6 +1312,7 @@ fn focus_pane_with_mouse() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -1345,6 +1372,7 @@ pub fn scrolling_inside_a_pane_with_mouse() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -1420,6 +1448,7 @@ pub fn start_without_pane_frames() { if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(2, 1) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -1489,6 +1518,7 @@ pub fn mirrored_sessions() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -1502,6 +1532,7 @@ pub fn mirrored_sessions() { if remote_terminal.cursor_position_is(63, 2) && remote_terminal.tip_appears() { // cursor is in the newly opened second pane remote_terminal.send_key(&TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); step_is_complete = true; } @@ -1544,6 +1575,7 @@ pub fn mirrored_sessions() { let mut step_is_complete = false; if remote_terminal.snapshot_contains("some text") { remote_terminal.send_key(&TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&MOVE_FOCUS_LEFT_IN_PANE_MODE); // same key as tab mode step_is_complete = true; } @@ -1726,6 +1758,7 @@ pub fn multiple_users_in_different_panes_and_same_tab() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_PANE_MODE); step_is_complete = true; } @@ -1817,6 +1850,7 @@ pub fn multiple_users_in_different_tabs() { if remote_terminal.cursor_position_is(3, 2) && remote_terminal.tip_appears() { // cursor is in the newly opened second pane remote_terminal.send_key(&TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); step_is_complete = true; } @@ -1839,6 +1873,7 @@ pub fn multiple_users_in_different_tabs() { && remote_terminal.snapshot_contains("Tab #1 [ ]") && remote_terminal.snapshot_contains("Tab #2") && remote_terminal.status_bar_appears() + && !remote_terminal.snapshot_contains("AND:") { // cursor is in the newly opened second tab step_is_complete = true; @@ -1899,11 +1934,17 @@ pub fn bracketed_paste() { && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&BRACKETED_PASTE_START); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key("a".as_bytes()); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key("b".as_bytes()); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key("c".as_bytes()); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&BRACKETED_PASTE_END); step_is_complete = true; } @@ -1952,6 +1993,7 @@ pub fn toggle_floating_panes() { if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&TOGGLE_FLOATING_PANES); // back to normal mode after split step_is_complete = true; @@ -2002,6 +2044,7 @@ pub fn tmux_mode() { if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&TMUX_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPLIT_RIGHT_IN_TMUX_MODE); // back to normal mode after split step_is_complete = true; @@ -2050,6 +2093,7 @@ pub fn edit_scrollback() { if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&SCROLL_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&EDIT_SCROLLBACK); step_is_complete = true; } @@ -2099,8 +2143,13 @@ pub fn undo_rename_tab() { && remote_terminal.snapshot_contains("Tab #1") { remote_terminal.send_key(&TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&RENAME_TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&[97, 97]); + std::thread::sleep(std::time::Duration::from_millis(100)); + remote_terminal.send_key(&ESC); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&ESC); step_is_complete = true; } @@ -2113,7 +2162,9 @@ pub fn undo_rename_tab() { name: "Wait for tab name to apper on screen", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.snapshot_contains("Tab #1") { + if remote_terminal.snapshot_contains("Tab #1") + && remote_terminal.snapshot_contains("Tip:") + { step_is_complete = true } step_is_complete @@ -2149,8 +2200,13 @@ pub fn undo_rename_pane() { if remote_terminal.status_bar_appears() && remote_terminal.cursor_position_is(3, 2) { remote_terminal.send_key(&PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&RENAME_PANE_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&[97, 97]); + std::thread::sleep(std::time::Duration::from_millis(100)); + remote_terminal.send_key(&ESC); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&ESC); step_is_complete = true; } @@ -2163,7 +2219,9 @@ pub fn undo_rename_pane() { name: "Wait for pane name to apper on screen", instruction: |remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.snapshot_contains("Pane #1") { + if remote_terminal.snapshot_contains("Pane #1") + && remote_terminal.snapshot_contains("Tip:") + { step_is_complete = true } step_is_complete @@ -2212,6 +2270,7 @@ pub fn send_command_through_the_cli() { "{}/append-echo-script.sh", fixture_folder )); + std::thread::sleep(std::time::Duration::from_millis(100)); step_is_complete = true; } step_is_complete @@ -2221,11 +2280,7 @@ pub fn send_command_through_the_cli() { name: "Initial run of suspended command", instruction: |mut remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.snapshot_contains("") - && remote_terminal.cursor_position_is(0, 0) - // cursor does not appear in - // suspend_start panes - { + if remote_terminal.snapshot_contains("") { std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&SPACE); // run script - here we use SPACE // instead of the default ENTER because diff --git a/src/tests/e2e/remote_runner.rs b/src/tests/e2e/remote_runner.rs index ab2c4a9e..09f23991 100644 --- a/src/tests/e2e/remote_runner.rs +++ b/src/tests/e2e/remote_runner.rs @@ -261,7 +261,7 @@ fn read_from_channel( break; } if should_sleep { - std::thread::sleep(std::time::Duration::from_millis(10)); + std::thread::sleep(std::time::Duration::from_millis(100)); should_sleep = false; } let mut buf = [0u8; 1280000]; diff --git a/src/tests/e2e/steps.rs b/src/tests/e2e/steps.rs index c09fc939..85009e19 100644 --- a/src/tests/e2e/steps.rs +++ b/src/tests/e2e/steps.rs @@ -11,6 +11,7 @@ pub fn new_tab() -> Step { let mut step_is_complete = false; if remote_terminal.tip_appears() && remote_terminal.status_bar_appears() { remote_terminal.send_key(&TAB_MODE); + std::thread::sleep(std::time::Duration::from_millis(100)); remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); step_is_complete = true; } @@ -37,6 +38,7 @@ pub fn move_tab_left() -> Step { let mut step_is_complete = false; if remote_terminal.tip_appears() && remote_terminal.status_bar_appears() { remote_terminal.send_key(&MOVE_TAB_LEFT); + std::thread::sleep(std::time::Duration::from_millis(100)); step_is_complete = true; } step_is_complete diff --git a/zellij-client/src/input_handler.rs b/zellij-client/src/input_handler.rs index b00d1280..a3759063 100644 --- a/zellij-client/src/input_handler.rs +++ b/zellij-client/src/input_handler.rs @@ -146,9 +146,6 @@ impl InputHandler { )) => { self.handle_key(&key_with_modifier, raw_bytes, true); }, - Ok((InputInstruction::SwitchToMode(input_mode), _error_context)) => { - self.mode = input_mode; - }, Ok(( InputInstruction::AnsiStdinInstructions(ansi_stdin_instructions), _error_context, @@ -180,18 +177,13 @@ impl InputHandler { raw_bytes: Vec, is_kitty_keyboard_protocol: bool, ) { - let keybinds = &self.config.keybinds; - for action in keybinds.get_actions_for_key_in_mode_or_default_action( - &self.mode, - key, + // we interpret the keys into actions on the server side so that we can change the + // keybinds at runtime + self.os_input.send_to_server(ClientToServerMsg::Key( + key.clone(), raw_bytes, is_kitty_keyboard_protocol, - ) { - let should_exit = self.dispatch_action(action, None); - if should_exit { - self.should_exit = true; - } - } + )); } fn handle_stdin_ansi_instruction(&mut self, ansi_stdin_instructions: AnsiStdinInstruction) { match ansi_stdin_instructions { @@ -316,14 +308,8 @@ impl InputHandler { self.exit(ExitReason::NormalDetached); should_break = true; }, - Action::SwitchToMode(mode) => { - // this is an optimistic update, we should get a SwitchMode instruction from the - // server later that atomically changes the mode as well - self.mode = mode; - self.os_input - .send_to_server(ClientToServerMsg::Action(action, None, None)); - }, Action::CloseFocus + | Action::SwitchToMode(..) | Action::ClearScreen | Action::NewPane(..) | Action::Run(_) diff --git a/zellij-client/src/lib.rs b/zellij-client/src/lib.rs index e0cd195e..422e2052 100644 --- a/zellij-client/src/lib.rs +++ b/zellij-client/src/lib.rs @@ -25,7 +25,7 @@ use crate::{ use zellij_utils::{ channels::{self, ChannelWithContext, SenderWithContext}, consts::{set_permissions, ZELLIJ_SOCK_DIR}, - data::{ClientId, ConnectToSession, InputMode, KeyWithModifier, Style}, + data::{ClientId, ConnectToSession, KeyWithModifier, Style}, envs, errors::{ClientContext, ContextType, ErrorInstruction}, input::{config::Config, options::Options}, @@ -42,7 +42,6 @@ pub(crate) enum ClientInstruction { Render(String), UnblockInputThread, Exit(ExitReason), - SwitchToMode(InputMode), Connected, ActiveClients(Vec), StartedParsingStdinQuery, @@ -62,9 +61,6 @@ impl From for ClientInstruction { ServerToClientMsg::Exit(e) => ClientInstruction::Exit(e), ServerToClientMsg::Render(buffer) => ClientInstruction::Render(buffer), ServerToClientMsg::UnblockInputThread => ClientInstruction::UnblockInputThread, - ServerToClientMsg::SwitchToMode(input_mode) => { - ClientInstruction::SwitchToMode(input_mode) - }, ServerToClientMsg::Connected => ClientInstruction::Connected, ServerToClientMsg::ActiveClients(clients) => ClientInstruction::ActiveClients(clients), ServerToClientMsg::Log(log_lines) => ClientInstruction::Log(log_lines), @@ -90,7 +86,6 @@ impl From<&ClientInstruction> for ClientContext { ClientInstruction::Error(_) => ClientContext::Error, ClientInstruction::Render(_) => ClientContext::Render, ClientInstruction::UnblockInputThread => ClientContext::UnblockInputThread, - ClientInstruction::SwitchToMode(_) => ClientContext::SwitchToMode, ClientInstruction::Connected => ClientContext::Connected, ClientInstruction::ActiveClients(_) => ClientContext::ActiveClients, ClientInstruction::Log(_) => ClientContext::Log, @@ -154,7 +149,6 @@ impl ClientInfo { pub(crate) enum InputInstruction { KeyEvent(InputEvent, Vec), KeyWithModifierEvent(KeyWithModifier, Vec), - SwitchToMode(InputMode), AnsiStdinInstructions(Vec), StartedParsing, DoneParsing, @@ -505,11 +499,6 @@ pub fn start_client( ClientInstruction::UnblockInputThread => { command_is_executing.unblock_input_thread(); }, - ClientInstruction::SwitchToMode(input_mode) => { - send_input_instructions - .send(InputInstruction::SwitchToMode(input_mode)) - .unwrap(); - }, ClientInstruction::Log(lines_to_log) => { for line in lines_to_log { log::info!("{line}"); @@ -634,7 +623,3 @@ pub fn start_server_detached( os_input.connect_to_server(&*ipc_pipe); os_input.send_to_server(first_msg); } - -#[cfg(test)] -#[path = "./unit/stdin_tests.rs"] -mod stdin_tests; diff --git a/zellij-client/src/unit/snapshots/zellij_client__input_handler__input_handler_tests__pixel_info_sent_to_server.snap b/zellij-client/src/unit/snapshots/zellij_client__input_handler__input_handler_tests__pixel_info_sent_to_server.snap deleted file mode 100644 index 14e5d101..00000000 --- a/zellij-client/src/unit/snapshots/zellij_client__input_handler__input_handler_tests__pixel_info_sent_to_server.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: zellij-client/src/./unit/input_handler_tests.rs -assertion_line: 429 -expression: "*format!(\"{:?}\", events_sent_to_server.lock().unwrap())" ---- -[TerminalPixelDimensions(PixelDimensions { text_area_size: Some(SizeInPixels { height: 401, width: 1566 }), character_cell_size: None }), TerminalPixelDimensions(PixelDimensions { text_area_size: None, character_cell_size: Some(SizeInPixels { height: 21, width: 8 }) }), BackgroundColor("rgb:0000/0000/0000"), ForegroundColor("rgb:ffff/ffff/ffff"), ColorRegisters([(0, "rgb:0000/0000/0000"), (1, "rgb:cdcd/0000/0000"), (2, "rgb:0000/cdcd/0000"), (3, "rgb:cdcd/cdcd/0000"), (4, "rgb:0000/0000/eeee"), (5, "rgb:cdcd/0000/cdcd"), (6, "rgb:0000/cdcd/cdcd"), (7, "rgb:e5e5/e5e5/e5e5"), (8, "rgb:7f7f/7f7f/7f7f"), (9, "rgb:ffff/0000/0000"), (10, "rgb:0000/ffff/0000"), (11, "rgb:ffff/ffff/0000"), (12, "rgb:5c5c/5c5c/ffff"), (13, "rgb:ffff/0000/ffff"), (14, "rgb:0000/ffff/ffff"), (15, "rgb:ffff/ffff/ffff"), (16, "rgb:0000/0000/0000"), (17, "rgb:0000/0000/5f5f"), (18, "rgb:0000/0000/8787"), (19, "rgb:0000/0000/afaf"), (20, "rgb:0000/0000/d7d7"), (21, "rgb:0000/0000/ffff"), (22, "rgb:0000/5f5f/0000"), (23, "rgb:0000/5f5f/5f5f"), (24, "rgb:0000/5f5f/8787"), (25, "rgb:0000/5f5f/afaf"), (26, "rgb:0000/5f5f/d7d7"), (27, "rgb:0000/5f5f/ffff"), (28, "rgb:0000/8787/0000"), (29, "rgb:0000/8787/5f5f"), (30, "rgb:0000/8787/8787"), (31, "rgb:0000/8787/afaf"), (32, "rgb:0000/8787/d7d7"), (33, "rgb:0000/8787/ffff"), (34, "rgb:0000/afaf/0000"), (35, "rgb:0000/afaf/5f5f"), (36, "rgb:0000/afaf/8787"), (37, "rgb:0000/afaf/afaf"), (38, "rgb:0000/afaf/d7d7"), (39, "rgb:0000/afaf/ffff"), (40, "rgb:0000/d7d7/0000"), (41, "rgb:0000/d7d7/5f5f"), (42, "rgb:0000/d7d7/8787"), (43, "rgb:0000/d7d7/afaf"), (44, "rgb:0000/d7d7/d7d7"), (45, "rgb:0000/d7d7/ffff"), (46, "rgb:0000/ffff/0000"), (47, "rgb:0000/ffff/5f5f"), (48, "rgb:0000/ffff/8787"), (49, "rgb:0000/ffff/afaf"), (50, "rgb:0000/ffff/d7d7"), (51, "rgb:0000/ffff/ffff"), (52, "rgb:5f5f/0000/0000"), (53, "rgb:5f5f/0000/5f5f"), (54, "rgb:5f5f/0000/8787"), (55, "rgb:5f5f/0000/afaf"), (56, "rgb:5f5f/0000/d7d7"), (57, "rgb:5f5f/0000/ffff"), (58, "rgb:5f5f/5f5f/0000"), (59, "rgb:5f5f/5f5f/5f5f"), (60, "rgb:5f5f/5f5f/8787"), (61, "rgb:5f5f/5f5f/afaf"), (62, "rgb:5f5f/5f5f/d7d7"), (63, "rgb:5f5f/5f5f/ffff"), (64, "rgb:5f5f/8787/0000"), (65, "rgb:5f5f/8787/5f5f"), (66, "rgb:5f5f/8787/8787"), (67, "rgb:5f5f/8787/afaf"), (68, "rgb:5f5f/8787/d7d7"), (69, "rgb:5f5f/8787/ffff"), (70, "rgb:5f5f/afaf/0000"), (71, "rgb:5f5f/afaf/5f5f"), (72, "rgb:5f5f/afaf/8787"), (73, "rgb:5f5f/afaf/afaf"), (74, "rgb:5f5f/afaf/d7d7"), (75, "rgb:5f5f/afaf/ffff"), (76, "rgb:5f5f/d7d7/0000"), (77, "rgb:5f5f/d7d7/5f5f"), (78, "rgb:5f5f/d7d7/8787"), (79, "rgb:5f5f/d7d7/afaf"), (80, "rgb:5f5f/d7d7/d7d7"), (81, "rgb:5f5f/d7d7/ffff"), (82, "rgb:5f5f/ffff/0000"), (83, "rgb:5f5f/ffff/5f5f"), (84, "rgb:5f5f/ffff/8787"), (85, "rgb:5f5f/ffff/afaf"), (86, "rgb:5f5f/ffff/d7d7"), (87, "rgb:5f5f/ffff/ffff"), (88, "rgb:8787/0000/0000"), (89, "rgb:8787/0000/5f5f"), (90, "rgb:8787/0000/8787"), (91, "rgb:8787/0000/afaf"), (92, "rgb:8787/0000/d7d7"), (93, "rgb:8787/0000/ffff"), (94, "rgb:8787/5f5f/0000"), (95, "rgb:8787/5f5f/5f5f"), (96, "rgb:8787/5f5f/8787"), (97, "rgb:8787/5f5f/afaf"), (98, "rgb:8787/5f5f/d7d7"), (99, "rgb:8787/5f5f/ffff"), (100, "rgb:8787/8787/0000"), (101, "rgb:8787/8787/5f5f"), (102, "rgb:8787/8787/8787"), (103, "rgb:8787/8787/afaf"), (104, "rgb:8787/8787/d7d7"), (105, "rgb:8787/8787/ffff"), (106, "rgb:8787/afaf/0000"), (107, "rgb:8787/afaf/5f5f"), (108, "rgb:8787/afaf/8787"), (109, "rgb:8787/afaf/afaf"), (110, "rgb:8787/afaf/d7d7"), (111, "rgb:8787/afaf/ffff"), (112, "rgb:8787/d7d7/0000"), (113, "rgb:8787/d7d7/5f5f"), (114, "rgb:8787/d7d7/8787"), (115, "rgb:8787/d7d7/afaf"), (116, "rgb:8787/d7d7/d7d7"), (117, "rgb:8787/d7d7/ffff"), (118, "rgb:8787/ffff/0000"), (119, "rgb:8787/ffff/5f5f"), (120, "rgb:8787/ffff/8787"), (121, "rgb:8787/ffff/afaf"), (122, "rgb:8787/ffff/d7d7"), (123, "rgb:8787/ffff/ffff"), (124, "rgb:afaf/0000/0000"), (125, "rgb:afaf/0000/5f5f"), (126, "rgb:afaf/0000/8787"), (127, "rgb:afaf/0000/afaf"), (128, "rgb:afaf/0000/d7d7"), (129, "rgb:afaf/0000/ffff"), (130, "rgb:afaf/5f5f/0000"), (131, "rgb:afaf/5f5f/5f5f"), (132, "rgb:afaf/5f5f/8787"), (133, "rgb:afaf/5f5f/afaf"), (134, "rgb:afaf/5f5f/d7d7"), (135, "rgb:afaf/5f5f/ffff"), (136, "rgb:afaf/8787/0000"), (137, "rgb:afaf/8787/5f5f"), (138, "rgb:afaf/8787/8787"), (139, "rgb:afaf/8787/afaf"), (140, "rgb:afaf/8787/d7d7"), (141, "rgb:afaf/8787/ffff"), (142, "rgb:afaf/afaf/0000"), (143, "rgb:afaf/afaf/5f5f"), (144, "rgb:afaf/afaf/8787"), (145, "rgb:afaf/afaf/afaf"), (146, "rgb:afaf/afaf/d7d7"), (147, "rgb:afaf/afaf/ffff"), (148, "rgb:afaf/d7d7/0000"), (149, "rgb:afaf/d7d7/5f5f"), (150, "rgb:afaf/d7d7/8787"), (151, "rgb:afaf/d7d7/afaf"), (152, "rgb:afaf/d7d7/d7d7"), (153, "rgb:afaf/d7d7/ffff"), (154, "rgb:afaf/ffff/0000"), (155, "rgb:afaf/ffff/5f5f"), (156, "rgb:afaf/ffff/8787"), (157, "rgb:afaf/ffff/afaf"), (158, "rgb:afaf/ffff/d7d7"), (159, "rgb:afaf/ffff/ffff"), (160, "rgb:d7d7/0000/0000"), (161, "rgb:d7d7/0000/5f5f"), (162, "rgb:d7d7/0000/8787"), (163, "rgb:d7d7/0000/afaf"), (164, "rgb:d7d7/0000/d7d7"), (165, "rgb:d7d7/0000/ffff"), (166, "rgb:d7d7/5f5f/0000"), (167, "rgb:d7d7/5f5f/5f5f"), (168, "rgb:d7d7/5f5f/8787"), (169, "rgb:d7d7/5f5f/afaf"), (170, "rgb:d7d7/5f5f/d7d7"), (171, "rgb:d7d7/5f5f/ffff"), (172, "rgb:d7d7/8787/0000"), (173, "rgb:d7d7/8787/5f5f"), (174, "rgb:d7d7/8787/8787"), (175, "rgb:d7d7/8787/afaf"), (176, "rgb:d7d7/8787/d7d7"), (177, "rgb:d7d7/8787/ffff"), (178, "rgb:d7d7/afaf/0000"), (179, "rgb:d7d7/afaf/5f5f"), (180, "rgb:d7d7/afaf/8787"), (181, "rgb:d7d7/afaf/afaf"), (182, "rgb:d7d7/afaf/d7d7"), (183, "rgb:d7d7/afaf/ffff"), (184, "rgb:d7d7/d7d7/0000"), (185, "rgb:d7d7/d7d7/5f5f"), (186, "rgb:d7d7/d7d7/8787"), (187, "rgb:d7d7/d7d7/afaf"), (188, "rgb:d7d7/d7d7/d7d7"), (189, "rgb:d7d7/d7d7/ffff"), (190, "rgb:d7d7/ffff/0000"), (191, "rgb:d7d7/ffff/5f5f"), (192, "rgb:d7d7/ffff/8787"), (193, "rgb:d7d7/ffff/afaf"), (194, "rgb:d7d7/ffff/d7d7"), (195, "rgb:d7d7/ffff/ffff"), (196, "rgb:ffff/0000/0000"), (197, "rgb:ffff/0000/5f5f"), (198, "rgb:ffff/0000/8787"), (199, "rgb:ffff/0000/afaf"), (200, "rgb:ffff/0000/d7d7"), (201, "rgb:ffff/0000/ffff"), (202, "rgb:ffff/5f5f/0000"), (203, "rgb:ffff/5f5f/5f5f"), (204, "rgb:ffff/5f5f/8787"), (205, "rgb:ffff/5f5f/afaf"), (206, "rgb:ffff/5f5f/d7d7"), (207, "rgb:ffff/5f5f/ffff"), (208, "rgb:ffff/8787/0000"), (209, "rgb:ffff/8787/5f5f"), (210, "rgb:ffff/8787/8787"), (211, "rgb:ffff/8787/afaf"), (212, "rgb:ffff/8787/d7d7"), (213, "rgb:ffff/8787/ffff"), (214, "rgb:ffff/afaf/0000"), (215, "rgb:ffff/afaf/5f5f"), (216, "rgb:ffff/afaf/8787"), (217, "rgb:ffff/afaf/afaf"), (218, "rgb:ffff/afaf/d7d7"), (219, "rgb:ffff/afaf/ffff"), (220, "rgb:ffff/d7d7/0000"), (221, "rgb:ffff/d7d7/5f5f"), (222, "rgb:ffff/d7d7/8787"), (223, "rgb:ffff/d7d7/afaf"), (224, "rgb:ffff/d7d7/d7d7"), (225, "rgb:ffff/d7d7/ffff"), (226, "rgb:ffff/ffff/0000"), (227, "rgb:ffff/ffff/5f5f"), (228, "rgb:ffff/ffff/8787"), (229, "rgb:ffff/ffff/afaf"), (230, "rgb:ffff/ffff/d7d7"), (231, "rgb:ffff/ffff/ffff"), (232, "rgb:0808/0808/0808"), (233, "rgb:1212/1212/1212"), (234, "rgb:1c1c/1c1c/1c1c"), (235, "rgb:2626/2626/2626"), (236, "rgb:3030/3030/3030"), (237, "rgb:3a3a/3a3a/3a3a"), (238, "rgb:4444/4444/4444"), (239, "rgb:4e4e/4e4e/4e4e"), (240, "rgb:5858/5858/5858"), (241, "rgb:6262/6262/6262"), (242, "rgb:6c6c/6c6c/6c6c"), (243, "rgb:7676/7676/7676"), (244, "rgb:8080/8080/8080"), (245, "rgb:8a8a/8a8a/8a8a"), (246, "rgb:9494/9494/9494"), (247, "rgb:9e9e/9e9e/9e9e"), (248, "rgb:a8a8/a8a8/a8a8"), (249, "rgb:b2b2/b2b2/b2b2"), (250, "rgb:bcbc/bcbc/bcbc"), (251, "rgb:c6c6/c6c6/c6c6"), (252, "rgb:d0d0/d0d0/d0d0"), (253, "rgb:dada/dada/dada"), (254, "rgb:e4e4/e4e4/e4e4"), (255, "rgb:eeee/eeee/eeee")])] diff --git a/zellij-client/src/unit/snapshots/zellij_client__stdin_tests__pixel_info_sent_to_server.snap b/zellij-client/src/unit/snapshots/zellij_client__stdin_tests__pixel_info_sent_to_server.snap deleted file mode 100644 index c58a2f5a..00000000 --- a/zellij-client/src/unit/snapshots/zellij_client__stdin_tests__pixel_info_sent_to_server.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: zellij-client/src/./unit/stdin_tests.rs -assertion_line: 399 -expression: "*format!(\"{:?}\", events_sent_to_server.lock().unwrap())" ---- -[TerminalPixelDimensions(PixelDimensions { text_area_size: Some(SizeInPixels { height: 401, width: 1566 }), character_cell_size: None }), TerminalPixelDimensions(PixelDimensions { text_area_size: None, character_cell_size: Some(SizeInPixels { height: 21, width: 8 }) }), BackgroundColor("rgb:0000/0000/0000"), ForegroundColor("rgb:ffff/ffff/ffff"), ColorRegisters([(0, "rgb:0000/0000/0000"), (1, "rgb:cdcd/0000/0000"), (2, "rgb:0000/cdcd/0000"), (3, "rgb:cdcd/cdcd/0000"), (4, "rgb:0000/0000/eeee"), (5, "rgb:cdcd/0000/cdcd"), (6, "rgb:0000/cdcd/cdcd"), (7, "rgb:e5e5/e5e5/e5e5"), (8, "rgb:7f7f/7f7f/7f7f"), (9, "rgb:ffff/0000/0000"), (10, "rgb:0000/ffff/0000"), (11, "rgb:ffff/ffff/0000"), (12, "rgb:5c5c/5c5c/ffff"), (13, "rgb:ffff/0000/ffff"), (14, "rgb:0000/ffff/ffff"), (15, "rgb:ffff/ffff/ffff"), (16, "rgb:0000/0000/0000"), (17, "rgb:0000/0000/5f5f"), (18, "rgb:0000/0000/8787"), (19, "rgb:0000/0000/afaf"), (20, "rgb:0000/0000/d7d7"), (21, "rgb:0000/0000/ffff"), (22, "rgb:0000/5f5f/0000"), (23, "rgb:0000/5f5f/5f5f"), (24, "rgb:0000/5f5f/8787"), (25, "rgb:0000/5f5f/afaf"), (26, "rgb:0000/5f5f/d7d7"), (27, "rgb:0000/5f5f/ffff"), (28, "rgb:0000/8787/0000"), (29, "rgb:0000/8787/5f5f"), (30, "rgb:0000/8787/8787"), (31, "rgb:0000/8787/afaf"), (32, "rgb:0000/8787/d7d7"), (33, "rgb:0000/8787/ffff"), (34, "rgb:0000/afaf/0000"), (35, "rgb:0000/afaf/5f5f"), (36, "rgb:0000/afaf/8787"), (37, "rgb:0000/afaf/afaf"), (38, "rgb:0000/afaf/d7d7"), (39, "rgb:0000/afaf/ffff"), (40, "rgb:0000/d7d7/0000"), (41, "rgb:0000/d7d7/5f5f"), (42, "rgb:0000/d7d7/8787"), (43, "rgb:0000/d7d7/afaf"), (44, "rgb:0000/d7d7/d7d7"), (45, "rgb:0000/d7d7/ffff"), (46, "rgb:0000/ffff/0000"), (47, "rgb:0000/ffff/5f5f"), (48, "rgb:0000/ffff/8787"), (49, "rgb:0000/ffff/afaf"), (50, "rgb:0000/ffff/d7d7"), (51, "rgb:0000/ffff/ffff"), (52, "rgb:5f5f/0000/0000"), (53, "rgb:5f5f/0000/5f5f"), (54, "rgb:5f5f/0000/8787"), (55, "rgb:5f5f/0000/afaf"), (56, "rgb:5f5f/0000/d7d7"), (57, "rgb:5f5f/0000/ffff"), (58, "rgb:5f5f/5f5f/0000"), (59, "rgb:5f5f/5f5f/5f5f"), (60, "rgb:5f5f/5f5f/8787"), (61, "rgb:5f5f/5f5f/afaf"), (62, "rgb:5f5f/5f5f/d7d7"), (63, "rgb:5f5f/5f5f/ffff"), (64, "rgb:5f5f/8787/0000"), (65, "rgb:5f5f/8787/5f5f"), (66, "rgb:5f5f/8787/8787"), (67, "rgb:5f5f/8787/afaf"), (68, "rgb:5f5f/8787/d7d7"), (69, "rgb:5f5f/8787/ffff"), (70, "rgb:5f5f/afaf/0000"), (71, "rgb:5f5f/afaf/5f5f"), (72, "rgb:5f5f/afaf/8787"), (73, "rgb:5f5f/afaf/afaf"), (74, "rgb:5f5f/afaf/d7d7"), (75, "rgb:5f5f/afaf/ffff"), (76, "rgb:5f5f/d7d7/0000"), (77, "rgb:5f5f/d7d7/5f5f"), (78, "rgb:5f5f/d7d7/8787"), (79, "rgb:5f5f/d7d7/afaf"), (80, "rgb:5f5f/d7d7/d7d7"), (81, "rgb:5f5f/d7d7/ffff"), (82, "rgb:5f5f/ffff/0000"), (83, "rgb:5f5f/ffff/5f5f"), (84, "rgb:5f5f/ffff/8787"), (85, "rgb:5f5f/ffff/afaf"), (86, "rgb:5f5f/ffff/d7d7"), (87, "rgb:5f5f/ffff/ffff"), (88, "rgb:8787/0000/0000"), (89, "rgb:8787/0000/5f5f"), (90, "rgb:8787/0000/8787"), (91, "rgb:8787/0000/afaf"), (92, "rgb:8787/0000/d7d7"), (93, "rgb:8787/0000/ffff"), (94, "rgb:8787/5f5f/0000"), (95, "rgb:8787/5f5f/5f5f"), (96, "rgb:8787/5f5f/8787"), (97, "rgb:8787/5f5f/afaf"), (98, "rgb:8787/5f5f/d7d7"), (99, "rgb:8787/5f5f/ffff"), (100, "rgb:8787/8787/0000"), (101, "rgb:8787/8787/5f5f"), (102, "rgb:8787/8787/8787"), (103, "rgb:8787/8787/afaf"), (104, "rgb:8787/8787/d7d7"), (105, "rgb:8787/8787/ffff"), (106, "rgb:8787/afaf/0000"), (107, "rgb:8787/afaf/5f5f"), (108, "rgb:8787/afaf/8787"), (109, "rgb:8787/afaf/afaf"), (110, "rgb:8787/afaf/d7d7"), (111, "rgb:8787/afaf/ffff"), (112, "rgb:8787/d7d7/0000"), (113, "rgb:8787/d7d7/5f5f"), (114, "rgb:8787/d7d7/8787"), (115, "rgb:8787/d7d7/afaf"), (116, "rgb:8787/d7d7/d7d7"), (117, "rgb:8787/d7d7/ffff"), (118, "rgb:8787/ffff/0000"), (119, "rgb:8787/ffff/5f5f"), (120, "rgb:8787/ffff/8787"), (121, "rgb:8787/ffff/afaf"), (122, "rgb:8787/ffff/d7d7"), (123, "rgb:8787/ffff/ffff"), (124, "rgb:afaf/0000/0000"), (125, "rgb:afaf/0000/5f5f"), (126, "rgb:afaf/0000/8787"), (127, "rgb:afaf/0000/afaf"), (128, "rgb:afaf/0000/d7d7"), (129, "rgb:afaf/0000/ffff"), (130, "rgb:afaf/5f5f/0000"), (131, "rgb:afaf/5f5f/5f5f"), (132, "rgb:afaf/5f5f/8787"), (133, "rgb:afaf/5f5f/afaf"), (134, "rgb:afaf/5f5f/d7d7"), (135, "rgb:afaf/5f5f/ffff"), (136, "rgb:afaf/8787/0000"), (137, "rgb:afaf/8787/5f5f"), (138, "rgb:afaf/8787/8787"), (139, "rgb:afaf/8787/afaf"), (140, "rgb:afaf/8787/d7d7"), (141, "rgb:afaf/8787/ffff"), (142, "rgb:afaf/afaf/0000"), (143, "rgb:afaf/afaf/5f5f"), (144, "rgb:afaf/afaf/8787"), (145, "rgb:afaf/afaf/afaf"), (146, "rgb:afaf/afaf/d7d7"), (147, "rgb:afaf/afaf/ffff"), (148, "rgb:afaf/d7d7/0000"), (149, "rgb:afaf/d7d7/5f5f"), (150, "rgb:afaf/d7d7/8787"), (151, "rgb:afaf/d7d7/afaf"), (152, "rgb:afaf/d7d7/d7d7"), (153, "rgb:afaf/d7d7/ffff"), (154, "rgb:afaf/ffff/0000"), (155, "rgb:afaf/ffff/5f5f"), (156, "rgb:afaf/ffff/8787"), (157, "rgb:afaf/ffff/afaf"), (158, "rgb:afaf/ffff/d7d7"), (159, "rgb:afaf/ffff/ffff"), (160, "rgb:d7d7/0000/0000"), (161, "rgb:d7d7/0000/5f5f"), (162, "rgb:d7d7/0000/8787"), (163, "rgb:d7d7/0000/afaf"), (164, "rgb:d7d7/0000/d7d7"), (165, "rgb:d7d7/0000/ffff"), (166, "rgb:d7d7/5f5f/0000"), (167, "rgb:d7d7/5f5f/5f5f"), (168, "rgb:d7d7/5f5f/8787"), (169, "rgb:d7d7/5f5f/afaf"), (170, "rgb:d7d7/5f5f/d7d7"), (171, "rgb:d7d7/5f5f/ffff"), (172, "rgb:d7d7/8787/0000"), (173, "rgb:d7d7/8787/5f5f"), (174, "rgb:d7d7/8787/8787"), (175, "rgb:d7d7/8787/afaf"), (176, "rgb:d7d7/8787/d7d7"), (177, "rgb:d7d7/8787/ffff"), (178, "rgb:d7d7/afaf/0000"), (179, "rgb:d7d7/afaf/5f5f"), (180, "rgb:d7d7/afaf/8787"), (181, "rgb:d7d7/afaf/afaf"), (182, "rgb:d7d7/afaf/d7d7"), (183, "rgb:d7d7/afaf/ffff"), (184, "rgb:d7d7/d7d7/0000"), (185, "rgb:d7d7/d7d7/5f5f"), (186, "rgb:d7d7/d7d7/8787"), (187, "rgb:d7d7/d7d7/afaf"), (188, "rgb:d7d7/d7d7/d7d7"), (189, "rgb:d7d7/d7d7/ffff"), (190, "rgb:d7d7/ffff/0000"), (191, "rgb:d7d7/ffff/5f5f"), (192, "rgb:d7d7/ffff/8787"), (193, "rgb:d7d7/ffff/afaf"), (194, "rgb:d7d7/ffff/d7d7"), (195, "rgb:d7d7/ffff/ffff"), (196, "rgb:ffff/0000/0000"), (197, "rgb:ffff/0000/5f5f"), (198, "rgb:ffff/0000/8787"), (199, "rgb:ffff/0000/afaf"), (200, "rgb:ffff/0000/d7d7"), (201, "rgb:ffff/0000/ffff"), (202, "rgb:ffff/5f5f/0000"), (203, "rgb:ffff/5f5f/5f5f"), (204, "rgb:ffff/5f5f/8787"), (205, "rgb:ffff/5f5f/afaf"), (206, "rgb:ffff/5f5f/d7d7"), (207, "rgb:ffff/5f5f/ffff"), (208, "rgb:ffff/8787/0000"), (209, "rgb:ffff/8787/5f5f"), (210, "rgb:ffff/8787/8787"), (211, "rgb:ffff/8787/afaf"), (212, "rgb:ffff/8787/d7d7"), (213, "rgb:ffff/8787/ffff"), (214, "rgb:ffff/afaf/0000"), (215, "rgb:ffff/afaf/5f5f"), (216, "rgb:ffff/afaf/8787"), (217, "rgb:ffff/afaf/afaf"), (218, "rgb:ffff/afaf/d7d7"), (219, "rgb:ffff/afaf/ffff"), (220, "rgb:ffff/d7d7/0000"), (221, "rgb:ffff/d7d7/5f5f"), (222, "rgb:ffff/d7d7/8787"), (223, "rgb:ffff/d7d7/afaf"), (224, "rgb:ffff/d7d7/d7d7"), (225, "rgb:ffff/d7d7/ffff"), (226, "rgb:ffff/ffff/0000"), (227, "rgb:ffff/ffff/5f5f"), (228, "rgb:ffff/ffff/8787"), (229, "rgb:ffff/ffff/afaf"), (230, "rgb:ffff/ffff/d7d7"), (231, "rgb:ffff/ffff/ffff"), (232, "rgb:0808/0808/0808"), (233, "rgb:1212/1212/1212"), (234, "rgb:1c1c/1c1c/1c1c"), (235, "rgb:2626/2626/2626"), (236, "rgb:3030/3030/3030"), (237, "rgb:3a3a/3a3a/3a3a"), (238, "rgb:4444/4444/4444"), (239, "rgb:4e4e/4e4e/4e4e"), (240, "rgb:5858/5858/5858"), (241, "rgb:6262/6262/6262"), (242, "rgb:6c6c/6c6c/6c6c"), (243, "rgb:7676/7676/7676"), (244, "rgb:8080/8080/8080"), (245, "rgb:8a8a/8a8a/8a8a"), (246, "rgb:9494/9494/9494"), (247, "rgb:9e9e/9e9e/9e9e"), (248, "rgb:a8a8/a8a8/a8a8"), (249, "rgb:b2b2/b2b2/b2b2"), (250, "rgb:bcbc/bcbc/bcbc"), (251, "rgb:c6c6/c6c6/c6c6"), (252, "rgb:d0d0/d0d0/d0d0"), (253, "rgb:dada/dada/dada"), (254, "rgb:e4e4/e4e4/e4e4"), (255, "rgb:eeee/eeee/eeee")])] diff --git a/zellij-client/src/unit/stdin_tests.rs b/zellij-client/src/unit/stdin_tests.rs deleted file mode 100644 index 8e104887..00000000 --- a/zellij-client/src/unit/stdin_tests.rs +++ /dev/null @@ -1,320 +0,0 @@ -use super::input_loop; -use crate::stdin_ansi_parser::StdinAnsiParser; -use crate::stdin_loop; -use zellij_utils::anyhow::Result; -use zellij_utils::data::{Direction, InputMode, Palette}; -use zellij_utils::input::actions::Action; -use zellij_utils::input::config::Config; -use zellij_utils::input::options::Options; -use zellij_utils::nix; -use zellij_utils::pane_size::Size; -use zellij_utils::termwiz::input::{InputEvent, KeyCode, KeyEvent, Modifiers}; - -use crate::InputInstruction; -use crate::{ - os_input_output::{ClientOsApi, StdinPoller}, - ClientInstruction, CommandIsExecuting, -}; - -use ::insta::assert_snapshot; -use std::path::Path; - -use std::io; -use std::os::unix::io::RawFd; -use std::sync::{Arc, Mutex}; -use std::thread; -use zellij_utils::{ - errors::ErrorContext, - ipc::{ClientToServerMsg, ServerToClientMsg}, -}; - -use zellij_utils::channels::{self, ChannelWithContext, SenderWithContext}; - -fn read_fixture(fixture_name: &str) -> Vec { - let mut path_to_file = std::path::PathBuf::new(); - path_to_file.push("../src"); - path_to_file.push("tests"); - path_to_file.push("fixtures"); - path_to_file.push(fixture_name); - std::fs::read(path_to_file) - .unwrap_or_else(|_| panic!("could not read fixture {:?}", &fixture_name)) -} - -#[allow(unused)] -pub mod commands { - pub const QUIT: [u8; 1] = [17]; // ctrl-q - pub const ESC: [u8; 1] = [27]; - pub const ENTER: [u8; 1] = [10]; // char '\n' - - 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 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 TOGGLE_ACTIVE_TERMINAL_FULLSCREEN_IN_PANE_MODE: [u8; 1] = [102]; // f - pub const CLOSE_PANE_IN_PANE_MODE: [u8; 1] = [120]; // x - pub const MOVE_FOCUS_DOWN_IN_PANE_MODE: [u8; 1] = [106]; // j - pub const MOVE_FOCUS_UP_IN_PANE_MODE: [u8; 1] = [107]; // k - pub const MOVE_FOCUS_LEFT_IN_PANE_MODE: [u8; 1] = [104]; // h - pub const MOVE_FOCUS_RIGHT_IN_PANE_MODE: [u8; 1] = [108]; // l - - pub const SCROLL_MODE: [u8; 1] = [19]; // ctrl-s - pub const SCROLL_UP_IN_SCROLL_MODE: [u8; 1] = [107]; // k - pub const SCROLL_DOWN_IN_SCROLL_MODE: [u8; 1] = [106]; // j - pub const SCROLL_PAGE_UP_IN_SCROLL_MODE: [u8; 1] = [2]; // ctrl-b - pub const SCROLL_PAGE_DOWN_IN_SCROLL_MODE: [u8; 1] = [6]; // ctrl-f - - pub const RESIZE_MODE: [u8; 1] = [18]; // ctrl-r - pub const RESIZE_DOWN_IN_RESIZE_MODE: [u8; 1] = [106]; // j - pub const RESIZE_UP_IN_RESIZE_MODE: [u8; 1] = [107]; // k - pub const RESIZE_LEFT_IN_RESIZE_MODE: [u8; 1] = [104]; // h - pub const RESIZE_RIGHT_IN_RESIZE_MODE: [u8; 1] = [108]; // l - - pub const TAB_MODE: [u8; 1] = [20]; // ctrl-t - pub const NEW_TAB_IN_TAB_MODE: [u8; 1] = [110]; // n - 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 BRACKETED_PASTE_START: [u8; 6] = [27, 91, 50, 48, 48, 126]; // \u{1b}[200~ - pub const BRACKETED_PASTE_END: [u8; 6] = [27, 91, 50, 48, 49, 126]; // \u{1b}[201 - pub const SLEEP: [u8; 0] = []; -} - -#[derive(Default, Clone)] -struct FakeStdoutWriter { - buffer: Arc>>, -} -impl FakeStdoutWriter { - pub fn new(buffer: Arc>>) -> Self { - FakeStdoutWriter { buffer } - } -} -impl io::Write for FakeStdoutWriter { - fn write(&mut self, buf: &[u8]) -> Result { - self.buffer.lock().unwrap().extend_from_slice(buf); - Ok(buf.len()) - } - fn flush(&mut self) -> Result<(), io::Error> { - Ok(()) - } -} - -#[derive(Clone)] -struct FakeClientOsApi { - events_sent_to_server: Arc>>, - command_is_executing: Arc>, - stdout_buffer: Arc>>, - stdin_buffer: Vec, -} - -impl FakeClientOsApi { - pub fn new( - events_sent_to_server: Arc>>, - command_is_executing: CommandIsExecuting, - ) -> Self { - // while command_is_executing itself is implemented with an Arc, we have to have an - // Arc here because we need interior mutability, otherwise we'll have to change the - // ClientOsApi trait, and that will cause a lot of havoc - let command_is_executing = Arc::new(Mutex::new(command_is_executing)); - let stdout_buffer = Arc::new(Mutex::new(vec![])); - FakeClientOsApi { - events_sent_to_server, - command_is_executing, - stdout_buffer, - stdin_buffer: vec![], - } - } - pub fn with_stdin_buffer(mut self, stdin_buffer: Vec) -> Self { - self.stdin_buffer = stdin_buffer; - self - } - pub fn stdout_buffer(&self) -> Vec { - self.stdout_buffer.lock().unwrap().drain(..).collect() - } -} - -impl ClientOsApi for FakeClientOsApi { - fn get_terminal_size_using_fd(&self, _fd: RawFd) -> Size { - unimplemented!() - } - fn set_raw_mode(&mut self, _fd: RawFd) { - unimplemented!() - } - fn unset_raw_mode(&self, _fd: RawFd) -> Result<(), nix::Error> { - unimplemented!() - } - fn get_stdout_writer(&self) -> Box { - let fake_stdout_writer = FakeStdoutWriter::new(self.stdout_buffer.clone()); - Box::new(fake_stdout_writer) - } - fn get_stdin_reader(&self) -> Box { - unimplemented!() - } - fn update_session_name(&mut self, _new_session_name: String) {} - fn read_from_stdin(&mut self) -> Result, &'static str> { - Ok(self.stdin_buffer.drain(..).collect()) - } - fn box_clone(&self) -> Box { - unimplemented!() - } - fn send_to_server(&self, msg: ClientToServerMsg) { - { - let mut events_sent_to_server = self.events_sent_to_server.lock().unwrap(); - events_sent_to_server.push(msg); - } - { - let mut command_is_executing = self.command_is_executing.lock().unwrap(); - command_is_executing.unblock_input_thread(); - } - } - fn recv_from_server(&self) -> Option<(ServerToClientMsg, ErrorContext)> { - unimplemented!() - } - fn handle_signals(&self, _sigwinch_cb: Box, _quit_cb: Box) { - unimplemented!() - } - fn connect_to_server(&self, _path: &Path) { - unimplemented!() - } - fn load_palette(&self) -> Palette { - unimplemented!() - } - fn enable_mouse(&self) -> Result<()> { - Ok(()) - } - fn disable_mouse(&self) -> Result<()> { - Ok(()) - } - fn stdin_poller(&self) -> StdinPoller { - unimplemented!() - } -} - -fn extract_actions_sent_to_server( - events_sent_to_server: Arc>>, -) -> Vec { - let events_sent_to_server = events_sent_to_server.lock().unwrap(); - events_sent_to_server.iter().fold(vec![], |mut acc, event| { - if let ClientToServerMsg::Action(action, None, None) = event { - acc.push(action.clone()); - } - acc - }) -} - -#[test] -pub fn quit_breaks_input_loop() { - let stdin_events = vec![( - commands::QUIT.to_vec(), - InputEvent::Key(KeyEvent { - key: KeyCode::Char('q'), - modifiers: Modifiers::CTRL, - }), - )]; - let events_sent_to_server = Arc::new(Mutex::new(vec![])); - let command_is_executing = CommandIsExecuting::new(); - let client_os_api = Box::new(FakeClientOsApi::new( - events_sent_to_server.clone(), - command_is_executing.clone(), - )); - let config = Config::from_default_assets().unwrap(); - let options = Options::default(); - - let (send_client_instructions, _receive_client_instructions): ChannelWithContext< - ClientInstruction, - > = channels::bounded(50); - let send_client_instructions = SenderWithContext::new(send_client_instructions); - - let (send_input_instructions, receive_input_instructions): ChannelWithContext< - InputInstruction, - > = channels::bounded(50); - let send_input_instructions = SenderWithContext::new(send_input_instructions); - for event in stdin_events { - send_input_instructions - .send(InputInstruction::KeyEvent(event.1, event.0)) - .unwrap(); - } - - let default_mode = InputMode::Normal; - input_loop( - client_os_api, - config, - options, - command_is_executing, - send_client_instructions, - default_mode, - receive_input_instructions, - ); - let expected_actions_sent_to_server = vec![Action::Quit]; - let received_actions = extract_actions_sent_to_server(events_sent_to_server); - assert_eq!( - expected_actions_sent_to_server, received_actions, - "All actions sent to server properly" - ); -} - -#[test] -pub fn move_focus_left_in_normal_mode() { - let stdin_events = vec![ - ( - commands::MOVE_FOCUS_LEFT_IN_NORMAL_MODE.to_vec(), - InputEvent::Key(KeyEvent { - key: KeyCode::Char('h'), - modifiers: Modifiers::ALT, - }), - ), - ( - commands::QUIT.to_vec(), - InputEvent::Key(KeyEvent { - key: KeyCode::Char('q'), - modifiers: Modifiers::CTRL, - }), - ), - ]; - - let events_sent_to_server = Arc::new(Mutex::new(vec![])); - let command_is_executing = CommandIsExecuting::new(); - let client_os_api = Box::new(FakeClientOsApi::new( - events_sent_to_server.clone(), - command_is_executing.clone(), - )); - let config = Config::from_default_assets().unwrap(); - let options = Options::default(); - - let (send_client_instructions, _receive_client_instructions): ChannelWithContext< - ClientInstruction, - > = channels::bounded(50); - let send_client_instructions = SenderWithContext::new(send_client_instructions); - - let (send_input_instructions, receive_input_instructions): ChannelWithContext< - InputInstruction, - > = channels::bounded(50); - let send_input_instructions = SenderWithContext::new(send_input_instructions); - for event in stdin_events { - send_input_instructions - .send(InputInstruction::KeyEvent(event.1, event.0)) - .unwrap(); - } - - let default_mode = InputMode::Normal; - input_loop( - client_os_api, - config, - options, - command_is_executing, - send_client_instructions, - default_mode, - receive_input_instructions, - ); - let expected_actions_sent_to_server = - vec![Action::MoveFocusOrTab(Direction::Left), Action::Quit]; - let received_actions = extract_actions_sent_to_server(events_sent_to_server); - assert_eq!( - expected_actions_sent_to_server, received_actions, - "All actions sent to server properly" - ); -} diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs index d33be7dd..8a264dc8 100644 --- a/zellij-server/src/lib.rs +++ b/zellij-server/src/lib.rs @@ -42,12 +42,13 @@ use zellij_utils::{ channels::{self, ChannelWithContext, SenderWithContext}, cli::CliArgs, consts::{DEFAULT_SCROLL_BUFFER_SIZE, SCROLL_BUFFER_SIZE}, - data::{ConnectToSession, Event, PluginCapabilities}, + data::{ConnectToSession, Event, InputMode, PluginCapabilities}, errors::{prelude::*, ContextType, ErrorInstruction, FatalError, ServerContext}, home::{default_layout_dir, get_default_data_dir}, input::{ command::{RunCommand, TerminalAction}, get_mode_info, + keybinds::Keybinds, layout::Layout, options::Options, plugins::PluginAliases, @@ -94,6 +95,9 @@ pub enum ServerInstruction { client_id: ClientId, }, DisconnectAllClientsExcept(ClientId), + ChangeMode(ClientId, InputMode), + ChangeModeForAllClients(InputMode), + RebindKeys(ClientId, String), // String -> stringified keybindings } impl From<&ServerInstruction> for ServerContext { @@ -121,6 +125,11 @@ impl From<&ServerInstruction> for ServerContext { ServerInstruction::DisconnectAllClientsExcept(..) => { ServerContext::DisconnectAllClientsExcept }, + ServerInstruction::ChangeMode(..) => ServerContext::ChangeMode, + ServerInstruction::ChangeModeForAllClients(..) => { + ServerContext::ChangeModeForAllClients + }, + ServerInstruction::RebindKeys(..) => ServerContext::RebindKeys, } } } @@ -138,6 +147,8 @@ pub(crate) struct SessionMetaData { pub default_shell: Option, pub layout: Box, pub config_options: Box, + pub client_keybinds: HashMap, + pub client_input_modes: HashMap, screen_thread: Option>, pty_thread: Option>, plugin_thread: Option>, @@ -145,6 +156,56 @@ pub(crate) struct SessionMetaData { background_jobs_thread: Option>, } +impl SessionMetaData { + pub fn set_client_keybinds(&mut self, client_id: ClientId, keybinds: Keybinds) { + self.client_keybinds.insert(client_id, keybinds); + self.client_input_modes.insert( + client_id, + self.config_options.default_mode.unwrap_or_default(), + ); + } + pub fn get_client_keybinds_and_mode( + &self, + client_id: &ClientId, + ) -> Option<(&Keybinds, &InputMode)> { + match ( + self.client_keybinds.get(client_id), + self.client_input_modes.get(client_id), + ) { + (Some(client_keybinds), Some(client_input_mode)) => { + Some((client_keybinds, client_input_mode)) + }, + _ => None, + } + } + pub fn change_mode_for_all_clients(&mut self, input_mode: InputMode) { + let all_clients: Vec = self.client_input_modes.keys().copied().collect(); + for client_id in all_clients { + self.client_input_modes.insert(client_id, input_mode); + } + } + pub fn rebind_keys(&mut self, client_id: ClientId, new_keybinds: String) -> Option { + if let Some(current_keybinds) = self.client_keybinds.get_mut(&client_id) { + match Keybinds::from_string( + new_keybinds, + current_keybinds.clone(), + &self.config_options, + ) { + Ok(new_keybinds) => { + *current_keybinds = new_keybinds.clone(); + return Some(new_keybinds); + }, + Err(e) => { + log::error!("Failed to parse keybindings: {}", e); + }, + } + } else { + log::error!("Failed to bind keys for client: {client_id}"); + } + None + } +} + impl Drop for SessionMetaData { fn drop(&mut self) { let _ = self.senders.send_to_pty(PtyInstruction::Exit); @@ -383,6 +444,12 @@ pub fn start_server(mut os_input: Box, socket_path: PathBuf) { plugin_aliases, ); *session_data.write().unwrap() = Some(session); + session_data + .write() + .unwrap() + .as_mut() + .unwrap() + .set_client_keybinds(client_id, client_attributes.keybinds.clone()); session_state .write() .unwrap() @@ -469,8 +536,9 @@ pub fn start_server(mut os_input: Box, socket_path: PathBuf) { pane_id_to_focus, client_id, ) => { - let rlock = session_data.read().unwrap(); - let session_data = rlock.as_ref().unwrap(); + let mut rlock = session_data.write().unwrap(); + let session_data = rlock.as_mut().unwrap(); + session_data.set_client_keybinds(client_id, attrs.keybinds.clone()); session_state .write() .unwrap() @@ -498,7 +566,6 @@ pub fn start_server(mut os_input: Box, socket_path: PathBuf) { .unwrap(); let default_mode = options.default_mode.unwrap_or_default(); let mode_info = get_mode_info(default_mode, &attrs, session_data.capabilities); - let mode = mode_info.mode; session_data .senders .send_to_screen(ScreenInstruction::ChangeMode(mode_info.clone(), client_id)) @@ -511,12 +578,6 @@ pub fn start_server(mut os_input: Box, socket_path: PathBuf) { Event::ModeUpdate(mode_info), )])) .unwrap(); - send_to_client!( - client_id, - os_input, - ServerToClientMsg::SwitchToMode(mode), - session_state - ); }, ServerInstruction::UnblockInputThread => { let client_ids = session_state.read().unwrap().client_ids(); @@ -827,6 +888,42 @@ pub fn start_server(mut os_input: Box, socket_path: PathBuf) { .unwrap() .associate_pipe_with_client(pipe_id, client_id); }, + ServerInstruction::ChangeMode(client_id, input_mode) => { + session_data + .write() + .unwrap() + .as_mut() + .unwrap() + .client_input_modes + .insert(client_id, input_mode); + }, + ServerInstruction::ChangeModeForAllClients(input_mode) => { + session_data + .write() + .unwrap() + .as_mut() + .unwrap() + .change_mode_for_all_clients(input_mode); + }, + ServerInstruction::RebindKeys(client_id, new_keybinds) => { + let new_keybinds = session_data + .write() + .unwrap() + .as_mut() + .unwrap() + .rebind_keys(client_id, new_keybinds) + .clone(); + if let Some(new_keybinds) = new_keybinds { + session_data + .write() + .unwrap() + .as_ref() + .unwrap() + .senders + .send_to_screen(ScreenInstruction::RebindKeys(new_keybinds, client_id)) + .unwrap(); + } + }, } } @@ -1054,6 +1151,8 @@ fn init_session( client_attributes, layout, config_options: config_options.clone(), + client_keybinds: HashMap::new(), + client_input_modes: HashMap::new(), screen_thread: Some(screen_thread), pty_thread: Some(pty_thread), plugin_thread: Some(plugin_thread), diff --git a/zellij-server/src/plugins/unit/plugin_tests.rs b/zellij-server/src/plugins/unit/plugin_tests.rs index 22a1bf1f..b644fe2f 100644 --- a/zellij-server/src/plugins/unit/plugin_tests.rs +++ b/zellij-server/src/plugins/unit/plugin_tests.rs @@ -6485,6 +6485,87 @@ pub fn disconnect_other_clients_plugins_command() { assert_snapshot!(format!("{:#?}", switch_session_event)); } +#[test] +#[ignore] +pub fn rebind_keys_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let cache_path = plugin_host_folder.join("permissions_test.kdl"); + let (plugin_thread_sender, server_receiver, screen_receiver, teardown) = + create_plugin_thread_with_server_receiver(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + configuration: Default::default(), + ..Default::default() + }); + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!( + received_screen_instructions, + ScreenInstruction::Exit, + screen_receiver, + 1, + &PermissionType::ChangeApplicationState, + cache_path, + plugin_thread_sender, + client_id + ); + let received_server_instruction = Arc::new(Mutex::new(vec![])); + let server_thread = log_actions_in_thread!( + received_server_instruction, + ServerInstruction::RebindKeys, + server_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + false, + plugin_title, + run_plugin, + tab_index, + None, + client_id, + size, + None, + false, + )); + std::thread::sleep(std::time::Duration::from_millis(500)); + + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(KeyWithModifier::new(BareKey::Char('0')).with_ctrl_modifier()), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(500)); + teardown(); + server_thread.join().unwrap(); // this might take a while if the cache is cold + let rebind_keys_event = received_server_instruction + .lock() + .unwrap() + .iter() + .rev() + .find_map(|i| { + if let ServerInstruction::RebindKeys(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", rebind_keys_event)); +} + #[test] #[ignore] pub fn run_plugin_in_specific_cwd() { diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__granted_permission_request_result.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__granted_permission_request_result.snap index 9c3ecd06..465f1088 100644 --- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__granted_permission_request_result.snap +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__granted_permission_request_result.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/plugins/./unit/plugin_tests.rs -assertion_line: 5307 +assertion_line: 5500 expression: "format!(\"{:#?}\", permissions)" --- Some( @@ -14,5 +14,6 @@ Some( WebAccess, ReadCliPipes, MessageAndLaunchOtherPlugins, + RebindKeys, ], ) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rebind_keys_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rebind_keys_plugin_command.snap new file mode 100644 index 00000000..b5375e96 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rebind_keys_plugin_command.snap @@ -0,0 +1,11 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 6566 +expression: "format!(\"{:#?}\", rebind_keys_event)" +--- +Some( + RebindKeys( + 1, + "\n keybinds {\n locked {\n bind \"a\" { NewTab; }\n }\n }\n ", + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__request_plugin_permissions.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__request_plugin_permissions.snap index 3d9f7cfe..a0fec410 100644 --- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__request_plugin_permissions.snap +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__request_plugin_permissions.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/plugins/./unit/plugin_tests.rs -assertion_line: 5217 +assertion_line: 5409 expression: "format!(\"{:#?}\", new_tab_event)" --- Some( @@ -16,5 +16,6 @@ Some( WebAccess, ReadCliPipes, MessageAndLaunchOtherPlugins, + RebindKeys, ], ) diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs index 8ec4064f..52ba0953 100644 --- a/zellij-server/src/plugins/zellij_exports.rs +++ b/zellij-server/src/plugins/zellij_exports.rs @@ -268,6 +268,7 @@ fn host_run_plugin_command(env: FunctionEnvMut) { PluginCommand::WatchFilesystem => watch_filesystem(env), PluginCommand::DumpSessionLayout => dump_session_layout(env), PluginCommand::CloseSelf => close_self(env), + PluginCommand::RebindKeys(new_keybinds) => rebind_keys(env, new_keybinds)?, }, (PermissionStatus::Denied, permission) => { log::error!( @@ -842,6 +843,16 @@ fn close_self(env: &ForeignFunctionEnv) { .non_fatal(); } +fn rebind_keys(env: &ForeignFunctionEnv, new_keybinds: String) -> Result<()> { + let err_context = || "Failed to rebind keys"; + let client_id = env.plugin_env.client_id; + env.plugin_env + .senders + .send_to_server(ServerInstruction::RebindKeys(client_id, new_keybinds)) + .with_context(err_context)?; + Ok(()) +} + fn switch_to_mode(env: &ForeignFunctionEnv, input_mode: InputMode) { let action = Action::SwitchToMode(input_mode); let error_msg = || { @@ -1594,6 +1605,7 @@ fn check_command_permission( | PluginCommand::CliPipeOutput(..) => PermissionType::ReadCliPipes, PluginCommand::MessageToPlugin(..) => PermissionType::MessageAndLaunchOtherPlugins, PluginCommand::DumpSessionLayout => PermissionType::ReadApplicationState, + PluginCommand::RebindKeys(..) => PermissionType::RebindKeys, _ => return (PermissionStatus::Granted, None), }; diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index 19f11ccb..28dc4387 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -101,6 +101,9 @@ pub(crate) fn route_action( Event::ModeUpdate(get_mode_info(mode, attrs, capabilities)), )])) .with_context(err_context)?; + senders + .send_to_server(ServerInstruction::ChangeMode(client_id, mode)) + .with_context(err_context)?; senders .send_to_screen(ScreenInstruction::ChangeMode( get_mode_info(mode, attrs, capabilities), @@ -344,6 +347,11 @@ pub(crate) fn route_action( Event::ModeUpdate(get_mode_info(input_mode, attrs, capabilities)), )])) .with_context(err_context)?; + + senders + .send_to_server(ServerInstruction::ChangeModeForAllClients(input_mode)) + .with_context(err_context)?; + senders .send_to_screen(ScreenInstruction::ChangeModeForAllClients(get_mode_info( input_mode, @@ -988,20 +996,42 @@ pub(crate) fn route_thread_main( -> Result { let mut should_break = false; match instruction { + ClientToServerMsg::Key(key, raw_bytes, is_kitty_keyboard_protocol) => { + if let Some(rlocked_sessions) = rlocked_sessions.as_ref() { + match rlocked_sessions.get_client_keybinds_and_mode(&client_id) { + Some((keybinds, input_mode)) => { + for action in keybinds + .get_actions_for_key_in_mode_or_default_action( + &input_mode, + &key, + raw_bytes, + is_kitty_keyboard_protocol, + ) + { + if route_action( + action, + client_id, + None, + rlocked_sessions.senders.clone(), + rlocked_sessions.capabilities.clone(), + rlocked_sessions.client_attributes.clone(), + rlocked_sessions.default_shell.clone(), + rlocked_sessions.layout.clone(), + Some(&mut seen_cli_pipes), + )? { + should_break = true; + } + } + }, + None => { + log::error!("Failed to get keybindings for client"); + }, + } + } + }, ClientToServerMsg::Action(action, maybe_pane_id, maybe_client_id) => { let client_id = maybe_client_id.unwrap_or(client_id); if let Some(rlocked_sessions) = rlocked_sessions.as_ref() { - if let Action::SwitchToMode(input_mode) = action { - let send_res = os_input.send_to_client( - client_id, - ServerToClientMsg::SwitchToMode(input_mode), - ); - if send_res.is_err() { - let _ = to_server - .send(ServerInstruction::RemoveClient(client_id)); - return Ok(true); - } - } if route_action( action, client_id, diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index cf3a6dd7..8e1e4002 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -13,6 +13,7 @@ use zellij_utils::data::{ }; use zellij_utils::errors::prelude::*; use zellij_utils::input::command::RunCommand; +use zellij_utils::input::keybinds::Keybinds; use zellij_utils::input::options::Clipboard; use zellij_utils::pane_size::{Size, SizeInPixels}; use zellij_utils::{ @@ -360,6 +361,7 @@ pub enum ScreenInstruction { DumpLayoutToHd, RenameSession(String, ClientId), // String -> new name ListClientsMetadata(Option, ClientId), // Option - default shell + RebindKeys(Keybinds, ClientId), } impl From<&ScreenInstruction> for ScreenContext { @@ -544,6 +546,7 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenInstruction::DumpLayoutToHd => ScreenContext::DumpLayoutToHd, ScreenInstruction::RenameSession(..) => ScreenContext::RenameSession, ScreenInstruction::ListClientsMetadata(..) => ScreenContext::ListClientsMetadata, + ScreenInstruction::RebindKeys(..) => ScreenContext::RebindKeys, } } } @@ -1774,12 +1777,6 @@ impl Screen { tab.mark_active_pane_for_rerender(client_id); tab.update_input_modes()?; } - - if let Some(os_input) = &mut self.bus.os_input { - let _ = - os_input.send_to_client(client_id, ServerToClientMsg::SwitchToMode(mode_info.mode)); - } - Ok(()) } pub fn change_mode_for_all_clients(&mut self, mode_info: ModeInfo) -> Result<()> { @@ -2154,6 +2151,23 @@ impl Screen { } Ok(()) } + pub fn rebind_keys(&mut self, new_keybinds: Keybinds, client_id: ClientId) -> Result<()> { + if self.connected_clients_contains(&client_id) { + let mode_info = self + .mode_info + .entry(client_id) + .or_insert_with(|| self.default_mode_info.clone()); + mode_info.update_keybinds(new_keybinds); + for tab in self.tabs.values_mut() { + tab.change_mode_info(mode_info.clone(), client_id); + tab.mark_active_pane_for_rerender(client_id); + tab.update_input_modes()?; + } + } else { + log::error!("Could not find client_id {client_id} to rebind keys"); + } + Ok(()) + } fn unblock_input(&self) -> Result<()> { self.bus .senders @@ -2295,6 +2309,9 @@ impl Screen { } found_plugin } + fn connected_clients_contains(&self, client_id: &ClientId) -> bool { + self.connected_clients.borrow().contains(client_id) + } } // The box is here in order to make the @@ -4010,6 +4027,9 @@ pub(crate) fn screen_thread_main( } screen.unblock_input()?; }, + ScreenInstruction::RebindKeys(new_keybinds, client_id) => { + screen.rebind_keys(new_keybinds, client_id).non_fatal(); + }, } } Ok(()) diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index bb26b5f4..1fe7af29 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -514,6 +514,8 @@ impl MockScreen { background_jobs_thread: None, config_options: Default::default(), layout, + client_input_modes: HashMap::new(), + client_keybinds: HashMap::new(), } } } @@ -571,6 +573,8 @@ impl MockScreen { background_jobs_thread: None, config_options: Default::default(), layout, + client_input_modes: HashMap::new(), + client_keybinds: HashMap::new(), }; let os_input = FakeInputOutput::default(); @@ -2449,31 +2453,41 @@ pub fn send_cli_edit_action_with_split_direction() { #[test] pub fn send_cli_switch_mode_action() { - let size = Size { - cols: 121, - rows: 20, - }; + let size = Size { cols: 80, rows: 10 }; let client_id = 10; // fake client id should not appear in the screen's state - let mut mock_screen = MockScreen::new(size); - let session_metadata = mock_screen.clone_session_metadata(); let mut initial_layout = TiledPaneLayout::default(); initial_layout.children_split_direction = SplitDirection::Vertical; initial_layout.children = vec![TiledPaneLayout::default(), TiledPaneLayout::default()]; + let mut mock_screen = MockScreen::new(size); + let session_metadata = mock_screen.clone_session_metadata(); let screen_thread = mock_screen.run(Some(initial_layout), vec![]); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_instruction = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let cli_switch_mode = CliAction::SwitchMode { input_mode: InputMode::Locked, }; send_cli_action_to_server(&session_metadata, cli_switch_mode, client_id); - std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be - mock_screen.teardown(vec![screen_thread]); - assert_snapshot!(format!( - "{:?}", - *mock_screen - .os_input - .server_to_client_messages - .lock() - .unwrap() - )); + + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_instruction, screen_thread]); + + let switch_mode_action = received_server_instructions + .lock() + .unwrap() + .iter() + .find(|instruction| match instruction { + ServerInstruction::ChangeModeForAllClients(..) => true, + _ => false, + }) + .cloned(); + + assert_snapshot!(format!("{:?}", switch_mode_action)); } #[test] diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_switch_mode_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_switch_mode_action.snap index f79859e9..283fafef 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_switch_mode_action.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_switch_mode_action.snap @@ -1,6 +1,6 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 2465 -expression: "format!(\"{:?}\", *\n mock_screen.os_input.server_to_client_messages.lock().unwrap())" +assertion_line: 2521 +expression: "format!(\"{:?}\", switch_mode_action)" --- -{1: [QueryTerminalSize, SwitchToMode(Locked)]} +Some(ChangeModeForAllClients(Locked)) diff --git a/zellij-tile/src/shim.rs b/zellij-tile/src/shim.rs index ead21332..01049b37 100644 --- a/zellij-tile/src/shim.rs +++ b/zellij-tile/src/shim.rs @@ -808,6 +808,14 @@ pub fn dump_session_layout() { unsafe { host_run_plugin_command() }; } +/// Rebind keys for the current user +pub fn rebind_keys(keys: String) { + let plugin_command = PluginCommand::RebindKeys(keys); + let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); + object_to_stdout(&protobuf_plugin_command.encode_to_vec()); + unsafe { host_run_plugin_command() }; +} + // Utility Functions #[allow(unused)] diff --git a/zellij-utils/assets/prost/api.plugin_command.rs b/zellij-utils/assets/prost/api.plugin_command.rs index 98883353..393f2e0c 100644 --- a/zellij-utils/assets/prost/api.plugin_command.rs +++ b/zellij-utils/assets/prost/api.plugin_command.rs @@ -5,7 +5,7 @@ pub struct PluginCommand { pub name: i32, #[prost( oneof = "plugin_command::Payload", - tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 60, 61, 62" + tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 60, 61, 62, 63" )] pub payload: ::core::option::Option, } @@ -118,6 +118,8 @@ pub mod plugin_command { ScanHostFolderPayload(::prost::alloc::string::String), #[prost(message, tag = "62")] NewTabsWithLayoutInfoPayload(super::NewTabsWithLayoutInfoPayload), + #[prost(string, tag = "63")] + RebindKeysPayload(::prost::alloc::string::String), } } #[allow(clippy::derive_partial_eq_without_eq)] @@ -431,6 +433,7 @@ pub enum CommandName { DumpSessionLayout = 84, CloseSelf = 85, NewTabsWithLayoutInfo = 86, + RebindKeys = 87, } impl CommandName { /// String value of the enum field names used in the ProtoBuf definition. @@ -526,6 +529,7 @@ impl CommandName { CommandName::DumpSessionLayout => "DumpSessionLayout", CommandName::CloseSelf => "CloseSelf", CommandName::NewTabsWithLayoutInfo => "NewTabsWithLayoutInfo", + CommandName::RebindKeys => "RebindKeys", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -618,6 +622,7 @@ impl CommandName { "DumpSessionLayout" => Some(Self::DumpSessionLayout), "CloseSelf" => Some(Self::CloseSelf), "NewTabsWithLayoutInfo" => Some(Self::NewTabsWithLayoutInfo), + "RebindKeys" => Some(Self::RebindKeys), _ => None, } } diff --git a/zellij-utils/assets/prost/api.plugin_permission.rs b/zellij-utils/assets/prost/api.plugin_permission.rs index f928625d..50bc853f 100644 --- a/zellij-utils/assets/prost/api.plugin_permission.rs +++ b/zellij-utils/assets/prost/api.plugin_permission.rs @@ -10,6 +10,7 @@ pub enum PermissionType { WebAccess = 6, ReadCliPipes = 7, MessageAndLaunchOtherPlugins = 8, + RebindKeys = 9, } impl PermissionType { /// String value of the enum field names used in the ProtoBuf definition. @@ -29,6 +30,7 @@ impl PermissionType { PermissionType::MessageAndLaunchOtherPlugins => { "MessageAndLaunchOtherPlugins" } + PermissionType::RebindKeys => "RebindKeys", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -43,6 +45,7 @@ impl PermissionType { "WebAccess" => Some(Self::WebAccess), "ReadCliPipes" => Some(Self::ReadCliPipes), "MessageAndLaunchOtherPlugins" => Some(Self::MessageAndLaunchOtherPlugins), + "RebindKeys" => Some(Self::RebindKeys), _ => None, } } diff --git a/zellij-utils/src/data.rs b/zellij-utils/src/data.rs index 2625b252..602b1942 100644 --- a/zellij-utils/src/data.rs +++ b/zellij-utils/src/data.rs @@ -1,5 +1,6 @@ use crate::input::actions::Action; use crate::input::config::ConversionError; +use crate::input::keybinds::Keybinds; use crate::input::layout::SplitSize; use clap::ArgEnum; use serde::{Deserialize, Serialize}; @@ -914,6 +915,7 @@ pub enum Permission { WebAccess, ReadCliPipes, MessageAndLaunchOtherPlugins, + RebindKeys, } impl PermissionType { @@ -934,6 +936,7 @@ impl PermissionType { PermissionType::MessageAndLaunchOtherPlugins => { "Send messages to and launch other plugins".to_owned() }, + PermissionType::RebindKeys => "Rebind keys".to_owned(), } } } @@ -1130,6 +1133,9 @@ impl ModeInfo { } vec![] } + pub fn update_keybinds(&mut self, keybinds: Keybinds) { + self.keybinds = keybinds.to_keybinds_vec(); + } } #[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)] @@ -1733,4 +1739,5 @@ pub enum PluginCommand { DumpSessionLayout, CloseSelf, NewTabsWithLayoutInfo(LayoutInfo), + RebindKeys(String), // String -> stringified keybindings } diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index 248ff9be..3656d8ad 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -353,6 +353,7 @@ pub enum ScreenContext { RenameSession, DumpLayoutToPlugin, ListClientsMetadata, + RebindKeys, } /// Stack call representations corresponding to the different types of [`PtyInstruction`]s. @@ -454,6 +455,9 @@ pub enum ServerContext { CliPipeOutput, AssociatePipeWithClient, DisconnectAllClientsExcept, + ChangeMode, + ChangeModeForAllClients, + RebindKeys, } #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] diff --git a/zellij-utils/src/ipc.rs b/zellij-utils/src/ipc.rs index fc004457..2713ca78 100644 --- a/zellij-utils/src/ipc.rs +++ b/zellij-utils/src/ipc.rs @@ -1,7 +1,7 @@ //! IPC stuff for starting to split things into a client and server model. use crate::{ cli::CliArgs, - data::{ClientId, ConnectToSession, InputMode, Style}, + data::{ClientId, ConnectToSession, KeyWithModifier, Style}, errors::{get_current_ctx, prelude::*, ErrorContext}, input::keybinds::Keybinds, input::{actions::Action, layout::Layout, options::Options, plugins::PluginAliases}, @@ -85,6 +85,7 @@ pub enum ClientToServerMsg { Option<(u32, bool)>, // (pane_id, is_plugin) => pane id to focus ), Action(Action, Option, Option), // u32 is the terminal id + Key(KeyWithModifier, Vec, bool), // key, raw_bytes, is_kitty_keyboard_protocol ClientExited, KillSession, ConnStatus, @@ -97,7 +98,6 @@ pub enum ServerToClientMsg { Render(String), UnblockInputThread, Exit(ExitReason), - SwitchToMode(InputMode), Connected, ActiveClients(Vec), Log(Vec), diff --git a/zellij-utils/src/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs index 288c09f7..a69b6b02 100644 --- a/zellij-utils/src/kdl/mod.rs +++ b/zellij-utils/src/kdl/mod.rs @@ -1880,6 +1880,22 @@ impl Keybinds { } Ok(input_mode_keybinds) } + pub fn from_string( + stringified_keybindings: String, + base_keybinds: Keybinds, + config_options: &Options, + ) -> Result { + let document: KdlDocument = stringified_keybindings.parse()?; + if let Some(kdl_keybinds) = document.get("keybinds") { + Keybinds::from_kdl(&kdl_keybinds, base_keybinds, config_options) + } else { + Err(ConfigError::new_kdl_error( + format!("Could not find keybinds node"), + document.span().offset(), + document.span().len(), + )) + } + } } impl Config { diff --git a/zellij-utils/src/plugin_api/plugin_command.proto b/zellij-utils/src/plugin_api/plugin_command.proto index 718e8b4c..14ab3045 100644 --- a/zellij-utils/src/plugin_api/plugin_command.proto +++ b/zellij-utils/src/plugin_api/plugin_command.proto @@ -98,6 +98,7 @@ enum CommandName { DumpSessionLayout = 84; CloseSelf = 85; NewTabsWithLayoutInfo = 86; + RebindKeys = 87; } message PluginCommand { @@ -155,6 +156,7 @@ message PluginCommand { KillSessionsPayload kill_sessions_payload = 60; string scan_host_folder_payload = 61; NewTabsWithLayoutInfoPayload new_tabs_with_layout_info_payload = 62; + string rebind_keys_payload = 63; } } diff --git a/zellij-utils/src/plugin_api/plugin_command.rs b/zellij-utils/src/plugin_api/plugin_command.rs index 771b6151..aeafc1d4 100644 --- a/zellij-utils/src/plugin_api/plugin_command.rs +++ b/zellij-utils/src/plugin_api/plugin_command.rs @@ -888,6 +888,12 @@ impl TryFrom for PluginCommand { }, _ => Err("Mismatched payload for NewTabsWithLayoutInfo"), }, + Some(CommandName::RebindKeys) => match protobuf_plugin_command.payload { + Some(Payload::RebindKeysPayload(rebind_keys_payload)) => { + Ok(PluginCommand::RebindKeys(rebind_keys_payload)) + }, + _ => Err("Mismatched payload for RebindKeys"), + }, None => Err("Unrecognized plugin command"), } } @@ -1420,6 +1426,10 @@ impl TryFrom for ProtobufPluginCommand { )), }) }, + PluginCommand::RebindKeys(rebind_keys_payload) => Ok(ProtobufPluginCommand { + name: CommandName::RebindKeys as i32, + payload: Some(Payload::RebindKeysPayload(rebind_keys_payload)), + }), } } } diff --git a/zellij-utils/src/plugin_api/plugin_permission.proto b/zellij-utils/src/plugin_api/plugin_permission.proto index 761384c1..cc1fda6a 100644 --- a/zellij-utils/src/plugin_api/plugin_permission.proto +++ b/zellij-utils/src/plugin_api/plugin_permission.proto @@ -12,4 +12,5 @@ enum PermissionType { WebAccess = 6; ReadCliPipes = 7; MessageAndLaunchOtherPlugins = 8; + RebindKeys = 9; } diff --git a/zellij-utils/src/plugin_api/plugin_permission.rs b/zellij-utils/src/plugin_api/plugin_permission.rs index 4f258ac2..968de917 100644 --- a/zellij-utils/src/plugin_api/plugin_permission.rs +++ b/zellij-utils/src/plugin_api/plugin_permission.rs @@ -24,6 +24,7 @@ impl TryFrom for PermissionType { ProtobufPermissionType::MessageAndLaunchOtherPlugins => { Ok(PermissionType::MessageAndLaunchOtherPlugins) }, + ProtobufPermissionType::RebindKeys => Ok(PermissionType::RebindKeys), } } } @@ -49,6 +50,7 @@ impl TryFrom for ProtobufPermissionType { PermissionType::MessageAndLaunchOtherPlugins => { Ok(ProtobufPermissionType::MessageAndLaunchOtherPlugins) }, + PermissionType::RebindKeys => Ok(ProtobufPermissionType::RebindKeys), } } }