use super::test_framework::*; use crate::data::{ BareKey, CommandOrPlugin, ConnectToSession, Direction, FloatingPaneCoordinates, HostTerminalThemeMode, InputMode, KeyModifier, KeyWithModifier, LayoutInfo, LayoutMetadata, NewPanePlacement, OriginatingPlugin, PaneId, PluginTag, Resize, WebSharing, }; use crate::input::actions::{Action, SearchDirection, SearchOption}; use crate::input::cli_assets::CliAssets; use crate::input::command::{OpenFilePayload, RunCommand, RunCommandAction}; use crate::input::layout::{ FloatingPaneLayout, LayoutConstraint, PercentOrFixed, PluginAlias, PluginUserConfiguration, Run, RunPlugin, RunPluginLocation, RunPluginOrAlias, SplitDirection, SplitSize, TiledPaneLayout, }; use crate::input::mouse::{MouseEvent, MouseEventType}; use crate::input::options::{ Clipboard, MobileLayoutConfiguration, NestedSessionHandling, OnForceClose, Options, PaneFrameStyle, }; use crate::ipc::{ ClientToServerMsg, ColorRegister, ExitReason, PaneReference, PixelDimensions, ResizeCause, ServerToClientMsg, }; use crate::pane_size::{Size, SizeInPixels}; use crate::position::Position; use std::collections::{BTreeMap, BTreeSet}; use std::path::PathBuf; const ROUNDTRIP_TEST_STACK_SIZE: usize = 32 * 1024 * 1024; #[test] fn server_client_contract() { std::thread::Builder::new() .stack_size(ROUNDTRIP_TEST_STACK_SIZE) .spawn(|| { test_client_messages(); test_server_messages(); }) .expect("failed to spawn roundtrip test thread") .join() .expect("roundtrip test thread panicked"); } fn test_client_messages() { let empty_context = BTreeMap::new(); let mut demo_context = BTreeMap::new(); demo_context.insert("demo_key1".to_owned(), "demo_value1".to_owned()); demo_context.insert("demo_key2".to_owned(), "demo_value2".to_owned()); demo_context.insert("demo_key3".to_owned(), "demo_value3".to_owned()); let mut swap_tiled_layouts_1 = BTreeMap::new(); swap_tiled_layouts_1.insert( LayoutConstraint::MaxPanes(1), TiledPaneLayout { name: Some("max_panes_1".to_owned()), ..Default::default() }, ); swap_tiled_layouts_1.insert( LayoutConstraint::MinPanes(2), TiledPaneLayout { name: Some("min_panes_2".to_owned()), ..Default::default() }, ); swap_tiled_layouts_1.insert( LayoutConstraint::ExactPanes(3), TiledPaneLayout { name: Some("exact_panes_2".to_owned()), ..Default::default() }, ); swap_tiled_layouts_1.insert( LayoutConstraint::NoConstraint, TiledPaneLayout { name: Some("no_constraint".to_owned()), ..Default::default() }, ); let swap_tiled_layouts_1 = ( swap_tiled_layouts_1, Some("swap_tiled_layouts_1".to_owned()), ); let mut swap_tiled_layouts_2 = BTreeMap::new(); swap_tiled_layouts_2.insert( LayoutConstraint::MaxPanes(1), TiledPaneLayout { name: Some("max_panes_1".to_owned()), ..Default::default() }, ); swap_tiled_layouts_2.insert( LayoutConstraint::MinPanes(2), TiledPaneLayout { name: Some("min_panes_2".to_owned()), ..Default::default() }, ); swap_tiled_layouts_2.insert( LayoutConstraint::ExactPanes(3), TiledPaneLayout { name: Some("exact_panes_2".to_owned()), ..Default::default() }, ); swap_tiled_layouts_2.insert( LayoutConstraint::NoConstraint, TiledPaneLayout { name: Some("no_constraint".to_owned()), ..Default::default() }, ); let swap_tiled_layouts_2 = ( swap_tiled_layouts_2, Some("swap_tiled_layouts_2".to_owned()), ); let mut swap_tiled_layouts_3 = BTreeMap::new(); swap_tiled_layouts_3.insert( LayoutConstraint::MaxPanes(1), TiledPaneLayout { name: Some("max_panes_1".to_owned()), ..Default::default() }, ); swap_tiled_layouts_3.insert( LayoutConstraint::MinPanes(2), TiledPaneLayout { name: Some("min_panes_2".to_owned()), ..Default::default() }, ); swap_tiled_layouts_3.insert( LayoutConstraint::ExactPanes(3), TiledPaneLayout { name: Some("exact_panes_2".to_owned()), ..Default::default() }, ); swap_tiled_layouts_3.insert( LayoutConstraint::NoConstraint, TiledPaneLayout { name: Some("no_constraint".to_owned()), ..Default::default() }, ); let swap_tiled_layouts_3 = (swap_tiled_layouts_3, None); let mut swap_floating_layouts_1 = BTreeMap::new(); swap_floating_layouts_1.insert( LayoutConstraint::MaxPanes(1), vec![ FloatingPaneLayout { name: Some("max_panes_1".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("max_panes_1_1".to_owned()), ..Default::default() }, ], ); swap_floating_layouts_1.insert( LayoutConstraint::MinPanes(2), vec![ FloatingPaneLayout { name: Some("min_panes_2".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("min_panes_2_1".to_owned()), ..Default::default() }, ], ); swap_floating_layouts_1.insert( LayoutConstraint::ExactPanes(3), vec![ FloatingPaneLayout { name: Some("exact_panes_2".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("exact_panes_2_1".to_owned()), ..Default::default() }, ], ); swap_floating_layouts_1.insert( LayoutConstraint::NoConstraint, vec![ FloatingPaneLayout { name: Some("no_constraint".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("no_constraint_1".to_owned()), ..Default::default() }, ], ); let swap_floating_layouts_1 = ( swap_floating_layouts_1, Some("swap_floating_layouts_1".to_owned()), ); let mut swap_floating_layouts_2 = BTreeMap::new(); swap_floating_layouts_2.insert( LayoutConstraint::MaxPanes(1), vec![ FloatingPaneLayout { name: Some("max_panes_1".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("max_panes_1_1".to_owned()), ..Default::default() }, ], ); swap_floating_layouts_2.insert( LayoutConstraint::MinPanes(2), vec![ FloatingPaneLayout { name: Some("min_panes_2".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("min_panes_2_1".to_owned()), ..Default::default() }, ], ); swap_floating_layouts_2.insert( LayoutConstraint::ExactPanes(3), vec![ FloatingPaneLayout { name: Some("exact_panes_2".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("exact_panes_2_1".to_owned()), ..Default::default() }, ], ); swap_floating_layouts_2.insert( LayoutConstraint::NoConstraint, vec![ FloatingPaneLayout { name: Some("no_constraint".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("no_constraint_1".to_owned()), ..Default::default() }, ], ); let swap_floating_layouts_2 = ( swap_floating_layouts_2, Some("swap_floating_layouts_2".to_owned()), ); let mut swap_floating_layouts_3 = BTreeMap::new(); swap_floating_layouts_3.insert( LayoutConstraint::MaxPanes(1), vec![ FloatingPaneLayout { name: Some("max_panes_1".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("max_panes_1_1".to_owned()), ..Default::default() }, ], ); swap_floating_layouts_3.insert( LayoutConstraint::MinPanes(2), vec![ FloatingPaneLayout { name: Some("min_panes_2".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("min_panes_2_1".to_owned()), ..Default::default() }, ], ); swap_floating_layouts_3.insert( LayoutConstraint::ExactPanes(3), vec![ FloatingPaneLayout { name: Some("exact_panes_2".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("exact_panes_2_1".to_owned()), ..Default::default() }, ], ); swap_floating_layouts_3.insert( LayoutConstraint::NoConstraint, vec![ FloatingPaneLayout { name: Some("no_constraint".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("no_constraint_1".to_owned()), ..Default::default() }, ], ); let swap_floating_layouts_3 = (swap_floating_layouts_3, None); let mut demo_modifiers_1 = BTreeSet::new(); let mut demo_modifiers_2 = BTreeSet::new(); let mut demo_modifiers_3 = BTreeSet::new(); let mut demo_modifiers_4 = BTreeSet::new(); demo_modifiers_1.insert(KeyModifier::Ctrl); demo_modifiers_2.insert(KeyModifier::Ctrl); demo_modifiers_3.insert(KeyModifier::Ctrl); demo_modifiers_4.insert(KeyModifier::Ctrl); demo_modifiers_2.insert(KeyModifier::Alt); demo_modifiers_3.insert(KeyModifier::Alt); demo_modifiers_4.insert(KeyModifier::Alt); demo_modifiers_3.insert(KeyModifier::Shift); demo_modifiers_4.insert(KeyModifier::Shift); demo_modifiers_4.insert(KeyModifier::Super); test_client_roundtrip!(ClientToServerMsg::DetachSession { client_ids: vec![] }); test_client_roundtrip!(ClientToServerMsg::DetachSession { client_ids: vec![1], }); test_client_roundtrip!(ClientToServerMsg::DetachSession { client_ids: vec![1, 2, 999], }); test_client_roundtrip!(ClientToServerMsg::TerminalPixelDimensions { pixel_dimensions: PixelDimensions { text_area_size: None, character_cell_size: None, }, }); test_client_roundtrip!(ClientToServerMsg::TerminalPixelDimensions { pixel_dimensions: PixelDimensions { text_area_size: Some(SizeInPixels { width: 800, height: 600 }), character_cell_size: Some(SizeInPixels { width: 10, height: 20 }), }, }); test_client_roundtrip!(ClientToServerMsg::KittyGraphicsSupport { supported: true }); test_client_roundtrip!(ClientToServerMsg::KittyGraphicsSupport { supported: false }); test_client_roundtrip!(ClientToServerMsg::BackgroundColor { color: "red".to_string(), }); test_client_roundtrip!(ClientToServerMsg::BackgroundColor { color: "#FF0000".to_string(), }); test_client_roundtrip!(ClientToServerMsg::BackgroundColor { color: "".to_string(), }); test_client_roundtrip!(ClientToServerMsg::ForegroundColor { color: "blue".to_string(), }); test_client_roundtrip!(ClientToServerMsg::ColorRegisters { color_registers: vec![], }); test_client_roundtrip!(ClientToServerMsg::ColorRegisters { color_registers: vec![ ColorRegister { index: 0, color: "black".to_string() }, ColorRegister { index: 1, color: "red".to_string() }, ColorRegister { index: 255, color: "#FFFFFF".to_string() }, ], }); test_client_roundtrip!(ClientToServerMsg::TerminalResize { new_size: Size { cols: 80, rows: 24 }, cause: ResizeCause::Viewport, }); test_client_roundtrip!(ClientToServerMsg::TerminalResize { new_size: Size { cols: 200, rows: 50 }, cause: ResizeCause::Viewport, }); test_client_roundtrip!(ClientToServerMsg::TerminalResize { new_size: Size { cols: 40, rows: 38 }, cause: ResizeCause::RenderingPreference, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets::default(), is_web_client: false, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets::default(), is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { config_file_path: Some(PathBuf::from("/path/to/config/file.kdl")), config_dir: Some(PathBuf::from("/path/to/config/dir")), should_ignore_config: true, configuration_options: None, layout: None, terminal_window_size: Size { rows: 80, cols: 42 }, data_dir: Some(PathBuf::from("/path/to/data/dir")), is_debug: true, max_panes: Some(4), force_run_layout_commands: true, cwd: Some(PathBuf::from("/path/to/cwd")), }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { config_file_path: Some(PathBuf::from("/path/to/config/file.kdl")), config_dir: Some(PathBuf::from("/path/to/config/dir")), should_ignore_config: true, configuration_options: Some(Options::default()), layout: None, terminal_window_size: Size { rows: 80, cols: 42 }, data_dir: Some(PathBuf::from("/path/to/data/dir")), is_debug: true, max_panes: Some(4), force_run_layout_commands: true, cwd: Some(PathBuf::from("/path/to/cwd")), }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { config_file_path: Some(PathBuf::from("/path/to/config/file.kdl")), config_dir: Some(PathBuf::from("/path/to/config/dir")), should_ignore_config: true, configuration_options: Some(Options { simplified_ui: Some(true), theme: Some("theme".to_owned()), theme_dark: Some("theme_dark".to_owned()), theme_light: Some("theme_light".to_owned()), default_mode: Some(InputMode::Normal), default_shell: Some(PathBuf::from("default_shell")), default_cwd: Some(PathBuf::from("default_cwd")), default_layout: Some(PathBuf::from("default_layout")), layout_dir: Some(PathBuf::from("layout_dir")), theme_dir: Some(PathBuf::from("theme_dir")), mouse_mode: Some(true), pane_frames: Some(true), pane_frame_style: Some(PaneFrameStyle::Full), mirror_session: Some(true), on_force_close: Some(OnForceClose::Quit), scroll_buffer_size: Some(100000), copy_command: Some("copy_command".to_owned()), copy_clipboard: Some(Clipboard::System), copy_on_select: Some(true), osc8_hyperlinks: Some(true), scrollback_editor: Some(PathBuf::from("scrollback_editor")), session_name: Some("session_name".to_owned()), attach_to_session: Some(true), auto_layout: Some(true), session_serialization: Some(true), serialize_pane_viewport: Some(true), scrollback_lines_to_serialize: Some(10000), styled_underlines: Some(true), serialization_interval: Some(1), disable_session_metadata: Some(true), support_kitty_keyboard_protocol: Some(true), support_kitty_graphics_protocol: Some(false), web_server: Some(true), web_sharing: Some(WebSharing::On), stacked_resize: Some(true), stacked_pane_list: Some(true), show_startup_tips: Some(true), show_release_notes: Some(true), advanced_mouse_actions: Some(true), mouse_scroll_resize: Some(true), web_server_ip: Some("1.1.1.1".parse().unwrap()), web_server_port: Some(8080), web_server_cert: Some(PathBuf::from("web_server_cert")), web_server_key: Some(PathBuf::from("web_server_key")), enforce_https_for_localhost: Some(true), post_command_discovery_hook: Some("post_command_discovery_hook".to_owned()), client_async_worker_tasks: Some(16), mouse_hover_effects: Some(false), visual_bell: Some(true), focus_follows_mouse: Some(false), mouse_click_through: Some(false), mobile_layout: Some(MobileLayoutConfiguration::Always), mobile_threshold_cols: Some(72), mobile_threshold_rows: Some(40), nested_session_handling: Some(NestedSessionHandling::Fullscreen), }), layout: None, terminal_window_size: Size { rows: 80, cols: 42 }, data_dir: Some(PathBuf::from("/path/to/data/dir")), is_debug: true, max_panes: Some(4), force_run_layout_commands: true, cwd: Some(PathBuf::from("/path/to/cwd")), }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::Normal), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::Locked), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::Resize), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::Pane), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::Tab), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::Scroll), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::EnterSearch), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::Search), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::RenameTab), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::RenamePane), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::Session), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::Move), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::Prompt), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { default_mode: Some(InputMode::Tmux), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { on_force_close: Some(OnForceClose::Detach), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { copy_clipboard: Some(Clipboard::Primary), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { web_sharing: Some(WebSharing::Off), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { web_sharing: Some(WebSharing::Disabled), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { nested_session_handling: Some(NestedSessionHandling::Ask), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { nested_session_handling: Some(NestedSessionHandling::Fullscreen), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { nested_session_handling: Some(NestedSessionHandling::Descend), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::FirstClientConnected { cli_assets: CliAssets { configuration_options: Some(Options { nested_session_handling: Some(NestedSessionHandling::Never), ..Default::default() }), ..Default::default() }, is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::AttachClient { cli_assets: CliAssets::default(), tab_position_to_focus: None, pane_to_focus: None, is_web_client: false, }); test_client_roundtrip!(ClientToServerMsg::AttachClient { cli_assets: CliAssets::default(), tab_position_to_focus: Some(0), pane_to_focus: None, is_web_client: false, }); test_client_roundtrip!(ClientToServerMsg::AttachClient { cli_assets: CliAssets::default(), tab_position_to_focus: None, pane_to_focus: Some(PaneReference { pane_id: 0, is_plugin: false, }), is_web_client: false, }); test_client_roundtrip!(ClientToServerMsg::AttachClient { cli_assets: CliAssets::default(), tab_position_to_focus: None, pane_to_focus: Some(PaneReference { pane_id: 100, is_plugin: true, }), is_web_client: true, }); test_client_roundtrip!(ClientToServerMsg::AttachClient { cli_assets: CliAssets { configuration_options: Some(Options { nested_session_handling: Some(NestedSessionHandling::Descend), ..Default::default() }), ..Default::default() }, tab_position_to_focus: None, pane_to_focus: None, is_web_client: false, }); // TODO: Action test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Quit, terminal_id: None, client_id: None, is_cli_client: false, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Quit, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Write { key_with_modifier: None, bytes: vec![], is_kitty_keyboard_protocol: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Write { key_with_modifier: Some(KeyWithModifier::new(BareKey::Char('a'))), bytes: "a".as_bytes().to_vec(), is_kitty_keyboard_protocol: true, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::WriteChars { chars: "my chars".to_owned(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SwitchToMode { input_mode: InputMode::Locked, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SwitchModeForAllClients { input_mode: InputMode::Locked, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Resize { resize: Resize::Increase, direction: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Resize { resize: Resize::Decrease, direction: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Resize { resize: Resize::Decrease, direction: Some(Direction::Left), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Resize { resize: Resize::Decrease, direction: Some(Direction::Right), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Resize { resize: Resize::Decrease, direction: Some(Direction::Up), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Resize { resize: Resize::Decrease, direction: Some(Direction::Down), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::FocusNextPane, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::FocusPreviousPane, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SwitchFocus, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::MoveFocus { direction: Direction::Up, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::MoveFocusOrTab { direction: Direction::Up, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::MovePane { direction: None }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::MovePane { direction: Some(Direction::Up), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::MovePaneBackwards, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ClearScreen, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::DumpScreen { file_path: Some("/path/to/file".to_owned()), include_scrollback: false, pane_id: None, ansi: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::DumpScreen { file_path: Some("/path/to/file".to_owned()), include_scrollback: true, pane_id: None, ansi: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::DumpScreen { file_path: Some("/path/to/file".to_owned()), include_scrollback: true, pane_id: Some(PaneId::Terminal(5)), ansi: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::DumpScreen { file_path: None, include_scrollback: false, pane_id: None, ansi: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::DumpLayout, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::EditScrollback { ansi: false }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ScrollUp, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ScrollUpAt { position: Position::new(0, 0), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ScrollUpAt { position: Position::new(-10, 0), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ScrollDown, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ScrollDownAt { position: Position::new(0, 0), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ScrollToBottom, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ScrollToTop, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::PageScrollUp, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::PageScrollDown, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::HalfPageScrollUp, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::HalfPageScrollDown, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ToggleFocusFullscreen, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ToggleFocusNoUiFullscreen, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::TogglePaneFrames, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ToggleActiveSyncTab, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewPane { direction: None, pane_name: None, start_suppressed: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewPane { direction: Some(Direction::Right), pane_name: Some("pane_name".to_owned()), start_suppressed: true, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::EditFile { payload: OpenFilePayload { path: PathBuf::from("/file/path"), line_number: None, cwd: None, originating_plugin: None, }, direction: None, floating: false, in_place: false, close_replaced_pane: false, start_suppressed: false, coordinates: None, near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::EditFile { payload: OpenFilePayload { path: PathBuf::from("/file/path"), line_number: Some(1), cwd: Some(PathBuf::from("/my/cwd")), originating_plugin: Some(OriginatingPlugin { plugin_id: 11, client_id: 22, context: empty_context.clone(), }) }, direction: None, floating: false, in_place: false, close_replaced_pane: false, start_suppressed: false, coordinates: None, near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::EditFile { payload: OpenFilePayload { path: PathBuf::from("/file/path"), line_number: Some(1), cwd: Some(PathBuf::from("/my/cwd")), originating_plugin: Some(OriginatingPlugin { plugin_id: 11, client_id: 22, context: demo_context.clone(), }) }, direction: None, floating: false, in_place: false, close_replaced_pane: false, start_suppressed: false, coordinates: None, near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::EditFile { payload: OpenFilePayload { path: PathBuf::from("/file/path"), line_number: Some(1), cwd: Some(PathBuf::from("/my/cwd")), originating_plugin: Some(OriginatingPlugin { plugin_id: 11, client_id: 22, context: demo_context.clone(), }) }, direction: Some(Direction::Right), floating: true, in_place: true, close_replaced_pane: false, start_suppressed: true, coordinates: FloatingPaneCoordinates::new(None, None, None, None, None, Some(false)), near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::EditFile { payload: OpenFilePayload { path: PathBuf::from("/file/path"), line_number: Some(1), cwd: Some(PathBuf::from("/my/cwd")), originating_plugin: Some(OriginatingPlugin { plugin_id: 11, client_id: 22, context: demo_context.clone(), }) }, direction: Some(Direction::Right), floating: true, in_place: true, close_replaced_pane: false, start_suppressed: true, coordinates: FloatingPaneCoordinates::new( Some("100%".to_owned()), None, None, None, None, Some(false), ), near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::EditFile { payload: OpenFilePayload { path: PathBuf::from("/file/path"), line_number: Some(1), cwd: Some(PathBuf::from("/my/cwd")), originating_plugin: Some(OriginatingPlugin { plugin_id: 11, client_id: 22, context: demo_context.clone(), }) }, direction: Some(Direction::Right), floating: true, in_place: true, close_replaced_pane: false, start_suppressed: true, coordinates: FloatingPaneCoordinates::new( Some("10".to_owned()), None, None, None, None, Some(false), ), near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::EditFile { payload: OpenFilePayload { path: PathBuf::from("/file/path"), line_number: Some(1), cwd: Some(PathBuf::from("/my/cwd")), originating_plugin: Some(OriginatingPlugin { plugin_id: 11, client_id: 22, context: demo_context.clone(), }) }, direction: Some(Direction::Right), floating: true, in_place: true, close_replaced_pane: false, start_suppressed: true, coordinates: FloatingPaneCoordinates::new( Some("10".to_owned()), Some("50%".to_owned()), Some("10".to_owned()), Some("20".to_owned()), Some(true), Some(false), ), near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::EditFile { payload: OpenFilePayload { path: PathBuf::from("/file/path"), line_number: Some(1), cwd: Some(PathBuf::from("/my/cwd")), originating_plugin: Some(OriginatingPlugin { plugin_id: 11, client_id: 22, context: demo_context.clone(), }) }, direction: Some(Direction::Right), floating: true, in_place: true, close_replaced_pane: false, start_suppressed: true, coordinates: FloatingPaneCoordinates::new( None, None, None, None, Some(false), Some(false) ), near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewFloatingPane { command: None, pane_name: None, coordinates: None, near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewFloatingPane { command: Some(RunCommandAction { command: PathBuf::from("/path/to/command"), args: vec![], cwd: None, direction: None, hold_on_close: false, hold_on_start: false, originating_plugin: None, use_terminal_title: false, }), pane_name: Some("my_pane_name".to_owned()), coordinates: FloatingPaneCoordinates::new( Some("10".to_owned()), None, None, None, None, Some(false), ), near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewFloatingPane { command: Some(RunCommandAction { command: PathBuf::from("/path/to/command"), args: vec!["arg1".to_owned(), "arg2".to_owned()], cwd: Some(PathBuf::from("/path/to/cwd")), direction: Some(Direction::Right), hold_on_close: true, hold_on_start: true, originating_plugin: Some(OriginatingPlugin { plugin_id: 1, client_id: 2, context: demo_context.clone(), }), use_terminal_title: false, }), pane_name: Some("my_pane_name".to_owned()), coordinates: FloatingPaneCoordinates::new( Some("10".to_owned()), None, None, None, None, Some(false), ), near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTiledPane { command: None, direction: None, pane_name: None, near_current_pane: false, no_focus: false, borderless: None, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTiledPane { command: Some(RunCommandAction { command: PathBuf::from("/path/to/command"), args: vec!["arg1".to_owned(), "arg2".to_owned()], cwd: Some(PathBuf::from("/path/to/cwd")), direction: Some(Direction::Right), hold_on_close: true, hold_on_start: true, originating_plugin: Some(OriginatingPlugin { plugin_id: 1, client_id: 2, context: demo_context.clone(), }), use_terminal_title: false, }), direction: Some(Direction::Right), pane_name: Some("my_pane_name".to_owned()), near_current_pane: false, no_focus: false, borderless: Some(true), tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewInPlacePane { command: Some(RunCommandAction { command: PathBuf::from("/path/to/command"), args: vec!["arg1".to_owned(), "arg2".to_owned()], cwd: Some(PathBuf::from("/path/to/cwd")), direction: Some(Direction::Right), hold_on_close: true, hold_on_start: true, originating_plugin: Some(OriginatingPlugin { plugin_id: 1, client_id: 2, context: demo_context.clone(), }), use_terminal_title: false, }), pane_name: Some("my_pane_name".to_owned()), near_current_pane: false, no_focus: false, pane_id_to_replace: None, close_replaced_pane: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewInPlacePane { command: None, pane_name: None, near_current_pane: false, no_focus: false, pane_id_to_replace: None, close_replaced_pane: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewStackedPane { command: Some(RunCommandAction { command: PathBuf::from("/path/to/command"), args: vec!["arg1".to_owned(), "arg2".to_owned()], cwd: Some(PathBuf::from("/path/to/cwd")), direction: Some(Direction::Right), hold_on_close: true, hold_on_start: true, originating_plugin: Some(OriginatingPlugin { plugin_id: 1, client_id: 2, context: demo_context.clone(), }), use_terminal_title: false, }), pane_name: Some("my_pane_name".to_owned()), near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewStackedPane { command: None, pane_name: None, near_current_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::TogglePaneEmbedOrFloating, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ToggleFloatingPanes, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::CloseFocus, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::PaneNameInput { input: "name input".as_bytes().to_vec(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::UndoRenamePane, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::RenamePaneByPaneId { pane_id: None, name: "spark".as_bytes().to_vec(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::RenamePaneByPaneId { pane_id: None, name: "x".as_bytes().to_vec(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: None, floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout::default()), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { children_split_direction: SplitDirection::Vertical, ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { children_split_direction: SplitDirection::Horizontal, ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { children_split_direction: SplitDirection::Horizontal, name: Some("tiled_layout_name".to_owned()), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { children: vec![ TiledPaneLayout { name: Some("first_item_in_vec".to_owned()), ..Default::default() }, TiledPaneLayout { name: Some("second_item_in_vec".to_owned()), ..Default::default() }, TiledPaneLayout { name: Some("third_item_in_vec".to_owned()), ..Default::default() }, ], ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { split_size: Some(SplitSize::Fixed(1)), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { split_size: Some(SplitSize::Percent(50)), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Plugin(RunPluginOrAlias::RunPlugin( RunPlugin::default() ))), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Plugin(RunPluginOrAlias::RunPlugin(RunPlugin { _allow_exec_host_cmd: true, ..Default::default() }))), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Plugin(RunPluginOrAlias::RunPlugin(RunPlugin { location: RunPluginLocation::File(PathBuf::from("/my/plugin/location")), ..Default::default() }))), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Plugin(RunPluginOrAlias::RunPlugin(RunPlugin { location: RunPluginLocation::Zellij(PluginTag::new("my_plugin_tag")), ..Default::default() }))), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Plugin(RunPluginOrAlias::RunPlugin(RunPlugin { location: RunPluginLocation::Remote("my_remote_url".to_owned()), ..Default::default() }))), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Plugin(RunPluginOrAlias::RunPlugin(RunPlugin { configuration: PluginUserConfiguration::new(demo_context.clone()), ..Default::default() }))), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Plugin(RunPluginOrAlias::RunPlugin(RunPlugin { configuration: PluginUserConfiguration::new(demo_context.clone()), ..Default::default() }))), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Plugin(RunPluginOrAlias::RunPlugin(RunPlugin { configuration: PluginUserConfiguration::new(empty_context.clone()), ..Default::default() }))), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Plugin(RunPluginOrAlias::RunPlugin(RunPlugin { initial_cwd: Some(PathBuf::from("/initial/cwd")), ..Default::default() }))), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Plugin(RunPluginOrAlias::Alias(PluginAlias::default()))), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Plugin(RunPluginOrAlias::Alias(PluginAlias { name: "alias name".to_owned(), configuration: Some(PluginUserConfiguration::new(demo_context.clone())), initial_cwd: Some(PathBuf::from("initial_cwd")), run_plugin: Some(RunPlugin::default()), ..Default::default() }))), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Command(RunCommand { command: PathBuf::from("/path/to/command"), args: vec![], cwd: None, hold_on_close: false, hold_on_start: false, originating_plugin: None, use_terminal_title: true, })), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Command(RunCommand { command: PathBuf::from("/path/to/command"), args: vec!["arg1".to_owned(), "arg2".to_owned(), "arg3".to_owned()], cwd: Some(PathBuf::from("/path/to/cwd")), hold_on_close: true, hold_on_start: true, originating_plugin: Some(OriginatingPlugin { plugin_id: 11, client_id: 22, context: empty_context.clone(), }), use_terminal_title: true, })), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::EditFile(PathBuf::from("/path/to/file"), None, None)), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::EditFile( PathBuf::from("/path/to/file"), Some(10), Some(PathBuf::from("/path")) )), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: Some(TiledPaneLayout { run: Some(Run::Cwd(PathBuf::from("/path/to/cwd"))), ..Default::default() }), floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: None, floating_layouts: vec![ FloatingPaneLayout { name: Some("first floating layout".to_owned()), ..Default::default() }, FloatingPaneLayout { name: Some("third floating layout".to_owned()), height: Some(PercentOrFixed::Percent(10)), width: Some(PercentOrFixed::Fixed(20)), x: Some(PercentOrFixed::Percent(30)), y: Some(PercentOrFixed::Percent(40)), pinned: Some(true), borderless: None, run: Some(Run::Cwd(PathBuf::from("/path/to/cwd"))), focus: Some(true), already_running: true, pane_initial_contents: Some("pane_initial_contents".to_owned()), logical_position: Some(15), default_fg: None, default_bg: None, }, FloatingPaneLayout { name: Some("third floating layout".to_owned()), ..Default::default() }, FloatingPaneLayout::default(), ], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: None, floating_layouts: vec![], swap_tiled_layouts: Some(vec![ swap_tiled_layouts_1.clone(), swap_tiled_layouts_2.clone(), swap_tiled_layouts_3.clone() ]), swap_floating_layouts: Some(vec![ swap_floating_layouts_1, swap_floating_layouts_2, swap_floating_layouts_3 ]), tab_name: None, should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: None, floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: Some("tab_name".to_owned()), should_change_focus_to_new_tab: false, cwd: None, initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: None, floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: true, cwd: Some(PathBuf::from("relative/path/to/cwd")), initial_panes: None, first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTab { tiled_layout: None, floating_layouts: vec![], swap_tiled_layouts: None, swap_floating_layouts: None, tab_name: None, should_change_focus_to_new_tab: true, cwd: None, initial_panes: Some(vec![ CommandOrPlugin::Command(RunCommandAction { command: PathBuf::from("/path/to/command"), args: vec![], cwd: None, direction: None, hold_on_close: false, hold_on_start: false, originating_plugin: None, use_terminal_title: false, }), CommandOrPlugin::Plugin(RunPluginOrAlias::RunPlugin(RunPlugin::default())), ]), first_pane_unblock_condition: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::OverrideLayout { tabs: vec![], retain_existing_terminal_panes: false, retain_existing_plugin_panes: false, apply_only_to_active_tab: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NoOp, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::GoToNextTab, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::GoToPreviousTab, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::CloseTab, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::GoToTab { index: 0 }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::GoToTabName { name: "tab_name".to_owned(), create: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::GoToTabName { name: "tab_name".to_owned(), create: true, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ToggleTab, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::TabNameInput { input: "my cool tab_name".as_bytes().to_vec(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::UndoRenameTab, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::MoveTab { direction: Direction::Right, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Run { command: RunCommandAction { command: PathBuf::from("/path/to/command"), args: vec![], cwd: None, direction: None, hold_on_close: false, hold_on_start: false, originating_plugin: None, use_terminal_title: false, }, near_current_pane: false, no_focus: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Detach, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SetDarkTheme, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SetLightTheme, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ToggleTheme, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::LaunchOrFocusPlugin { plugin: RunPluginOrAlias::RunPlugin(RunPlugin::default()), should_float: true, move_to_focused_tab: true, should_open_in_place: true, close_replaced_pane: false, skip_cache: true, tab_id: None, close_if_focused: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::LaunchOrFocusPlugin { plugin: RunPluginOrAlias::Alias(PluginAlias::default()), should_float: false, move_to_focused_tab: false, should_open_in_place: false, close_replaced_pane: false, skip_cache: false, tab_id: None, close_if_focused: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::LaunchPlugin { plugin: RunPluginOrAlias::RunPlugin(RunPlugin::default()), should_float: true, should_open_in_place: true, close_replaced_pane: false, skip_cache: true, cwd: None, no_focus: true, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::LaunchPlugin { plugin: RunPluginOrAlias::Alias(PluginAlias::default()), should_float: false, should_open_in_place: false, close_replaced_pane: false, skip_cache: false, cwd: Some(PathBuf::from("/path/to/cwd")), no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::MouseEvent { event: MouseEvent { event_type: MouseEventType::Motion, left: true, right: true, middle: true, wheel_up: true, wheel_down: true, wheel_left: true, wheel_right: true, shift: true, alt: true, ctrl: true, position: Position::new(-10, 0), } }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::MouseEvent { event: MouseEvent { event_type: MouseEventType::Press, left: true, right: true, middle: true, wheel_up: true, wheel_down: true, wheel_left: true, wheel_right: true, shift: true, alt: true, ctrl: true, position: Position::new(-10, 0), } }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::MouseEvent { event: MouseEvent { event_type: MouseEventType::Release, left: true, right: true, middle: true, wheel_up: true, wheel_down: true, wheel_left: true, wheel_right: true, shift: true, alt: true, ctrl: true, position: Position::new(10, 0), } }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Copy, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Confirm, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Deny, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SkipConfirm { action: Box::new(Action::Quit) }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SearchInput { input: "my_search_input".as_bytes().to_vec(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Search { direction: SearchDirection::Up, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::Search { direction: SearchDirection::Down, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SearchToggleOption { option: SearchOption::CaseSensitivity, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SearchToggleOption { option: SearchOption::WholeWord, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SearchToggleOption { option: SearchOption::Wrap, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ToggleMouseMode, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::PreviousSwapLayout, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NextSwapLayout, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::QueryTabNames, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTiledPluginPane { plugin: RunPluginOrAlias::Alias(PluginAlias::default()), pane_name: Some("my_pane_name".to_owned()), skip_cache: false, cwd: Some(PathBuf::from("relative/path/to/cwd")), no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewFloatingPluginPane { plugin: RunPluginOrAlias::RunPlugin(RunPlugin::default()), pane_name: Some("my_pane_name".to_owned()), skip_cache: true, cwd: Some(PathBuf::from("relative/path/to/cwd")), coordinates: None, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewFloatingPluginPane { plugin: RunPluginOrAlias::Alias(PluginAlias::default()), pane_name: Some("my_pane_name".to_owned()), skip_cache: true, cwd: Some(PathBuf::from("relative/path/to/cwd")), coordinates: FloatingPaneCoordinates::new( Some("10".to_owned()), Some("10%".to_owned()), None, None, Some(true), Some(false), ), no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewInPlacePluginPane { plugin: RunPluginOrAlias::Alias(PluginAlias::default()), pane_name: Some("my_pane_name".to_owned()), skip_cache: true, close_replaced_pane: false, no_focus: false, tab_id: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTiledPane { direction: Some(Direction::Right), command: None, pane_name: None, near_current_pane: false, no_focus: false, borderless: None, tab_id: Some(3), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewFloatingPane { command: None, pane_name: None, coordinates: None, near_current_pane: false, no_focus: false, tab_id: Some(5), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewStackedPane { command: None, pane_name: None, near_current_pane: false, no_focus: false, tab_id: Some(2), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewBlockingPane { placement: NewPanePlacement::Tiled { direction: None, borderless: None }, pane_name: None, command: None, unblock_condition: None, near_current_pane: false, no_focus: false, tab_id: Some(1), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::EditFile { payload: OpenFilePayload { path: PathBuf::from("/file/path"), line_number: None, cwd: None, originating_plugin: None, }, direction: None, floating: false, in_place: false, close_replaced_pane: false, start_suppressed: false, coordinates: None, near_current_pane: false, no_focus: false, tab_id: Some(4), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewInPlacePane { command: None, pane_name: None, near_current_pane: false, no_focus: false, pane_id_to_replace: None, close_replaced_pane: false, tab_id: Some(7), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::LaunchOrFocusPlugin { plugin: RunPluginOrAlias::RunPlugin(RunPlugin::default()), should_float: true, move_to_focused_tab: false, should_open_in_place: false, close_replaced_pane: false, skip_cache: false, tab_id: Some(2), close_if_focused: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::LaunchPlugin { plugin: RunPluginOrAlias::RunPlugin(RunPlugin::default()), should_float: false, should_open_in_place: false, close_replaced_pane: false, skip_cache: false, cwd: None, no_focus: false, tab_id: Some(6), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewTiledPluginPane { plugin: RunPluginOrAlias::RunPlugin(RunPlugin::default()), pane_name: None, skip_cache: false, cwd: None, no_focus: false, tab_id: Some(1), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewFloatingPluginPane { plugin: RunPluginOrAlias::RunPlugin(RunPlugin::default()), pane_name: None, skip_cache: false, cwd: None, coordinates: None, no_focus: false, tab_id: Some(3), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::NewInPlacePluginPane { plugin: RunPluginOrAlias::RunPlugin(RunPlugin::default()), pane_name: None, skip_cache: false, close_replaced_pane: false, no_focus: false, tab_id: Some(2), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::StartOrReloadPlugin { plugin: RunPluginOrAlias::Alias(PluginAlias::default()), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::CloseTerminalPane { pane_id: 11 }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ClosePluginPane { pane_id: 12 }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::FocusTerminalPaneWithId { pane_id: 12, should_float_if_hidden: false, should_be_in_place_if_hidden: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::FocusTerminalPaneWithId { pane_id: 12, should_float_if_hidden: true, should_be_in_place_if_hidden: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::FocusPluginPaneWithId { pane_id: 12, should_float_if_hidden: false, should_be_in_place_if_hidden: true, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::FocusPluginPaneWithId { pane_id: 12, should_float_if_hidden: true, should_be_in_place_if_hidden: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::RenameTerminalPane { pane_id: 12, name: "terminal_pane_new_name".as_bytes().to_vec(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::RenamePluginPane { pane_id: 12, name: "plugin_pane_new_name".as_bytes().to_vec(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::RenameTab { tab_index: 11, name: "tab_new_name".as_bytes().to_vec(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::BreakPane, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::BreakPaneRight, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::BreakPaneLeft, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::RenameSession { name: "new_session_name".to_owned(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::CliPipe { pipe_id: "pipe_id_name".to_owned(), name: None, payload: None, args: None, plugin: None, configuration: None, launch_new: false, skip_cache: false, floating: None, in_place: None, cwd: None, pane_title: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::CliPipe { pipe_id: "pipe_id_name".to_owned(), name: Some("pipe_name".to_owned()), payload: Some("pipe_payload".to_owned()), args: Some(demo_context.clone()), plugin: Some("zellij:status-bare".to_owned()), configuration: Some(demo_context.to_owned()), launch_new: true, skip_cache: true, floating: Some(true), in_place: Some(false), cwd: Some(PathBuf::from("/path/to/cwd")), pane_title: Some("pane_title".to_owned()), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::KeybindPipe { plugin_id: None, name: None, payload: None, args: None, plugin: None, configuration: None, launch_new: false, skip_cache: false, floating: None, in_place: None, cwd: None, pane_title: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::KeybindPipe { plugin_id: Some(112), name: Some("pipe_name".to_owned()), payload: Some("pipe_payload".to_owned()), args: Some(demo_context.clone()), plugin: Some("zellij:status-bare".to_owned()), configuration: Some(demo_context.to_owned()), launch_new: true, skip_cache: true, floating: Some(true), in_place: Some(false), cwd: Some(PathBuf::from("/path/to/cwd")), pane_title: Some("pane_title".to_owned()), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ListClients, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::TogglePanePinned, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::StackPanes { pane_ids: vec![] }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::StackPanes { pane_ids: vec![ PaneId::Terminal(0), PaneId::Plugin(1), PaneId::Terminal(2), PaneId::Plugin(3) ], }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ChangeFloatingPaneCoordinates { pane_id: PaneId::Terminal(0), coordinates: FloatingPaneCoordinates::new( None, None, None, Some("10%".to_owned()), Some(false), Some(false), ) .unwrap(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ChangeFloatingPaneCoordinates { pane_id: PaneId::Terminal(0), coordinates: FloatingPaneCoordinates::new( None, None, None, Some("10%".to_owned()), Some(false), Some(true), ) .unwrap(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::TogglePaneInGroup, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::ToggleGroupMarking, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SetPaneColor { pane_id: PaneId::Terminal(0), fg: Some("#00e000".to_owned()), bg: Some("#001a3a".to_owned()), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SetPaneColor { pane_id: PaneId::Plugin(2), fg: None, bg: None, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::PageDown, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::PageDown, key_modifiers: demo_modifiers_1, }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::PageDown, key_modifiers: demo_modifiers_2, }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::PageDown, key_modifiers: demo_modifiers_3, }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::PageDown, key_modifiers: demo_modifiers_4, }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::PageUp, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Down, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Up, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Right, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Home, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::End, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Backspace, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Delete, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Insert, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Tab, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Esc, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Enter, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::CapsLock, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::ScrollLock, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::NumLock, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::PrintScreen, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Pause, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Menu, key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::F(1), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::F(2), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::F(3), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::F(4), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::F(5), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::F(6), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::F(7), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::F(8), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::F(9), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::F(10), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::F(11), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::F(12), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::Key { key: KeyWithModifier { bare_key: BareKey::Char('a'), key_modifiers: BTreeSet::new(), }, raw_bytes: "raw_bytes".as_bytes().to_vec(), is_kitty_keyboard_protocol: false, }); test_client_roundtrip!(ClientToServerMsg::ClientExited); test_client_roundtrip!(ClientToServerMsg::KillSession); test_client_roundtrip!(ClientToServerMsg::ConnStatus); test_client_roundtrip!(ClientToServerMsg::WebServerStarted { base_url: "http://localhost:8080".to_string(), }); test_client_roundtrip!(ClientToServerMsg::FailedToStartWebServer { error: "Port already in use".to_string(), }); test_client_roundtrip!(ClientToServerMsg::SubscribeToPaneRenders { pane_ids: vec![PaneId::Terminal(1), PaneId::Plugin(2)], scrollback: Some(100), ansi: false, }); test_client_roundtrip!(ClientToServerMsg::SubscribeToPaneRenders { pane_ids: vec![PaneId::Terminal(0)], scrollback: None, ansi: false, }); test_client_roundtrip!(ClientToServerMsg::SubscribeToPaneRenders { pane_ids: vec![PaneId::Terminal(1)], scrollback: Some(0), ansi: true, }); 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), ansi: false, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::DumpScreen { file_path: Some("/path".to_owned()), include_scrollback: true, pane_id: None, ansi: true, }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::EditScrollback { ansi: true }, 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), ansi: true, }, 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::ToggleFocusNoUiFullscreenByPaneId { 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: Some(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, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::FocusPaneByPaneId { pane_id: PaneId::Terminal(1), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); 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, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SetPaneFrameStyle(PaneFrameStyle::Full), terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SetPaneFrameStyle(PaneFrameStyle::Titles), terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::Action { action: Action::SetPaneFrameStyle(PaneFrameStyle::None), terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }); test_client_roundtrip!(ClientToServerMsg::ForwardedReplyFromHost { token: 0, reply_bytes: vec![], }); test_client_roundtrip!(ClientToServerMsg::ForwardedReplyFromHost { token: 42, reply_bytes: b"\x1b]11;rgb:ffff/ffff/ffff\x1b\\".to_vec(), }); test_client_roundtrip!(ClientToServerMsg::ForwardedReplyFromHost { token: u32::MAX, reply_bytes: (0u8..=255u8).collect(), }); // Guard against protobuf string-vs-bytes encoding regressions: a // payload mixing NULs, ESC, and CSI framing must round-trip // byte-for-byte or the pane will receive corrupt terminal data. test_client_roundtrip!(ClientToServerMsg::ForwardedReplyFromHost { token: 17, reply_bytes: vec![ 0x00, 0x1b, b'[', b'?', b'6', b'2', b';', b'1', b';', b'6', b'c', 0x00, 0x1b, b']', b'1', b'1', b';', b'r', b'g', b'b', b':', b'f', b'f', b'f', b'f', b'/', b'f', b'f', b'f', b'f', b'/', b'f', b'f', b'f', b'f', 0x07, 0xff, 0x00, ], }); test_client_roundtrip!(ClientToServerMsg::HostTerminalThemeChanged { mode: HostTerminalThemeMode::Dark, }); test_client_roundtrip!(ClientToServerMsg::HostTerminalThemeChanged { mode: HostTerminalThemeMode::Light, }); test_client_roundtrip!(ClientToServerMsg::NestedSessionFrameFromHost { payload_bytes: vec![], }); test_client_roundtrip!(ClientToServerMsg::NestedSessionFrameFromHost { payload_bytes: (0u8..=255u8).collect(), }); } fn test_server_messages() { test_server_roundtrip!(ServerToClientMsg::Render { content: "Hello, World!".to_string(), }); test_server_roundtrip!(ServerToClientMsg::Render { content: "".to_string(), }); test_server_roundtrip!(ServerToClientMsg::Render { content: "x".repeat(10000), }); test_server_roundtrip!(ServerToClientMsg::UnblockInputThread); test_server_roundtrip!(ServerToClientMsg::Connected); test_server_roundtrip!(ServerToClientMsg::QueryTerminalSize); test_server_roundtrip!(ServerToClientMsg::StartWebServer); test_server_roundtrip!(ServerToClientMsg::ConfigFileUpdated); test_server_roundtrip!(ServerToClientMsg::RenamedSession { name: "my-session".to_string(), }); test_server_roundtrip!(ServerToClientMsg::UnblockCliPipeInput { pipe_name: "stdout".to_string(), }); test_server_roundtrip!(ServerToClientMsg::CliPipeOutput { pipe_name: "stderr".to_string(), output: "Error occurred\n".to_string(), }); test_server_roundtrip!(ServerToClientMsg::Exit { exit_reason: ExitReason::Normal, }); test_server_roundtrip!(ServerToClientMsg::Exit { exit_reason: ExitReason::Error("Something went wrong".to_string()), }); test_server_roundtrip!(ServerToClientMsg::Exit { exit_reason: ExitReason::NormalDetached, }); test_server_roundtrip!(ServerToClientMsg::Exit { exit_reason: ExitReason::ForceDetached, }); test_server_roundtrip!(ServerToClientMsg::Exit { exit_reason: ExitReason::CannotAttach, }); test_server_roundtrip!(ServerToClientMsg::Exit { exit_reason: ExitReason::Disconnect, }); test_server_roundtrip!(ServerToClientMsg::Exit { exit_reason: ExitReason::WebClientsForbidden, }); test_server_roundtrip!(ServerToClientMsg::Log { lines: vec![] }); test_server_roundtrip!(ServerToClientMsg::Log { lines: vec![ "Starting server...".to_string(), "Server ready on port 8080".to_string(), "Accepting connections".to_string(), ], }); test_server_roundtrip!(ServerToClientMsg::LogError { lines: vec![] }); test_server_roundtrip!(ServerToClientMsg::LogError { lines: vec![ "ERROR: Failed to bind socket".to_string(), "ERROR: Retrying in 5 seconds".to_string(), ], }); test_server_roundtrip!(ServerToClientMsg::SwitchSession { connect_to_session: ConnectToSession::default(), }); test_server_roundtrip!(ServerToClientMsg::SwitchSession { connect_to_session: ConnectToSession { name: Some("new_session_name".to_owned()), tab_position: Some(5), pane_id: Some((5, true)), layout: Some(LayoutInfo::BuiltIn("compact".to_owned())), cwd: Some(PathBuf::from("/path/to/cwd")), } }); test_server_roundtrip!(ServerToClientMsg::SwitchSession { connect_to_session: ConnectToSession { name: Some("new_session_name".to_owned()), tab_position: Some(5), pane_id: Some((5, true)), layout: Some(LayoutInfo::File( "/path/to/my/file.kdl".to_owned(), LayoutMetadata { tabs: vec![], creation_time: "0".to_owned(), update_time: "0".to_owned() } )), cwd: Some(PathBuf::from("/path/to/cwd")), } }); test_server_roundtrip!(ServerToClientMsg::SwitchSession { connect_to_session: ConnectToSession { name: Some("new_session_name".to_owned()), tab_position: Some(5), pane_id: Some((5, true)), layout: Some(LayoutInfo::Url("https://example.com/layout.kdl".to_owned())), cwd: Some(PathBuf::from("/path/to/cwd")), } }); test_server_roundtrip!(ServerToClientMsg::SwitchSession { connect_to_session: ConnectToSession { name: Some("new_session_name".to_owned()), tab_position: Some(5), pane_id: Some((5, true)), layout: Some(LayoutInfo::Stringified( "layout { pane; pane; pane; }".to_owned() )), cwd: Some(PathBuf::from("/path/to/cwd")), } }); test_server_roundtrip!(ServerToClientMsg::PaneRenderUpdate { pane_id: PaneId::Terminal(1), viewport: vec!["hello".to_string(), "world".to_string()], scrollback: Some(vec!["line1".to_string()]), is_initial: true, }); test_server_roundtrip!(ServerToClientMsg::PaneRenderUpdate { pane_id: PaneId::Plugin(2), viewport: vec!["viewport line".to_string()], scrollback: None, is_initial: false, }); test_server_roundtrip!(ServerToClientMsg::PaneRenderUpdate { pane_id: PaneId::Terminal(0), viewport: vec![], scrollback: Some(vec![]), is_initial: true, }); test_server_roundtrip!(ServerToClientMsg::SubscribedPaneClosed { pane_id: PaneId::Terminal(1), }); test_server_roundtrip!(ServerToClientMsg::SubscribedPaneClosed { pane_id: PaneId::Plugin(3), }); test_server_roundtrip!(ServerToClientMsg::ForwardQueryToHost { token: 0, query_bytes: vec![], }); test_server_roundtrip!(ServerToClientMsg::ForwardQueryToHost { token: 7, query_bytes: b"\x1b[14t".to_vec(), }); test_server_roundtrip!(ServerToClientMsg::ForwardQueryToHost { token: u32::MAX, query_bytes: (0u8..=255u8).collect(), }); test_server_roundtrip!(ServerToClientMsg::EmitNestedSessionFrame { payload_bytes: vec![], }); test_server_roundtrip!(ServerToClientMsg::EmitNestedSessionFrame { payload_bytes: (0u8..=255u8).collect(), }); } #[test] fn set_pane_color_wire_roundtrip() { use prost::Message; let original = ClientToServerMsg::Action { action: Action::SetPaneColor { pane_id: PaneId::Terminal(0), fg: Some("#00e000".to_owned()), bg: Some("#001a3a".to_owned()), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }; let proto: crate::client_server_contract::client_server_contract::ClientToServerMsg = original.clone().into(); let bytes = proto.encode_to_vec(); let decoded_proto = crate::client_server_contract::client_server_contract::ClientToServerMsg::decode( &bytes[..], ) .expect("Failed to decode protobuf bytes"); let roundtrip: ClientToServerMsg = decoded_proto .try_into() .expect("Failed to convert decoded protobuf back to Rust"); assert_eq!(original, roundtrip); } /// Tests that RenamePaneByPaneId with `pane_id: None` (the active-pane CLI /// rename case) survives a full wire-level round-trip /// (Rust → proto struct → bytes → proto struct → Rust). /// /// The struct-level round-trip in `test_client_roundtrip!` doesn't catch /// issues with prost's `tags` attribute on oneof fields, because prost /// only uses the tags list during byte decoding, not struct-to-struct /// conversion. #[test] fn rename_active_pane_wire_roundtrip() { use prost::Message; let original = ClientToServerMsg::Action { action: Action::RenamePaneByPaneId { pane_id: None, name: "x".as_bytes().to_vec(), }, terminal_id: Some(1), client_id: Some(100), is_cli_client: true, }; // Rust → proto struct let proto: crate::client_server_contract::client_server_contract::ClientToServerMsg = original.clone().into(); let mut buf = Vec::new(); proto.encode(&mut buf).expect("Failed to encode protobuf"); let decoded = crate::client_server_contract::client_server_contract::ClientToServerMsg::decode(&buf[..]) .expect("Failed to decode protobuf bytes"); let roundtrip: ClientToServerMsg = decoded .try_into() .expect("Failed to convert decoded protobuf back to Rust"); assert_eq!(original, roundtrip); }