From fed661920359e7dfcd3487d2b1b81ea61defb7c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=93=87=E5=91=9C=E5=93=87=E5=91=9C=E5=91=80=E5=92=A6?= =?UTF-8?q?=E8=80=B6?= Date: Thu, 2 Mar 2023 00:28:17 +0800 Subject: [PATCH] feat(cli): `QueryTabNames` cli action to list all tab names (#2145) * extend display char in tab * Add action to list all tab names * print tab names and remove logs * change msg name, and handle Log in normal client * fix log * resolve code conflict * change var name * add snapshot test * fix failed test case * restore snapshot * Revert "restore snapshot" This reverts commit b97a9512ab106615a1a1e5882392a03a17cdf1a3. * restore snapshot * revert snapshot * fix(layout): various parser and ui fixes (#2191) * fix(layout): error on nodes outside layout node * fix(layout): move stacked property to pane * fix(layout): various stack exceptions * fix(ui): non-flexible stacked pane titles now take up their full length * fix(ui): stack titles with no-pane-frames take up their proper length * style(fmt): rustfmt * docs(changelog): layout fixes * fix(messaging): cache hold pane messages by their tab_id if the tab is not ready (#2196) * fix(messaging): cache hold pane messages by their tab_id if the tab is not ready * style(fmt): rustfmt * docs(changelog): open panes fix * fix(layout): tab focus (#2197) * fix(layout): tab focus * style(fmt): rustfmt * docs(changel0g): tab focus fix * fix(cli): new-tab now also looks in layout_dir for layouts (#2198) * fix(cli): the new-tab action now also searches for layouts in the layout dir * style(fmt): rustfmt * fix(tests): add missing parameter to cli action * docs(changelog): new-tab cli layout folder fix * fix(kdl): new-tab keybind looks in layout_dir for layouts (#2200) * fix(themes): missing tokyo-night-dark theme * fix(kdl): new-tab keybind also looks in layout_dir for layouts * docs(changelog): new-tab keybind layout folder fix * fix(cli): edit cwd (#2201) * fix(cli): properly set cwd for edit panes * fix(layouts): properly set cwd for edit panes * style(fmt): rustfmt * docs(changelog0 * fix(layouts): do not relayout twice on auto_layout (#2202) * fix(layouts): do not relayout twice on auto_layout * style(fmt): rustfmt * fix(new-tab): get config parameters from config file (#2203) * fix(cli): take default shell from config if it exists when opening new tab * fix(cli): take layout dir from config when opening new tab if it exists * style(fmt): rustfmt * docs(changelog): new-tab config parameters * fix(grid): only use background pending styling when deleting characters (#2204) * docs(changelog): neovim underline fix * feat(layouts): exact panes constraint (#2206) * style(fmt): remove warnings * fix(swap-layouts): introduce exact panes constraint * fix(swap-layouts): improve floating pane swap layout ux * style(fmt): rustfmt * docs(changelog): exact panes constraint * fix(pty): report no-cwd for empty path returned from sysinfo (#2213) * fix(sixel): report pixel size in winsize change ioctl (#2212) * fix(sixel): report pixel size in winsize change ioctl * style(fmt): rustfmt * docs(changelog): various fixes * style(code): naming * test(log): adjust query tab names test to look at the log message * style(fmt): rustfmt --------- Co-authored-by: Aram Drevekenin Co-authored-by: Jae-Heon Ji <32578710+jaeheonji@users.noreply.github.com> --- zellij-client/src/cli_client.rs | 4 +++ zellij-client/src/lib.rs | 8 +++++ zellij-server/src/lib.rs | 10 ++++++ zellij-server/src/route.rs | 6 ++++ zellij-server/src/screen.rs | 15 +++++++- zellij-server/src/tab/mod.rs | 2 +- zellij-server/src/unit/screen_tests.rs | 36 +++++++++++++++++++ ...ests__send_cli_query_tab_names_action.snap | 14 ++++++++ zellij-utils/src/cli.rs | 2 ++ zellij-utils/src/errors.rs | 3 ++ zellij-utils/src/input/actions.rs | 3 ++ zellij-utils/src/input/unit/layout_test.rs | 1 + zellij-utils/src/ipc.rs | 1 + 13 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_query_tab_names_action.snap diff --git a/zellij-client/src/cli_client.rs b/zellij-client/src/cli_client.rs index 95cd9d133d..197efa141e 100644 --- a/zellij-client/src/cli_client.rs +++ b/zellij-client/src/cli_client.rs @@ -28,6 +28,10 @@ pub fn start_cli_client(os_input: Box, session_name: &str, acti os_input.send_to_server(ClientToServerMsg::ClientExited); process::exit(0); }, + Some((ServerToClientMsg::Log(log_lines), _)) => { + log_lines.iter().for_each(|line| println!("{line}")); + process::exit(0); + }, _ => {}, } } diff --git a/zellij-client/src/lib.rs b/zellij-client/src/lib.rs index 67a7fb902e..68bc45e9e9 100644 --- a/zellij-client/src/lib.rs +++ b/zellij-client/src/lib.rs @@ -45,6 +45,7 @@ pub(crate) enum ClientInstruction { ActiveClients(Vec), StartedParsingStdinQuery, DoneParsingStdinQuery, + Log(Vec), } impl From for ClientInstruction { @@ -58,6 +59,7 @@ impl From for ClientInstruction { }, ServerToClientMsg::Connected => ClientInstruction::Connected, ServerToClientMsg::ActiveClients(clients) => ClientInstruction::ActiveClients(clients), + ServerToClientMsg::Log(log_lines) => ClientInstruction::Log(log_lines), } } } @@ -72,6 +74,7 @@ impl From<&ClientInstruction> for ClientContext { ClientInstruction::SwitchToMode(_) => ClientContext::SwitchToMode, ClientInstruction::Connected => ClientContext::Connected, ClientInstruction::ActiveClients(_) => ClientContext::ActiveClients, + ClientInstruction::Log(_) => ClientContext::Log, ClientInstruction::StartedParsingStdinQuery => ClientContext::StartedParsingStdinQuery, ClientInstruction::DoneParsingStdinQuery => ClientContext::DoneParsingStdinQuery, } @@ -406,6 +409,11 @@ pub fn start_client( .send(InputInstruction::SwitchToMode(input_mode)) .unwrap(); }, + ClientInstruction::Log(lines_to_log) => { + for line in lines_to_log { + log::info!("{line}"); + } + }, _ => {}, } } diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs index 5dc728fb4e..34c807f16e 100644 --- a/zellij-server/src/lib.rs +++ b/zellij-server/src/lib.rs @@ -77,6 +77,7 @@ pub enum ServerInstruction { AttachClient(ClientAttributes, Options, ClientId), ConnStatus(ClientId), ActiveClients(ClientId), + Log(Vec, ClientId), } impl From<&ServerInstruction> for ServerContext { @@ -93,6 +94,7 @@ impl From<&ServerInstruction> for ServerContext { ServerInstruction::AttachClient(..) => ServerContext::AttachClient, ServerInstruction::ConnStatus(..) => ServerContext::ConnStatus, ServerInstruction::ActiveClients(_) => ServerContext::ActiveClients, + ServerInstruction::Log(..) => ServerContext::Log, } } } @@ -623,6 +625,14 @@ pub fn start_server(mut os_input: Box, socket_path: PathBuf) { session_state ); }, + ServerInstruction::Log(lines_to_log, client_id) => { + send_to_client!( + client_id, + os_input, + ServerToClientMsg::Log(lines_to_log), + session_state + ); + }, } } diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index 53ccf964da..a4ab8dcf96 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -659,6 +659,12 @@ pub(crate) fn route_action( .send_to_screen(ScreenInstruction::NextSwapLayout(client_id)) .with_context(err_context)?; }, + Action::QueryTabNames => { + session + .senders + .send_to_screen(ScreenInstruction::QueryTabNames(client_id)) + .with_context(err_context)?; + }, } Ok(should_break) } diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index 97acc0fdf0..a5b8b8cd0f 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -248,6 +248,7 @@ pub enum ScreenInstruction { ClearPaneFrameColorOverride(Vec), PreviousSwapLayout(ClientId), NextSwapLayout(ClientId), + QueryTabNames(ClientId), } impl From<&ScreenInstruction> for ScreenContext { @@ -390,6 +391,7 @@ impl From<&ScreenInstruction> for ScreenContext { }, ScreenInstruction::PreviousSwapLayout(..) => ScreenContext::PreviousSwapLayout, ScreenInstruction::NextSwapLayout(..) => ScreenContext::NextSwapLayout, + ScreenInstruction::QueryTabNames(..) => ScreenContext::QueryTabNames, } } } @@ -1171,7 +1173,7 @@ impl Screen { }, c => { // It only allows printable unicode - if buf.iter().all(|u| matches!(u, 0x20..=0x7E | 0x80..=0xFF)) { + if buf.iter().all(|u| matches!(u, 0x20..=0x7E | 0xA0..=0xFF)) { active_tab.name.push_str(c); } }, @@ -2360,6 +2362,17 @@ pub(crate) fn screen_thread_main( screen.update_tabs()?; screen.unblock_input()?; }, + ScreenInstruction::QueryTabNames(client_id) => { + let tab_names = screen + .get_tabs_mut() + .values() + .map(|tab| tab.name.clone()) + .collect::>(); + screen + .bus + .senders + .send_to_server(ServerInstruction::Log(tab_names, client_id))?; + }, } } Ok(()) diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index 7cdef96191..d009a3714c 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -3082,7 +3082,7 @@ impl Tab { // It only allows printable unicode, delete and backspace keys. let is_updatable = buf .iter() - .all(|u| matches!(u, 0x20..=0x7E | 0x80..=0xFF | 0x08 | 0x7F)); + .all(|u| matches!(u, 0x20..=0x7E | 0xA0..=0xFF | 0x08 | 0x7F)); if is_updatable { let s = str::from_utf8(&buf).with_context(err_context)?; active_terminal.update_name(s); diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index 8383a24629..3cde1d8183 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -2674,3 +2674,39 @@ pub fn send_cli_undo_rename_tab() { *received_plugin_instructions.lock().unwrap() )) } + +#[test] +pub fn send_cli_query_tab_names_action() { + 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); + mock_screen.new_tab(TiledPaneLayout::default()); + let session_metadata = mock_screen.clone_session_metadata(); + let screen_thread = mock_screen.run(Some(TiledPaneLayout::default())); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_thread = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let query_tab_names = CliAction::QueryTabNames; + send_cli_action_to_server( + &session_metadata, + query_tab_names, + &mut mock_screen, + client_id, + ); + std::thread::sleep(std::time::Duration::from_millis(100)); + mock_screen.teardown(vec![server_thread, screen_thread]); + let log_tab_names_instruction = received_server_instructions + .lock() + .unwrap() + .iter() + .find(|instruction| match instruction { + ServerInstruction::Log(..) => true, + _ => false, + }) + .cloned(); + assert_snapshot!(format!("{:#?}", log_tab_names_instruction)); +} diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_query_tab_names_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_query_tab_names_action.snap new file mode 100644 index 0000000000..bdaf546fe4 --- /dev/null +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_query_tab_names_action.snap @@ -0,0 +1,14 @@ +--- +source: zellij-server/src/./unit/screen_tests.rs +assertion_line: 2713 +expression: "format!(\"{:#?}\", log_tab_names_action)" +--- +Some( + Log( + [ + "Tab #1", + "Tab #2", + ], + 10, + ), +) diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs index 2733f1c747..3947dfad39 100644 --- a/zellij-utils/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -366,4 +366,6 @@ pub enum CliAction { }, PreviousSwapLayout, NextSwapLayout, + /// Query all tab names + QueryTabNames, } diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index 3493f84b7f..f1522c1de9 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -323,6 +323,7 @@ pub enum ScreenContext { ClearPaneFrameColorOverride, PreviousSwapLayout, NextSwapLayout, + QueryTabNames, } /// Stack call representations corresponding to the different types of [`PtyInstruction`]s. @@ -366,6 +367,7 @@ pub enum ClientContext { SwitchToMode, Connected, ActiveClients, + Log, OwnClientId, StartedParsingStdinQuery, DoneParsingStdinQuery, @@ -385,6 +387,7 @@ pub enum ServerContext { AttachClient, ConnStatus, ActiveClients, + Log, } #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index 7b7f78c433..b2ec8d8287 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -223,6 +223,8 @@ pub enum Action { ToggleMouseMode, PreviousSwapLayout, NextSwapLayout, + /// Query all tab names + QueryTabNames, } impl Action { @@ -456,6 +458,7 @@ impl Action { }, CliAction::PreviousSwapLayout => Ok(vec![Action::PreviousSwapLayout]), CliAction::NextSwapLayout => Ok(vec![Action::NextSwapLayout]), + CliAction::QueryTabNames => Ok(vec![Action::QueryTabNames]), } } } diff --git a/zellij-utils/src/input/unit/layout_test.rs b/zellij-utils/src/input/unit/layout_test.rs index c8c6c64dc3..237cf978c6 100644 --- a/zellij-utils/src/input/unit/layout_test.rs +++ b/zellij-utils/src/input/unit/layout_test.rs @@ -1943,6 +1943,7 @@ fn cannot_define_stacked_panes_with_grandchildren_in_pane_template() { assert!(layout.is_err(), "error provided for tab name with space"); } +#[test] fn run_plugin_location_parsing() { let kdl_layout = r#" layout { diff --git a/zellij-utils/src/ipc.rs b/zellij-utils/src/ipc.rs index e76a21bd82..149a157ae4 100644 --- a/zellij-utils/src/ipc.rs +++ b/zellij-utils/src/ipc.rs @@ -109,6 +109,7 @@ pub enum ServerToClientMsg { SwitchToMode(InputMode), Connected, ActiveClients(Vec), + Log(Vec), } #[derive(Serialize, Deserialize, Debug, Clone)]