aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2026-03-13 16:33:25 +0100
committerGitHub <noreply@github.com>2026-03-13 16:33:25 +0100
commitaa5ca34d4b84254c4f22787e671e34dcd376ad17 (patch)
treef21cf7f58854dd741d6c91f6c49a323ec19dc3f7
parentFix debug-mode stack overflow on Windows (#4843) (diff)
downloadsl0ppij-aa5ca34d4b84254c4f22787e671e34dcd376ad17.tar.gz
sl0ppij-aa5ca34d4b84254c4f22787e671e34dcd376ad17.tar.xz
sl0ppij-aa5ca34d4b84254c4f22787e671e34dcd376ad17.zip
Add `--pane-id` and `--tab-id` to all relevant CLI commands (#4846)
* add missing pane-id and tab-id arguments to all cli actions * rustfmt * fix tests * update e2e snapshots * add pr
-rw-r--r--CHANGELOG.md1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__break_panes_to_new_tab_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__break_panes_to_tab_with_index_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__clear_screen_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focus_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focused_tab_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_plugin_pane_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_terminal_pane_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__detach_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_layout_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_scrollback_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_next_pane_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_or_create_tab_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_plugin_pane_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_previous_pane_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_terminal_pane_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_next_tab_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_previous_tab_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab_name_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_or_tab_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_with_direction_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tab_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command-2.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__next_swap_layout_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_background_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_floating_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_floating_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_floating_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_floating_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__override_layout_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_down_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_up_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__previous_swap_layout_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__quit_zellij_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_plugin_pane_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_tab_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_terminal_pane_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_with_direction_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__run_action_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_down_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_bottom_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_top_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_up_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__send_configuration_to_plugins.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__show_self_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_and_cwd_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_mode_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_active_tab_sync_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_focus_fullscreen_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_embed_or_eject_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_frames_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_tab_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_pane_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_tab_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_to_pane_id_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_plugin_command.snap1
-rw-r--r--zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_to_pane_id_plugin_command.snap1
-rw-r--r--zellij-server/src/route.rs238
-rw-r--r--zellij-server/src/screen.rs798
-rw-r--r--zellij-server/src/tab/mod.rs185
-rw-r--r--zellij-server/src/tab/unit/tab_tests.rs247
-rw-r--r--zellij-server/src/unit/screen_tests.rs888
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_default_parameters.snap2
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_line_number.snap2
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_split_direction.snap2
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_in_place_with_close_replaced_pane.snap1
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap1
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_in_place_with_close_replaced_pane.snap1
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap2
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_default_parameters.snap2
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_floating_pane_and_coordinates.snap2
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_split_direction.snap2
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_in_place_with_close_replaced_pane.snap1
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap4
-rw-r--r--zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_query_tab_names_action.snap1
-rw-r--r--zellij-utils/assets/prost_ipc/client_server_contract.rs214
-rw-r--r--zellij-utils/src/cli.rs147
-rw-r--r--zellij-utils/src/client_server_contract/common_types.proto56
-rw-r--r--zellij-utils/src/errors.rs27
-rw-r--r--zellij-utils/src/input/actions.rs1214
-rw-r--r--zellij-utils/src/ipc/protobuf_conversion.rs485
-rw-r--r--zellij-utils/src/ipc/tests/roundtrip_tests.rs224
-rw-r--r--zellij-utils/src/plugin_api/action.rs43
96 files changed, 4626 insertions, 233 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1c35384a..74d64743 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -80,6 +80,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* fix: make sure clients are focused when atomically showing floating panes (https://github.com/zellij-org/zellij/pull/4834)
* feat: allow configuring focus_follows_mouse and mouse_click_through (https://github.com/zellij-org/zellij/pull/4836)
* fix: handle very large writes to the pty (https://github.com/zellij-org/zellij/pull/4818)
+* feat: add --pane-id and --tab-id to all relevant CLI actions (https://github.com/zellij-org/zellij/pull/4846)
## [0.43.1] - 2025-08-08
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__break_panes_to_new_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__break_panes_to_new_tab_plugin_command.snap
index 59cf66f3..38ce1e9e 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__break_panes_to_new_tab_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__break_panes_to_new_tab_plugin_command.snap
@@ -37,6 +37,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
},
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__break_panes_to_tab_with_index_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__break_panes_to_tab_with_index_plugin_command.snap
index c51575ed..28c62b2a 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__break_panes_to_tab_with_index_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__break_panes_to_tab_with_index_plugin_command.snap
@@ -22,6 +22,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
},
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__clear_screen_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__clear_screen_plugin_command.snap
index f376f4e6..7b31ca71 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__clear_screen_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__clear_screen_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focus_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focus_plugin_command.snap
index 876de3d2..2b758c6a 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focus_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focus_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focused_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focused_tab_plugin_command.snap
index 97528cac..b31bd2c5 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focused_tab_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focused_tab_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_plugin_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_plugin_pane_plugin_command.snap
index f20b4c65..e47bc89b 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_plugin_pane_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_plugin_pane_plugin_command.snap
@@ -15,6 +15,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
None,
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_terminal_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_terminal_pane_plugin_command.snap
index af53bf2a..d76b1a2f 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_terminal_pane_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_terminal_pane_plugin_command.snap
@@ -15,6 +15,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
None,
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__detach_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__detach_plugin_command.snap
index b834fae6..f42fc911 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__detach_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__detach_plugin_command.snap
@@ -14,6 +14,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_layout_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_layout_plugin_command.snap
index fa22e69d..a1a2c63c 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_layout_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_layout_plugin_command.snap
@@ -40,6 +40,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_scrollback_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_scrollback_plugin_command.snap
index 1b0575e2..ec0711fa 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_scrollback_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_scrollback_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_next_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_next_pane_plugin_command.snap
index 3a062e7c..9c1483ed 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_next_pane_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_next_pane_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_or_create_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_or_create_tab_plugin_command.snap
index b6056657..413e183a 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_or_create_tab_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_or_create_tab_plugin_command.snap
@@ -21,6 +21,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_plugin_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_plugin_pane_plugin_command.snap
index 946656ce..cba3338c 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_plugin_pane_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_plugin_pane_plugin_command.snap
@@ -17,6 +17,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_previous_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_previous_pane_plugin_command.snap
index a3b89e0e..251e585f 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_previous_pane_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_previous_pane_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_terminal_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_terminal_pane_plugin_command.snap
index 2f9600c4..67166535 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_terminal_pane_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_terminal_pane_plugin_command.snap
@@ -17,6 +17,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_next_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_next_tab_plugin_command.snap
index 7b12ea28..50806aec 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_next_tab_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_next_tab_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_previous_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_previous_tab_plugin_command.snap
index eb385864..a82b40a7 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_previous_tab_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_previous_tab_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab.snap
index f730b254..66727a92 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab.snap
@@ -15,6 +15,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab_name_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab_name_plugin_command.snap
index 75b5dd62..7847f3bd 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab_name_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab_name_plugin_command.snap
@@ -21,6 +21,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_or_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_or_tab_plugin_command.snap
index 323dd29b..a03ad540 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_or_tab_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_or_tab_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_plugin_command.snap
index 43c28c07..e236fb9b 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_plugin_command.snap
index 704220a8..0de2f0f9 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_with_direction_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_with_direction_plugin_command.snap
index 9beccaf4..e41284da 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_with_direction_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_with_direction_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tab_plugin_command.snap
index 6f749f98..81b08d6c 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tab_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tab_plugin_command.snap
@@ -31,6 +31,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command-2.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command-2.snap
index 8a11021c..cd1466ae 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command-2.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command-2.snap
@@ -83,6 +83,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command.snap
index 4e5076b1..eccf2bd0 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command.snap
@@ -83,6 +83,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__next_swap_layout_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__next_swap_layout_plugin_command.snap
index 3de5d347..c019c09e 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__next_swap_layout_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__next_swap_layout_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_background_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_background_plugin_command.snap
index 47a7b8c1..603deaa8 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_background_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_background_plugin_command.snap
@@ -43,6 +43,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
false,
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_floating_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_floating_plugin_command.snap
index 023f92e8..6207efb3 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_floating_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_floating_plugin_command.snap
@@ -41,6 +41,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
false,
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_plugin_command.snap
index 6dc703be..3089d85a 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_plugin_command.snap
@@ -42,6 +42,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
false,
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_floating_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_floating_plugin_command.snap
index 8b400575..9c1b42d6 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_floating_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_floating_plugin_command.snap
@@ -39,6 +39,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
false,
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_plugin_command.snap
index 66662754..675cac9a 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_plugin_command.snap
@@ -40,6 +40,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
false,
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_floating_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_floating_plugin_command.snap
index ac0cffca..a98b3e19 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_floating_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_floating_plugin_command.snap
@@ -41,6 +41,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
false,
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_plugin_command.snap
index 16cb9276..aa308679 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_plugin_command.snap
@@ -42,6 +42,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
false,
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_floating_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_floating_plugin_command.snap
index f80864c1..a895910a 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_floating_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_floating_plugin_command.snap
@@ -34,6 +34,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
false,
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_plugin_command.snap
index a8b46d9e..dfa6bcbf 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_plugin_command.snap
@@ -35,6 +35,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
false,
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__override_layout_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__override_layout_plugin_command.snap
index 0320d754..30e9d8ce 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__override_layout_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__override_layout_plugin_command.snap
@@ -2188,6 +2188,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_down_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_down_plugin_command.snap
index 1d353741..b642064f 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_down_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_down_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_up_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_up_plugin_command.snap
index f36650ad..5f3a7d70 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_up_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_up_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__previous_swap_layout_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__previous_swap_layout_plugin_command.snap
index 9c2e4f17..78bfe2ab 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__previous_swap_layout_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__previous_swap_layout_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__quit_zellij_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__quit_zellij_plugin_command.snap
index 014f7cc4..bde1eaee 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__quit_zellij_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__quit_zellij_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_plugin_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_plugin_pane_plugin_command.snap
index 6baf42fb..2c279b00 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_plugin_pane_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_plugin_pane_plugin_command.snap
@@ -36,6 +36,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_tab_plugin_command.snap
index 6d88c8d0..ff67468d 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_tab_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_tab_plugin_command.snap
@@ -26,6 +26,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_terminal_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_terminal_pane_plugin_command.snap
index 4c7953f5..b3fb351f 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_terminal_pane_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__rename_terminal_pane_plugin_command.snap
@@ -38,6 +38,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_plugin_command.snap
index 12b26384..19ecd531 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_plugin_command.snap
@@ -17,6 +17,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_with_direction_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_with_direction_plugin_command.snap
index c933f52e..3634bac2 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_with_direction_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_with_direction_plugin_command.snap
@@ -19,6 +19,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__run_action_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__run_action_plugin_command.snap
index 94413d72..a43ab56a 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__run_action_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__run_action_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_down_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_down_plugin_command.snap
index cfb58f3f..3f536271 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_down_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_down_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_bottom_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_bottom_plugin_command.snap
index b67d5e30..5b110d01 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_bottom_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_bottom_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_top_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_top_plugin_command.snap
index 6c38598a..a76af090 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_top_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_top_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_up_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_up_plugin_command.snap
index 90f7008d..c116da80 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_up_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_up_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__send_configuration_to_plugins.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__send_configuration_to_plugins.snap
index 5f65db08..b63fe174 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__send_configuration_to_plugins.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__send_configuration_to_plugins.snap
@@ -21,6 +21,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__show_self_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__show_self_plugin_command.snap
index 5971b313..e9986253 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__show_self_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__show_self_plugin_command.snap
@@ -17,6 +17,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap
index 2f553d6c..531c882b 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap
@@ -24,6 +24,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_plugin_command.snap
index 5f9f524c..90ad25e0 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_plugin_command.snap
@@ -23,6 +23,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_and_cwd_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_and_cwd_plugin_command.snap
index c847c31b..0fab6fed 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_and_cwd_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_and_cwd_plugin_command.snap
@@ -27,6 +27,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_plugin_command.snap
index cbd966d3..056365a7 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_session_with_layout_plugin_command.snap
@@ -27,6 +27,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_mode_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_mode_plugin_command.snap
index 3e1f9e71..6180f6fa 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_mode_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_mode_plugin_command.snap
@@ -333,6 +333,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_active_tab_sync_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_active_tab_sync_plugin_command.snap
index 93ca8b8a..69d8616b 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_active_tab_sync_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_active_tab_sync_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_focus_fullscreen_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_focus_fullscreen_plugin_command.snap
index ec786521..e2998b4d 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_focus_fullscreen_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_focus_fullscreen_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_embed_or_eject_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_embed_or_eject_plugin_command.snap
index c966e97a..f8fc7c47 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_embed_or_eject_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_embed_or_eject_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_frames_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_frames_plugin_command.snap
index ad86b0d8..86104bb4 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_frames_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_frames_plugin_command.snap
@@ -11,6 +11,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_tab_plugin_command.snap
index da58b12e..2c355cb5 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_tab_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_tab_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_pane_plugin_command.snap
index 9218fe37..870abd96 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_pane_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_pane_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_tab_plugin_command.snap
index 41665cf2..fc24b7f8 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_tab_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_tab_plugin_command.snap
@@ -12,6 +12,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_plugin_command.snap
index 78e0286e..0a7ab0e9 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_plugin_command.snap
@@ -19,6 +19,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_to_pane_id_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_to_pane_id_plugin_command.snap
index 7a1ccab1..9c071f78 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_to_pane_id_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_to_pane_id_plugin_command.snap
@@ -20,6 +20,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_plugin_command.snap
index 78e0286e..0a7ab0e9 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_plugin_command.snap
@@ -19,6 +19,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_to_pane_id_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_to_pane_id_plugin_command.snap
index 90209815..1ee5dfad 100644
--- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_to_pane_id_plugin_command.snap
+++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_to_pane_id_plugin_command.snap
@@ -19,6 +19,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs
index ea19402e..d6b3b48e 100644
--- a/zellij-server/src/route.rs
+++ b/zellij-server/src/route.rs
@@ -45,6 +45,7 @@ pub struct ActionCompletionResult {
pub exit_status: Option<i32>,
pub affected_pane_id: Option<PaneId>,
pub affected_tab_id: Option<usize>,
+ pub error_message: Option<String>,
}
pub fn wait_for_action_completion(
@@ -63,6 +64,7 @@ pub fn wait_for_action_completion(
exit_status: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
}
},
}
@@ -82,6 +84,7 @@ pub fn wait_for_action_completion(
exit_status: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
}
},
}
@@ -101,6 +104,7 @@ pub struct NotificationEnd {
unblock_condition: Option<UnblockCondition>,
affected_pane_id: Option<PaneId>, // optional payload of the pane id affected by this action
affected_tab_id: Option<usize>, // optional payload of the tab id affected by this action
+ error_message: Option<String>,
}
impl Clone for NotificationEnd {
@@ -112,6 +116,7 @@ impl Clone for NotificationEnd {
unblock_condition: self.unblock_condition,
affected_pane_id: self.affected_pane_id,
affected_tab_id: self.affected_tab_id,
+ error_message: self.error_message.clone(),
}
}
}
@@ -124,6 +129,7 @@ impl NotificationEnd {
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
}
}
@@ -137,6 +143,7 @@ impl NotificationEnd {
unblock_condition: Some(unblock_condition),
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
}
}
@@ -152,6 +159,10 @@ impl NotificationEnd {
self.affected_tab_id = Some(tab_id);
}
+ pub fn set_error_message(&mut self, message: String) {
+ self.error_message = Some(message);
+ }
+
pub fn unblock_condition(&self) -> Option<UnblockCondition> {
self.unblock_condition
}
@@ -164,6 +175,7 @@ impl Drop for NotificationEnd {
exit_status: self.exit_status,
affected_pane_id: self.affected_pane_id,
affected_tab_id: self.affected_tab_id,
+ error_message: self.error_message.take(),
};
let _ = tx.send(result);
}
@@ -1795,9 +1807,232 @@ pub(crate) fn route_action(
})
.with_context(err_context)?;
},
+ // Pane-targeting CLI-only variants
+ Action::ScrollUpByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::ScrollUpWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::ScrollDownByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::ScrollDownWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::ScrollToTopByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::ScrollToTopWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::ScrollToBottomByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::ScrollToBottomWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::PageScrollUpByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::PageScrollUpWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::PageScrollDownByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::PageScrollDownWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::HalfPageScrollUpByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::HalfPageScrollUpWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::HalfPageScrollDownByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::HalfPageScrollDownWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::ResizeByPaneId {
+ pane_id,
+ resize,
+ direction,
+ } => {
+ let resize_strategy = ResizeStrategy::new(resize, direction);
+ senders
+ .send_to_screen(ScreenInstruction::ResizeWithPaneId(
+ pane_id.into(),
+ resize_strategy,
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::MovePaneByPaneId { pane_id, direction } => {
+ senders
+ .send_to_screen(ScreenInstruction::MovePaneWithPaneIdCli(
+ pane_id.into(),
+ direction,
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::MovePaneBackwardsByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::MovePaneBackwardsWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::ClearScreenByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::ClearScreenWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::EditScrollbackByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::EditScrollbackWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::ToggleFocusFullscreenByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::ToggleFullscreenWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::TogglePaneEmbedOrFloatingByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::TogglePaneEmbedOrFloatingWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::CloseFocusByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::CloseFocusWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::RenamePaneByPaneId { pane_id, name } => {
+ senders
+ .send_to_screen(ScreenInstruction::RenamePaneWithPaneId(
+ pane_id.into(),
+ name,
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::UndoRenamePaneByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::UndoRenamePaneWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::TogglePanePinnedByPaneId { pane_id } => {
+ senders
+ .send_to_screen(ScreenInstruction::TogglePanePinnedWithPaneId(
+ pane_id.into(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ // Tab-targeting CLI-only variants
+ Action::UndoRenameTabByTabId { id } => {
+ senders
+ .send_to_screen(ScreenInstruction::UndoRenameTabWithTabId(
+ id as usize,
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::ToggleActiveSyncTabByTabId { id } => {
+ senders
+ .send_to_screen(ScreenInstruction::ToggleActiveSyncTabWithTabId(
+ id as usize,
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::ToggleFloatingPanesByTabId { id } => {
+ senders
+ .send_to_screen(ScreenInstruction::ToggleFloatingPanesWithTabId(
+ id as usize,
+ default_shell.clone(),
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::PreviousSwapLayoutByTabId { id } => {
+ senders
+ .send_to_screen(ScreenInstruction::PreviousSwapLayoutWithTabId(
+ id as usize,
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::NextSwapLayoutByTabId { id } => {
+ senders
+ .send_to_screen(ScreenInstruction::NextSwapLayoutWithTabId(
+ id as usize,
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
+ Action::MoveTabByTabId { id, direction } => {
+ senders
+ .send_to_screen(ScreenInstruction::MoveTabWithTabId(
+ id as usize,
+ direction,
+ Some(NotificationEnd::new(completion_tx)),
+ ))
+ .with_context(err_context)?;
+ },
}
let result = wait_for_action_completion(completion_rx, &action_name, wait_forever);
- if let Some(exit_status) = result.exit_status {
+ if let Some(error_message) = &result.error_message {
+ if let Some(cli_client_id) = cli_client_id {
+ if let Some(ref os_input) = os_input {
+ let _ = os_input.send_to_client(
+ cli_client_id,
+ ServerToClientMsg::LogError {
+ lines: vec![error_message.clone()],
+ },
+ );
+ }
+ }
+ } else if let Some(exit_status) = result.exit_status {
if let Some(cli_client_id) = cli_client_id {
if let Some(ref os_input) = os_input {
let _ = os_input.send_to_client(
@@ -2857,6 +3092,7 @@ mod tests {
exit_status: None,
affected_pane_id: None,
affected_tab_id: Some(123),
+ error_message: None,
};
assert_eq!(result.affected_tab_id, Some(123));
diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs
index 565aa8b9..0b90c7f9 100644
--- a/zellij-server/src/screen.rs
+++ b/zellij-server/src/screen.rs
@@ -700,6 +700,33 @@ pub enum ScreenInstruction {
NotifyPaneClosedToSubscribers {
pane_id: zellij_utils::data::PaneId,
},
+ // Pane-targeting CLI variants
+ ScrollUpWithPaneId(PaneId, Option<NotificationEnd>),
+ ScrollDownWithPaneId(PaneId, Option<NotificationEnd>),
+ ScrollToTopWithPaneId(PaneId, Option<NotificationEnd>),
+ ScrollToBottomWithPaneId(PaneId, Option<NotificationEnd>),
+ PageScrollUpWithPaneId(PaneId, Option<NotificationEnd>),
+ PageScrollDownWithPaneId(PaneId, Option<NotificationEnd>),
+ HalfPageScrollUpWithPaneId(PaneId, Option<NotificationEnd>),
+ HalfPageScrollDownWithPaneId(PaneId, Option<NotificationEnd>),
+ ResizeWithPaneId(PaneId, ResizeStrategy, Option<NotificationEnd>),
+ MovePaneWithPaneIdCli(PaneId, Option<Direction>, Option<NotificationEnd>),
+ MovePaneBackwardsWithPaneId(PaneId, Option<NotificationEnd>),
+ ClearScreenWithPaneId(PaneId, Option<NotificationEnd>),
+ EditScrollbackWithPaneId(PaneId, Option<NotificationEnd>),
+ ToggleFullscreenWithPaneId(PaneId, Option<NotificationEnd>),
+ TogglePaneEmbedOrFloatingWithPaneId(PaneId, Option<NotificationEnd>),
+ CloseFocusWithPaneId(PaneId, Option<NotificationEnd>),
+ RenamePaneWithPaneId(PaneId, Vec<u8>, Option<NotificationEnd>),
+ UndoRenamePaneWithPaneId(PaneId, Option<NotificationEnd>),
+ TogglePanePinnedWithPaneId(PaneId, Option<NotificationEnd>),
+ // Tab-targeting CLI variants
+ UndoRenameTabWithTabId(usize, Option<NotificationEnd>),
+ ToggleActiveSyncTabWithTabId(usize, Option<NotificationEnd>),
+ ToggleFloatingPanesWithTabId(usize, Option<TerminalAction>, Option<NotificationEnd>),
+ PreviousSwapLayoutWithTabId(usize, Option<NotificationEnd>),
+ NextSwapLayoutWithTabId(usize, Option<NotificationEnd>),
+ MoveTabWithTabId(usize, Direction, Option<NotificationEnd>),
}
impl From<&ScreenInstruction> for ScreenContext {
@@ -975,6 +1002,61 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::NotifyPaneClosedToSubscribers { .. } => {
ScreenContext::NotifyPaneClosedToSubscribers
},
+ // Pane-targeting CLI variants
+ ScreenInstruction::ScrollUpWithPaneId(..) => ScreenContext::ScrollUpWithPaneId,
+ ScreenInstruction::ScrollDownWithPaneId(..) => ScreenContext::ScrollDownWithPaneId,
+ ScreenInstruction::ScrollToTopWithPaneId(..) => ScreenContext::ScrollToTopWithPaneId,
+ ScreenInstruction::ScrollToBottomWithPaneId(..) => {
+ ScreenContext::ScrollToBottomWithPaneId
+ },
+ ScreenInstruction::PageScrollUpWithPaneId(..) => ScreenContext::PageScrollUpWithPaneId,
+ ScreenInstruction::PageScrollDownWithPaneId(..) => {
+ ScreenContext::PageScrollDownWithPaneId
+ },
+ ScreenInstruction::HalfPageScrollUpWithPaneId(..) => {
+ ScreenContext::HalfPageScrollUpWithPaneId
+ },
+ ScreenInstruction::HalfPageScrollDownWithPaneId(..) => {
+ ScreenContext::HalfPageScrollDownWithPaneId
+ },
+ ScreenInstruction::ResizeWithPaneId(..) => ScreenContext::ResizeWithPaneId,
+ ScreenInstruction::MovePaneWithPaneIdCli(..) => ScreenContext::MovePaneWithPaneIdCli,
+ ScreenInstruction::MovePaneBackwardsWithPaneId(..) => {
+ ScreenContext::MovePaneBackwardsWithPaneId
+ },
+ ScreenInstruction::ClearScreenWithPaneId(..) => ScreenContext::ClearScreenWithPaneId,
+ ScreenInstruction::EditScrollbackWithPaneId(..) => {
+ ScreenContext::EditScrollbackWithPaneId
+ },
+ ScreenInstruction::ToggleFullscreenWithPaneId(..) => {
+ ScreenContext::ToggleFullscreenWithPaneId
+ },
+ ScreenInstruction::TogglePaneEmbedOrFloatingWithPaneId(..) => {
+ ScreenContext::TogglePaneEmbedOrFloatingWithPaneId
+ },
+ ScreenInstruction::CloseFocusWithPaneId(..) => ScreenContext::CloseFocusWithPaneId,
+ ScreenInstruction::RenamePaneWithPaneId(..) => ScreenContext::RenamePaneWithPaneId,
+ ScreenInstruction::UndoRenamePaneWithPaneId(..) => {
+ ScreenContext::UndoRenamePaneWithPaneId
+ },
+ ScreenInstruction::TogglePanePinnedWithPaneId(..) => {
+ ScreenContext::TogglePanePinnedWithPaneId
+ },
+ // Tab-targeting CLI variants
+ ScreenInstruction::UndoRenameTabWithTabId(..) => ScreenContext::UndoRenameTabWithTabId,
+ ScreenInstruction::ToggleActiveSyncTabWithTabId(..) => {
+ ScreenContext::ToggleActiveSyncTabWithTabId
+ },
+ ScreenInstruction::ToggleFloatingPanesWithTabId(..) => {
+ ScreenContext::ToggleFloatingPanesWithTabId
+ },
+ ScreenInstruction::PreviousSwapLayoutWithTabId(..) => {
+ ScreenContext::PreviousSwapLayoutWithTabId
+ },
+ ScreenInstruction::NextSwapLayoutWithTabId(..) => {
+ ScreenContext::NextSwapLayoutWithTabId
+ },
+ ScreenInstruction::MoveTabWithTabId(..) => ScreenContext::MoveTabWithTabId,
}
}
}
@@ -2133,6 +2215,7 @@ impl Screen {
let mut completion = completion;
if let Some(c) = completion.as_mut() {
c.set_exit_status(1);
+ c.set_error_message("Tab not found".to_string());
}
drop(completion);
},
@@ -2156,6 +2239,7 @@ impl Screen {
let mut completion = completion;
if let Some(c) = completion.as_mut() {
c.set_exit_status(1);
+ c.set_error_message("Tab not found".to_string());
}
drop(completion);
},
@@ -2945,6 +3029,31 @@ impl Screen {
Ok(())
}
+ pub fn move_tab_by_id(&mut self, tab_id: usize, direction: Direction) -> Result<()> {
+ if self.tabs.len() < 2 {
+ return Ok(());
+ }
+ if let Some(tab) = self.tabs.get(&tab_id) {
+ let tab_pos = tab.position;
+ let swap_pos = match direction {
+ Direction::Left => {
+ if tab_pos == 0 {
+ self.tabs.len() - 1
+ } else {
+ tab_pos - 1
+ }
+ },
+ Direction::Right => (tab_pos + 1) % self.tabs.len(),
+ _ => return Ok(()),
+ };
+ self.switch_tabs(tab_pos, swap_pos);
+ self.log_and_report_session_state()?;
+ } else {
+ log::error!("Tab with id {} not found", tab_id);
+ }
+ Ok(())
+ }
+
pub fn change_mode(&mut self, mut mode_info: ModeInfo, client_id: ClientId) -> Result<()> {
if mode_info.session_name.as_ref() != Some(&self.session_name) {
mode_info.session_name = Some(self.session_name.clone());
@@ -5019,116 +5128,148 @@ pub(crate) fn screen_thread_main(
screen.render(None)?;
screen.log_and_report_session_state()?;
},
- ScreenInstruction::FocusNextPane(
- client_id,
- _completion_tx, // the action ends here, dropping this will release anything
- // waiting for it
- ) => {
- active_tab_and_connected_client_id!(
- screen,
- client_id,
- |tab: &mut Tab, client_id: ClientId| tab.focus_next_pane(client_id)
- );
- screen.render(None)?;
+ ScreenInstruction::FocusNextPane(client_id, mut _completion_tx) => {
+ if screen.get_first_client_id().is_none() {
+ log::error!("No connected clients to change focus for");
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message("No connected clients to change focus for".to_string());
+ }
+ } else {
+ active_tab_and_connected_client_id!(
+ screen,
+ client_id,
+ |tab: &mut Tab, client_id: ClientId| tab.focus_next_pane(client_id)
+ );
+ screen.render(None)?;
+ }
},
- ScreenInstruction::FocusPreviousPane(
- client_id,
- _completion_tx, // the action ends here, dropping this will release anything
- // waiting for it
- ) => {
- active_tab_and_connected_client_id!(
- screen,
- client_id,
- |tab: &mut Tab, client_id: ClientId| tab.focus_previous_pane(client_id)
- );
- screen.render(None)?;
- screen.log_and_report_session_state()?;
+ ScreenInstruction::FocusPreviousPane(client_id, mut _completion_tx) => {
+ if screen.get_first_client_id().is_none() {
+ log::error!("No connected clients to change focus for");
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message("No connected clients to change focus for".to_string());
+ }
+ } else {
+ active_tab_and_connected_client_id!(
+ screen,
+ client_id,
+ |tab: &mut Tab, client_id: ClientId| tab.focus_previous_pane(client_id)
+ );
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ }
},
- ScreenInstruction::MoveFocusLeft(
- client_id,
- _completion_tx, // the action ends here, dropping this will release anything
- // waiting for it
- ) => {
- active_tab_and_connected_client_id!(
- screen,
- client_id,
- |tab: &mut Tab, client_id: ClientId| tab.move_focus_left(client_id),
- ?
- );
- screen.clear_bell_for_focused_pane(client_id);
- screen.add_active_pane_to_group_if_marking(&client_id);
- screen.render(None)?;
- screen.log_and_report_session_state()?;
+ ScreenInstruction::MoveFocusLeft(client_id, mut _completion_tx) => {
+ if screen.get_first_client_id().is_none() {
+ log::error!("No connected clients to move focus for");
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message("No connected clients to move focus for".to_string());
+ }
+ } else {
+ active_tab_and_connected_client_id!(
+ screen,
+ client_id,
+ |tab: &mut Tab, client_id: ClientId| tab.move_focus_left(client_id),
+ ?
+ );
+ screen.clear_bell_for_focused_pane(client_id);
+ screen.add_active_pane_to_group_if_marking(&client_id);
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ }
},
- ScreenInstruction::MoveFocusLeftOrPreviousTab(
- client_id,
- _completion_tx, // the action ends here, dropping this will release anything
- // waiting for it
- ) => {
- screen.move_focus_left_or_previous_tab(client_id)?;
- screen.clear_bell_for_focused_pane(client_id);
- screen.add_active_pane_to_group_if_marking(&client_id);
- screen.render(None)?;
- screen.log_and_report_session_state()?;
+ ScreenInstruction::MoveFocusLeftOrPreviousTab(client_id, mut _completion_tx) => {
+ if screen.get_first_client_id().is_none() {
+ log::error!("No connected clients to move focus for");
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message("No connected clients to move focus for".to_string());
+ }
+ } else {
+ screen.move_focus_left_or_previous_tab(client_id)?;
+ screen.clear_bell_for_focused_pane(client_id);
+ screen.add_active_pane_to_group_if_marking(&client_id);
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ }
},
- ScreenInstruction::MoveFocusDown(
- client_id,
- _completion_tx, // the action ends here, dropping this will release anything
- // waiting for it
- ) => {
- active_tab_and_connected_client_id!(
- screen,
- client_id,
- |tab: &mut Tab, client_id: ClientId| tab.move_focus_down(client_id),
- ?
- );
- screen.clear_bell_for_focused_pane(client_id);
- screen.add_active_pane_to_group_if_marking(&client_id);
- screen.render(None)?;
- screen.log_and_report_session_state()?;
+ ScreenInstruction::MoveFocusDown(client_id, mut _completion_tx) => {
+ if screen.get_first_client_id().is_none() {
+ log::error!("No connected clients to move focus for");
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message("No connected clients to move focus for".to_string());
+ }
+ } else {
+ active_tab_and_connected_client_id!(
+ screen,
+ client_id,
+ |tab: &mut Tab, client_id: ClientId| tab.move_focus_down(client_id),
+ ?
+ );
+ screen.clear_bell_for_focused_pane(client_id);
+ screen.add_active_pane_to_group_if_marking(&client_id);
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ }
},
- ScreenInstruction::MoveFocusRight(
- client_id,
- _completion_tx, // the action ends here, dropping this will release anything
- // waiting for it
- ) => {
- active_tab_and_connected_client_id!(
- screen,
- client_id,
- |tab: &mut Tab, client_id: ClientId| tab.move_focus_right(client_id),
- ?
- );
- screen.clear_bell_for_focused_pane(client_id);
- screen.add_active_pane_to_group_if_marking(&client_id);
- screen.render(None)?;
- screen.log_and_report_session_state()?;
+ ScreenInstruction::MoveFocusRight(client_id, mut _completion_tx) => {
+ if screen.get_first_client_id().is_none() {
+ log::error!("No connected clients to move focus for");
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message("No connected clients to move focus for".to_string());
+ }
+ } else {
+ active_tab_and_connected_client_id!(
+ screen,
+ client_id,
+ |tab: &mut Tab, client_id: ClientId| tab.move_focus_right(client_id),
+ ?
+ );
+ screen.clear_bell_for_focused_pane(client_id);
+ screen.add_active_pane_to_group_if_marking(&client_id);
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ }
},
- ScreenInstruction::MoveFocusRightOrNextTab(
- client_id,
- _completion_tx, // the action ends here, dropping this will release anything
- // waiting for it
- ) => {
- screen.move_focus_right_or_next_tab(client_id)?;
- screen.clear_bell_for_focused_pane(client_id);
- screen.add_active_pane_to_group_if_marking(&client_id);
- screen.render(None)?;
- screen.log_and_report_session_state()?;
+ ScreenInstruction::MoveFocusRightOrNextTab(client_id, mut _completion_tx) => {
+ if screen.get_first_client_id().is_none() {
+ log::error!("No connected clients to move focus for");
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message("No connected clients to move focus for".to_string());
+ }
+ } else {
+ screen.move_focus_right_or_next_tab(client_id)?;
+ screen.clear_bell_for_focused_pane(client_id);
+ screen.add_active_pane_to_group_if_marking(&client_id);
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ }
},
- ScreenInstruction::MoveFocusUp(
- client_id,
- _completion_tx, // the action ends here, dropping this will release anything
- // waiting for it
- ) => {
- active_tab_and_connected_client_id!(
- screen,
- client_id,
- |tab: &mut Tab, client_id: ClientId| tab.move_focus_up(client_id),
- ?
- );
- screen.clear_bell_for_focused_pane(client_id);
- screen.add_active_pane_to_group_if_marking(&client_id);
- screen.render(None)?;
- screen.log_and_report_session_state()?;
+ ScreenInstruction::MoveFocusUp(client_id, mut _completion_tx) => {
+ if screen.get_first_client_id().is_none() {
+ log::error!("No connected clients to move focus for");
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message("No connected clients to move focus for".to_string());
+ }
+ } else {
+ active_tab_and_connected_client_id!(
+ screen,
+ client_id,
+ |tab: &mut Tab, client_id: ClientId| tab.move_focus_up(client_id),
+ ?
+ );
+ screen.clear_bell_for_focused_pane(client_id);
+ screen.add_active_pane_to_group_if_marking(&client_id);
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ }
},
ScreenInstruction::ClearScreen(
client_id,
@@ -8082,6 +8223,457 @@ pub(crate) fn screen_thread_main(
ScreenInstruction::NotifyPaneClosedToSubscribers { pane_id } => {
screen.notify_pane_closed_to_subscribers(pane_id);
},
+ // Pane-targeting CLI handlers
+ ScreenInstruction::ScrollUpWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.scroll_up_by_pane_id(pane_id);
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ },
+ ScreenInstruction::ScrollDownWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.scroll_down_by_pane_id(pane_id).non_fatal();
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ },
+ ScreenInstruction::ScrollToTopWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.scroll_to_top_by_pane_id(pane_id).non_fatal();
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ },
+ ScreenInstruction::ScrollToBottomWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.scroll_to_bottom_by_pane_id(pane_id).non_fatal();
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ },
+ ScreenInstruction::PageScrollUpWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.page_scroll_up_by_pane_id(pane_id);
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ },
+ ScreenInstruction::PageScrollDownWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.page_scroll_down_by_pane_id(pane_id).non_fatal();
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ },
+ ScreenInstruction::HalfPageScrollUpWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.half_page_scroll_up_by_pane_id(pane_id);
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ },
+ ScreenInstruction::HalfPageScrollDownWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.half_page_scroll_down_by_pane_id(pane_id).non_fatal();
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ },
+ ScreenInstruction::ResizeWithPaneId(pane_id, strategy, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.resize_by_pane_id(pane_id, strategy);
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ },
+ ScreenInstruction::MovePaneWithPaneIdCli(pane_id, direction, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.move_pane_by_pane_id(pane_id, direction);
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ },
+ ScreenInstruction::MovePaneBackwardsWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.move_pane_backwards_by_pane_id(pane_id);
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ },
+ ScreenInstruction::ClearScreenWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.clear_screen_by_pane_id(pane_id).non_fatal();
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ },
+ ScreenInstruction::EditScrollbackWithPaneId(pane_id, completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.edit_scrollback_for_pane_with_id(pane_id, completion_tx)
+ .non_fatal();
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ }
+ screen.render(None)?;
+ },
+ ScreenInstruction::ToggleFullscreenWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.toggle_fullscreen_by_pane_id(pane_id);
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ },
+ ScreenInstruction::TogglePaneEmbedOrFloatingWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.toggle_pane_embed_or_floating_for_pane_id(pane_id, None)
+ .non_fatal();
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.log_and_report_session_state()?;
+ screen.render(None)?;
+ },
+ ScreenInstruction::CloseFocusWithPaneId(pane_id, completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.close_pane_by_pane_id(pane_id, completion_tx)
+ .non_fatal();
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ }
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ },
+ ScreenInstruction::RenamePaneWithPaneId(pane_id, name, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.rename_pane_by_pane_id(pane_id, name).non_fatal();
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ },
+ ScreenInstruction::UndoRenamePaneWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.undo_rename_pane_by_pane_id(pane_id);
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ screen.render(None)?;
+ },
+ ScreenInstruction::TogglePanePinnedWithPaneId(pane_id, mut _completion_tx) => {
+ let all_tabs = screen.get_tabs_mut();
+ let mut found = false;
+ for tab in all_tabs.values_mut() {
+ if tab.has_pane_with_pid(&pane_id) {
+ tab.toggle_pane_pinned_by_pane_id(pane_id);
+ found = true;
+ break;
+ }
+ }
+ if !found {
+ log::error!("Pane with id {:?} not found", pane_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Pane with id {:?} not found", pane_id));
+ }
+ }
+ },
+ // Tab-targeting CLI handlers
+ ScreenInstruction::UndoRenameTabWithTabId(tab_id, mut _completion_tx) => {
+ if let Some(tab) = screen.tabs.get_mut(&tab_id) {
+ if tab.name != tab.prev_name {
+ tab.name = tab.prev_name.clone();
+ screen.log_and_report_session_state()?;
+ }
+ } else {
+ log::error!("Tab with id {} not found", tab_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Tab with id {} not found", tab_id));
+ }
+ }
+ screen.render(None)?;
+ },
+ ScreenInstruction::ToggleActiveSyncTabWithTabId(tab_id, mut _completion_tx) => {
+ if let Some(tab) = screen.tabs.get_mut(&tab_id) {
+ tab.toggle_sync_panes_is_active();
+ } else {
+ log::error!("Tab with id {} not found", tab_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Tab with id {} not found", tab_id));
+ }
+ }
+ screen.log_and_report_session_state()?;
+ screen.render(None)?;
+ },
+ ScreenInstruction::ToggleFloatingPanesWithTabId(
+ tab_id,
+ default_shell,
+ mut completion_tx,
+ ) => {
+ if let Some(tab) = screen.tabs.get_mut(&tab_id) {
+ // Pass None as client_id so that if a new floating pane must be spawned,
+ // it targets this tab (via TabIndex) rather than the focused tab of some client.
+ tab.toggle_floating_panes(None, default_shell, completion_tx)
+ .non_fatal();
+ } else {
+ log::error!("Tab with id {} not found", tab_id);
+ if let Some(ref mut c) = completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Tab with id {} not found", tab_id));
+ }
+ drop(completion_tx);
+ }
+ screen.log_and_report_session_state()?;
+ screen.render(None)?;
+ },
+ ScreenInstruction::PreviousSwapLayoutWithTabId(tab_id, mut _completion_tx) => {
+ if let Some(tab) = screen.tabs.get_mut(&tab_id) {
+ tab.previous_swap_layout().non_fatal();
+ } else {
+ log::error!("Tab with id {} not found", tab_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Tab with id {} not found", tab_id));
+ }
+ }
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ },
+ ScreenInstruction::NextSwapLayoutWithTabId(tab_id, mut _completion_tx) => {
+ if let Some(tab) = screen.tabs.get_mut(&tab_id) {
+ tab.next_swap_layout().non_fatal();
+ } else {
+ log::error!("Tab with id {} not found", tab_id);
+ if let Some(ref mut c) = _completion_tx {
+ c.set_exit_status(1);
+ c.set_error_message(format!("Tab with id {} not found", tab_id));
+ }
+ }
+ screen.render(None)?;
+ screen.log_and_report_session_state()?;
+ },
+ ScreenInstruction::MoveTabWithTabId(tab_id, direction, _completion_tx) => {
+ if pending_tab_ids.is_empty() {
+ screen.move_tab_by_id(tab_id, direction)?;
+ screen.render(None)?;
+ } else {
+ pending_events_waiting_for_tab.push(ScreenInstruction::MoveTabWithTabId(
+ tab_id,
+ direction,
+ _completion_tx,
+ ));
+ }
+ },
}
}
Ok(())
diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs
index bcefc510..b95567c1 100644
--- a/zellij-server/src/tab/mod.rs
+++ b/zellij-server/src/tab/mod.rs
@@ -5697,6 +5697,191 @@ impl Tab {
.map(|p| p.position_and_size().stacked.is_some())
.unwrap_or(false)
}
+ // --- Pane-targeting CLI methods ---
+ pub fn scroll_up_by_pane_id(&mut self, pane_id: PaneId) {
+ let fictitious_client_id = 1;
+ if let Some(pane) = self.get_pane_with_id_mut(pane_id) {
+ pane.scroll_up(1, fictitious_client_id);
+ }
+ }
+ pub fn scroll_down_by_pane_id(&mut self, pane_id: PaneId) -> Result<()> {
+ let fictitious_client_id = 1;
+ if let Some(pane) = self.get_pane_with_id_mut(pane_id) {
+ pane.scroll_down(1, fictitious_client_id);
+ if !pane.is_scrolled() {
+ if let PaneId::Terminal(raw_fd) = pane.pid() {
+ self.process_pending_vte_events(raw_fd)?;
+ }
+ }
+ }
+ Ok(())
+ }
+ pub fn scroll_to_top_by_pane_id(&mut self, pane_id: PaneId) -> Result<()> {
+ let fictitious_client_id = 1;
+ if let Some(pane) = self.get_pane_with_id_mut(pane_id) {
+ pane.clear_scroll();
+ if let Some(size) = pane.get_line_number() {
+ pane.scroll_up(size, fictitious_client_id);
+ }
+ }
+ Ok(())
+ }
+ pub fn scroll_to_bottom_by_pane_id(&mut self, pane_id: PaneId) -> Result<()> {
+ if let Some(pane) = self.get_pane_with_id_mut(pane_id) {
+ pane.clear_scroll();
+ if !pane.is_scrolled() {
+ if let PaneId::Terminal(raw_fd) = pane.pid() {
+ self.process_pending_vte_events(raw_fd)?;
+ }
+ }
+ }
+ Ok(())
+ }
+ pub fn page_scroll_up_by_pane_id(&mut self, pane_id: PaneId) {
+ let fictitious_client_id = 1;
+ if let Some(pane) = self.get_pane_with_id_mut(pane_id) {
+ let scroll_rows = pane.rows().max(1).saturating_sub(1);
+ pane.scroll_up(scroll_rows, fictitious_client_id);
+ }
+ }
+ pub fn page_scroll_down_by_pane_id(&mut self, pane_id: PaneId) -> Result<()> {
+ let fictitious_client_id = 1;
+ if let Some(pane) = self.get_pane_with_id_mut(pane_id) {
+ let scroll_rows = pane.get_content_rows();
+ pane.scroll_down(scroll_rows, fictitious_client_id);
+ if !pane.is_scrolled() {
+ if let PaneId::Terminal(raw_fd) = pane.pid() {
+ self.process_pending_vte_events(raw_fd)?;
+ }
+ }
+ }
+ Ok(())
+ }
+ pub fn half_page_scroll_up_by_pane_id(&mut self, pane_id: PaneId) {
+ let fictitious_client_id = 1;
+ if let Some(pane) = self.get_pane_with_id_mut(pane_id) {
+ let scroll_rows = (pane.rows().max(1).saturating_sub(1)) / 2;
+ pane.scroll_up(scroll_rows, fictitious_client_id);
+ }
+ }
+ pub fn half_page_scroll_down_by_pane_id(&mut self, pane_id: PaneId) -> Result<()> {
+ let fictitious_client_id = 1;
+ if let Some(pane) = self.get_pane_with_id_mut(pane_id) {
+ let scroll_rows = (pane.rows().max(1).saturating_sub(1)) / 2;
+ pane.scroll_down(scroll_rows, fictitious_client_id);
+ if !pane.is_scrolled() {
+ if let PaneId::Terminal(raw_fd) = pane.pid() {
+ self.process_pending_vte_events(raw_fd)?;
+ }
+ }
+ }
+ Ok(())
+ }
+ pub fn resize_by_pane_id(&mut self, pane_id: PaneId, strategy: ResizeStrategy) {
+ self.resize_pane_with_id(strategy, pane_id).non_fatal();
+ }
+ pub fn move_pane_by_pane_id(&mut self, pane_id: PaneId, direction: Option<Direction>) {
+ if !self.has_selectable_panes() {
+ return;
+ }
+ if self.tiled_panes.fullscreen_is_active() {
+ return;
+ }
+ match direction {
+ Some(Direction::Left) => {
+ if self.floating_panes.panes_contain(&pane_id) {
+ self.floating_panes.move_pane_left(pane_id);
+ self.swap_layouts.set_is_floating_damaged();
+ self.set_force_render();
+ } else {
+ self.tiled_panes.move_pane_left(pane_id);
+ }
+ },
+ Some(Direction::Right) => {
+ if self.floating_panes.panes_contain(&pane_id) {
+ self.floating_panes.move_pane_right(pane_id);
+ self.swap_layouts.set_is_floating_damaged();
+ self.set_force_render();
+ } else {
+ self.tiled_panes.move_pane_right(pane_id);
+ }
+ },
+ Some(Direction::Up) => {
+ if self.floating_panes.panes_contain(&pane_id) {
+ self.floating_panes.move_pane_up(pane_id);
+ self.swap_layouts.set_is_floating_damaged();
+ self.set_force_render();
+ } else {
+ self.tiled_panes.move_pane_up(pane_id);
+ }
+ },
+ Some(Direction::Down) => {
+ if self.floating_panes.panes_contain(&pane_id) {
+ self.floating_panes.move_pane_down(pane_id);
+ self.swap_layouts.set_is_floating_damaged();
+ self.set_force_render();
+ } else {
+ self.tiled_panes.move_pane_down(pane_id);
+ }
+ },
+ None => {
+ let search_backwards = false;
+ if self.floating_panes.panes_contain(&pane_id) {
+ self.floating_panes.move_pane(search_backwards, pane_id);
+ } else {
+ self.tiled_panes.move_pane(search_backwards, pane_id);
+ }
+ },
+ }
+ }
+ pub fn move_pane_backwards_by_pane_id(&mut self, pane_id: PaneId) {
+ if !self.has_selectable_panes() {
+ return;
+ }
+ if self.tiled_panes.fullscreen_is_active() {
+ return;
+ }
+ let search_backwards = true;
+ if self.floating_panes.panes_contain(&pane_id) {
+ self.floating_panes.move_pane(search_backwards, pane_id);
+ } else {
+ self.tiled_panes.move_pane(search_backwards, pane_id);
+ }
+ }
+ pub fn clear_screen_by_pane_id(&mut self, pane_id: PaneId) -> Result<()> {
+ self.clear_screen_for_pane_id(pane_id);
+ Ok(())
+ }
+ pub fn toggle_fullscreen_by_pane_id(&mut self, pane_id: PaneId) {
+ self.toggle_pane_fullscreen(pane_id);
+ }
+ pub fn close_pane_by_pane_id(
+ &mut self,
+ pane_id: PaneId,
+ completion_tx: Option<NotificationEnd>,
+ ) -> Result<()> {
+ self.close_pane(pane_id, false, None);
+ self.senders
+ .send_to_pty(PtyInstruction::ClosePane(pane_id, completion_tx))?;
+ Ok(())
+ }
+ pub fn rename_pane_by_pane_id(&mut self, pane_id: PaneId, name: Vec<u8>) -> Result<()> {
+ if let Some(pane) = self.get_pane_with_id_mut(pane_id) {
+ pane.rename(name);
+ }
+ Ok(())
+ }
+ pub fn undo_rename_pane_by_pane_id(&mut self, pane_id: PaneId) {
+ if let Some(pane) = self.get_pane_with_id_mut(pane_id) {
+ pane.load_pane_name();
+ }
+ }
+ pub fn toggle_pane_pinned_by_pane_id(&mut self, pane_id: PaneId) {
+ if let Some(pane) = self.get_pane_with_id_mut(pane_id) {
+ pane.toggle_pinned();
+ self.set_force_render();
+ }
+ }
}
pub fn pane_info_for_pane(
diff --git a/zellij-server/src/tab/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs
index 00444c4a..363786f0 100644
--- a/zellij-server/src/tab/unit/tab_tests.rs
+++ b/zellij-server/src/tab/unit/tab_tests.rs
@@ -15340,3 +15340,250 @@ pub fn clearing_last_pane_bell_clears_tab_bell() {
"tab_has_pending_bell should be false after last pane bell cleared"
);
}
+
+// Category 5: pane-id-based operations
+
+#[test]
+pub fn scroll_up_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ tab.scroll_up_by_pane_id(pane_id);
+}
+
+#[test]
+pub fn scroll_down_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ tab.scroll_down_by_pane_id(pane_id);
+}
+
+#[test]
+pub fn scroll_to_top_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ tab.scroll_to_top_by_pane_id(pane_id);
+}
+
+#[test]
+pub fn scroll_to_bottom_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ tab.scroll_to_bottom_by_pane_id(pane_id);
+}
+
+#[test]
+pub fn page_scroll_up_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ tab.page_scroll_up_by_pane_id(pane_id);
+}
+
+#[test]
+pub fn page_scroll_down_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ tab.page_scroll_down_by_pane_id(pane_id);
+}
+
+#[test]
+pub fn half_page_scroll_up_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ tab.half_page_scroll_up_by_pane_id(pane_id);
+}
+
+#[test]
+pub fn half_page_scroll_down_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ tab.half_page_scroll_down_by_pane_id(pane_id);
+}
+
+#[test]
+pub fn rename_pane_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ tab.rename_pane_by_pane_id(pane_id, "new-name".as_bytes().to_vec());
+}
+
+#[test]
+pub fn undo_rename_pane_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ tab.rename_pane_by_pane_id(pane_id, "new-name".as_bytes().to_vec());
+ tab.undo_rename_pane_by_pane_id(pane_id);
+}
+
+#[test]
+pub fn close_pane_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let stacked_resize = true;
+ let mut tab = create_new_tab(size, stacked_resize);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.horizontal_split(new_pane_id, None, 1, None, None)
+ .unwrap();
+ assert_eq!(tab.tiled_panes.panes.len(), 2);
+ tab.close_pane_by_pane_id(new_pane_id, None).unwrap();
+ assert_eq!(tab.tiled_panes.panes.len(), 1);
+ assert!(!tab.has_pane_with_pid(&new_pane_id));
+}
+
+#[test]
+pub fn resize_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.horizontal_split(new_pane_id, None, 1, None, None)
+ .unwrap();
+ assert_eq!(tab.tiled_panes.panes.len(), 2);
+ tab.resize_by_pane_id(
+ new_pane_id,
+ ResizeStrategy::new(Resize::Increase, Some(Direction::Down)),
+ );
+}
+
+#[test]
+pub fn toggle_fullscreen_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.horizontal_split(new_pane_id, None, 1, None, None)
+ .unwrap();
+ assert_eq!(tab.tiled_panes.panes.len(), 2);
+ tab.toggle_fullscreen_by_pane_id(new_pane_id);
+}
+
+#[test]
+pub fn move_pane_by_pane_id_down() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.horizontal_split(new_pane_id, None, 1, None, None)
+ .unwrap();
+ assert_eq!(tab.tiled_panes.panes.len(), 2);
+ tab.move_pane_by_pane_id(new_pane_id, Some(Direction::Down));
+}
+
+#[test]
+pub fn move_pane_backwards_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let new_pane_id = PaneId::Terminal(2);
+ tab.horizontal_split(new_pane_id, None, 1, None, None)
+ .unwrap();
+ assert_eq!(tab.tiled_panes.panes.len(), 2);
+ tab.move_pane_backwards_by_pane_id(new_pane_id);
+}
+
+#[test]
+pub fn clear_screen_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ tab.clear_screen_by_pane_id(pane_id);
+}
+
+#[test]
+pub fn toggle_pane_embed_or_floating_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ let _ = tab.toggle_pane_embed_or_floating_for_pane_id(pane_id, None);
+}
+
+#[test]
+pub fn toggle_pane_pinned_by_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(1);
+ assert!(tab.has_pane_with_pid(&pane_id));
+ tab.toggle_pane_pinned_by_pane_id(pane_id);
+}
+
+#[test]
+pub fn scroll_up_nonexistent_pane_id_does_not_panic() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut tab = create_new_tab(size, true);
+ let pane_id = PaneId::Terminal(999);
+ assert!(!tab.has_pane_with_pid(&pane_id));
+ tab.scroll_up_by_pane_id(pane_id);
+}
diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs
index 49dbeb5d..1bbe2479 100644
--- a/zellij-server/src/unit/screen_tests.rs
+++ b/zellij-server/src/unit/screen_tests.rs
@@ -2233,6 +2233,7 @@ pub fn send_cli_resize_action_to_screen() {
let resize_cli_action = CliAction::Resize {
resize: Resize::Increase,
direction: Some(Direction::Left),
+ pane_id: None,
};
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for the async render
send_cli_action_to_server(&session_metadata, resize_cli_action, client_id);
@@ -2404,6 +2405,7 @@ pub fn send_cli_move_pane_action() {
);
let cli_action = CliAction::MovePane {
direction: Some(Direction::Right),
+ pane_id: None,
};
send_cli_action_to_server(&session_metadata, cli_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
@@ -2471,7 +2473,7 @@ pub fn send_cli_edit_scrollback_action() {
PtyInstruction::Exit,
pty_receiver
);
- let cli_action = CliAction::EditScrollback;
+ let cli_action = CliAction::EditScrollback { pane_id: None };
let _ = mock_screen.to_screen.send(ScreenInstruction::PtyBytes(
0,
"fill pane up with something".as_bytes().to_vec(),
@@ -2523,7 +2525,7 @@ pub fn send_cli_scroll_up_action() {
ServerInstruction::KillSession,
server_receiver
);
- let cli_action = CliAction::ScrollUp;
+ let cli_action = CliAction::ScrollUp { pane_id: None };
let mut pane_contents = String::new();
for i in 0..20 {
pane_contents.push_str(&format!("fill pane up with something {}\n\r", i));
@@ -2567,8 +2569,8 @@ pub fn send_cli_scroll_down_action() {
ServerInstruction::KillSession,
server_receiver
);
- let scroll_up_cli_action = CliAction::ScrollUp;
- let scroll_down_cli_action = CliAction::ScrollDown;
+ let scroll_up_cli_action = CliAction::ScrollUp { pane_id: None };
+ let scroll_down_cli_action = CliAction::ScrollDown { pane_id: None };
let mut pane_contents = String::new();
for i in 0..20 {
pane_contents.push_str(&format!("fill pane up with something {}\n\r", i));
@@ -2614,8 +2616,8 @@ pub fn send_cli_scroll_to_bottom_action() {
ServerInstruction::KillSession,
server_receiver
);
- let scroll_up_cli_action = CliAction::ScrollUp;
- let scroll_to_bottom_action = CliAction::ScrollToBottom;
+ let scroll_up_cli_action = CliAction::ScrollUp { pane_id: None };
+ let scroll_to_bottom_action = CliAction::ScrollToBottom { pane_id: None };
let mut pane_contents = String::new();
for i in 0..20 {
pane_contents.push_str(&format!("fill pane up with something {}\n\r", i));
@@ -2664,7 +2666,7 @@ pub fn send_cli_scroll_to_top_action() {
ServerInstruction::KillSession,
server_receiver
);
- let scroll_to_top_action = CliAction::ScrollToTop;
+ let scroll_to_top_action = CliAction::ScrollToTop { pane_id: None };
let mut pane_contents = String::new();
for i in 0..20 {
pane_contents.push_str(&format!("fill pane up with something {}\n\r", i));
@@ -2706,7 +2708,7 @@ pub fn send_cli_page_scroll_up_action() {
ServerInstruction::KillSession,
server_receiver
);
- let page_scroll_up_action = CliAction::PageScrollUp;
+ let page_scroll_up_action = CliAction::PageScrollUp { pane_id: None };
let mut pane_contents = String::new();
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for the async render
for i in 0..20 {
@@ -2748,8 +2750,8 @@ pub fn send_cli_page_scroll_down_action() {
ServerInstruction::KillSession,
server_receiver
);
- let page_scroll_up_action = CliAction::PageScrollUp;
- let page_scroll_down_action = CliAction::PageScrollDown;
+ let page_scroll_up_action = CliAction::PageScrollUp { pane_id: None };
+ let page_scroll_down_action = CliAction::PageScrollDown { pane_id: None };
let mut pane_contents = String::new();
for i in 0..20 {
pane_contents.push_str(&format!("fill pane up with something {}\n\r", i));
@@ -2800,7 +2802,7 @@ pub fn send_cli_half_page_scroll_up_action() {
ServerInstruction::KillSession,
server_receiver
);
- let half_page_scroll_up_action = CliAction::HalfPageScrollUp;
+ let half_page_scroll_up_action = CliAction::HalfPageScrollUp { pane_id: None };
let mut pane_contents = String::new();
for i in 0..20 {
pane_contents.push_str(&format!("fill pane up with something {}\n\r", i));
@@ -2841,8 +2843,8 @@ pub fn send_cli_half_page_scroll_down_action() {
ServerInstruction::KillSession,
server_receiver
);
- let half_page_scroll_up_action = CliAction::HalfPageScrollUp;
- let half_page_scroll_down_action = CliAction::HalfPageScrollDown;
+ let half_page_scroll_up_action = CliAction::HalfPageScrollUp { pane_id: None };
+ let half_page_scroll_down_action = CliAction::HalfPageScrollDown { pane_id: None };
let mut pane_contents = String::new();
std::thread::sleep(std::time::Duration::from_millis(100)); // give time for the async render
for i in 0..20 {
@@ -2900,7 +2902,7 @@ pub fn send_cli_toggle_full_screen_action() {
ServerInstruction::KillSession,
server_receiver
);
- let toggle_full_screen_action = CliAction::ToggleFullscreen;
+ let toggle_full_screen_action = CliAction::ToggleFullscreen { pane_id: None };
send_cli_action_to_server(&session_metadata, toggle_full_screen_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
@@ -2967,7 +2969,7 @@ pub fn send_cli_toggle_active_tab_sync_action() {
PtyWriteInstruction::Exit,
pty_writer_receiver
);
- let cli_toggle_active_tab_sync_action = CliAction::ToggleActiveSyncTab;
+ let cli_toggle_active_tab_sync_action = CliAction::ToggleActiveSyncTab { tab_id: None };
let cli_write_action = CliAction::Write {
bytes: vec![102, 111, 111],
pane_id: None,
@@ -3384,7 +3386,7 @@ pub fn send_cli_toggle_pane_embed_or_float() {
ServerInstruction::KillSession,
server_receiver
);
- let toggle_pane_embed_or_floating = CliAction::TogglePaneEmbedOrFloating;
+ let toggle_pane_embed_or_floating = CliAction::TogglePaneEmbedOrFloating { pane_id: None };
// first time to float
send_cli_action_to_server(
&session_metadata,
@@ -3435,8 +3437,8 @@ pub fn send_cli_toggle_floating_panes() {
ServerInstruction::KillSession,
server_receiver
);
- let toggle_pane_embed_or_floating = CliAction::TogglePaneEmbedOrFloating;
- let toggle_floating_panes = CliAction::ToggleFloatingPanes;
+ let toggle_pane_embed_or_floating = CliAction::TogglePaneEmbedOrFloating { pane_id: None };
+ let toggle_floating_panes = CliAction::ToggleFloatingPanes { tab_id: None };
// float the focused pane
send_cli_action_to_server(&session_metadata, toggle_pane_embed_or_floating, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
@@ -3476,7 +3478,7 @@ pub fn send_cli_close_pane_action() {
ServerInstruction::KillSession,
server_receiver
);
- let close_pane_action = CliAction::ClosePane;
+ let close_pane_action = CliAction::ClosePane { pane_id: None };
send_cli_action_to_server(&session_metadata, close_pane_action, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_instruction, screen_thread]);
@@ -3722,7 +3724,7 @@ pub fn send_cli_close_tab_action() {
ServerInstruction::KillSession,
server_receiver
);
- let close_tab = CliAction::CloseTab;
+ let close_tab = CliAction::CloseTab { tab_id: None };
send_cli_action_to_server(&session_metadata, close_tab, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
mock_screen.teardown(vec![server_thread, screen_thread]);
@@ -3760,6 +3762,7 @@ pub fn send_cli_rename_tab() {
);
let rename_tab = CliAction::RenameTab {
name: "new-tab-name".into(),
+ tab_id: None,
};
send_cli_action_to_server(&session_metadata, rename_tab, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
@@ -3805,8 +3808,9 @@ pub fn send_cli_undo_rename_tab() {
);
let rename_tab = CliAction::RenameTab {
name: "new-tab-name".into(),
+ tab_id: None,
};
- let undo_rename_tab = CliAction::UndoRenameTab;
+ let undo_rename_tab = CliAction::UndoRenameTab { tab_id: None };
// first rename the tab
send_cli_action_to_server(&session_metadata, rename_tab, client_id);
std::thread::sleep(std::time::Duration::from_millis(100));
@@ -6088,3 +6092,845 @@ fn integration_subscriber_survives_after_regular_client_detach() {
subscriber_msgs
);
}
+
+// ==========================================
+// Category 3: MockScreen end-to-end CLI tests
+// ==========================================
+
+#[test]
+pub fn send_cli_scroll_up_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::ScrollUp {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "ScrollUp with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_scroll_down_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::ScrollDown {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "ScrollDown with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_scroll_to_top_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::ScrollToTop {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "ScrollToTop with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_scroll_to_bottom_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::ScrollToBottom {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "ScrollToBottom with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_page_scroll_up_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::PageScrollUp {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "PageScrollUp with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_page_scroll_down_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::PageScrollDown {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "PageScrollDown with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_half_page_scroll_up_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::HalfPageScrollUp {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "HalfPageScrollUp with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_half_page_scroll_down_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::HalfPageScrollDown {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "HalfPageScrollDown with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_resize_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::Resize {
+ resize: Resize::Increase,
+ direction: Some(Direction::Left),
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "Resize with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_move_pane_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::MovePane {
+ direction: Some(Direction::Right),
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "MovePane with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_move_pane_backwards_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::MovePaneBackwards {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "MovePaneBackwards with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_clear_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::Clear {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "Clear with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_edit_scrollback_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::EditScrollback {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "EditScrollback with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_toggle_fullscreen_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::ToggleFullscreen {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "ToggleFullscreen with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_toggle_pane_embed_or_floating_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::TogglePaneEmbedOrFloating {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "TogglePaneEmbedOrFloating with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_close_pane_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ 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 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_thread = log_actions_in_thread!(
+ received_server_instructions,
+ ServerInstruction::KillSession,
+ server_receiver
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::ClosePane {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "ClosePane with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_rename_pane_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::RenamePane {
+ name: "targeted-name".to_string(),
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "RenamePane with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_undo_rename_pane_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::UndoRenamePane {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "UndoRenamePane with pane_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_toggle_pane_pinned_with_pane_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::TogglePanePinned {
+ pane_id: Some("terminal_0".to_string()),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "TogglePanePinned with pane_id CLI action completed without errors"
+ );
+}
+
+// TAB-TARGETING MockScreen tests
+
+#[test]
+pub fn send_cli_close_tab_with_tab_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.new_tab(TiledPaneLayout::default());
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::CloseTab { tab_id: Some(1) };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "CloseTab with tab_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_rename_tab_with_tab_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.new_tab(TiledPaneLayout::default());
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::RenameTab {
+ name: "targeted-tab".to_string(),
+ tab_id: Some(1),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "RenameTab with tab_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_undo_rename_tab_with_tab_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.new_tab(TiledPaneLayout::default());
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::UndoRenameTab { tab_id: Some(0) };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "UndoRenameTab with tab_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_toggle_active_sync_tab_with_tab_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::ToggleActiveSyncTab { tab_id: Some(0) };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "ToggleActiveSyncTab with tab_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_toggle_floating_panes_with_tab_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::ToggleFloatingPanes { tab_id: Some(0) };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "ToggleFloatingPanes with tab_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_previous_swap_layout_with_tab_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::PreviousSwapLayout { tab_id: Some(0) };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "PreviousSwapLayout with tab_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_next_swap_layout_with_tab_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::NextSwapLayout { tab_id: Some(0) };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "NextSwapLayout with tab_id CLI action completed without errors"
+ );
+}
+
+#[test]
+pub fn send_cli_move_tab_with_tab_id() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let client_id = 10;
+ let mut mock_screen = MockScreen::new(size);
+ let session_metadata = mock_screen.clone_session_metadata();
+ let screen_thread = mock_screen.run(None, vec![]);
+ 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
+ );
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.new_tab(TiledPaneLayout::default());
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ let cli_action = CliAction::MoveTab {
+ direction: Direction::Right,
+ tab_id: Some(0),
+ };
+ send_cli_action_to_server(&session_metadata, cli_action, client_id);
+ std::thread::sleep(std::time::Duration::from_millis(100));
+ mock_screen.teardown(vec![server_thread, screen_thread]);
+ assert!(
+ true,
+ "MoveTab with tab_id CLI action completed without errors"
+ );
+}
+
+// ==========================================
+// Category 4: Direct Screen method tests
+// ==========================================
+
+#[test]
+pub fn move_tab_by_id_verifies_screen_state() {
+ let size = Size {
+ cols: 121,
+ rows: 20,
+ };
+ let mut screen = create_new_screen(size, true, true);
+ new_tab(&mut screen, 1, 0);
+ new_tab(&mut screen, 2, 1);
+ new_tab(&mut screen, 3, 2);
+ let original_pos_0 = screen.get_tab_by_id(0).unwrap().position;
+ let original_pos_1 = screen.get_tab_by_id(1).unwrap().position;
+ screen.move_tab_by_id(0, Direction::Right).expect("TEST");
+ assert_eq!(screen.get_tab_by_id(0).unwrap().position, original_pos_1);
+ assert_eq!(screen.get_tab_by_id(1).unwrap().position, original_pos_0);
+}
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_default_parameters.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_default_parameters.snap
index 2a2c8a4f..742f2480 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_default_parameters.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_default_parameters.snap
@@ -2,4 +2,4 @@
source: zellij-server/src/./unit/screen_tests.rs
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
---
-[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(OpenFile(OpenFilePayload { path: "/file/to/edit", line_number: None, cwd: Some("."), originating_plugin: None })), Some("Editing: /file/to/edit"), Tiled { direction: None, borderless: None }, false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None }), false), Exit]
+[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(OpenFile(OpenFilePayload { path: "/file/to/edit", line_number: None, cwd: Some("."), originating_plugin: None })), Some("Editing: /file/to/edit"), Tiled { direction: None, borderless: None }, false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None, error_message: None }), false), Exit]
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_line_number.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_line_number.snap
index b93701a2..21195f58 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_line_number.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_line_number.snap
@@ -2,4 +2,4 @@
source: zellij-server/src/./unit/screen_tests.rs
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
---
-[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(OpenFile(OpenFilePayload { path: "/file/to/edit", line_number: Some(100), cwd: Some("."), originating_plugin: None })), Some("Editing: /file/to/edit"), Tiled { direction: None, borderless: None }, false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None }), false), Exit]
+[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(OpenFile(OpenFilePayload { path: "/file/to/edit", line_number: Some(100), cwd: Some("."), originating_plugin: None })), Some("Editing: /file/to/edit"), Tiled { direction: None, borderless: None }, false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None, error_message: None }), false), Exit]
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_split_direction.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_split_direction.snap
index 1c61a5c4..21f4b55d 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_split_direction.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_action_with_split_direction.snap
@@ -2,4 +2,4 @@
source: zellij-server/src/./unit/screen_tests.rs
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
---
-[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(OpenFile(OpenFilePayload { path: "/file/to/edit", line_number: None, cwd: Some("."), originating_plugin: None })), Some("Editing: /file/to/edit"), Tiled { direction: Some(Down), borderless: None }, false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None }), false), Exit]
+[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(OpenFile(OpenFilePayload { path: "/file/to/edit", line_number: None, cwd: Some("."), originating_plugin: None })), Some("Editing: /file/to/edit"), Tiled { direction: Some(Down), borderless: None }, false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None, error_message: None }), false), Exit]
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_in_place_with_close_replaced_pane.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_in_place_with_close_replaced_pane.snap
index 35b8f9cb..bece1bab 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_in_place_with_close_replaced_pane.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_edit_in_place_with_close_replaced_pane.snap
@@ -30,6 +30,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap
index 7b3226d9..3c2a1097 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap
@@ -40,6 +40,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_in_place_with_close_replaced_pane.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_in_place_with_close_replaced_pane.snap
index cb65be5b..44c00845 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_in_place_with_close_replaced_pane.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_in_place_with_close_replaced_pane.snap
@@ -40,6 +40,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap
index 3004bba7..7434e18c 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_command_and_cwd.snap
@@ -2,4 +2,4 @@
source: zellij-server/src/./unit/screen_tests.rs
expression: "format!(\"{:?}\", new_pane_instruction)"
---
-Some(SpawnTerminal(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder"), hold_on_close: true, hold_on_start: false, originating_plugin: None, use_terminal_title: false })), None, Tiled { direction: Some(Right), borderless: Some(false) }, false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None }), false))
+Some(SpawnTerminal(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder"), hold_on_close: true, hold_on_start: false, originating_plugin: None, use_terminal_title: false })), None, Tiled { direction: Some(Right), borderless: Some(false) }, false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None, error_message: None }), false))
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_default_parameters.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_default_parameters.snap
index 345421ea..0e62cd90 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_default_parameters.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_default_parameters.snap
@@ -2,4 +2,4 @@
source: zellij-server/src/./unit/screen_tests.rs
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
---
-[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(None, None, Tiled { direction: None, borderless: Some(false) }, false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None }), false), Exit]
+[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(None, None, Tiled { direction: None, borderless: Some(false) }, false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None, error_message: None }), false), Exit]
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_floating_pane_and_coordinates.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_floating_pane_and_coordinates.snap
index e11a9f23..c9efed6d 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_floating_pane_and_coordinates.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_floating_pane_and_coordinates.snap
@@ -2,4 +2,4 @@
source: zellij-server/src/./unit/screen_tests.rs
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
---
-[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder"), hold_on_close: true, hold_on_start: false, originating_plugin: None, use_terminal_title: false })), None, Floating(Some(FloatingPaneCoordinates { x: Some(Fixed(10)), y: None, width: Some(Percent(20)), height: None, pinned: None, borderless: Some(false) })), false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None }), false), Exit]
+[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(Some(RunCommand(RunCommand { command: "htop", args: [], cwd: Some("/some/folder"), hold_on_close: true, hold_on_start: false, originating_plugin: None, use_terminal_title: false })), None, Floating(Some(FloatingPaneCoordinates { x: Some(Fixed(10)), y: None, width: Some(Percent(20)), height: None, pinned: None, borderless: Some(false) })), false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None, error_message: None }), false), Exit]
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_split_direction.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_split_direction.snap
index 04dde5a4..2ebc8665 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_split_direction.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_action_with_split_direction.snap
@@ -2,4 +2,4 @@
source: zellij-server/src/./unit/screen_tests.rs
expression: "format!(\"{:?}\", *received_pty_instructions.lock().unwrap())"
---
-[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(None, None, Tiled { direction: Some(Right), borderless: Some(false) }, false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None }), false), Exit]
+[UpdateActivePane(Some(Terminal(0)), 1), UpdateActivePane(Some(Terminal(0)), 1), SpawnTerminal(None, None, Tiled { direction: Some(Right), borderless: Some(false) }, false, ClientId(10), Some(NotificationEnd { channel: None, exit_status: None, unblock_condition: None, affected_pane_id: None, affected_tab_id: None, error_message: None }), false), Exit]
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_in_place_with_close_replaced_pane.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_in_place_with_close_replaced_pane.snap
index 209981ae..fbdfc98c 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_in_place_with_close_replaced_pane.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_pane_in_place_with_close_replaced_pane.snap
@@ -31,6 +31,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap
index cd39bac6..2277cd57 100644
--- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap
+++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_new_tab_action_with_name_and_layout.snap
@@ -1,7 +1,6 @@
---
source: zellij-server/src/./unit/screen_tests.rs
-assertion_line: 3568
-expression: "format!(\"{:#?}\", new_tab_instruction)"
+expression: output
---
NewTab(
None,
@@ -113,6 +112,7 @@ NewTab(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
)
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
index e38487fa..de7276ab 100644
--- 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
@@ -16,6 +16,7 @@ Some(
unblock_condition: None,
affected_pane_id: None,
affected_tab_id: None,
+ error_message: None,
},
),
),
diff --git a/zellij-utils/assets/prost_ipc/client_server_contract.rs b/zellij-utils/assets/prost_ipc/client_server_contract.rs
index c7e58bf0..3496655c 100644
--- a/zellij-utils/assets/prost_ipc/client_server_contract.rs
+++ b/zellij-utils/assets/prost_ipc/client_server_contract.rs
@@ -119,7 +119,7 @@ pub struct RgbColor {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Action {
- #[prost(oneof="action::ActionType", tags="1, 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, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109")]
+ #[prost(oneof="action::ActionType", tags="1, 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, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134")]
pub action_type: ::core::option::Option<action::ActionType>,
}
/// Nested message and enum types in `Action`.
@@ -345,6 +345,58 @@ pub mod action {
SetPaneColor(super::SetPaneColorAction),
#[prost(message, tag="109")]
Paste(super::PasteAction),
+ /// Pane-targeting
+ #[prost(message, tag="110")]
+ ScrollUpByPaneId(super::ScrollUpByPaneIdAction),
+ #[prost(message, tag="111")]
+ ScrollDownByPaneId(super::ScrollDownByPaneIdAction),
+ #[prost(message, tag="112")]
+ ScrollToTopByPaneId(super::ScrollToTopByPaneIdAction),
+ #[prost(message, tag="113")]
+ ScrollToBottomByPaneId(super::ScrollToBottomByPaneIdAction),
+ #[prost(message, tag="114")]
+ PageScrollUpByPaneId(super::PageScrollUpByPaneIdAction),
+ #[prost(message, tag="115")]
+ PageScrollDownByPaneId(super::PageScrollDownByPaneIdAction),
+ #[prost(message, tag="116")]
+ HalfPageScrollUpByPaneId(super::HalfPageScrollUpByPaneIdAction),
+ #[prost(message, tag="117")]
+ HalfPageScrollDownByPaneId(super::HalfPageScrollDownByPaneIdAction),
+ #[prost(message, tag="118")]
+ ResizeByPaneId(super::ResizeByPaneIdAction),
+ #[prost(message, tag="119")]
+ MovePaneByPaneId(super::MovePaneByPaneIdAction),
+ #[prost(message, tag="120")]
+ MovePaneBackwardsByPaneId(super::MovePaneBackwardsByPaneIdAction),
+ #[prost(message, tag="121")]
+ ClearScreenByPaneId(super::ClearScreenByPaneIdAction),
+ #[prost(message, tag="122")]
+ EditScrollbackByPaneId(super::EditScrollbackByPaneIdAction),
+ #[prost(message, tag="123")]
+ ToggleFullscreenByPaneId(super::ToggleFullscreenByPaneIdAction),
+ #[prost(message, tag="124")]
+ TogglePaneEmbedOrFloatingByPaneId(super::TogglePaneEmbedOrFloatingByPaneIdAction),
+ #[prost(message, tag="125")]
+ CloseFocusByPaneId(super::CloseFocusByPaneIdAction),
+ #[prost(message, tag="126")]
+ RenamePaneByPaneId(super::RenamePaneByPaneIdAction),
+ #[prost(message, tag="127")]
+ UndoRenamePaneByPaneId(super::UndoRenamePaneByPaneIdAction),
+ #[prost(message, tag="128")]
+ TogglePanePinnedByPaneId(super::TogglePanePinnedByPaneIdAction),
+ /// Tab-targeting
+ #[prost(message, tag="129")]
+ UndoRenameTabByTabId(super::UndoRenameTabByTabIdAction),
+ #[prost(message, tag="130")]
+ ToggleActiveSyncTabByTabId(super::ToggleActiveSyncTabByTabIdAction),
+ #[prost(message, tag="131")]
+ ToggleFloatingPanesByTabId(super::ToggleFloatingPanesByTabIdAction),
+ #[prost(message, tag="132")]
+ PreviousSwapLayoutByTabId(super::PreviousSwapLayoutByTabIdAction),
+ #[prost(message, tag="133")]
+ NextSwapLayoutByTabId(super::NextSwapLayoutByTabIdAction),
+ #[prost(message, tag="134")]
+ MoveTabByTabId(super::MoveTabByTabIdAction),
}
}
// Action message definitions (all 92 variants)
@@ -1840,6 +1892,166 @@ pub struct Options {
#[prost(bool, optional, tag="45")]
pub mouse_click_through: ::core::option::Option<bool>,
}
+/// Pane-targeting action messages
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ScrollUpByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ScrollDownByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ScrollToTopByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ScrollToBottomByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct PageScrollUpByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct PageScrollDownByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct HalfPageScrollUpByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct HalfPageScrollDownByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ResizeByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+ #[prost(message, optional, tag="2")]
+ pub resize_action: ::core::option::Option<ResizeAction>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct MovePaneByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+ #[prost(enumeration="Direction", optional, tag="2")]
+ pub direction: ::core::option::Option<i32>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct MovePaneBackwardsByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ClearScreenByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct EditScrollbackByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ToggleFullscreenByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct TogglePaneEmbedOrFloatingByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct CloseFocusByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct RenamePaneByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+ #[prost(bytes="vec", tag="2")]
+ pub name: ::prost::alloc::vec::Vec<u8>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct UndoRenamePaneByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct TogglePanePinnedByPaneIdAction {
+ #[prost(message, optional, tag="1")]
+ pub pane_id: ::core::option::Option<PaneId>,
+}
+/// Tab-targeting action messages
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct UndoRenameTabByTabIdAction {
+ #[prost(uint64, tag="1")]
+ pub id: u64,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ToggleActiveSyncTabByTabIdAction {
+ #[prost(uint64, tag="1")]
+ pub id: u64,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ToggleFloatingPanesByTabIdAction {
+ #[prost(uint64, tag="1")]
+ pub id: u64,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct PreviousSwapLayoutByTabIdAction {
+ #[prost(uint64, tag="1")]
+ pub id: u64,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct NextSwapLayoutByTabIdAction {
+ #[prost(uint64, tag="1")]
+ pub id: u64,
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct MoveTabByTabIdAction {
+ #[prost(uint64, tag="1")]
+ pub id: u64,
+ #[prost(enumeration="Direction", tag="2")]
+ pub direction: i32,
+}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum BareKey {
diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs
index 0d5e847c..005c8b66 100644
--- a/zellij-utils/src/cli.rs
+++ b/zellij-utils/src/cli.rs
@@ -723,6 +723,9 @@ pub enum CliAction {
Resize {
resize: Resize,
direction: Option<Direction>,
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
},
/// Change focus to the next pane
FocusNextPane,
@@ -741,11 +744,22 @@ pub enum CliAction {
/// [right|left|up|down]
MovePane {
direction: Option<Direction>,
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
},
/// Rotate the location of the previous pane backwards
- MovePaneBackwards,
+ MovePaneBackwards {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Clear all buffers for a focused pane
- Clear,
+ Clear {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Dumps the viewport and optionally scrollback of a pane to a file or STDOUT
DumpScreen {
/// File path to dump the pane content to. If omitted, prints to STDOUT.
@@ -765,29 +779,73 @@ pub enum CliAction {
/// Save the current session state to disk immediately
SaveSession,
/// Open the pane scrollback in your default editor
- EditScrollback,
+ EditScrollback {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Scroll up in the focused pane
- ScrollUp,
+ ScrollUp {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Scroll down in focus pane.
- ScrollDown,
+ ScrollDown {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Scroll down to bottom in focus pane.
- ScrollToBottom,
+ ScrollToBottom {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Scroll up to top in focus pane.
- ScrollToTop,
+ ScrollToTop {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Scroll up one page in focus pane.
- PageScrollUp,
+ PageScrollUp {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Scroll down one page in focus pane.
- PageScrollDown,
+ PageScrollDown {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Scroll up half page in focus pane.
- HalfPageScrollUp,
+ HalfPageScrollUp {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Scroll down half page in focus pane.
- HalfPageScrollDown,
+ HalfPageScrollDown {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Toggle between fullscreen focus pane and normal layout.
- ToggleFullscreen,
+ ToggleFullscreen {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Toggle frames around panes in the UI
TogglePaneFrames,
/// Toggle between sending text commands to all panes on the current tab and normal mode.
- ToggleActiveSyncTab,
+ ToggleActiveSyncTab {
+ /// Target a specific tab by ID
+ #[clap(short, long, value_parser)]
+ tab_id: Option<usize>,
+ },
/// Open a new pane in the specified direction [right|down]
/// If no direction is specified, will try to use the biggest available space.
/// Returns: Created pane ID (format: terminal_<id> or plugin_<id>)
@@ -969,9 +1027,17 @@ pub enum CliAction {
input_mode: InputMode,
},
/// Embed focused pane if floating or float focused pane if embedded
- TogglePaneEmbedOrFloating,
+ TogglePaneEmbedOrFloating {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Toggle the visibility of all floating panes in the current Tab, open one if none exist
- ToggleFloatingPanes,
+ ToggleFloatingPanes {
+ /// Target a specific tab by ID
+ #[clap(short, long, value_parser)]
+ tab_id: Option<usize>,
+ },
/// Show all floating panes in the specified tab (or active tab if tab_id is not provided).
///
/// Returns exit code 0 if state was changed, 2 if already visible, 1 if tab not found.
@@ -987,19 +1053,34 @@ pub enum CliAction {
tab_id: Option<usize>,
},
/// Close the focused pane.
- ClosePane,
+ ClosePane {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Renames the focused pane
RenamePane {
name: String,
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
},
/// Remove a previously set pane name
- UndoRenamePane,
+ UndoRenamePane {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Go to the next tab.
GoToNextTab,
/// Go to the previous tab.
GoToPreviousTab,
/// Close the current tab.
- CloseTab,
+ CloseTab {
+ /// Target a specific tab by ID
+ #[clap(short, long, value_parser)]
+ tab_id: Option<usize>,
+ },
/// Go to tab with index [index]
GoToTab {
index: u32,
@@ -1016,9 +1097,16 @@ pub enum CliAction {
/// Renames the focused pane
RenameTab {
name: String,
+ /// Target a specific tab by ID
+ #[clap(short, long, value_parser)]
+ tab_id: Option<usize>,
},
/// Remove a previously set tab name
- UndoRenameTab,
+ UndoRenameTab {
+ /// Target a specific tab by ID
+ #[clap(short, long, value_parser)]
+ tab_id: Option<usize>,
+ },
/// Go to tab with stable ID
GoToTabById {
id: u64,
@@ -1125,9 +1213,20 @@ pub enum CliAction {
/// Move the focused tab in the specified direction. [right|left]
MoveTab {
direction: Direction,
+ /// Target a specific tab by ID
+ #[clap(short, long, value_parser)]
+ tab_id: Option<usize>,
+ },
+ PreviousSwapLayout {
+ /// Target a specific tab by ID
+ #[clap(short, long, value_parser)]
+ tab_id: Option<usize>,
+ },
+ NextSwapLayout {
+ /// Target a specific tab by ID
+ #[clap(short, long, value_parser)]
+ tab_id: Option<usize>,
},
- PreviousSwapLayout,
- NextSwapLayout,
/// Override the layout of the active tab
OverrideLayout {
/// Path to the layout file
@@ -1345,7 +1444,11 @@ tail -f /tmp/my-live-logfile | zellij action pipe --name logs --plugin https://e
#[clap(short, long, value_parser)]
json: bool,
},
- TogglePanePinned,
+ TogglePanePinned {
+ /// Target a specific pane by ID (eg. terminal_1, plugin_2, or 3)
+ #[clap(short, long, value_parser)]
+ pane_id: Option<String>,
+ },
/// Stack pane ids
/// Ids are a space separated list of pane ids.
/// They should either be in the form of `terminal_<int>` (eg. terminal_1), `plugin_<int>` (eg.
diff --git a/zellij-utils/src/client_server_contract/common_types.proto b/zellij-utils/src/client_server_contract/common_types.proto
index ec4f03a9..f93f2632 100644
--- a/zellij-utils/src/client_server_contract/common_types.proto
+++ b/zellij-utils/src/client_server_contract/common_types.proto
@@ -245,6 +245,33 @@ message Action {
HideFloatingPanesAction hide_floating_panes = 107;
SetPaneColorAction set_pane_color = 108;
PasteAction paste = 109;
+ // Pane-targeting
+ ScrollUpByPaneIdAction scroll_up_by_pane_id = 110;
+ ScrollDownByPaneIdAction scroll_down_by_pane_id = 111;
+ ScrollToTopByPaneIdAction scroll_to_top_by_pane_id = 112;
+ ScrollToBottomByPaneIdAction scroll_to_bottom_by_pane_id = 113;
+ PageScrollUpByPaneIdAction page_scroll_up_by_pane_id = 114;
+ PageScrollDownByPaneIdAction page_scroll_down_by_pane_id = 115;
+ HalfPageScrollUpByPaneIdAction half_page_scroll_up_by_pane_id = 116;
+ HalfPageScrollDownByPaneIdAction half_page_scroll_down_by_pane_id = 117;
+ ResizeByPaneIdAction resize_by_pane_id = 118;
+ MovePaneByPaneIdAction move_pane_by_pane_id = 119;
+ MovePaneBackwardsByPaneIdAction move_pane_backwards_by_pane_id = 120;
+ ClearScreenByPaneIdAction clear_screen_by_pane_id = 121;
+ EditScrollbackByPaneIdAction edit_scrollback_by_pane_id = 122;
+ ToggleFullscreenByPaneIdAction toggle_fullscreen_by_pane_id = 123;
+ TogglePaneEmbedOrFloatingByPaneIdAction toggle_pane_embed_or_floating_by_pane_id = 124;
+ CloseFocusByPaneIdAction close_focus_by_pane_id = 125;
+ RenamePaneByPaneIdAction rename_pane_by_pane_id = 126;
+ UndoRenamePaneByPaneIdAction undo_rename_pane_by_pane_id = 127;
+ TogglePanePinnedByPaneIdAction toggle_pane_pinned_by_pane_id = 128;
+ // Tab-targeting
+ UndoRenameTabByTabIdAction undo_rename_tab_by_tab_id = 129;
+ ToggleActiveSyncTabByTabIdAction toggle_active_sync_tab_by_tab_id = 130;
+ ToggleFloatingPanesByTabIdAction toggle_floating_panes_by_tab_id = 131;
+ PreviousSwapLayoutByTabIdAction previous_swap_layout_by_tab_id = 132;
+ NextSwapLayoutByTabIdAction next_swap_layout_by_tab_id = 133;
+ MoveTabByTabIdAction move_tab_by_tab_id = 134;
}
}
@@ -1146,3 +1173,32 @@ enum WebSharing {
WEB_SHARING_OFF = 2;
WEB_SHARING_DISABLED = 3;
}
+
+// Pane-targeting action messages
+message ScrollUpByPaneIdAction { PaneId pane_id = 1; }
+message ScrollDownByPaneIdAction { PaneId pane_id = 1; }
+message ScrollToTopByPaneIdAction { PaneId pane_id = 1; }
+message ScrollToBottomByPaneIdAction { PaneId pane_id = 1; }
+message PageScrollUpByPaneIdAction { PaneId pane_id = 1; }
+message PageScrollDownByPaneIdAction { PaneId pane_id = 1; }
+message HalfPageScrollUpByPaneIdAction { PaneId pane_id = 1; }
+message HalfPageScrollDownByPaneIdAction { PaneId pane_id = 1; }
+message ResizeByPaneIdAction { PaneId pane_id = 1; ResizeAction resize_action = 2; }
+message MovePaneByPaneIdAction { PaneId pane_id = 1; optional Direction direction = 2; }
+message MovePaneBackwardsByPaneIdAction { PaneId pane_id = 1; }
+message ClearScreenByPaneIdAction { PaneId pane_id = 1; }
+message EditScrollbackByPaneIdAction { PaneId pane_id = 1; }
+message ToggleFullscreenByPaneIdAction { PaneId pane_id = 1; }
+message TogglePaneEmbedOrFloatingByPaneIdAction { PaneId pane_id = 1; }
+message CloseFocusByPaneIdAction { PaneId pane_id = 1; }
+message RenamePaneByPaneIdAction { PaneId pane_id = 1; bytes name = 2; }
+message UndoRenamePaneByPaneIdAction { PaneId pane_id = 1; }
+message TogglePanePinnedByPaneIdAction { PaneId pane_id = 1; }
+
+// Tab-targeting action messages
+message UndoRenameTabByTabIdAction { uint64 id = 1; }
+message ToggleActiveSyncTabByTabIdAction { uint64 id = 1; }
+message ToggleFloatingPanesByTabIdAction { uint64 id = 1; }
+message PreviousSwapLayoutByTabIdAction { uint64 id = 1; }
+message NextSwapLayoutByTabIdAction { uint64 id = 1; }
+message MoveTabByTabIdAction { uint64 id = 1; Direction direction = 2; }
diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs
index 82016f7c..a07f4c84 100644
--- a/zellij-utils/src/errors.rs
+++ b/zellij-utils/src/errors.rs
@@ -418,6 +418,33 @@ pub enum ScreenContext {
ClearPluginHighlights,
SubscribeToPaneRenders,
NotifyPaneClosedToSubscribers,
+ // Pane-targeting CLI variants
+ ScrollUpWithPaneId,
+ ScrollDownWithPaneId,
+ ScrollToTopWithPaneId,
+ ScrollToBottomWithPaneId,
+ PageScrollUpWithPaneId,
+ PageScrollDownWithPaneId,
+ HalfPageScrollUpWithPaneId,
+ HalfPageScrollDownWithPaneId,
+ ResizeWithPaneId,
+ MovePaneWithPaneIdCli,
+ MovePaneBackwardsWithPaneId,
+ ClearScreenWithPaneId,
+ EditScrollbackWithPaneId,
+ ToggleFullscreenWithPaneId,
+ TogglePaneEmbedOrFloatingWithPaneId,
+ CloseFocusWithPaneId,
+ RenamePaneWithPaneId,
+ UndoRenamePaneWithPaneId,
+ TogglePanePinnedWithPaneId,
+ // Tab-targeting CLI variants
+ UndoRenameTabWithTabId,
+ ToggleActiveSyncTabWithTabId,
+ ToggleFloatingPanesWithTabId,
+ PreviousSwapLayoutWithTabId,
+ NextSwapLayoutWithTabId,
+ MoveTabWithTabId,
}
/// Stack call representations corresponding to the different types of [`PtyInstruction`]s.
diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs
index d56389c8..f26f6e9a 100644
--- a/zellij-utils/src/input/actions.rs
+++ b/zellij-utils/src/input/actions.rs
@@ -538,6 +538,88 @@ pub enum Action {
},
TogglePaneInGroup,
ToggleGroupMarking,
+ // Pane-targeting CLI-only variants
+ ScrollUpByPaneId {
+ pane_id: PaneId,
+ },
+ ScrollDownByPaneId {
+ pane_id: PaneId,
+ },
+ ScrollToTopByPaneId {
+ pane_id: PaneId,
+ },
+ ScrollToBottomByPaneId {
+ pane_id: PaneId,
+ },
+ PageScrollUpByPaneId {
+ pane_id: PaneId,
+ },
+ PageScrollDownByPaneId {
+ pane_id: PaneId,
+ },
+ HalfPageScrollUpByPaneId {
+ pane_id: PaneId,
+ },
+ HalfPageScrollDownByPaneId {
+ pane_id: PaneId,
+ },
+ ResizeByPaneId {
+ pane_id: PaneId,
+ resize: Resize,
+ direction: Option<Direction>,
+ },
+ MovePaneByPaneId {
+ pane_id: PaneId,
+ direction: Option<Direction>,
+ },
+ MovePaneBackwardsByPaneId {
+ pane_id: PaneId,
+ },
+ ClearScreenByPaneId {
+ pane_id: PaneId,
+ },
+ EditScrollbackByPaneId {
+ pane_id: PaneId,
+ },
+ ToggleFocusFullscreenByPaneId {
+ pane_id: PaneId,
+ },
+ TogglePaneEmbedOrFloatingByPaneId {
+ pane_id: PaneId,
+ },
+ CloseFocusByPaneId {
+ pane_id: PaneId,
+ },
+ RenamePaneByPaneId {
+ pane_id: PaneId,
+ name: Vec<u8>,
+ },
+ UndoRenamePaneByPaneId {
+ pane_id: PaneId,
+ },
+ TogglePanePinnedByPaneId {
+ pane_id: PaneId,
+ },
+ // Tab-targeting CLI-only variants
+ UndoRenameTabByTabId {
+ id: u64,
+ },
+ ToggleActiveSyncTabByTabId {
+ id: u64,
+ },
+ ToggleFloatingPanesByTabId {
+ id: u64,
+ },
+ PreviousSwapLayoutByTabId {
+ id: u64,
+ },
+ NextSwapLayoutByTabId {
+ id: u64,
+ },
+ MoveTabByTabId {
+ id: u64,
+ direction: Direction,
+ },
}
impl Default for Action {
@@ -691,8 +773,23 @@ impl Action {
Ok(actions)
},
- CliAction::Resize { resize, direction } => {
- Ok(vec![Action::Resize { resize, direction }])
+ CliAction::Resize {
+ resize,
+ direction,
+ pane_id,
+ } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::ResizeByPaneId {
+ pane_id,
+ resize,
+ direction,
+ }])
+ },
+ None => Ok(vec![Action::Resize { resize, direction }]),
},
CliAction::FocusNextPane => Ok(vec![Action::FocusNextPane]),
CliAction::FocusPreviousPane => Ok(vec![Action::FocusPreviousPane]),
@@ -700,10 +797,43 @@ impl Action {
CliAction::MoveFocusOrTab { direction } => {
Ok(vec![Action::MoveFocusOrTab { direction }])
},
- CliAction::MovePane { direction } => Ok(vec![Action::MovePane { direction }]),
- CliAction::MovePaneBackwards => Ok(vec![Action::MovePaneBackwards]),
- CliAction::MoveTab { direction } => Ok(vec![Action::MoveTab { direction }]),
- CliAction::Clear => Ok(vec![Action::ClearScreen]),
+ CliAction::MovePane { direction, pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::MovePaneByPaneId { pane_id, direction }])
+ },
+ None => Ok(vec![Action::MovePane { direction }]),
+ },
+ CliAction::MovePaneBackwards { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::MovePaneBackwardsByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::MovePaneBackwards]),
+ },
+ CliAction::MoveTab { direction, tab_id } => match tab_id {
+ Some(id) => Ok(vec![Action::MoveTabByTabId {
+ id: id as u64,
+ direction,
+ }]),
+ None => Ok(vec![Action::MoveTab { direction }]),
+ },
+ CliAction::Clear { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::ClearScreenByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::ClearScreen]),
+ },
CliAction::DumpScreen {
path,
full,
@@ -735,18 +865,111 @@ impl Action {
},
CliAction::DumpLayout => Ok(vec![Action::DumpLayout]),
CliAction::SaveSession => Ok(vec![Action::SaveSession]),
- CliAction::EditScrollback => Ok(vec![Action::EditScrollback]),
- CliAction::ScrollUp => Ok(vec![Action::ScrollUp]),
- CliAction::ScrollDown => Ok(vec![Action::ScrollDown]),
- CliAction::ScrollToBottom => Ok(vec![Action::ScrollToBottom]),
- CliAction::ScrollToTop => Ok(vec![Action::ScrollToTop]),
- CliAction::PageScrollUp => Ok(vec![Action::PageScrollUp]),
- CliAction::PageScrollDown => Ok(vec![Action::PageScrollDown]),
- CliAction::HalfPageScrollUp => Ok(vec![Action::HalfPageScrollUp]),
- CliAction::HalfPageScrollDown => Ok(vec![Action::HalfPageScrollDown]),
- CliAction::ToggleFullscreen => Ok(vec![Action::ToggleFocusFullscreen]),
+ CliAction::EditScrollback { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::EditScrollbackByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::EditScrollback]),
+ },
+ CliAction::ScrollUp { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::ScrollUpByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::ScrollUp]),
+ },
+ CliAction::ScrollDown { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::ScrollDownByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::ScrollDown]),
+ },
+ CliAction::ScrollToBottom { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::ScrollToBottomByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::ScrollToBottom]),
+ },
+ CliAction::ScrollToTop { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::ScrollToTopByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::ScrollToTop]),
+ },
+ CliAction::PageScrollUp { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::PageScrollUpByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::PageScrollUp]),
+ },
+ CliAction::PageScrollDown { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::PageScrollDownByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::PageScrollDown]),
+ },
+ CliAction::HalfPageScrollUp { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::HalfPageScrollUpByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::HalfPageScrollUp]),
+ },
+ CliAction::HalfPageScrollDown { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::HalfPageScrollDownByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::HalfPageScrollDown]),
+ },
+ CliAction::ToggleFullscreen { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::ToggleFocusFullscreenByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::ToggleFocusFullscreen]),
+ },
CliAction::TogglePaneFrames => Ok(vec![Action::TogglePaneFrames]),
- CliAction::ToggleActiveSyncTab => Ok(vec![Action::ToggleActiveSyncTab]),
+ CliAction::ToggleActiveSyncTab { tab_id } => match tab_id {
+ Some(id) => Ok(vec![Action::ToggleActiveSyncTabByTabId { id: id as u64 }]),
+ None => Ok(vec![Action::ToggleActiveSyncTab]),
+ },
CliAction::NewPane {
direction,
command,
@@ -1007,36 +1230,90 @@ impl Action {
}])
},
CliAction::SwitchMode { input_mode } => Ok(vec![Action::SwitchToMode { input_mode }]),
- CliAction::TogglePaneEmbedOrFloating => Ok(vec![Action::TogglePaneEmbedOrFloating]),
- CliAction::ToggleFloatingPanes => Ok(vec![Action::ToggleFloatingPanes]),
+ CliAction::TogglePaneEmbedOrFloating { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::TogglePaneEmbedOrFloatingByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::TogglePaneEmbedOrFloating]),
+ },
+ CliAction::ToggleFloatingPanes { tab_id } => match tab_id {
+ Some(id) => Ok(vec![Action::ToggleFloatingPanesByTabId { id: id as u64 }]),
+ None => Ok(vec![Action::ToggleFloatingPanes]),
+ },
CliAction::ShowFloatingPanes { tab_id } => {
Ok(vec![Action::ShowFloatingPanes { tab_id }])
},
CliAction::HideFloatingPanes { tab_id } => {
Ok(vec![Action::HideFloatingPanes { tab_id }])
},
- CliAction::ClosePane => Ok(vec![Action::CloseFocus]),
- CliAction::RenamePane { name } => Ok(vec![
- Action::UndoRenamePane,
- Action::PaneNameInput {
- input: name.as_bytes().to_vec(),
+ CliAction::ClosePane { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::CloseFocusByPaneId { pane_id }])
},
- ]),
- CliAction::UndoRenamePane => Ok(vec![Action::UndoRenamePane]),
+ None => Ok(vec![Action::CloseFocus]),
+ },
+ CliAction::RenamePane { name, pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::RenamePaneByPaneId {
+ pane_id,
+ name: name.as_bytes().to_vec(),
+ }])
+ },
+ None => Ok(vec![
+ Action::UndoRenamePane,
+ Action::PaneNameInput {
+ input: name.as_bytes().to_vec(),
+ },
+ ]),
+ },
+ CliAction::UndoRenamePane { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::UndoRenamePaneByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::UndoRenamePane]),
+ },
CliAction::GoToNextTab => Ok(vec![Action::GoToNextTab]),
CliAction::GoToPreviousTab => Ok(vec![Action::GoToPreviousTab]),
- CliAction::CloseTab => Ok(vec![Action::CloseTab]),
+ CliAction::CloseTab { tab_id } => match tab_id {
+ Some(id) => Ok(vec![Action::CloseTabById { id: id as u64 }]),
+ None => Ok(vec![Action::CloseTab]),
+ },
CliAction::GoToTab { index } => Ok(vec![Action::GoToTab { index }]),
CliAction::GoToTabName { name, create } => {
Ok(vec![Action::GoToTabName { name, create }])
},
- CliAction::RenameTab { name } => Ok(vec![
- Action::TabNameInput { input: vec![0] },
- Action::TabNameInput {
- input: name.as_bytes().to_vec(),
- },
- ]),
- CliAction::UndoRenameTab => Ok(vec![Action::UndoRenameTab]),
+ CliAction::RenameTab { name, tab_id } => match tab_id {
+ Some(id) => Ok(vec![Action::RenameTabById {
+ id: id as u64,
+ name,
+ }]),
+ None => Ok(vec![
+ Action::TabNameInput { input: vec![0] },
+ Action::TabNameInput {
+ input: name.as_bytes().to_vec(),
+ },
+ ]),
+ },
+ CliAction::UndoRenameTab { tab_id } => match tab_id {
+ Some(id) => Ok(vec![Action::UndoRenameTabByTabId { id: id as u64 }]),
+ None => Ok(vec![Action::UndoRenameTab]),
+ },
CliAction::GoToTabById { id } => Ok(vec![Action::GoToTabById { id }]),
CliAction::CloseTabById { id } => Ok(vec![Action::CloseTabById { id }]),
CliAction::RenameTabById { id, name } => Ok(vec![Action::RenameTabById { id, name }]),
@@ -1231,8 +1508,14 @@ impl Action {
}])
}
},
- CliAction::PreviousSwapLayout => Ok(vec![Action::PreviousSwapLayout]),
- CliAction::NextSwapLayout => Ok(vec![Action::NextSwapLayout]),
+ CliAction::PreviousSwapLayout { tab_id } => match tab_id {
+ Some(id) => Ok(vec![Action::PreviousSwapLayoutByTabId { id: id as u64 }]),
+ None => Ok(vec![Action::PreviousSwapLayout]),
+ },
+ CliAction::NextSwapLayout { tab_id } => match tab_id {
+ Some(id) => Ok(vec![Action::NextSwapLayoutByTabId { id: id as u64 }]),
+ None => Ok(vec![Action::NextSwapLayout]),
+ },
CliAction::OverrideLayout {
layout,
layout_dir,
@@ -1460,7 +1743,16 @@ impl Action {
CliAction::CurrentTabInfo { json } => {
Ok(vec![Action::CurrentTabInfo { output_json: json }])
},
- CliAction::TogglePanePinned => Ok(vec![Action::TogglePanePinned]),
+ CliAction::TogglePanePinned { pane_id } => match pane_id {
+ Some(pane_id_str) => {
+ let pane_id = PaneId::from_str(&pane_id_str)
+ .map_err(|_| format!(
+ "Malformed pane id: {pane_id_str}, expecting either a bare integer (eg. 1), a terminal pane id (eg. terminal_1) or a plugin pane id (eg. plugin_1)"
+ ))?;
+ Ok(vec![Action::TogglePanePinnedByPaneId { pane_id }])
+ },
+ None => Ok(vec![Action::TogglePanePinned]),
+ },
CliAction::StackPanes { pane_ids } => {
let mut malformed_ids = vec![];
let pane_ids = pane_ids
@@ -1855,4 +2147,852 @@ mod tests {
let err = result.unwrap_err();
assert!(err.contains("Malformed pane id"));
}
+
+ // =============================================
+ // Category 1: Pane-targeting tests
+ // =============================================
+
+ // 1. ScrollUp
+ #[test]
+ fn test_scroll_up_with_pane_id() {
+ let cli_action = CliAction::ScrollUp {
+ pane_id: Some("terminal_5".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::ScrollUpByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(5)));
+ },
+ _ => panic!("Expected ScrollUpByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_scroll_up_without_pane_id() {
+ let cli_action = CliAction::ScrollUp { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::ScrollUp));
+ }
+
+ // 2. ScrollDown
+ #[test]
+ fn test_scroll_down_with_pane_id() {
+ let cli_action = CliAction::ScrollDown {
+ pane_id: Some("terminal_2".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::ScrollDownByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(2)));
+ },
+ _ => panic!("Expected ScrollDownByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_scroll_down_without_pane_id() {
+ let cli_action = CliAction::ScrollDown { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::ScrollDown));
+ }
+
+ // 3. ScrollToTop
+ #[test]
+ fn test_scroll_to_top_with_pane_id() {
+ let cli_action = CliAction::ScrollToTop {
+ pane_id: Some("terminal_1".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::ScrollToTopByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(1)));
+ },
+ _ => panic!("Expected ScrollToTopByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_scroll_to_top_without_pane_id() {
+ let cli_action = CliAction::ScrollToTop { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::ScrollToTop));
+ }
+
+ // 4. ScrollToBottom
+ #[test]
+ fn test_scroll_to_bottom_with_pane_id() {
+ let cli_action = CliAction::ScrollToBottom {
+ pane_id: Some("terminal_4".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::ScrollToBottomByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(4)));
+ },
+ _ => panic!("Expected ScrollToBottomByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_scroll_to_bottom_without_pane_id() {
+ let cli_action = CliAction::ScrollToBottom { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::ScrollToBottom));
+ }
+
+ // 5. PageScrollUp
+ #[test]
+ fn test_page_scroll_up_with_pane_id() {
+ let cli_action = CliAction::PageScrollUp {
+ pane_id: Some("terminal_6".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::PageScrollUpByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(6)));
+ },
+ _ => panic!("Expected PageScrollUpByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_page_scroll_up_without_pane_id() {
+ let cli_action = CliAction::PageScrollUp { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::PageScrollUp));
+ }
+
+ // 6. PageScrollDown
+ #[test]
+ fn test_page_scroll_down_with_pane_id() {
+ let cli_action = CliAction::PageScrollDown {
+ pane_id: Some("terminal_8".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::PageScrollDownByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(8)));
+ },
+ _ => panic!("Expected PageScrollDownByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_page_scroll_down_without_pane_id() {
+ let cli_action = CliAction::PageScrollDown { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::PageScrollDown));
+ }
+
+ // 7. HalfPageScrollUp
+ #[test]
+ fn test_half_page_scroll_up_with_pane_id() {
+ let cli_action = CliAction::HalfPageScrollUp {
+ pane_id: Some("terminal_10".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::HalfPageScrollUpByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(10)));
+ },
+ _ => panic!("Expected HalfPageScrollUpByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_half_page_scroll_up_without_pane_id() {
+ let cli_action = CliAction::HalfPageScrollUp { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::HalfPageScrollUp));
+ }
+
+ // 8. HalfPageScrollDown
+ #[test]
+ fn test_half_page_scroll_down_with_pane_id() {
+ let cli_action = CliAction::HalfPageScrollDown {
+ pane_id: Some("terminal_12".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::HalfPageScrollDownByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(12)));
+ },
+ _ => panic!("Expected HalfPageScrollDownByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_half_page_scroll_down_without_pane_id() {
+ let cli_action = CliAction::HalfPageScrollDown { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::HalfPageScrollDown));
+ }
+
+ // 9. Resize
+ #[test]
+ fn test_resize_with_pane_id() {
+ let cli_action = CliAction::Resize {
+ resize: Resize::Increase,
+ direction: Some(Direction::Left),
+ pane_id: Some("terminal_3".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::ResizeByPaneId {
+ pane_id,
+ resize,
+ direction,
+ } => {
+ assert!(matches!(pane_id, PaneId::Terminal(3)));
+ assert!(matches!(resize, Resize::Increase));
+ assert!(matches!(direction, Some(Direction::Left)));
+ },
+ _ => panic!("Expected ResizeByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_resize_without_pane_id() {
+ let cli_action = CliAction::Resize {
+ resize: Resize::Increase,
+ direction: Some(Direction::Left),
+ pane_id: None,
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::Resize { resize, direction } => {
+ assert!(matches!(resize, Resize::Increase));
+ assert!(matches!(direction, Some(Direction::Left)));
+ },
+ _ => panic!("Expected Resize action"),
+ }
+ }
+
+ // 10. MovePane
+ #[test]
+ fn test_move_pane_with_pane_id() {
+ let cli_action = CliAction::MovePane {
+ direction: Some(Direction::Right),
+ pane_id: Some("terminal_9".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::MovePaneByPaneId { pane_id, direction } => {
+ assert!(matches!(pane_id, PaneId::Terminal(9)));
+ assert!(matches!(direction, Some(Direction::Right)));
+ },
+ _ => panic!("Expected MovePaneByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_move_pane_without_pane_id() {
+ let cli_action = CliAction::MovePane {
+ direction: Some(Direction::Right),
+ pane_id: None,
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::MovePane { direction } => {
+ assert!(matches!(direction, Some(Direction::Right)));
+ },
+ _ => panic!("Expected MovePane action"),
+ }
+ }
+
+ // 11. MovePaneBackwards
+ #[test]
+ fn test_move_pane_backwards_with_pane_id() {
+ let cli_action = CliAction::MovePaneBackwards {
+ pane_id: Some("terminal_11".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::MovePaneBackwardsByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(11)));
+ },
+ _ => panic!("Expected MovePaneBackwardsByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_move_pane_backwards_without_pane_id() {
+ let cli_action = CliAction::MovePaneBackwards { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::MovePaneBackwards));
+ }
+
+ // 12. Clear
+ #[test]
+ fn test_clear_with_pane_id() {
+ let cli_action = CliAction::Clear {
+ pane_id: Some("terminal_14".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::ClearScreenByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(14)));
+ },
+ _ => panic!("Expected ClearScreenByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_clear_without_pane_id() {
+ let cli_action = CliAction::Clear { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::ClearScreen));
+ }
+
+ // 13. EditScrollback
+ #[test]
+ fn test_edit_scrollback_with_pane_id() {
+ let cli_action = CliAction::EditScrollback {
+ pane_id: Some("terminal_15".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::EditScrollbackByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(15)));
+ },
+ _ => panic!("Expected EditScrollbackByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_edit_scrollback_without_pane_id() {
+ let cli_action = CliAction::EditScrollback { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::EditScrollback));
+ }
+
+ // 14. ToggleFullscreen
+ #[test]
+ fn test_toggle_fullscreen_with_pane_id() {
+ let cli_action = CliAction::ToggleFullscreen {
+ pane_id: Some("terminal_16".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::ToggleFocusFullscreenByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(16)));
+ },
+ _ => panic!("Expected ToggleFocusFullscreenByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_toggle_fullscreen_without_pane_id() {
+ let cli_action = CliAction::ToggleFullscreen { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::ToggleFocusFullscreen));
+ }
+
+ // 15. TogglePaneEmbedOrFloating
+ #[test]
+ fn test_toggle_pane_embed_or_floating_with_pane_id() {
+ let cli_action = CliAction::TogglePaneEmbedOrFloating {
+ pane_id: Some("terminal_17".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::TogglePaneEmbedOrFloatingByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(17)));
+ },
+ _ => panic!("Expected TogglePaneEmbedOrFloatingByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_toggle_pane_embed_or_floating_without_pane_id() {
+ let cli_action = CliAction::TogglePaneEmbedOrFloating { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::TogglePaneEmbedOrFloating));
+ }
+
+ // 16. ClosePane
+ #[test]
+ fn test_close_pane_with_pane_id() {
+ let cli_action = CliAction::ClosePane {
+ pane_id: Some("terminal_18".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::CloseFocusByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(18)));
+ },
+ _ => panic!("Expected CloseFocusByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_close_pane_without_pane_id() {
+ let cli_action = CliAction::ClosePane { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::CloseFocus));
+ }
+
+ // 17. RenamePane
+ #[test]
+ fn test_rename_pane_with_pane_id() {
+ let cli_action = CliAction::RenamePane {
+ name: "my-pane".to_string(),
+ pane_id: Some("terminal_19".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::RenamePaneByPaneId { pane_id, name } => {
+ assert!(matches!(pane_id, PaneId::Terminal(19)));
+ assert_eq!(name, &"my-pane".as_bytes().to_vec());
+ },
+ _ => panic!("Expected RenamePaneByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_rename_pane_without_pane_id() {
+ let cli_action = CliAction::RenamePane {
+ name: "my-pane".to_string(),
+ pane_id: None,
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 2);
+ assert!(matches!(actions[0], Action::UndoRenamePane));
+ assert!(matches!(actions[1], Action::PaneNameInput { .. }));
+ }
+
+ // 18. UndoRenamePane
+ #[test]
+ fn test_undo_rename_pane_with_pane_id() {
+ let cli_action = CliAction::UndoRenamePane {
+ pane_id: Some("terminal_20".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::UndoRenamePaneByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(20)));
+ },
+ _ => panic!("Expected UndoRenamePaneByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_undo_rename_pane_without_pane_id() {
+ let cli_action = CliAction::UndoRenamePane { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::UndoRenamePane));
+ }
+
+ // 19. TogglePanePinned
+ #[test]
+ fn test_toggle_pane_pinned_with_pane_id() {
+ let cli_action = CliAction::TogglePanePinned {
+ pane_id: Some("terminal_21".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::TogglePanePinnedByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(21)));
+ },
+ _ => panic!("Expected TogglePanePinnedByPaneId action"),
+ }
+ }
+
+ #[test]
+ fn test_toggle_pane_pinned_without_pane_id() {
+ let cli_action = CliAction::TogglePanePinned { pane_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::TogglePanePinned));
+ }
+
+ // Extra pane tests
+ #[test]
+ fn test_scroll_up_with_plugin_pane_id() {
+ let cli_action = CliAction::ScrollUp {
+ pane_id: Some("plugin_3".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::ScrollUpByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Plugin(3)));
+ },
+ _ => panic!("Expected ScrollUpByPaneId action with plugin pane id"),
+ }
+ }
+
+ #[test]
+ fn test_scroll_up_with_bare_integer_pane_id() {
+ let cli_action = CliAction::ScrollUp {
+ pane_id: Some("7".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::ScrollUpByPaneId { pane_id } => {
+ assert!(matches!(pane_id, PaneId::Terminal(7)));
+ },
+ _ => panic!("Expected ScrollUpByPaneId action with bare integer pane id"),
+ }
+ }
+
+ #[test]
+ fn test_scroll_up_with_invalid_pane_id() {
+ let cli_action = CliAction::ScrollUp {
+ pane_id: Some("invalid_id".to_string()),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_err());
+ let err = result.unwrap_err();
+ assert!(err.contains("Malformed pane id"));
+ }
+
+ // =============================================
+ // Category 1: Tab-targeting tests
+ // =============================================
+
+ // 20. CloseTab
+ #[test]
+ fn test_close_tab_with_tab_id() {
+ let cli_action = CliAction::CloseTab { tab_id: Some(5) };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::CloseTabById { id } => {
+ assert_eq!(*id, 5u64);
+ },
+ _ => panic!("Expected CloseTabById action"),
+ }
+ }
+
+ #[test]
+ fn test_close_tab_without_tab_id() {
+ let cli_action = CliAction::CloseTab { tab_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::CloseTab));
+ }
+
+ // 21. RenameTab
+ #[test]
+ fn test_rename_tab_with_tab_id() {
+ let cli_action = CliAction::RenameTab {
+ name: "my-tab".to_string(),
+ tab_id: Some(3),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::RenameTabById { id, name } => {
+ assert_eq!(*id, 3u64);
+ assert_eq!(name, "my-tab");
+ },
+ _ => panic!("Expected RenameTabById action"),
+ }
+ }
+
+ #[test]
+ fn test_rename_tab_without_tab_id() {
+ let cli_action = CliAction::RenameTab {
+ name: "my-tab".to_string(),
+ tab_id: None,
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 2);
+ assert!(matches!(actions[0], Action::TabNameInput { .. }));
+ assert!(matches!(actions[1], Action::TabNameInput { .. }));
+ }
+
+ // 22. UndoRenameTab
+ #[test]
+ fn test_undo_rename_tab_with_tab_id() {
+ let cli_action = CliAction::UndoRenameTab { tab_id: Some(7) };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::UndoRenameTabByTabId { id } => {
+ assert_eq!(*id, 7u64);
+ },
+ _ => panic!("Expected UndoRenameTabByTabId action"),
+ }
+ }
+
+ #[test]
+ fn test_undo_rename_tab_without_tab_id() {
+ let cli_action = CliAction::UndoRenameTab { tab_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::UndoRenameTab));
+ }
+
+ // 23. ToggleActiveSyncTab
+ #[test]
+ fn test_toggle_active_sync_tab_with_tab_id() {
+ let cli_action = CliAction::ToggleActiveSyncTab { tab_id: Some(2) };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::ToggleActiveSyncTabByTabId { id } => {
+ assert_eq!(*id, 2u64);
+ },
+ _ => panic!("Expected ToggleActiveSyncTabByTabId action"),
+ }
+ }
+
+ #[test]
+ fn test_toggle_active_sync_tab_without_tab_id() {
+ let cli_action = CliAction::ToggleActiveSyncTab { tab_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::ToggleActiveSyncTab));
+ }
+
+ // 24. ToggleFloatingPanes
+ #[test]
+ fn test_toggle_floating_panes_with_tab_id() {
+ let cli_action = CliAction::ToggleFloatingPanes { tab_id: Some(4) };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::ToggleFloatingPanesByTabId { id } => {
+ assert_eq!(*id, 4u64);
+ },
+ _ => panic!("Expected ToggleFloatingPanesByTabId action"),
+ }
+ }
+
+ #[test]
+ fn test_toggle_floating_panes_without_tab_id() {
+ let cli_action = CliAction::ToggleFloatingPanes { tab_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::ToggleFloatingPanes));
+ }
+
+ // 25. PreviousSwapLayout
+ #[test]
+ fn test_previous_swap_layout_with_tab_id() {
+ let cli_action = CliAction::PreviousSwapLayout { tab_id: Some(6) };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::PreviousSwapLayoutByTabId { id } => {
+ assert_eq!(*id, 6u64);
+ },
+ _ => panic!("Expected PreviousSwapLayoutByTabId action"),
+ }
+ }
+
+ #[test]
+ fn test_previous_swap_layout_without_tab_id() {
+ let cli_action = CliAction::PreviousSwapLayout { tab_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::PreviousSwapLayout));
+ }
+
+ // 26. NextSwapLayout
+ #[test]
+ fn test_next_swap_layout_with_tab_id() {
+ let cli_action = CliAction::NextSwapLayout { tab_id: Some(8) };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::NextSwapLayoutByTabId { id } => {
+ assert_eq!(*id, 8u64);
+ },
+ _ => panic!("Expected NextSwapLayoutByTabId action"),
+ }
+ }
+
+ #[test]
+ fn test_next_swap_layout_without_tab_id() {
+ let cli_action = CliAction::NextSwapLayout { tab_id: None };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ assert!(matches!(actions[0], Action::NextSwapLayout));
+ }
+
+ // 27. MoveTab
+ #[test]
+ fn test_move_tab_with_tab_id() {
+ let cli_action = CliAction::MoveTab {
+ direction: Direction::Right,
+ tab_id: Some(10),
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::MoveTabByTabId { id, direction } => {
+ assert_eq!(*id, 10u64);
+ assert!(matches!(direction, Direction::Right));
+ },
+ _ => panic!("Expected MoveTabByTabId action"),
+ }
+ }
+
+ #[test]
+ fn test_move_tab_without_tab_id() {
+ let cli_action = CliAction::MoveTab {
+ direction: Direction::Right,
+ tab_id: None,
+ };
+ let result = Action::actions_from_cli(cli_action, Box::new(|| PathBuf::from("/tmp")), None);
+ assert!(result.is_ok());
+ let actions = result.unwrap();
+ assert_eq!(actions.len(), 1);
+ match &actions[0] {
+ Action::MoveTab { direction } => {
+ assert!(matches!(direction, Direction::Right));
+ },
+ _ => panic!("Expected MoveTab action"),
+ }
+ }
}
diff --git a/zellij-utils/src/ipc/protobuf_conversion.rs b/zellij-utils/src/ipc/protobuf_conversion.rs
index 17860407..11948521 100644
--- a/zellij-utils/src/ipc/protobuf_conversion.rs
+++ b/zellij-utils/src/ipc/protobuf_conversion.rs
@@ -780,35 +780,143 @@ impl From<crate::input::actions::Action>
{
fn from(action: crate::input::actions::Action) -> Self {
use crate::client_server_contract::client_server_contract::{
- action::ActionType, BreakPaneAction, BreakPaneLeftAction, BreakPaneRightAction,
- ChangeFloatingPaneCoordinatesAction, ClearScreenAction, CliPipeAction,
- CloseFocusAction, ClosePluginPaneAction, CloseTabAction, CloseTabByIdAction,
- CloseTerminalPaneAction, ConfirmAction, CopyAction, CurrentTabInfoAction, DenyAction,
- DetachAction, DumpLayoutAction, DumpScreenAction, EditFileAction, EditScrollbackAction,
- FocusNextPaneAction, FocusPluginPaneWithIdAction, FocusPreviousPaneAction,
- FocusTerminalPaneWithIdAction, GoToNextTabAction, GoToPreviousTabAction, GoToTabAction,
- GoToTabByIdAction, GoToTabNameAction, HalfPageScrollDownAction, HalfPageScrollUpAction,
- HideFloatingPanesAction, KeybindPipeAction, LaunchOrFocusPluginAction,
- LaunchPluginAction, ListClientsAction, ListPanesAction, ListTabsAction,
- MouseEventAction, MoveFocusAction, MoveFocusOrTabAction, MovePaneAction,
- MovePaneBackwardsAction, MoveTabAction, NewBlockingPaneAction, NewFloatingPaneAction,
- NewFloatingPluginPaneAction, NewInPlacePaneAction, NewInPlacePluginPaneAction,
- NewPaneAction, NewStackedPaneAction, NewTabAction, NewTiledPaneAction,
- NewTiledPluginPaneAction, NextSwapLayoutAction, NoOpAction, OverrideLayoutAction,
- PageScrollDownAction, PageScrollUpAction, PaneIdWithPlugin, PaneNameInputAction,
- PasteAction, PreviousSwapLayoutAction, QueryTabNamesAction, QuitAction,
- RenamePluginPaneAction, RenameSessionAction, RenameTabAction, RenameTabByIdAction,
- RenameTerminalPaneAction, ResizeAction, RunAction, SaveSessionAction, ScrollDownAction,
- ScrollDownAtAction, ScrollToBottomAction, ScrollToTopAction, ScrollUpAction,
- ScrollUpAtAction, SearchAction, SearchInputAction, SearchToggleOptionAction,
- SetPaneBorderlessAction, SetPaneColorAction, ShowFloatingPanesAction,
- SkipConfirmAction, StackPanesAction, StartOrReloadPluginAction, SwitchFocusAction,
- SwitchModeForAllClientsAction, SwitchSessionAction, SwitchToModeAction,
- TabNameInputAction, ToggleActiveSyncTabAction, ToggleFloatingPanesAction,
- ToggleFocusFullscreenAction, ToggleGroupMarkingAction, ToggleMouseModeAction,
- TogglePaneBorderlessAction, TogglePaneEmbedOrFloatingAction, TogglePaneFramesAction,
- TogglePaneInGroupAction, TogglePanePinnedAction, ToggleTabAction, UndoRenamePaneAction,
- UndoRenameTabAction, WriteAction, WriteCharsAction, WriteCharsToPaneIdAction,
+ action::ActionType,
+ BreakPaneAction,
+ BreakPaneLeftAction,
+ BreakPaneRightAction,
+ ChangeFloatingPaneCoordinatesAction,
+ ClearScreenAction,
+ ClearScreenByPaneIdAction,
+ CliPipeAction,
+ CloseFocusAction,
+ CloseFocusByPaneIdAction,
+ ClosePluginPaneAction,
+ CloseTabAction,
+ CloseTabByIdAction,
+ CloseTerminalPaneAction,
+ ConfirmAction,
+ CopyAction,
+ CurrentTabInfoAction,
+ DenyAction,
+ DetachAction,
+ DumpLayoutAction,
+ DumpScreenAction,
+ EditFileAction,
+ EditScrollbackAction,
+ EditScrollbackByPaneIdAction,
+ FocusNextPaneAction,
+ FocusPluginPaneWithIdAction,
+ FocusPreviousPaneAction,
+ FocusTerminalPaneWithIdAction,
+ GoToNextTabAction,
+ GoToPreviousTabAction,
+ GoToTabAction,
+ GoToTabByIdAction,
+ GoToTabNameAction,
+ HalfPageScrollDownAction,
+ HalfPageScrollDownByPaneIdAction,
+ HalfPageScrollUpAction,
+ HalfPageScrollUpByPaneIdAction,
+ HideFloatingPanesAction,
+ KeybindPipeAction,
+ LaunchOrFocusPluginAction,
+ LaunchPluginAction,
+ ListClientsAction,
+ ListPanesAction,
+ ListTabsAction,
+ MouseEventAction,
+ MoveFocusAction,
+ MoveFocusOrTabAction,
+ MovePaneAction,
+ MovePaneBackwardsAction,
+ MovePaneBackwardsByPaneIdAction,
+ MovePaneByPaneIdAction,
+ MoveTabAction,
+ MoveTabByTabIdAction,
+ NewBlockingPaneAction,
+ NewFloatingPaneAction,
+ NewFloatingPluginPaneAction,
+ NewInPlacePaneAction,
+ NewInPlacePluginPaneAction,
+ NewPaneAction,
+ NewStackedPaneAction,
+ NewTabAction,
+ NewTiledPaneAction,
+ NewTiledPluginPaneAction,
+ NextSwapLayoutAction,
+ NextSwapLayoutByTabIdAction,
+ NoOpAction,
+ OverrideLayoutAction,
+ PageScrollDownAction,
+ PageScrollDownByPaneIdAction,
+ PageScrollUpAction,
+ PageScrollUpByPaneIdAction,
+ PaneIdWithPlugin,
+ PaneNameInputAction,
+ PasteAction,
+ PreviousSwapLayoutAction,
+ PreviousSwapLayoutByTabIdAction,
+ QueryTabNamesAction,
+ QuitAction,
+ RenamePaneByPaneIdAction,
+ RenamePluginPaneAction,
+ RenameSessionAction,
+ RenameTabAction,
+ RenameTabByIdAction,
+ RenameTerminalPaneAction,
+ ResizeAction,
+ ResizeByPaneIdAction,
+ RunAction,
+ SaveSessionAction,
+ ScrollDownAction,
+ ScrollDownAtAction,
+ ScrollDownByPaneIdAction,
+ ScrollToBottomAction,
+ ScrollToBottomByPaneIdAction,
+ ScrollToTopAction,
+ ScrollToTopByPaneIdAction,
+ ScrollUpAction,
+ ScrollUpAtAction,
+ // Pane-targeting
+ ScrollUpByPaneIdAction,
+ SearchAction,
+ SearchInputAction,
+ SearchToggleOptionAction,
+ SetPaneBorderlessAction,
+ SetPaneColorAction,
+ ShowFloatingPanesAction,
+ SkipConfirmAction,
+ StackPanesAction,
+ StartOrReloadPluginAction,
+ SwitchFocusAction,
+ SwitchModeForAllClientsAction,
+ SwitchSessionAction,
+ SwitchToModeAction,
+ TabNameInputAction,
+ ToggleActiveSyncTabAction,
+ ToggleActiveSyncTabByTabIdAction,
+ ToggleFloatingPanesAction,
+ ToggleFloatingPanesByTabIdAction,
+ ToggleFocusFullscreenAction,
+ ToggleFullscreenByPaneIdAction,
+ ToggleGroupMarkingAction,
+ ToggleMouseModeAction,
+ TogglePaneBorderlessAction,
+ TogglePaneEmbedOrFloatingAction,
+ TogglePaneEmbedOrFloatingByPaneIdAction,
+ TogglePaneFramesAction,
+ TogglePaneInGroupAction,
+ TogglePanePinnedAction,
+ TogglePanePinnedByPaneIdAction,
+ ToggleTabAction,
+ UndoRenamePaneAction,
+ UndoRenamePaneByPaneIdAction,
+ UndoRenameTabAction,
+ // Tab-targeting
+ UndoRenameTabByTabIdAction,
+ WriteAction,
+ WriteCharsAction,
+ WriteCharsToPaneIdAction,
WriteToPaneIdAction,
};
use std::collections::HashMap;
@@ -1472,6 +1580,134 @@ impl From<crate::input::actions::Action>
bg,
})
},
+ // Pane-targeting CLI-only variants
+ crate::input::actions::Action::ScrollUpByPaneId { pane_id } => {
+ ActionType::ScrollUpByPaneId(ScrollUpByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::ScrollDownByPaneId { pane_id } => {
+ ActionType::ScrollDownByPaneId(ScrollDownByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::ScrollToTopByPaneId { pane_id } => {
+ ActionType::ScrollToTopByPaneId(ScrollToTopByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::ScrollToBottomByPaneId { pane_id } => {
+ ActionType::ScrollToBottomByPaneId(ScrollToBottomByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::PageScrollUpByPaneId { pane_id } => {
+ ActionType::PageScrollUpByPaneId(PageScrollUpByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::PageScrollDownByPaneId { pane_id } => {
+ ActionType::PageScrollDownByPaneId(PageScrollDownByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::HalfPageScrollUpByPaneId { pane_id } => {
+ ActionType::HalfPageScrollUpByPaneId(HalfPageScrollUpByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::HalfPageScrollDownByPaneId { pane_id } => {
+ ActionType::HalfPageScrollDownByPaneId(HalfPageScrollDownByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::ResizeByPaneId {
+ pane_id,
+ resize,
+ direction,
+ } => ActionType::ResizeByPaneId(ResizeByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ resize_action: Some(ResizeAction {
+ resize: resize_to_proto_i32(resize),
+ direction: direction.map(|d| direction_to_proto_i32(d)),
+ }),
+ }),
+ crate::input::actions::Action::MovePaneByPaneId { pane_id, direction } => {
+ ActionType::MovePaneByPaneId(MovePaneByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ direction: direction.map(|d| direction_to_proto_i32(d)),
+ })
+ },
+ crate::input::actions::Action::MovePaneBackwardsByPaneId { pane_id } => {
+ ActionType::MovePaneBackwardsByPaneId(MovePaneBackwardsByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::ClearScreenByPaneId { pane_id } => {
+ ActionType::ClearScreenByPaneId(ClearScreenByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::EditScrollbackByPaneId { pane_id } => {
+ ActionType::EditScrollbackByPaneId(EditScrollbackByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::ToggleFocusFullscreenByPaneId { pane_id } => {
+ ActionType::ToggleFullscreenByPaneId(ToggleFullscreenByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::TogglePaneEmbedOrFloatingByPaneId { pane_id } => {
+ ActionType::TogglePaneEmbedOrFloatingByPaneId(
+ TogglePaneEmbedOrFloatingByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ },
+ )
+ },
+ crate::input::actions::Action::CloseFocusByPaneId { pane_id } => {
+ ActionType::CloseFocusByPaneId(CloseFocusByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::RenamePaneByPaneId { pane_id, name } => {
+ ActionType::RenamePaneByPaneId(RenamePaneByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ name,
+ })
+ },
+ crate::input::actions::Action::UndoRenamePaneByPaneId { pane_id } => {
+ ActionType::UndoRenamePaneByPaneId(UndoRenamePaneByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ crate::input::actions::Action::TogglePanePinnedByPaneId { pane_id } => {
+ ActionType::TogglePanePinnedByPaneId(TogglePanePinnedByPaneIdAction {
+ pane_id: Some(pane_id.into()),
+ })
+ },
+ // Tab-targeting CLI-only variants
+ crate::input::actions::Action::UndoRenameTabByTabId { id } => {
+ ActionType::UndoRenameTabByTabId(UndoRenameTabByTabIdAction { id })
+ },
+ crate::input::actions::Action::ToggleActiveSyncTabByTabId { id } => {
+ ActionType::ToggleActiveSyncTabByTabId(ToggleActiveSyncTabByTabIdAction { id })
+ },
+ crate::input::actions::Action::ToggleFloatingPanesByTabId { id } => {
+ ActionType::ToggleFloatingPanesByTabId(ToggleFloatingPanesByTabIdAction { id })
+ },
+ crate::input::actions::Action::PreviousSwapLayoutByTabId { id } => {
+ ActionType::PreviousSwapLayoutByTabId(PreviousSwapLayoutByTabIdAction { id })
+ },
+ crate::input::actions::Action::NextSwapLayoutByTabId { id } => {
+ ActionType::NextSwapLayoutByTabId(NextSwapLayoutByTabIdAction { id })
+ },
+ crate::input::actions::Action::MoveTabByTabId { id, direction } => {
+ ActionType::MoveTabByTabId(MoveTabByTabIdAction {
+ id,
+ direction: direction_to_proto_i32(direction),
+ })
+ },
};
Self {
@@ -2180,6 +2416,197 @@ impl TryFrom<crate::client_server_contract::client_server_contract::Action>
bg: set_pane_color_action.bg,
})
},
+ // Pane-targeting CLI-only variants
+ ActionType::ScrollUpByPaneId(a) => {
+ Ok(crate::input::actions::Action::ScrollUpByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("ScrollUpByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::ScrollDownByPaneId(a) => {
+ Ok(crate::input::actions::Action::ScrollDownByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("ScrollDownByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::ScrollToTopByPaneId(a) => {
+ Ok(crate::input::actions::Action::ScrollToTopByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("ScrollToTopByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::ScrollToBottomByPaneId(a) => {
+ Ok(crate::input::actions::Action::ScrollToBottomByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("ScrollToBottomByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::PageScrollUpByPaneId(a) => {
+ Ok(crate::input::actions::Action::PageScrollUpByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("PageScrollUpByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::PageScrollDownByPaneId(a) => {
+ Ok(crate::input::actions::Action::PageScrollDownByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("PageScrollDownByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::HalfPageScrollUpByPaneId(a) => {
+ Ok(crate::input::actions::Action::HalfPageScrollUpByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("HalfPageScrollUpByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::HalfPageScrollDownByPaneId(a) => {
+ Ok(crate::input::actions::Action::HalfPageScrollDownByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("HalfPageScrollDownByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::ResizeByPaneId(a) => {
+ let resize_action = a
+ .resize_action
+ .ok_or_else(|| anyhow!("ResizeByPaneId missing resize_action"))?;
+ let resize = proto_i32_to_resize(resize_action.resize)?;
+ let direction = resize_action
+ .direction
+ .map(|d| proto_i32_to_direction(d))
+ .transpose()?;
+ Ok(crate::input::actions::Action::ResizeByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("ResizeByPaneId missing pane_id"))?
+ .try_into()?,
+ resize,
+ direction,
+ })
+ },
+ ActionType::MovePaneByPaneId(a) => {
+ let direction = a.direction.map(|d| proto_i32_to_direction(d)).transpose()?;
+ Ok(crate::input::actions::Action::MovePaneByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("MovePaneByPaneId missing pane_id"))?
+ .try_into()?,
+ direction,
+ })
+ },
+ ActionType::MovePaneBackwardsByPaneId(a) => {
+ Ok(crate::input::actions::Action::MovePaneBackwardsByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("MovePaneBackwardsByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::ClearScreenByPaneId(a) => {
+ Ok(crate::input::actions::Action::ClearScreenByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("ClearScreenByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::EditScrollbackByPaneId(a) => {
+ Ok(crate::input::actions::Action::EditScrollbackByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("EditScrollbackByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::ToggleFullscreenByPaneId(a) => Ok(
+ crate::input::actions::Action::ToggleFocusFullscreenByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("ToggleFullscreenByPaneId missing pane_id"))?
+ .try_into()?,
+ },
+ ),
+ ActionType::TogglePaneEmbedOrFloatingByPaneId(a) => Ok(
+ crate::input::actions::Action::TogglePaneEmbedOrFloatingByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| {
+ anyhow!("TogglePaneEmbedOrFloatingByPaneId missing pane_id")
+ })?
+ .try_into()?,
+ },
+ ),
+ ActionType::CloseFocusByPaneId(a) => {
+ Ok(crate::input::actions::Action::CloseFocusByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("CloseFocusByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::RenamePaneByPaneId(a) => {
+ Ok(crate::input::actions::Action::RenamePaneByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("RenamePaneByPaneId missing pane_id"))?
+ .try_into()?,
+ name: a.name,
+ })
+ },
+ ActionType::UndoRenamePaneByPaneId(a) => {
+ Ok(crate::input::actions::Action::UndoRenamePaneByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("UndoRenamePaneByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ ActionType::TogglePanePinnedByPaneId(a) => {
+ Ok(crate::input::actions::Action::TogglePanePinnedByPaneId {
+ pane_id: a
+ .pane_id
+ .ok_or_else(|| anyhow!("TogglePanePinnedByPaneId missing pane_id"))?
+ .try_into()?,
+ })
+ },
+ // Tab-targeting CLI-only variants
+ ActionType::UndoRenameTabByTabId(a) => {
+ Ok(crate::input::actions::Action::UndoRenameTabByTabId { id: a.id })
+ },
+ ActionType::ToggleActiveSyncTabByTabId(a) => {
+ Ok(crate::input::actions::Action::ToggleActiveSyncTabByTabId { id: a.id })
+ },
+ ActionType::ToggleFloatingPanesByTabId(a) => {
+ Ok(crate::input::actions::Action::ToggleFloatingPanesByTabId { id: a.id })
+ },
+ ActionType::PreviousSwapLayoutByTabId(a) => {
+ Ok(crate::input::actions::Action::PreviousSwapLayoutByTabId { id: a.id })
+ },
+ ActionType::NextSwapLayoutByTabId(a) => {
+ Ok(crate::input::actions::Action::NextSwapLayoutByTabId { id: a.id })
+ },
+ ActionType::MoveTabByTabId(a) => {
+ let direction = proto_i32_to_direction(a.direction)?;
+ Ok(crate::input::actions::Action::MoveTabByTabId {
+ id: a.id,
+ direction,
+ })
+ },
}
}
}
diff --git a/zellij-utils/src/ipc/tests/roundtrip_tests.rs b/zellij-utils/src/ipc/tests/roundtrip_tests.rs
index b4dbb163..3202f28a 100644
--- a/zellij-utils/src/ipc/tests/roundtrip_tests.rs
+++ b/zellij-utils/src/ipc/tests/roundtrip_tests.rs
@@ -3076,6 +3076,230 @@ fn test_client_messages() {
pane_ids: vec![PaneId::Terminal(1)],
scrollback: Some(0),
});
+ // Pane-targeting roundtrips
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::ScrollUpByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::ScrollUpByPaneId {
+ pane_id: PaneId::Plugin(5),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::ScrollDownByPaneId {
+ pane_id: PaneId::Terminal(2),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::ScrollToTopByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::ScrollToBottomByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::PageScrollUpByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::PageScrollDownByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::HalfPageScrollUpByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::HalfPageScrollDownByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::ResizeByPaneId {
+ pane_id: PaneId::Terminal(1),
+ resize: Resize::Increase,
+ direction: Some(Direction::Left),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::ResizeByPaneId {
+ pane_id: PaneId::Terminal(1),
+ resize: Resize::Decrease,
+ direction: None,
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::MovePaneByPaneId {
+ pane_id: PaneId::Terminal(3),
+ direction: Some(Direction::Up),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::MovePaneByPaneId {
+ pane_id: PaneId::Terminal(3),
+ direction: None,
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::MovePaneBackwardsByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::ClearScreenByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::EditScrollbackByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::ToggleFocusFullscreenByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::TogglePaneEmbedOrFloatingByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::CloseFocusByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::RenamePaneByPaneId {
+ pane_id: PaneId::Terminal(1),
+ name: "test-name".as_bytes().to_vec(),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::UndoRenamePaneByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::TogglePanePinnedByPaneId {
+ pane_id: PaneId::Terminal(1),
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ // Tab-targeting roundtrips
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::UndoRenameTabByTabId { id: 5 },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::ToggleActiveSyncTabByTabId { id: 2 },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::ToggleFloatingPanesByTabId { id: 0 },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::PreviousSwapLayoutByTabId { id: 1 },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::NextSwapLayoutByTabId { id: 3 },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
+ test_client_roundtrip!(ClientToServerMsg::Action {
+ action: Action::MoveTabByTabId {
+ id: 1,
+ direction: Direction::Left,
+ },
+ terminal_id: Some(1),
+ client_id: Some(100),
+ is_cli_client: true,
+ });
}
fn test_server_messages() {
diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs
index aef9d881..9117bee5 100644
--- a/zellij-utils/src/plugin_api/action.rs
+++ b/zellij-utils/src/plugin_api/action.rs
@@ -1065,8 +1065,33 @@ impl TryFrom<Action> for ProtobufAction {
| Action::Paste { .. }
| Action::GoToTabById { .. }
| Action::CloseTabById { .. }
- | Action::RenameTabById { .. } => {
- Err("WriteToPaneId, WriteCharsToPaneId, Paste, GoToTabById, CloseTabById, and RenameTabById are CLI-only actions, not available in keybindings")
+ | Action::RenameTabById { .. }
+ | Action::ScrollUpByPaneId { .. }
+ | Action::ScrollDownByPaneId { .. }
+ | Action::ScrollToTopByPaneId { .. }
+ | Action::ScrollToBottomByPaneId { .. }
+ | Action::PageScrollUpByPaneId { .. }
+ | Action::PageScrollDownByPaneId { .. }
+ | Action::HalfPageScrollUpByPaneId { .. }
+ | Action::HalfPageScrollDownByPaneId { .. }
+ | Action::ResizeByPaneId { .. }
+ | Action::MovePaneByPaneId { .. }
+ | Action::MovePaneBackwardsByPaneId { .. }
+ | Action::ClearScreenByPaneId { .. }
+ | Action::EditScrollbackByPaneId { .. }
+ | Action::ToggleFocusFullscreenByPaneId { .. }
+ | Action::TogglePaneEmbedOrFloatingByPaneId { .. }
+ | Action::CloseFocusByPaneId { .. }
+ | Action::RenamePaneByPaneId { .. }
+ | Action::UndoRenamePaneByPaneId { .. }
+ | Action::TogglePanePinnedByPaneId { .. }
+ | Action::UndoRenameTabByTabId { .. }
+ | Action::ToggleActiveSyncTabByTabId { .. }
+ | Action::ToggleFloatingPanesByTabId { .. }
+ | Action::PreviousSwapLayoutByTabId { .. }
+ | Action::NextSwapLayoutByTabId { .. }
+ | Action::MoveTabByTabId { .. } => {
+ Err("These are CLI-only actions, not available in keybindings")
},
Action::SwitchToMode { input_mode } => {
let input_mode: ProtobufInputMode = input_mode.try_into()?;
@@ -1157,14 +1182,12 @@ impl TryFrom<Action> for ProtobufAction {
let dump_to_stdout = file_path.is_none();
Ok(ProtobufAction {
name: ProtobufActionName::DumpScreen as i32,
- optional_payload: Some(OptionalPayload::DumpScreenPayload(
- DumpScreenPayload {
- file_path: file_path.unwrap_or_default(),
- include_scrollback,
- pane_id: pane_id.and_then(|p| p.try_into().ok()),
- dump_to_stdout,
- },
- )),
+ optional_payload: Some(OptionalPayload::DumpScreenPayload(DumpScreenPayload {
+ file_path: file_path.unwrap_or_default(),
+ include_scrollback,
+ pane_id: pane_id.and_then(|p| p.try_into().ok()),
+ dump_to_stdout,
+ })),
})
},
Action::EditScrollback => Ok(ProtobufAction {