diff --git a/default-plugins/fixture-plugin-for-tests/src/main.rs b/default-plugins/fixture-plugin-for-tests/src/main.rs index 7e4139f5..2107137d 100644 --- a/default-plugins/fixture-plugin-for-tests/src/main.rs +++ b/default-plugins/fixture-plugin-for-tests/src/main.rs @@ -38,10 +38,10 @@ impl ZellijPlugin for State { fn load(&mut self) { subscribe(&[ EventType::InputReceived, + EventType::Key, EventType::SystemClipboardFailure, EventType::CustomMessage, EventType::FileSystemCreate, - EventType::FileSystemRead, EventType::FileSystemUpdate, EventType::FileSystemDelete, ]); @@ -49,6 +49,142 @@ impl ZellijPlugin for State { fn update(&mut self, event: Event) -> bool { match &event { + Event::Key(key) => match key { + Key::Char('a') => { + switch_to_input_mode(&InputMode::Tab); + }, + Key::Char('b') => { + new_tabs_with_layout( + "layout { + tab { + pane + pane + } + tab split_direction=\"vertical\" { + pane + pane + } + }", + ); + }, + Key::Char('c') => new_tab(), + Key::Char('d') => go_to_next_tab(), + Key::Char('e') => go_to_previous_tab(), + Key::Char('f') => { + let resize = Resize::Increase; + resize_focused_pane(resize) + }, + Key::Char('g') => { + let resize = Resize::Increase; + let direction = Direction::Left; + resize_focused_pane_with_direction(resize, direction); + }, + Key::Char('h') => focus_next_pane(), + Key::Char('i') => focus_previous_pane(), + Key::Char('j') => { + let direction = Direction::Left; + move_focus(direction) + }, + Key::Char('k') => { + let direction = Direction::Left; + move_focus_or_tab(direction) + }, + Key::Char('l') => detach(), + Key::Char('m') => edit_scrollback(), + Key::Char('n') => { + let bytes = vec![102, 111, 111]; + write(bytes) + }, + Key::Char('o') => { + let chars = "foo"; + write_chars(chars); + }, + Key::Char('p') => toggle_tab(), + Key::Char('q') => move_pane(), + Key::Char('r') => { + let direction = Direction::Left; + move_pane_with_direction(direction) + }, + Key::Char('s') => clear_screen(), + Key::Char('t') => scroll_up(), + Key::Char('u') => scroll_down(), + Key::Char('v') => scroll_to_top(), + Key::Char('w') => scroll_to_bottom(), + Key::Char('x') => page_scroll_up(), + Key::Char('y') => page_scroll_down(), + Key::Char('z') => toggle_focus_fullscreen(), + Key::Char('1') => toggle_pane_frames(), + Key::Char('2') => toggle_pane_embed_or_eject(), + Key::Char('3') => undo_rename_pane(), + Key::Char('4') => close_focus(), + Key::Char('5') => toggle_active_tab_sync(), + Key::Char('6') => close_focused_tab(), + Key::Char('7') => undo_rename_tab(), + Key::Char('8') => quit_zellij(), + Key::Ctrl('a') => previous_swap_layout(), + Key::Ctrl('b') => next_swap_layout(), + Key::Ctrl('c') => { + let tab_name = "my tab name"; + go_to_tab_name(tab_name) + }, + Key::Ctrl('d') => { + let tab_name = "my tab name"; + focus_or_create_tab(tab_name) + }, + Key::Ctrl('e') => { + let tab_index = 2; + go_to_tab(tab_index) + }, + Key::Ctrl('f') => { + let plugin_url = "file:/path/to/my/plugin.wasm"; + start_or_reload_plugin(plugin_url) + }, + Key::Ctrl('g') => { + open_file(std::path::PathBuf::from("/path/to/my/file.rs").as_path()); + }, + Key::Ctrl('h') => { + open_file_floating(std::path::PathBuf::from("/path/to/my/file.rs").as_path()); + }, + Key::Ctrl('i') => { + open_file_with_line( + std::path::PathBuf::from("/path/to/my/file.rs").as_path(), + 42, + ); + }, + Key::Ctrl('j') => { + open_file_with_line_floating( + std::path::PathBuf::from("/path/to/my/file.rs").as_path(), + 42, + ); + }, + Key::Ctrl('k') => { + open_terminal(std::path::PathBuf::from("/path/to/my/file.rs").as_path()); + }, + Key::Ctrl('l') => { + open_terminal_floating( + std::path::PathBuf::from("/path/to/my/file.rs").as_path(), + ); + }, + Key::Ctrl('m') => { + open_command_pane( + std::path::PathBuf::from("/path/to/my/file.rs").as_path(), + vec!["arg1".to_owned(), "arg2".to_owned()], + ); + }, + Key::Ctrl('n') => { + open_command_pane_floating( + std::path::PathBuf::from("/path/to/my/file.rs").as_path(), + vec!["arg1".to_owned(), "arg2".to_owned()], + ); + }, + Key::Ctrl('o') => { + switch_tab_to(1); + }, + Key::Ctrl('p') => { + hide_self(); + }, + _ => {}, + }, Event::CustomMessage(message, payload) => { if message == "pong" { self.received_payload = Some(payload.clone()); diff --git a/default-plugins/strider/src/search/mod.rs b/default-plugins/strider/src/search/mod.rs index 5aba9c4d..1a9db2da 100644 --- a/default-plugins/strider/src/search/mod.rs +++ b/default-plugins/strider/src/search/mod.rs @@ -204,17 +204,7 @@ impl Search { ) -> Vec { let mut matches = vec![]; for ((file_name, line_number), line_entry) in &self.file_contents { - if line_entry.contains("struct") { - if line_entry.len() < 400 { - eprintln!("matching against: {:?}", line_entry) - } else { - eprintln!("matching again line that has struct but is very long") - } - } if let Some((score, indices)) = matcher.fuzzy_indices(&line_entry, &search_term) { - if line_entry.contains("struct") { - eprintln!("score: {:?}", score) - } matches.push(SearchResult::new_file_line( score, indices, @@ -222,10 +212,6 @@ impl Search { line_entry.clone(), *line_number, )); - } else { - if line_entry.contains("struct") { - eprintln!("no score!") - } } } matches diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs index 4e491142..9707e61e 100644 --- a/zellij-server/src/lib.rs +++ b/zellij-server/src/lib.rs @@ -778,6 +778,9 @@ fn init_session( let store = get_store(); let layout = layout.clone(); + let client_attributes = client_attributes.clone(); + let default_shell = default_shell.clone(); + let capabilities = capabilities.clone(); move || { plugin_thread_main( plugin_bus, @@ -787,6 +790,9 @@ fn init_session( layout, path_to_default_shell, zellij_cwd, + capabilities, + client_attributes, + default_shell, ) .fatal() } @@ -834,7 +840,7 @@ fn init_session( to_plugin: Some(to_plugin), to_pty_writer: Some(to_pty_writer), to_background_jobs: Some(to_background_jobs), - to_server: None, + to_server: Some(to_server), should_silently_fail: false, }, capabilities, diff --git a/zellij-server/src/plugins/mod.rs b/zellij-server/src/plugins/mod.rs index 7b322b05..55e97f03 100644 --- a/zellij-server/src/plugins/mod.rs +++ b/zellij-server/src/plugins/mod.rs @@ -14,13 +14,14 @@ use crate::{pty::PtyInstruction, thread_bus::Bus, ClientId, ServerInstruction}; use wasm_bridge::WasmBridge; use zellij_utils::{ - data::Event, + data::{Event, PluginCapabilities}, errors::{prelude::*, ContextType, PluginContext}, input::{ command::TerminalAction, layout::{FloatingPaneLayout, Layout, Run, RunPlugin, RunPluginLocation, TiledPaneLayout}, plugins::PluginsConfig, }, + ipc::ClientAttributes, pane_size::Size, }; @@ -108,6 +109,9 @@ pub(crate) fn plugin_thread_main( layout: Box, path_to_default_shell: PathBuf, zellij_cwd: PathBuf, + capabilities: PluginCapabilities, + client_attributes: ClientAttributes, + default_shell: Option, ) -> Result<()> { info!("Wasm main thread starts"); @@ -121,6 +125,10 @@ pub(crate) fn plugin_thread_main( plugin_dir, path_to_default_shell, zellij_cwd, + capabilities, + client_attributes, + default_shell, + layout.clone(), ); loop { diff --git a/zellij-server/src/plugins/plugin_loader.rs b/zellij-server/src/plugins/plugin_loader.rs index 4d77bd9e..324b540d 100644 --- a/zellij-server/src/plugins/plugin_loader.rs +++ b/zellij-server/src/plugins/plugin_loader.rs @@ -22,8 +22,12 @@ use crate::{ use zellij_utils::{ consts::{VERSION, ZELLIJ_CACHE_DIR, ZELLIJ_SESSION_CACHE_DIR, ZELLIJ_TMP_DIR}, + data::PluginCapabilities, errors::prelude::*, + input::command::TerminalAction, + input::layout::Layout, input::plugins::PluginConfig, + ipc::ClientAttributes, pane_size::Size, }; @@ -165,6 +169,10 @@ pub struct PluginLoader<'a> { wasm_blob_on_hd: Option<(Vec, PathBuf)>, path_to_default_shell: PathBuf, zellij_cwd: PathBuf, + capabilities: PluginCapabilities, + client_attributes: ClientAttributes, + default_shell: Option, + default_layout: Box, } impl<'a> PluginLoader<'a> { @@ -179,6 +187,10 @@ impl<'a> PluginLoader<'a> { loading_indication: &mut LoadingIndication, path_to_default_shell: PathBuf, zellij_cwd: PathBuf, + capabilities: PluginCapabilities, + client_attributes: ClientAttributes, + default_shell: Option, + default_layout: Box, ) -> Result<()> { let err_context = || format!("failed to reload plugin {plugin_id} from memory"); let mut connected_clients: Vec = @@ -199,6 +211,10 @@ impl<'a> PluginLoader<'a> { &plugin_dir, path_to_default_shell, zellij_cwd, + capabilities, + client_attributes, + default_shell, + default_layout, )?; plugin_loader .load_module_from_memory() @@ -234,6 +250,10 @@ impl<'a> PluginLoader<'a> { loading_indication: &mut LoadingIndication, path_to_default_shell: PathBuf, zellij_cwd: PathBuf, + capabilities: PluginCapabilities, + client_attributes: ClientAttributes, + default_shell: Option, + default_layout: Box, ) -> Result<()> { let err_context = || format!("failed to start plugin {plugin_id} for client {client_id}"); let mut plugin_loader = PluginLoader::new( @@ -249,6 +269,10 @@ impl<'a> PluginLoader<'a> { size, path_to_default_shell, zellij_cwd, + capabilities, + client_attributes, + default_shell, + default_layout, )?; plugin_loader .load_module_from_memory() @@ -284,6 +308,10 @@ impl<'a> PluginLoader<'a> { loading_indication: &mut LoadingIndication, path_to_default_shell: PathBuf, zellij_cwd: PathBuf, + capabilities: PluginCapabilities, + client_attributes: ClientAttributes, + default_shell: Option, + default_layout: Box, ) -> Result<()> { let mut new_plugins = HashSet::new(); for plugin_id in plugin_map.lock().unwrap().plugin_ids() { @@ -301,6 +329,10 @@ impl<'a> PluginLoader<'a> { &plugin_dir, path_to_default_shell.clone(), zellij_cwd.clone(), + capabilities.clone(), + client_attributes.clone(), + default_shell.clone(), + default_layout.clone(), )?; plugin_loader .load_module_from_memory() @@ -329,6 +361,10 @@ impl<'a> PluginLoader<'a> { loading_indication: &mut LoadingIndication, path_to_default_shell: PathBuf, zellij_cwd: PathBuf, + capabilities: PluginCapabilities, + client_attributes: ClientAttributes, + default_shell: Option, + default_layout: Box, ) -> Result<()> { let err_context = || format!("failed to reload plugin id {plugin_id}"); @@ -350,6 +386,10 @@ impl<'a> PluginLoader<'a> { &plugin_dir, path_to_default_shell, zellij_cwd, + capabilities, + client_attributes, + default_shell, + default_layout, )?; plugin_loader .compile_module() @@ -382,6 +422,10 @@ impl<'a> PluginLoader<'a> { size: Size, path_to_default_shell: PathBuf, zellij_cwd: PathBuf, + capabilities: PluginCapabilities, + client_attributes: ClientAttributes, + default_shell: Option, + default_layout: Box, ) -> Result { let plugin_own_data_dir = ZELLIJ_SESSION_CACHE_DIR .join(Url::from(&plugin.location).to_string()) @@ -404,6 +448,10 @@ impl<'a> PluginLoader<'a> { wasm_blob_on_hd: None, path_to_default_shell, zellij_cwd, + capabilities, + client_attributes, + default_shell, + default_layout, }) } pub fn new_from_existing_plugin_attributes( @@ -417,6 +465,10 @@ impl<'a> PluginLoader<'a> { plugin_dir: &'a PathBuf, path_to_default_shell: PathBuf, zellij_cwd: PathBuf, + capabilities: PluginCapabilities, + client_attributes: ClientAttributes, + default_shell: Option, + default_layout: Box, ) -> Result { let err_context = || "Failed to find existing plugin"; let (running_plugin, _subscriptions, _workers) = { @@ -446,6 +498,10 @@ impl<'a> PluginLoader<'a> { size, path_to_default_shell, zellij_cwd, + capabilities, + client_attributes, + default_shell, + default_layout, ) } pub fn new_from_different_client_id( @@ -459,6 +515,10 @@ impl<'a> PluginLoader<'a> { plugin_dir: &'a PathBuf, path_to_default_shell: PathBuf, zellij_cwd: PathBuf, + capabilities: PluginCapabilities, + client_attributes: ClientAttributes, + default_shell: Option, + default_layout: Box, ) -> Result { let err_context = || "Failed to find existing plugin"; let running_plugin = { @@ -489,6 +549,10 @@ impl<'a> PluginLoader<'a> { size, path_to_default_shell, zellij_cwd, + capabilities, + client_attributes, + default_shell, + default_layout, ) } pub fn load_module_from_memory(&mut self) -> Result { @@ -721,6 +785,10 @@ impl<'a> PluginLoader<'a> { &self.plugin_dir, self.path_to_default_shell.clone(), self.zellij_cwd.clone(), + self.capabilities.clone(), + self.client_attributes.clone(), + self.default_shell.clone(), + self.default_layout.clone(), )?; plugin_loader_for_client .load_module_from_memory() @@ -804,6 +872,10 @@ impl<'a> PluginLoader<'a> { plugin_own_data_dir: self.plugin_own_data_dir.clone(), tab_index: self.tab_index, path_to_default_shell: self.path_to_default_shell.clone(), + capabilities: self.capabilities.clone(), + client_attributes: self.client_attributes.clone(), + default_shell: self.default_shell.clone(), + default_layout: self.default_layout.clone(), }; let subscriptions = Arc::new(Mutex::new(HashSet::new())); diff --git a/zellij-server/src/plugins/plugin_map.rs b/zellij-server/src/plugins/plugin_map.rs index 040c9f9f..2f7454c7 100644 --- a/zellij-server/src/plugins/plugin_map.rs +++ b/zellij-server/src/plugins/plugin_map.rs @@ -13,7 +13,12 @@ use crate::{thread_bus::ThreadSenders, ClientId}; use zellij_utils::async_channel::Sender; use zellij_utils::errors::prelude::*; use zellij_utils::{ - data::EventType, input::layout::RunPluginLocation, input::plugins::PluginConfig, + data::EventType, + data::PluginCapabilities, + input::command::TerminalAction, + input::layout::{Layout, RunPluginLocation}, + input::plugins::PluginConfig, + ipc::ClientAttributes, }; // the idea here is to provide atomicity when adding/removing plugins from the map (eg. when a new @@ -195,6 +200,10 @@ pub struct PluginEnv { #[allow(dead_code)] pub plugin_own_data_dir: PathBuf, pub path_to_default_shell: PathBuf, + pub capabilities: PluginCapabilities, + pub client_attributes: ClientAttributes, + pub default_shell: Option, + pub default_layout: Box, } impl PluginEnv { diff --git a/zellij-server/src/plugins/unit/plugin_tests.rs b/zellij-server/src/plugins/unit/plugin_tests.rs index d41a477b..f15ac126 100644 --- a/zellij-server/src/plugins/unit/plugin_tests.rs +++ b/zellij-server/src/plugins/unit/plugin_tests.rs @@ -5,10 +5,11 @@ use insta::assert_snapshot; use std::path::PathBuf; use tempfile::tempdir; use wasmer::Store; -use zellij_utils::data::Event; +use zellij_utils::data::{Event, Key, PluginCapabilities}; use zellij_utils::errors::ErrorContext; use zellij_utils::input::layout::{Layout, RunPlugin, RunPluginLocation}; use zellij_utils::input::plugins::PluginsConfig; +use zellij_utils::ipc::ClientAttributes; use zellij_utils::lazy_static::lazy_static; use zellij_utils::pane_size::Size; @@ -50,6 +51,35 @@ macro_rules! log_actions_in_thread { }; } +macro_rules! log_actions_in_thread_naked_variant { + ( $arc_mutex_log:expr, $exit_event:path, $receiver:expr, $exit_after_count:expr ) => { + std::thread::Builder::new() + .name("logger thread".to_string()) + .spawn({ + let log = $arc_mutex_log.clone(); + let mut exit_event_count = 0; + move || loop { + let (event, _err_ctx) = $receiver + .recv() + .expect("failed to receive event on channel"); + match event { + $exit_event => { + exit_event_count += 1; + log.lock().unwrap().push(event); + if exit_event_count == $exit_after_count { + break; + } + }, + _ => { + log.lock().unwrap().push(event); + }, + } + } + }) + .unwrap() + }; +} + fn create_plugin_thread( zellij_cwd: Option, ) -> ( @@ -92,6 +122,9 @@ fn create_plugin_thread( let store = Store::new(&wasmer::Universal::new(wasmer::Singlepass::default()).engine()); let data_dir = PathBuf::from(tempdir().unwrap().path()); let default_shell = PathBuf::from("."); + let plugin_capabilities = PluginCapabilities::default(); + let client_attributes = ClientAttributes::default(); + let default_shell_action = None; // TODO: change me let _plugin_thread = std::thread::Builder::new() .name("plugin_thread".to_string()) .spawn(move || { @@ -104,6 +137,9 @@ fn create_plugin_thread( Box::new(Layout::default()), default_shell, zellij_cwd, + plugin_capabilities, + client_attributes, + default_shell_action, ) .expect("TEST") }) @@ -116,11 +152,178 @@ fn create_plugin_thread( let _ = to_screen.send(ScreenInstruction::Exit); let _ = to_server.send(ServerInstruction::KillSession); let _ = to_plugin.send(PluginInstruction::Exit); + std::thread::sleep(std::time::Duration::from_millis(100)); // we need to do this + // otherwise there are race + // conditions with removing + // the plugin cache } }; (to_plugin, screen_receiver, Box::new(teardown)) } +fn create_plugin_thread_with_server_receiver( + zellij_cwd: Option, +) -> ( + SenderWithContext, + Receiver<(ServerInstruction, ErrorContext)>, + Box, +) { + let zellij_cwd = zellij_cwd.unwrap_or_else(|| PathBuf::from(".")); + let (to_server, server_receiver): ChannelWithContext = channels::bounded(50); + let to_server = SenderWithContext::new(to_server); + + let (to_screen, _screen_receiver): ChannelWithContext = + channels::unbounded(); + let to_screen = SenderWithContext::new(to_screen); + + let (to_plugin, plugin_receiver): ChannelWithContext = channels::unbounded(); + let to_plugin = SenderWithContext::new(to_plugin); + let (to_pty, _pty_receiver): ChannelWithContext = channels::unbounded(); + let to_pty = SenderWithContext::new(to_pty); + + let (to_pty_writer, _pty_writer_receiver): ChannelWithContext = + channels::unbounded(); + let to_pty_writer = SenderWithContext::new(to_pty_writer); + + let (to_background_jobs, _background_jobs_receiver): ChannelWithContext = + channels::unbounded(); + let to_background_jobs = SenderWithContext::new(to_background_jobs); + + let plugin_bus = Bus::new( + vec![plugin_receiver], + Some(&to_screen), + Some(&to_pty), + Some(&to_plugin), + Some(&to_server), + Some(&to_pty_writer), + Some(&to_background_jobs), + None, + ) + .should_silently_fail(); + let store = Store::new(&wasmer::Universal::new(wasmer::Singlepass::default()).engine()); + let data_dir = PathBuf::from(tempdir().unwrap().path()); + let default_shell = PathBuf::from("."); + let plugin_capabilities = PluginCapabilities::default(); + let client_attributes = ClientAttributes::default(); + let default_shell_action = None; // TODO: change me + let _plugin_thread = std::thread::Builder::new() + .name("plugin_thread".to_string()) + .spawn(move || { + set_var("ZELLIJ_SESSION_NAME", "zellij-test"); + plugin_thread_main( + plugin_bus, + store, + data_dir, + PluginsConfig::default(), + Box::new(Layout::default()), + default_shell, + zellij_cwd, + plugin_capabilities, + client_attributes, + default_shell_action, + ) + .expect("TEST") + }) + .unwrap(); + let teardown = { + let to_plugin = to_plugin.clone(); + move || { + let _ = to_pty.send(PtyInstruction::Exit); + let _ = to_pty_writer.send(PtyWriteInstruction::Exit); + let _ = to_screen.send(ScreenInstruction::Exit); + let _ = to_server.send(ServerInstruction::KillSession); + let _ = to_plugin.send(PluginInstruction::Exit); + std::thread::sleep(std::time::Duration::from_millis(100)); // we need to do this + // otherwise there are race + // conditions with removing + // the plugin cache + } + }; + (to_plugin, server_receiver, Box::new(teardown)) +} + +fn create_plugin_thread_with_pty_receiver( + zellij_cwd: Option, +) -> ( + SenderWithContext, + Receiver<(PtyInstruction, ErrorContext)>, + Box, +) { + let zellij_cwd = zellij_cwd.unwrap_or_else(|| PathBuf::from(".")); + let (to_server, _server_receiver): ChannelWithContext = + channels::bounded(50); + let to_server = SenderWithContext::new(to_server); + + let (to_screen, _screen_receiver): ChannelWithContext = + channels::unbounded(); + let to_screen = SenderWithContext::new(to_screen); + + let (to_plugin, plugin_receiver): ChannelWithContext = channels::unbounded(); + let to_plugin = SenderWithContext::new(to_plugin); + let (to_pty, pty_receiver): ChannelWithContext = channels::unbounded(); + let to_pty = SenderWithContext::new(to_pty); + + let (to_pty_writer, _pty_writer_receiver): ChannelWithContext = + channels::unbounded(); + let to_pty_writer = SenderWithContext::new(to_pty_writer); + + let (to_background_jobs, _background_jobs_receiver): ChannelWithContext = + channels::unbounded(); + let to_background_jobs = SenderWithContext::new(to_background_jobs); + + let plugin_bus = Bus::new( + vec![plugin_receiver], + Some(&to_screen), + Some(&to_pty), + Some(&to_plugin), + Some(&to_server), + Some(&to_pty_writer), + Some(&to_background_jobs), + None, + ) + .should_silently_fail(); + let store = Store::new(&wasmer::Universal::new(wasmer::Singlepass::default()).engine()); + let data_dir = PathBuf::from(tempdir().unwrap().path()); + let default_shell = PathBuf::from("."); + let plugin_capabilities = PluginCapabilities::default(); + let client_attributes = ClientAttributes::default(); + let default_shell_action = None; // TODO: change me + let _plugin_thread = std::thread::Builder::new() + .name("plugin_thread".to_string()) + .spawn(move || { + set_var("ZELLIJ_SESSION_NAME", "zellij-test"); + plugin_thread_main( + plugin_bus, + store, + data_dir, + PluginsConfig::default(), + Box::new(Layout::default()), + default_shell, + zellij_cwd, + plugin_capabilities, + client_attributes, + default_shell_action, + ) + .expect("TEST") + }) + .unwrap(); + let teardown = { + let to_plugin = to_plugin.clone(); + move || { + let _ = to_pty.send(PtyInstruction::Exit); + let _ = to_pty_writer.send(PtyWriteInstruction::Exit); + let _ = to_screen.send(ScreenInstruction::Exit); + let _ = to_server.send(ServerInstruction::KillSession); + let _ = to_plugin.send(PluginInstruction::Exit); + std::thread::sleep(std::time::Duration::from_millis(100)); // we need to do this + // otherwise there are race + // conditions with removing + // the plugin cache + } + }; + (to_plugin, pty_receiver, Box::new(teardown)) +} + lazy_static! { static ref PLUGIN_FIXTURE: String = format!( // to populate this file, make sure to run the build-e2e CI job @@ -383,12 +586,3029 @@ pub fn can_subscribe_to_hd_events() { if let ScreenInstruction::PluginBytes(plugin_bytes) = i { for (plugin_id, client_id, plugin_bytes) in plugin_bytes { let plugin_bytes = String::from_utf8_lossy(plugin_bytes).to_string(); - if plugin_bytes.contains("FileSystem") { + if plugin_bytes.contains("FileSystemCreate") { return Some((*plugin_id, *client_id, plugin_bytes)); } } } None }); - assert_snapshot!(format!("{:#?}", plugin_bytes_event)); + assert!(plugin_bytes_event.is_some()); +} + +#[test] +#[ignore] +pub fn switch_to_mode_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::ChangeMode, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('a')), // this triggers a SwitchToMode(Tab) command in the fixture + // plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let switch_to_mode_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::ChangeMode(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", switch_to_mode_event)); +} + +#[test] +#[ignore] +pub fn new_tabs_with_layout_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::NewTab, + screen_receiver, + 2 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('b')), // this triggers a new_tabs_with_layout command in the fixture + // plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let first_new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::NewTab(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + let second_new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .rev() + .find_map(|i| { + if let ScreenInstruction::NewTab(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", first_new_tab_event)); + assert_snapshot!(format!("{:#?}", second_new_tab_event)); +} + +#[test] +#[ignore] +pub fn new_tab_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::NewTab, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('c')), // this triggers a new_tab command in the fixture + // plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::NewTab(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn go_to_next_tab_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::SwitchTabNext, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('d')), // this triggers the event in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::SwitchTabNext(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn go_to_previous_tab_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::SwitchTabPrev, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('e')), // this triggers the event in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::SwitchTabPrev(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn resize_focused_pane_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::Resize, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('f')), // this triggers the event in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::Resize(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn resize_focused_pane_with_direction_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::Resize, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('g')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::Resize(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn focus_next_pane_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::FocusNextPane, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('h')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::FocusNextPane(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn focus_previous_pane_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::FocusPreviousPane, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('i')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::FocusPreviousPane(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn move_focus_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::MoveFocusLeft, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('j')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::MoveFocusLeft(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn move_focus_or_tab_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::MoveFocusLeftOrPreviousTab, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('k')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::MoveFocusLeftOrPreviousTab(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn edit_scrollback_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::EditScrollback, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('m')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::EditScrollback(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn write_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::WriteCharacter, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('n')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::WriteCharacter(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn write_chars_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::WriteCharacter, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('o')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::WriteCharacter(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn toggle_tab_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::ToggleTab, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('p')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::ToggleTab(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn move_pane_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::MovePane, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('q')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::MovePane(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn move_pane_with_direction_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::MovePaneLeft, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('r')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::MovePaneLeft(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn clear_screen_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::ClearScreen, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('s')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::ClearScreen(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn scroll_up_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::ScrollUp, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('t')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::ScrollUp(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn scroll_down_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::ScrollDown, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('u')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::ScrollDown(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn scroll_to_top_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::ScrollToTop, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('v')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::ScrollToTop(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn scroll_to_bottom_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::ScrollToBottom, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('w')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::ScrollToBottom(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn page_scroll_up_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::PageScrollUp, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('x')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::PageScrollUp(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn page_scroll_down_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::PageScrollDown, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('y')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::PageScrollDown(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn toggle_focus_fullscreen_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::ToggleActiveTerminalFullscreen, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('z')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::ToggleActiveTerminalFullscreen(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn toggle_pane_frames_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread_naked_variant!( + received_screen_instructions, + ScreenInstruction::TogglePaneFrames, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('1')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::TogglePaneFrames = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn toggle_pane_embed_or_eject_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::TogglePaneEmbedOrFloating, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('2')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::TogglePaneEmbedOrFloating(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn undo_rename_pane_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::UndoRenamePane, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('3')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::UndoRenamePane(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn close_focus_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::CloseFocusedPane, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('4')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::CloseFocusedPane(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn toggle_active_tab_sync_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::ToggleActiveSyncTab, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('5')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::ToggleActiveSyncTab(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn close_focused_tab_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::CloseTab, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('6')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::CloseTab(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn undo_rename_tab_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::UndoRenameTab, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('7')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::UndoRenameTab(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn previous_swap_layout_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::PreviousSwapLayout, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('a')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::PreviousSwapLayout(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn next_swap_layout_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::NextSwapLayout, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('b')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::NextSwapLayout(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn go_to_tab_name_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::GoToTabName, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('c')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::GoToTabName(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn focus_or_create_tab_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::GoToTabName, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('d')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::GoToTabName(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn go_to_tab() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::GoToTab, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('e')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::GoToTab(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn start_or_reload_plugin() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::StartOrReloadPluginPane, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('f')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::StartOrReloadPluginPane(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn quit_zellij_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, server_receiver, mut teardown) = + create_plugin_thread_with_server_receiver(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_server_instruction = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_server_instruction, + ServerInstruction::ClientExit, + server_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('8')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_server_instruction + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ServerInstruction::ClientExit(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn detach_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, server_receiver, mut teardown) = + create_plugin_thread_with_server_receiver(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_server_instruction = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_server_instruction, + ServerInstruction::DetachSession, + server_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Char('l')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_server_instruction + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ServerInstruction::DetachSession(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn open_file_floating_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, pty_receiver, mut teardown) = + create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + PtyInstruction::SpawnTerminal, + pty_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('h')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let PtyInstruction::SpawnTerminal(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn open_file_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, pty_receiver, mut teardown) = + create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + PtyInstruction::SpawnTerminal, + pty_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('g')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let PtyInstruction::SpawnTerminal(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn open_file_with_line_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, pty_receiver, mut teardown) = + create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + PtyInstruction::SpawnTerminal, + pty_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('i')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let PtyInstruction::SpawnTerminal(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn open_file_with_line_floating_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, pty_receiver, mut teardown) = + create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + PtyInstruction::SpawnTerminal, + pty_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('j')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let PtyInstruction::SpawnTerminal(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn open_terminal_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, pty_receiver, mut teardown) = + create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + PtyInstruction::SpawnTerminal, + pty_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('k')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let PtyInstruction::SpawnTerminal(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn open_terminal_floating_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, pty_receiver, mut teardown) = + create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + PtyInstruction::SpawnTerminal, + pty_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('l')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let PtyInstruction::SpawnTerminal(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn open_command_pane_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, pty_receiver, mut teardown) = + create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + PtyInstruction::SpawnTerminal, + pty_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('m')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let PtyInstruction::SpawnTerminal(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn open_command_pane_floating_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, pty_receiver, mut teardown) = + create_plugin_thread_with_pty_receiver(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + PtyInstruction::SpawnTerminal, + pty_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('n')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let PtyInstruction::SpawnTerminal(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn switch_to_tab_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::GoToTab, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('o')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::GoToTab(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); +} + +#[test] +#[ignore] +pub fn hide_self_plugin_command() { + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + // destructor removes the directory + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let (plugin_thread_sender, screen_receiver, mut teardown) = + create_plugin_thread(Some(plugin_host_folder)); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + let run_plugin = RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)), + }; + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::SuppressPane, + screen_receiver, + 1 + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + plugin_title, + run_plugin, + tab_index, + client_id, + size, + )); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::Key(Key::Ctrl('p')), // this triggers the enent in the fixture plugin + )])); + std::thread::sleep(std::time::Duration::from_millis(100)); + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let new_tab_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::SuppressPane(..) = i { + Some(i.clone()) + } else { + None + } + }) + .clone(); + assert_snapshot!(format!("{:#?}", new_tab_event)); } diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__can_subscribe_to_hd_events.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__can_subscribe_to_hd_events.snap index 57e31f15..fc317baf 100644 --- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__can_subscribe_to_hd_events.snap +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__can_subscribe_to_hd_events.snap @@ -1,12 +1,12 @@ --- source: zellij-server/src/plugins/./unit/plugin_tests.rs -assertion_line: 387 +assertion_line: 400 expression: "format!(\"{:#?}\", plugin_bytes_event)" --- Some( ( 0, 1, - "Rows: 20, Cols: 121, Received events: [InputReceived, FileSystemRead([\"/host/test1\"])]\n\r", + "Rows: 20, Cols: 121, Received events: [FileSystemCreate([\"/host/test1\"])]\n\r", ), ) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__clear_screen_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__clear_screen_plugin_command.snap new file mode 100644 index 00000000..07eaf0e5 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__clear_screen_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1387 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + ClearScreen( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focus_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focus_plugin_command.snap new file mode 100644 index 00000000..78bf48eb --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focus_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2010 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + CloseFocusedPane( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focused_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focused_tab_plugin_command.snap new file mode 100644 index 00000000..3904a121 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__close_focused_tab_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2118 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + CloseTab( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__detach_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__detach_plugin_command.snap new file mode 100644 index 00000000..779f8cd7 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__detach_plugin_command.snap @@ -0,0 +1,12 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2685 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + DetachSession( + [ + 1, + ], + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_scrollback_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_scrollback_plugin_command.snap new file mode 100644 index 00000000..dca337fa --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__edit_scrollback_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1063 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + EditScrollback( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_next_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_next_pane_plugin_command.snap new file mode 100644 index 00000000..22832bb0 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_next_pane_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 847 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + FocusNextPane( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_or_create_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_or_create_tab_plugin_command.snap new file mode 100644 index 00000000..16ed8498 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_or_create_tab_plugin_command.snap @@ -0,0 +1,19 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2388 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + GoToTabName( + "my tab name", + ( + [], + [], + ), + None, + true, + Some( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_previous_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_previous_pane_plugin_command.snap new file mode 100644 index 00000000..4b2712e5 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_previous_pane_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 901 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + FocusPreviousPane( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_next_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_next_tab_plugin_command.snap new file mode 100644 index 00000000..cb87f071 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_next_tab_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 632 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + SwitchTabNext( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_previous_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_previous_tab_plugin_command.snap new file mode 100644 index 00000000..a6fd094e --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_previous_tab_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 687 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + SwitchTabPrev( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab.snap new file mode 100644 index 00000000..c3b12bd1 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab.snap @@ -0,0 +1,13 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2442 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + GoToTab( + 2, + Some( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab_name_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab_name_plugin_command.snap new file mode 100644 index 00000000..7934131f --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab_name_plugin_command.snap @@ -0,0 +1,19 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2334 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + GoToTabName( + "my tab name\n\r", + ( + [], + [], + ), + None, + false, + Some( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__hide_self_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__hide_self_plugin_command.snap new file mode 100644 index 00000000..67750c82 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__hide_self_plugin_command.snap @@ -0,0 +1,13 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 3306 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + SuppressPane( + Plugin( + 0, + ), + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_or_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_or_tab_plugin_command.snap new file mode 100644 index 00000000..a04c4a72 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_or_tab_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1009 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + MoveFocusLeftOrPreviousTab( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_plugin_command.snap new file mode 100644 index 00000000..10182cac --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_focus_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 955 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + MoveFocusLeft( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_plugin_command.snap new file mode 100644 index 00000000..97488981 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1279 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + MovePane( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_with_direction_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_with_direction_plugin_command.snap new file mode 100644 index 00000000..48be5c2a --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__move_pane_with_direction_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1333 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + MovePaneLeft( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tab_plugin_command.snap new file mode 100644 index 00000000..2a187935 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tab_plugin_command.snap @@ -0,0 +1,19 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 573 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + NewTab( + None, + None, + None, + [], + None, + ( + [], + [], + ), + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command-2.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command-2.snap new file mode 100644 index 00000000..e165dab1 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command-2.snap @@ -0,0 +1,60 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 521 +expression: "format!(\"{:#?}\", second_new_tab_event)" +--- +Some( + NewTab( + None, + None, + Some( + TiledPaneLayout { + children_split_direction: Vertical, + name: None, + children: [ + TiledPaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + children_are_stacked: false, + is_expanded_in_stack: false, + exclude_from_sync: None, + }, + TiledPaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + children_are_stacked: false, + is_expanded_in_stack: false, + exclude_from_sync: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + children_are_stacked: false, + is_expanded_in_stack: false, + exclude_from_sync: None, + }, + ), + [], + None, + ( + [], + [], + ), + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command.snap new file mode 100644 index 00000000..af83de32 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command.snap @@ -0,0 +1,60 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 520 +expression: "format!(\"{:#?}\", first_new_tab_event)" +--- +Some( + NewTab( + None, + None, + Some( + TiledPaneLayout { + children_split_direction: Horizontal, + name: None, + children: [ + TiledPaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + children_are_stacked: false, + is_expanded_in_stack: false, + exclude_from_sync: None, + }, + TiledPaneLayout { + children_split_direction: Horizontal, + name: None, + children: [], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + children_are_stacked: false, + is_expanded_in_stack: false, + exclude_from_sync: None, + }, + ], + split_size: None, + run: None, + borderless: false, + focus: None, + external_children_index: None, + children_are_stacked: false, + is_expanded_in_stack: false, + exclude_from_sync: None, + }, + ), + [], + None, + ( + [], + [], + ), + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__next_swap_layout_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__next_swap_layout_plugin_command.snap new file mode 100644 index 00000000..e83e1d93 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__next_swap_layout_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2280 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + NextSwapLayout( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_floating_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_floating_plugin_command.snap new file mode 100644 index 00000000..a222f4fa --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_floating_plugin_command.snap @@ -0,0 +1,30 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 3198 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + SpawnTerminal( + Some( + RunCommand( + RunCommand { + command: "/path/to/my/file.rs", + args: [ + "arg1", + "arg2", + ], + cwd: None, + hold_on_close: true, + hold_on_start: false, + }, + ), + ), + Some( + true, + ), + None, + ClientId( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_plugin_command.snap new file mode 100644 index 00000000..2807e495 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_command_pane_plugin_command.snap @@ -0,0 +1,30 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 3144 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + SpawnTerminal( + Some( + RunCommand( + RunCommand { + command: "/path/to/my/file.rs", + args: [ + "arg1", + "arg2", + ], + cwd: None, + hold_on_close: true, + hold_on_start: false, + }, + ), + ), + Some( + false, + ), + None, + ClientId( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_floating_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_floating_plugin_command.snap new file mode 100644 index 00000000..3cef859f --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_floating_plugin_command.snap @@ -0,0 +1,25 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2820 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + SpawnTerminal( + Some( + OpenFile( + "/path/to/my/file.rs", + None, + None, + ), + ), + Some( + true, + ), + Some( + "Editing: /path/to/my/file.rs", + ), + ClientId( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_plugin_command.snap new file mode 100644 index 00000000..7cf9c0c8 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_plugin_command.snap @@ -0,0 +1,25 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2874 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + SpawnTerminal( + Some( + OpenFile( + "/path/to/my/file.rs", + None, + None, + ), + ), + Some( + false, + ), + Some( + "Editing: /path/to/my/file.rs", + ), + ClientId( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_floating_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_floating_plugin_command.snap new file mode 100644 index 00000000..2c632abe --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_floating_plugin_command.snap @@ -0,0 +1,27 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2982 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + SpawnTerminal( + Some( + OpenFile( + "/path/to/my/file.rs", + Some( + 42, + ), + None, + ), + ), + Some( + true, + ), + Some( + "Editing: /path/to/my/file.rs", + ), + ClientId( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_plugin_command.snap new file mode 100644 index 00000000..54a04ceb --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_file_with_line_plugin_command.snap @@ -0,0 +1,27 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2927 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + SpawnTerminal( + Some( + OpenFile( + "/path/to/my/file.rs", + Some( + 42, + ), + None, + ), + ), + Some( + false, + ), + Some( + "Editing: /path/to/my/file.rs", + ), + ClientId( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_flie_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_flie_plugin_command.snap new file mode 100644 index 00000000..4de81086 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_flie_plugin_command.snap @@ -0,0 +1,25 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2820 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + SpawnTerminal( + Some( + OpenFile( + "/path/to/my/file.rs", + None, + None, + ), + ), + Some( + false, + ), + Some( + "Editing: /path/to/my/file.rs", + ), + ClientId( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_floating_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_floating_plugin_command.snap new file mode 100644 index 00000000..c43958a7 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_floating_plugin_command.snap @@ -0,0 +1,29 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 3090 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + SpawnTerminal( + Some( + RunCommand( + RunCommand { + command: "", + args: [], + cwd: Some( + "/path/to/my/file.rs", + ), + hold_on_close: false, + hold_on_start: false, + }, + ), + ), + Some( + true, + ), + None, + ClientId( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_plugin_command.snap new file mode 100644 index 00000000..88fdd2ed --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__open_terminal_plugin_command.snap @@ -0,0 +1,29 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 3036 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + SpawnTerminal( + Some( + RunCommand( + RunCommand { + command: "", + args: [], + cwd: Some( + "/path/to/my/file.rs", + ), + hold_on_close: false, + hold_on_start: false, + }, + ), + ), + Some( + false, + ), + None, + ClientId( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_down_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_down_plugin_command.snap new file mode 100644 index 00000000..dc06b3d5 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_down_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1711 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + PageScrollDown( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_up_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_up_plugin_command.snap new file mode 100644 index 00000000..5f0b7ab3 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__page_scroll_up_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1657 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + PageScrollUp( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__previous_swap_layout_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__previous_swap_layout_plugin_command.snap new file mode 100644 index 00000000..34eff5ad --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__previous_swap_layout_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2226 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + PreviousSwapLayout( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__quit_zellij_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__quit_zellij_plugin_command.snap new file mode 100644 index 00000000..aa600320 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__quit_zellij_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2631 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + ClientExit( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_plugin_command.snap new file mode 100644 index 00000000..f260c361 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_plugin_command.snap @@ -0,0 +1,15 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 742 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + Resize( + 1, + ResizeStrategy { + resize: Increase, + direction: None, + invert_on_boundaries: true, + }, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_with_direction_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_with_direction_plugin_command.snap new file mode 100644 index 00000000..4e5c8ea4 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__resize_focused_pane_with_direction_plugin_command.snap @@ -0,0 +1,17 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 793 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + Resize( + 1, + ResizeStrategy { + resize: Increase, + direction: Some( + Left, + ), + invert_on_boundaries: true, + }, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_down_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_down_plugin_command.snap new file mode 100644 index 00000000..338f315e --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_down_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1495 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + ScrollDown( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_bottom_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_bottom_plugin_command.snap new file mode 100644 index 00000000..08b41ce3 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_bottom_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1603 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + ScrollToBottom( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_top_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_top_plugin_command.snap new file mode 100644 index 00000000..eb852c7b --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_to_top_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1549 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + ScrollToTop( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_up_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_up_plugin_command.snap new file mode 100644 index 00000000..9700c556 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__scroll_up_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1441 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + ScrollUp( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap new file mode 100644 index 00000000..173b0ce4 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap @@ -0,0 +1,13 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2496 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + StartOrReloadPluginPane( + File( + "/path/to/my/plugin.wasm", + ), + None, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_mode_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_mode_plugin_command.snap new file mode 100644 index 00000000..8d699ae6 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_mode_plugin_command.snap @@ -0,0 +1,79 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 455 +expression: "format!(\"{:#?}\", switch_to_mode_event)" +--- +Some( + ChangeMode( + ModeInfo { + mode: Tab, + keybinds: [], + style: Style { + colors: Palette { + source: Default, + theme_hue: Dark, + fg: EightBit( + 0, + ), + bg: EightBit( + 0, + ), + black: EightBit( + 0, + ), + red: EightBit( + 0, + ), + green: EightBit( + 0, + ), + yellow: EightBit( + 0, + ), + blue: EightBit( + 0, + ), + magenta: EightBit( + 0, + ), + cyan: EightBit( + 0, + ), + white: EightBit( + 0, + ), + orange: EightBit( + 0, + ), + gray: EightBit( + 0, + ), + purple: EightBit( + 0, + ), + gold: EightBit( + 0, + ), + silver: EightBit( + 0, + ), + pink: EightBit( + 0, + ), + brown: EightBit( + 0, + ), + }, + rounded_corners: false, + hide_session_name: false, + }, + capabilities: PluginCapabilities { + arrow_fonts: true, + }, + session_name: Some( + "zellij-test", + ), + }, + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_tab_plugin_command.snap new file mode 100644 index 00000000..b785c27e --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_tab_plugin_command.snap @@ -0,0 +1,13 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 3252 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + GoToTab( + 1, + Some( + 1, + ), + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_active_tab_sync_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_active_tab_sync_plugin_command.snap new file mode 100644 index 00000000..4ff349b3 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_active_tab_sync_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2064 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + ToggleActiveSyncTab( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_focus_fullscreen_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_focus_fullscreen_plugin_command.snap new file mode 100644 index 00000000..c906b8df --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_focus_fullscreen_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1765 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + ToggleActiveTerminalFullscreen( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_embed_or_eject_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_embed_or_eject_plugin_command.snap new file mode 100644 index 00000000..1f249d1a --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_embed_or_eject_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1902 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + TogglePaneEmbedOrFloating( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_frames_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_frames_plugin_command.snap new file mode 100644 index 00000000..535eff30 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_pane_frames_plugin_command.snap @@ -0,0 +1,8 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1848 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + TogglePaneFrames, +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_tab_plugin_command.snap new file mode 100644 index 00000000..45f70576 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__toggle_tab_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1225 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + ToggleTab( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_pane_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_pane_plugin_command.snap new file mode 100644 index 00000000..8f8b8c4f --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_pane_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1956 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + UndoRenamePane( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_tab_plugin_command.snap new file mode 100644 index 00000000..c9b3e09f --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__undo_rename_tab_plugin_command.snap @@ -0,0 +1,10 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 2172 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + UndoRenameTab( + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_plugin_command.snap new file mode 100644 index 00000000..504134d0 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_chars_plugin_command.snap @@ -0,0 +1,17 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1171 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + WriteCharacter( + [ + 102, + 111, + 111, + 10, + 13, + ], + 1, + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_plugin_command.snap new file mode 100644 index 00000000..7f8f3622 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__write_plugin_command.snap @@ -0,0 +1,15 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 1117 +expression: "format!(\"{:#?}\", new_tab_event)" +--- +Some( + WriteCharacter( + [ + 102, + 111, + 111, + ], + 1, + ), +) diff --git a/zellij-server/src/plugins/wasm_bridge.rs b/zellij-server/src/plugins/wasm_bridge.rs index 1ede55e2..319b26cd 100644 --- a/zellij-server/src/plugins/wasm_bridge.rs +++ b/zellij-server/src/plugins/wasm_bridge.rs @@ -21,12 +21,14 @@ use crate::{ }; use zellij_utils::{ consts::VERSION, - data::{Event, EventType}, + data::{Event, EventType, PluginCapabilities}, errors::prelude::*, input::{ - layout::{RunPlugin, RunPluginLocation}, + command::TerminalAction, + layout::{Layout, RunPlugin, RunPluginLocation}, plugins::PluginsConfig, }, + ipc::ClientAttributes, pane_size::Size, }; @@ -50,6 +52,10 @@ pub struct WasmBridge { path_to_default_shell: PathBuf, watcher: Option, zellij_cwd: PathBuf, + capabilities: PluginCapabilities, + client_attributes: ClientAttributes, + default_shell: Option, + default_layout: Box, } impl WasmBridge { @@ -60,6 +66,10 @@ impl WasmBridge { plugin_dir: PathBuf, path_to_default_shell: PathBuf, zellij_cwd: PathBuf, + capabilities: PluginCapabilities, + client_attributes: ClientAttributes, + default_shell: Option, + default_layout: Box, ) -> Self { let plugin_map = Arc::new(Mutex::new(PluginMap::default())); let connected_clients: Arc>> = Arc::new(Mutex::new(vec![])); @@ -89,6 +99,10 @@ impl WasmBridge { loading_plugins: HashMap::new(), pending_plugin_reloads: HashSet::new(), zellij_cwd, + capabilities, + client_attributes, + default_shell, + default_layout, } } pub fn load_plugin( @@ -137,6 +151,10 @@ impl WasmBridge { let connected_clients = self.connected_clients.clone(); let path_to_default_shell = self.path_to_default_shell.clone(); let zellij_cwd = self.zellij_cwd.clone(); + let capabilities = self.capabilities.clone(); + let client_attributes = self.client_attributes.clone(); + let default_shell = self.default_shell.clone(); + let default_layout = self.default_layout.clone(); async move { let _ = senders.send_to_background_jobs(BackgroundJob::AnimatePluginLoading(plugin_id)); @@ -156,6 +174,10 @@ impl WasmBridge { &mut loading_indication, path_to_default_shell, zellij_cwd.clone(), + capabilities, + client_attributes, + default_shell, + default_layout, ) { Ok(_) => handle_plugin_successful_loading(&senders, plugin_id), Err(e) => handle_plugin_loading_failure( @@ -217,6 +239,10 @@ impl WasmBridge { let connected_clients = self.connected_clients.clone(); let path_to_default_shell = self.path_to_default_shell.clone(); let zellij_cwd = self.zellij_cwd.clone(); + let capabilities = self.capabilities.clone(); + let client_attributes = self.client_attributes.clone(); + let default_shell = self.default_shell.clone(); + let default_layout = self.default_layout.clone(); async move { match PluginLoader::reload_plugin( first_plugin_id, @@ -229,6 +255,10 @@ impl WasmBridge { &mut loading_indication, path_to_default_shell.clone(), zellij_cwd.clone(), + capabilities.clone(), + client_attributes.clone(), + default_shell.clone(), + default_layout.clone(), ) { Ok(_) => { handle_plugin_successful_loading(&senders, first_plugin_id); @@ -249,6 +279,10 @@ impl WasmBridge { &mut loading_indication, path_to_default_shell.clone(), zellij_cwd.clone(), + capabilities.clone(), + client_attributes.clone(), + default_shell.clone(), + default_layout.clone(), ) { Ok(_) => handle_plugin_successful_loading(&senders, *plugin_id), Err(e) => handle_plugin_loading_failure( @@ -291,6 +325,10 @@ impl WasmBridge { &mut loading_indication, self.path_to_default_shell.clone(), self.zellij_cwd.clone(), + self.capabilities.clone(), + self.client_attributes.clone(), + self.default_shell.clone(), + self.default_layout.clone(), ) { Ok(_) => { let _ = self diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs index d64d867b..f0c7ba1b 100644 --- a/zellij-server/src/plugins/zellij_exports.rs +++ b/zellij-server/src/plugins/zellij_exports.rs @@ -1,6 +1,7 @@ use super::PluginInstruction; use crate::plugins::plugin_map::{PluginEnv, Subscriptions}; use crate::plugins::wasm_bridge::handle_plugin_crash; +use crate::route::route_action; use log::{debug, warn}; use serde::{de::DeserializeOwned, Serialize}; use std::{ @@ -14,23 +15,39 @@ use std::{ use wasmer::{imports, Function, ImportObject, Store, WasmerEnv}; use wasmer_wasi::WasiEnv; -use crate::{ - panes::PaneId, - pty::{ClientOrTabIndex, PtyInstruction}, - screen::ScreenInstruction, -}; +use url::Url; + +use crate::{panes::PaneId, screen::ScreenInstruction}; use zellij_utils::{ consts::VERSION, - data::{Event, EventType, PluginIds}, + data::{Direction, Event, EventType, InputMode, PluginIds, Resize}, errors::prelude::*, input::{ - command::{RunCommand, TerminalAction}, + actions::Action, + command::{RunCommand, RunCommandAction, TerminalAction}, + layout::{Layout, RunPlugin, RunPluginLocation}, plugins::PluginType, }, serde, }; +macro_rules! apply_action { + ($action:ident, $error_message:ident, $env: ident) => { + if let Err(e) = route_action( + $action, + $env.plugin_env.client_id, + $env.plugin_env.senders.clone(), + $env.plugin_env.capabilities.clone(), + $env.plugin_env.client_attributes.clone(), + $env.plugin_env.default_shell.clone(), + $env.plugin_env.default_layout.clone(), + ) { + log::error!("{}: {:?}", $error_message(), e); + } + }; +} + pub fn zellij_exports( store: &Store, plugin_env: &PluginEnv, @@ -59,6 +76,8 @@ pub fn zellij_exports( host_open_file_with_line_floating, host_open_terminal, host_open_terminal_floating, + host_open_command_pane, + host_open_command_pane_floating, host_switch_tab_to, host_set_timeout, host_exec_cmd, @@ -66,6 +85,46 @@ pub fn zellij_exports( host_post_message_to, host_post_message_to_plugin, host_hide_self, + host_switch_to_mode, + host_new_tabs_with_layout, + host_new_tab, + host_go_to_next_tab, + host_go_to_previous_tab, + host_resize, + host_resize_with_direction, + host_focus_next_pane, + host_focus_previous_pane, + host_move_focus, + host_move_focus_or_tab, + host_detach, + host_edit_scrollback, + host_write, + host_write_chars, + host_toggle_tab, + host_move_pane, + host_move_pane_with_direction, + host_clear_screen, + host_scroll_up, + host_scroll_down, + host_scroll_to_top, + host_scroll_to_bottom, + host_page_scroll_up, + host_page_scroll_down, + host_toggle_focus_fullscreen, + host_toggle_pane_frames, + host_toggle_pane_embed_or_eject, + host_undo_rename_pane, + host_close_focus, + host_toggle_active_tab_sync, + host_close_focused_tab, + host_undo_rename_tab, + host_quit_zellij, + host_previous_swap_layout, + host_next_swap_layout, + host_go_to_tab_name, + host_focus_or_create_tab, + host_go_to_tab, + host_start_or_reload_plugin, } } @@ -165,14 +224,16 @@ fn host_get_zellij_version(env: &ForeignFunctionEnv) { fn host_open_file(env: &ForeignFunctionEnv) { wasi_read_object::(&env.plugin_env.wasi_env) .and_then(|path| { - env.plugin_env - .senders - .send_to_pty(PtyInstruction::SpawnTerminal( - Some(TerminalAction::OpenFile(path, None, None)), - Some(false), - None, - ClientOrTabIndex::ClientId(env.plugin_env.client_id), - )) + let error_msg = || { + format!( + "failed to open floating file in plugin {}", + env.plugin_env.name() + ) + }; + let floating = false; + let action = Action::EditFile(path, None, None, None, floating); // TODO: add cwd + apply_action!(action, error_msg, env); + Ok(()) }) .with_context(|| { format!( @@ -186,14 +247,11 @@ fn host_open_file(env: &ForeignFunctionEnv) { fn host_open_file_floating(env: &ForeignFunctionEnv) { wasi_read_object::(&env.plugin_env.wasi_env) .and_then(|path| { - env.plugin_env - .senders - .send_to_pty(PtyInstruction::SpawnTerminal( - Some(TerminalAction::OpenFile(path, None, None)), - Some(true), - None, - ClientOrTabIndex::ClientId(env.plugin_env.client_id), - )) + let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name()); + let floating = true; + let action = Action::EditFile(path, None, None, None, floating); // TODO: add cwd + apply_action!(action, error_msg, env); + Ok(()) }) .with_context(|| { format!( @@ -207,14 +265,11 @@ fn host_open_file_floating(env: &ForeignFunctionEnv) { fn host_open_file_with_line(env: &ForeignFunctionEnv) { wasi_read_object::<(PathBuf, usize)>(&env.plugin_env.wasi_env) .and_then(|(path, line)| { - env.plugin_env - .senders - .send_to_pty(PtyInstruction::SpawnTerminal( - Some(TerminalAction::OpenFile(path, Some(line), None)), // TODO: add cwd - Some(false), - None, - ClientOrTabIndex::ClientId(env.plugin_env.client_id), - )) + let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name()); + let floating = false; + let action = Action::EditFile(path, Some(line), None, None, floating); // TODO: add cwd + apply_action!(action, error_msg, env); + Ok(()) }) .with_context(|| { format!( @@ -228,14 +283,11 @@ fn host_open_file_with_line(env: &ForeignFunctionEnv) { fn host_open_file_with_line_floating(env: &ForeignFunctionEnv) { wasi_read_object::<(PathBuf, usize)>(&env.plugin_env.wasi_env) .and_then(|(path, line)| { - env.plugin_env - .senders - .send_to_pty(PtyInstruction::SpawnTerminal( - Some(TerminalAction::OpenFile(path, Some(line), None)), // TODO: add cwd - Some(true), - None, - ClientOrTabIndex::ClientId(env.plugin_env.client_id), - )) + let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name()); + let floating = true; + let action = Action::EditFile(path, Some(line), None, None, floating); // TODO: add cwd + apply_action!(action, error_msg, env); + Ok(()) }) .with_context(|| { format!( @@ -249,21 +301,24 @@ fn host_open_file_with_line_floating(env: &ForeignFunctionEnv) { fn host_open_terminal(env: &ForeignFunctionEnv) { wasi_read_object::(&env.plugin_env.wasi_env) .and_then(|path| { - env.plugin_env - .senders - .send_to_pty(PtyInstruction::SpawnTerminal( - Some(TerminalAction::RunCommand( - RunCommand::new(env.plugin_env.path_to_default_shell.clone()) - .with_cwd(path), - )), - Some(false), - None, - ClientOrTabIndex::ClientId(env.plugin_env.client_id), - )) + let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name()); + let mut default_shell = env + .plugin_env + .default_shell + .clone() + .unwrap_or_else(|| TerminalAction::RunCommand(RunCommand::default())); + default_shell.change_cwd(path); + let run_command_action: Option = match default_shell { + TerminalAction::RunCommand(run_command) => Some(run_command.into()), + _ => None, + }; + let action = Action::NewTiledPane(None, run_command_action, None); + apply_action!(action, error_msg, env); + Ok(()) }) .with_context(|| { format!( - "failed to open terminal on host from plugin {}", + "failed to open file on host from plugin {}", env.plugin_env.name() ) }) @@ -273,27 +328,80 @@ fn host_open_terminal(env: &ForeignFunctionEnv) { fn host_open_terminal_floating(env: &ForeignFunctionEnv) { wasi_read_object::(&env.plugin_env.wasi_env) .and_then(|path| { - env.plugin_env - .senders - .send_to_pty(PtyInstruction::SpawnTerminal( - Some(TerminalAction::RunCommand( - RunCommand::new(env.plugin_env.path_to_default_shell.clone()) - .with_cwd(path), - )), - Some(true), - None, - ClientOrTabIndex::ClientId(env.plugin_env.client_id), - )) + let error_msg = || format!("failed to open file in plugin {}", env.plugin_env.name()); + let mut default_shell = env + .plugin_env + .default_shell + .clone() + .unwrap_or_else(|| TerminalAction::RunCommand(RunCommand::default())); + default_shell.change_cwd(path); + let run_command_action: Option = match default_shell { + TerminalAction::RunCommand(run_command) => Some(run_command.into()), + _ => None, + }; + let action = Action::NewFloatingPane(run_command_action, None); + apply_action!(action, error_msg, env); + Ok(()) }) .with_context(|| { format!( - "failed to open terminal on host from plugin {}", + "failed to open file on host from plugin {}", env.plugin_env.name() ) }) .non_fatal(); } +fn host_open_command_pane(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to run command in plugin {}", env.plugin_env.name()); + wasi_read_object::<(PathBuf, Vec)>(&env.plugin_env.wasi_env) + .and_then(|(command, args)| { + let cwd = None; + let direction = None; + let hold_on_close = true; + let hold_on_start = false; + let name = None; + let run_command_action = RunCommandAction { + command, + args, + cwd, + direction, + hold_on_close, + hold_on_start, + }; + let action = Action::NewTiledPane(direction, Some(run_command_action), name); + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(error_msg) + .non_fatal(); +} + +fn host_open_command_pane_floating(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to run command in plugin {}", env.plugin_env.name()); + wasi_read_object::<(PathBuf, Vec)>(&env.plugin_env.wasi_env) + .and_then(|(command, args)| { + let cwd = None; + let direction = None; + let hold_on_close = true; + let hold_on_start = false; + let name = None; + let run_command_action = RunCommandAction { + command, + args, + cwd, + direction, + hold_on_close, + hold_on_start, + }; + let action = Action::NewFloatingPane(Some(run_command_action), name); + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(error_msg) + .non_fatal(); +} + fn host_switch_tab_to(env: &ForeignFunctionEnv, tab_idx: u32) { env.plugin_env .senders @@ -424,6 +532,422 @@ fn host_hide_self(env: &ForeignFunctionEnv) { .fatal(); } +fn host_switch_to_mode(env: &ForeignFunctionEnv) { + wasi_read_object::(&env.plugin_env.wasi_env) + .and_then(|input_mode| { + let action = Action::SwitchToMode(input_mode); + let error_msg = || { + format!( + "failed to switch to mode in plugin {}", + env.plugin_env.name() + ) + }; + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(|| format!("failed to subscribe for plugin {}", env.plugin_env.name())) + .fatal(); +} + +fn host_new_tabs_with_layout(env: &ForeignFunctionEnv) { + wasi_read_string(&env.plugin_env.wasi_env) + .and_then(|raw_layout| { + Layout::from_str( + &raw_layout, + format!("Layout from plugin: {}", env.plugin_env.name()), + None, + None, + ) + .map_err(|e| anyhow!("Failed to parse layout: {:?}", e)) + }) // TODO: cwd? + .and_then(|layout| { + let mut tabs_to_open = vec![]; + let tabs = layout.tabs(); + if tabs.is_empty() { + let action = Action::NewTab( + layout.template.as_ref().map(|t| t.0.clone()), + layout.template.map(|t| t.1).unwrap_or_default(), + None, + None, + None, + ); + tabs_to_open.push(action); + } else { + for (tab_name, tiled_pane_layout, floating_pane_layout) in layout.tabs() { + let action = Action::NewTab( + Some(tiled_pane_layout), + floating_pane_layout, + None, + None, + tab_name, + ); + tabs_to_open.push(action); + } + } + for action in tabs_to_open { + let error_msg = || format!("Failed to create layout tab"); + apply_action!(action, error_msg, env); + } + Ok(()) + }) + .non_fatal(); +} + +fn host_new_tab(env: &ForeignFunctionEnv) { + let action = Action::NewTab(None, vec![], None, None, None); + let error_msg = || format!("Failed to open new tab"); + apply_action!(action, error_msg, env); +} + +fn host_go_to_next_tab(env: &ForeignFunctionEnv) { + let action = Action::GoToNextTab; + let error_msg = || format!("Failed to go to next tab"); + apply_action!(action, error_msg, env); +} + +fn host_go_to_previous_tab(env: &ForeignFunctionEnv) { + let action = Action::GoToPreviousTab; + let error_msg = || format!("Failed to go to previous tab"); + apply_action!(action, error_msg, env); +} + +fn host_resize(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to resize in plugin {}", env.plugin_env.name()); + wasi_read_object::(&env.plugin_env.wasi_env) + .and_then(|resize| { + let action = Action::Resize(resize, None); + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(error_msg) + .fatal(); +} + +fn host_resize_with_direction(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to resize in plugin {}", env.plugin_env.name()); + wasi_read_object::<(Resize, Direction)>(&env.plugin_env.wasi_env) + .and_then(|(resize, direction)| { + let action = Action::Resize(resize, Some(direction)); + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(error_msg) + .fatal(); +} + +fn host_focus_next_pane(env: &ForeignFunctionEnv) { + let action = Action::FocusNextPane; + let error_msg = || format!("Failed to focus next pane"); + apply_action!(action, error_msg, env); +} + +fn host_focus_previous_pane(env: &ForeignFunctionEnv) { + let action = Action::FocusPreviousPane; + let error_msg = || format!("Failed to focus previous pane"); + apply_action!(action, error_msg, env); +} + +fn host_move_focus(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to move focus in plugin {}", env.plugin_env.name()); + wasi_read_object::(&env.plugin_env.wasi_env) + .and_then(|direction| { + let action = Action::MoveFocus(direction); + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(error_msg) + .fatal(); +} + +fn host_move_focus_or_tab(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to move focus in plugin {}", env.plugin_env.name()); + wasi_read_object::(&env.plugin_env.wasi_env) + .and_then(|direction| { + let action = Action::MoveFocusOrTab(direction); + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(error_msg) + .fatal(); +} + +fn host_detach(env: &ForeignFunctionEnv) { + let action = Action::Detach; + let error_msg = || format!("Failed to detach"); + apply_action!(action, error_msg, env); +} + +fn host_edit_scrollback(env: &ForeignFunctionEnv) { + let action = Action::EditScrollback; + let error_msg = || format!("Failed to edit scrollback"); + apply_action!(action, error_msg, env); +} + +fn host_write(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to write in plugin {}", env.plugin_env.name()); + wasi_read_object::>(&env.plugin_env.wasi_env) + .and_then(|bytes| { + let action = Action::Write(bytes); + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(error_msg) + .fatal(); +} + +fn host_write_chars(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to write in plugin {}", env.plugin_env.name()); + wasi_read_string(&env.plugin_env.wasi_env) + .and_then(|chars_to_write| { + let action = Action::WriteChars(chars_to_write); + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(error_msg) + .fatal(); +} + +fn host_toggle_tab(env: &ForeignFunctionEnv) { + let action = Action::ToggleTab; + let error_msg = || format!("Failed to toggle tab"); + apply_action!(action, error_msg, env); +} + +fn host_move_pane(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to move pane in plugin {}", env.plugin_env.name()); + let action = Action::MovePane(None); + apply_action!(action, error_msg, env); +} + +fn host_move_pane_with_direction(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to move pane in plugin {}", env.plugin_env.name()); + wasi_read_object::(&env.plugin_env.wasi_env) + .and_then(|direction| { + let action = Action::MovePane(Some(direction)); + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(error_msg) + .fatal(); +} + +fn host_clear_screen(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to clear screen in plugin {}", env.plugin_env.name()); + let action = Action::ClearScreen; + apply_action!(action, error_msg, env); +} +fn host_scroll_up(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to scroll up in plugin {}", env.plugin_env.name()); + let action = Action::ScrollUp; + apply_action!(action, error_msg, env); +} + +fn host_scroll_down(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to scroll down in plugin {}", env.plugin_env.name()); + let action = Action::ScrollDown; + apply_action!(action, error_msg, env); +} + +fn host_scroll_to_top(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to scroll in plugin {}", env.plugin_env.name()); + let action = Action::ScrollToTop; + apply_action!(action, error_msg, env); +} + +fn host_scroll_to_bottom(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to scroll in plugin {}", env.plugin_env.name()); + let action = Action::ScrollToBottom; + apply_action!(action, error_msg, env); +} + +fn host_page_scroll_up(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to scroll in plugin {}", env.plugin_env.name()); + let action = Action::PageScrollUp; + apply_action!(action, error_msg, env); +} + +fn host_page_scroll_down(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to scroll in plugin {}", env.plugin_env.name()); + let action = Action::PageScrollDown; + apply_action!(action, error_msg, env); +} + +fn host_toggle_focus_fullscreen(env: &ForeignFunctionEnv) { + let error_msg = || { + format!( + "failed to toggle full screen in plugin {}", + env.plugin_env.name() + ) + }; + let action = Action::ToggleFocusFullscreen; + apply_action!(action, error_msg, env); +} + +fn host_toggle_pane_frames(env: &ForeignFunctionEnv) { + let error_msg = || { + format!( + "failed to toggle full screen in plugin {}", + env.plugin_env.name() + ) + }; + let action = Action::TogglePaneFrames; + apply_action!(action, error_msg, env); +} + +fn host_toggle_pane_embed_or_eject(env: &ForeignFunctionEnv) { + let error_msg = || { + format!( + "failed to toggle pane embed or eject in plugin {}", + env.plugin_env.name() + ) + }; + let action = Action::TogglePaneEmbedOrFloating; + apply_action!(action, error_msg, env); +} + +fn host_undo_rename_pane(env: &ForeignFunctionEnv) { + let error_msg = || { + format!( + "failed to undo rename pane in plugin {}", + env.plugin_env.name() + ) + }; + let action = Action::UndoRenamePane; + apply_action!(action, error_msg, env); +} + +fn host_close_focus(env: &ForeignFunctionEnv) { + let error_msg = || { + format!( + "failed to close focused pane in plugin {}", + env.plugin_env.name() + ) + }; + let action = Action::CloseFocus; + apply_action!(action, error_msg, env); +} + +fn host_toggle_active_tab_sync(env: &ForeignFunctionEnv) { + let error_msg = || { + format!( + "failed to toggle active tab sync in plugin {}", + env.plugin_env.name() + ) + }; + let action = Action::ToggleActiveSyncTab; + apply_action!(action, error_msg, env); +} + +fn host_close_focused_tab(env: &ForeignFunctionEnv) { + let error_msg = || { + format!( + "failed to close active tab in plugin {}", + env.plugin_env.name() + ) + }; + let action = Action::CloseTab; + apply_action!(action, error_msg, env); +} + +fn host_undo_rename_tab(env: &ForeignFunctionEnv) { + let error_msg = || { + format!( + "failed to undo rename tab in plugin {}", + env.plugin_env.name() + ) + }; + let action = Action::UndoRenameTab; + apply_action!(action, error_msg, env); +} + +fn host_quit_zellij(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to quit zellij in plugin {}", env.plugin_env.name()); + let action = Action::Quit; + apply_action!(action, error_msg, env); +} + +fn host_previous_swap_layout(env: &ForeignFunctionEnv) { + let error_msg = || { + format!( + "failed to switch swap layout in plugin {}", + env.plugin_env.name() + ) + }; + let action = Action::PreviousSwapLayout; + apply_action!(action, error_msg, env); +} + +fn host_next_swap_layout(env: &ForeignFunctionEnv) { + let error_msg = || { + format!( + "failed to switch swap layout in plugin {}", + env.plugin_env.name() + ) + }; + let action = Action::NextSwapLayout; + apply_action!(action, error_msg, env); +} + +fn host_go_to_tab_name(env: &ForeignFunctionEnv) { + let error_msg = || format!("failed to change tab in plugin {}", env.plugin_env.name()); + wasi_read_string(&env.plugin_env.wasi_env) + .and_then(|tab_name| { + let create = false; + let action = Action::GoToTabName(tab_name, create); + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(error_msg) + .fatal(); +} + +fn host_focus_or_create_tab(env: &ForeignFunctionEnv) { + let error_msg = || { + format!( + "failed to change or create tab in plugin {}", + env.plugin_env.name() + ) + }; + wasi_read_string(&env.plugin_env.wasi_env) + .and_then(|tab_name| { + let create = true; + let action = Action::GoToTabName(tab_name, create); + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(error_msg) + .fatal(); +} + +fn host_go_to_tab(env: &ForeignFunctionEnv, tab_index: i32) { + let error_msg = || { + format!( + "failed to change tab focus in plugin {}", + env.plugin_env.name() + ) + }; + let action = Action::GoToTab(tab_index as u32); + apply_action!(action, error_msg, env); +} + +fn host_start_or_reload_plugin(env: &ForeignFunctionEnv) { + let error_msg = || { + format!( + "failed to start or reload plugin in plugin {}", + env.plugin_env.name() + ) + }; + wasi_read_string(&env.plugin_env.wasi_env) + .and_then(|url| Url::parse(&url).map_err(|e| anyhow!("Failed to parse url: {}", e))) + .and_then(|url| { + let action = Action::StartOrReloadPlugin(url); + apply_action!(action, error_msg, env); + Ok(()) + }) + .with_context(error_msg) + .fatal(); +} + // Custom panic handler for plugins. // // This is called when a panic occurs in a plugin. Since most panics will likely originate in the diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index c43e99f1..2d78ae74 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -1,6 +1,7 @@ use std::collections::VecDeque; use std::sync::{Arc, RwLock}; +use crate::thread_bus::ThreadSenders; use crate::{ os_input_output::ServerOsApi, plugins::PluginInstruction, @@ -10,25 +11,29 @@ use crate::{ }; use zellij_utils::{ channels::SenderWithContext, - data::{Direction, Event, ResizeStrategy}, + data::{Direction, Event, PluginCapabilities, ResizeStrategy}, errors::prelude::*, input::{ actions::{Action, SearchDirection, SearchOption}, command::TerminalAction, get_mode_info, - layout::RunPluginLocation, + layout::{Layout, RunPluginLocation}, + }, + ipc::{ + ClientAttributes, ClientToServerMsg, ExitReason, IpcReceiverWithContext, ServerToClientMsg, }, - ipc::{ClientToServerMsg, ExitReason, IpcReceiverWithContext, ServerToClientMsg}, }; use crate::ClientId; pub(crate) fn route_action( action: Action, - session: &SessionMetaData, - _os_input: &dyn ServerOsApi, - to_server: &SenderWithContext, client_id: ClientId, + senders: ThreadSenders, + capabilities: PluginCapabilities, + client_attributes: ClientAttributes, + default_shell: Option, + default_layout: Box, ) -> Result { let mut should_break = false; let err_context = || format!("failed to route action for client {client_id}"); @@ -39,8 +44,7 @@ pub(crate) fn route_action( match action { Action::MouseHoldLeft(..) | Action::MouseHoldRight(..) => {}, _ => { - session - .senders + senders .send_to_plugin(PluginInstruction::Update(vec![( None, Some(client_id), @@ -52,81 +56,69 @@ pub(crate) fn route_action( match action { Action::ToggleTab => { - session - .senders + senders .send_to_screen(ScreenInstruction::ToggleTab(client_id)) .with_context(err_context)?; }, Action::Write(val) => { - session - .senders + senders .send_to_screen(ScreenInstruction::ClearScroll(client_id)) .with_context(err_context)?; - session - .senders + senders .send_to_screen(ScreenInstruction::WriteCharacter(val, client_id)) .with_context(err_context)?; }, Action::WriteChars(val) => { - session - .senders + senders .send_to_screen(ScreenInstruction::ClearScroll(client_id)) .with_context(err_context)?; let val = val.into_bytes(); - session - .senders + senders .send_to_screen(ScreenInstruction::WriteCharacter(val, client_id)) .with_context(err_context)?; }, Action::SwitchToMode(mode) => { - let attrs = &session.client_attributes; + let attrs = &client_attributes; // TODO: use the palette from the client and remove it from the server os api // this is left here as a stop gap measure until we shift some code around // to allow for this // TODO: Need access to `ClientAttributes` here - session - .senders + senders .send_to_plugin(PluginInstruction::Update(vec![( None, Some(client_id), - Event::ModeUpdate(get_mode_info(mode, attrs, session.capabilities)), + Event::ModeUpdate(get_mode_info(mode, attrs, capabilities)), )])) .with_context(err_context)?; - session - .senders + senders .send_to_screen(ScreenInstruction::ChangeMode( - get_mode_info(mode, attrs, session.capabilities), + get_mode_info(mode, attrs, capabilities), client_id, )) .with_context(err_context)?; - session - .senders + senders .send_to_screen(ScreenInstruction::Render) .with_context(err_context)?; }, Action::Resize(resize, direction) => { let screen_instr = ScreenInstruction::Resize(client_id, ResizeStrategy::new(resize, direction)); - session - .senders + senders .send_to_screen(screen_instr) .with_context(err_context)?; }, Action::SwitchFocus => { - session - .senders + senders .send_to_screen(ScreenInstruction::SwitchFocus(client_id)) .with_context(err_context)?; }, Action::FocusNextPane => { - session - .senders + senders .send_to_screen(ScreenInstruction::FocusNextPane(client_id)) .with_context(err_context)?; }, Action::FocusPreviousPane => { - session - .senders + senders .send_to_screen(ScreenInstruction::FocusPreviousPane(client_id)) .with_context(err_context)?; }, @@ -137,8 +129,7 @@ pub(crate) fn route_action( Direction::Up => ScreenInstruction::MoveFocusUp(client_id), Direction::Down => ScreenInstruction::MoveFocusDown(client_id), }; - session - .senders + senders .send_to_screen(screen_instr) .with_context(err_context)?; }, @@ -149,8 +140,7 @@ pub(crate) fn route_action( Direction::Up => ScreenInstruction::SwitchTabNext(client_id), Direction::Down => ScreenInstruction::SwitchTabPrev(client_id), }; - session - .senders + senders .send_to_screen(screen_instr) .with_context(err_context)?; }, @@ -162,109 +152,92 @@ pub(crate) fn route_action( Some(Direction::Down) => ScreenInstruction::MovePaneDown(client_id), None => ScreenInstruction::MovePane(client_id), }; - session - .senders + senders .send_to_screen(screen_instr) .with_context(err_context)?; }, Action::MovePaneBackwards => { - session - .senders + senders .send_to_screen(ScreenInstruction::MovePaneBackwards(client_id)) .with_context(err_context)?; }, Action::ClearScreen => { - session - .senders + senders .send_to_screen(ScreenInstruction::ClearScreen(client_id)) .with_context(err_context)?; }, Action::DumpScreen(val, full) => { - session - .senders + senders .send_to_screen(ScreenInstruction::DumpScreen(val, client_id, full)) .with_context(err_context)?; }, Action::EditScrollback => { - session - .senders + senders .send_to_screen(ScreenInstruction::EditScrollback(client_id)) .with_context(err_context)?; }, Action::ScrollUp => { - session - .senders + senders .send_to_screen(ScreenInstruction::ScrollUp(client_id)) .with_context(err_context)?; }, Action::ScrollUpAt(point) => { - session - .senders + senders .send_to_screen(ScreenInstruction::ScrollUpAt(point, client_id)) .with_context(err_context)?; }, Action::ScrollDown => { - session - .senders + senders .send_to_screen(ScreenInstruction::ScrollDown(client_id)) .with_context(err_context)?; }, Action::ScrollDownAt(point) => { - session - .senders + senders .send_to_screen(ScreenInstruction::ScrollDownAt(point, client_id)) .with_context(err_context)?; }, Action::ScrollToBottom => { - session - .senders + senders .send_to_screen(ScreenInstruction::ScrollToBottom(client_id)) .with_context(err_context)?; }, Action::ScrollToTop => { - session - .senders + senders .send_to_screen(ScreenInstruction::ScrollToTop(client_id)) .with_context(err_context)?; }, Action::PageScrollUp => { - session - .senders + senders .send_to_screen(ScreenInstruction::PageScrollUp(client_id)) .with_context(err_context)?; }, Action::PageScrollDown => { - session - .senders + senders .send_to_screen(ScreenInstruction::PageScrollDown(client_id)) .with_context(err_context)?; }, Action::HalfPageScrollUp => { - session - .senders + senders .send_to_screen(ScreenInstruction::HalfPageScrollUp(client_id)) .with_context(err_context)?; }, Action::HalfPageScrollDown => { - session - .senders + senders .send_to_screen(ScreenInstruction::HalfPageScrollDown(client_id)) .with_context(err_context)?; }, Action::ToggleFocusFullscreen => { - session - .senders + senders .send_to_screen(ScreenInstruction::ToggleActiveTerminalFullscreen(client_id)) .with_context(err_context)?; }, Action::TogglePaneFrames => { - session - .senders + senders .send_to_screen(ScreenInstruction::TogglePaneFrames) .with_context(err_context)?; }, Action::NewPane(direction, name) => { - let shell = session.default_shell.clone(); + let shell = default_shell.clone(); let pty_instr = match direction { Some(Direction::Left) => { PtyInstruction::SpawnTerminalVertically(shell, name, client_id) @@ -286,10 +259,7 @@ pub(crate) fn route_action( ClientOrTabIndex::ClientId(client_id), ), }; - session - .senders - .send_to_pty(pty_instr) - .with_context(err_context)?; + senders.send_to_pty(pty_instr).with_context(err_context)?; }, Action::EditFile(path_to_file, line_number, cwd, split_direction, should_float) => { let title = format!("Editing: {}", path_to_file.display()); @@ -319,27 +289,22 @@ pub(crate) fn route_action( ClientOrTabIndex::ClientId(client_id), ), }; - session - .senders - .send_to_pty(pty_instr) - .with_context(err_context)?; + senders.send_to_pty(pty_instr).with_context(err_context)?; }, Action::SwitchModeForAllClients(input_mode) => { - let attrs = &session.client_attributes; - session - .senders + let attrs = &client_attributes; + senders .send_to_plugin(PluginInstruction::Update(vec![( None, None, - Event::ModeUpdate(get_mode_info(input_mode, attrs, session.capabilities)), + Event::ModeUpdate(get_mode_info(input_mode, attrs, capabilities)), )])) .with_context(err_context)?; - session - .senders + senders .send_to_screen(ScreenInstruction::ChangeModeForAllClients(get_mode_info( input_mode, attrs, - session.capabilities, + capabilities, ))) .with_context(err_context)?; }, @@ -347,9 +312,8 @@ pub(crate) fn route_action( let should_float = true; let run_cmd = run_command .map(|cmd| TerminalAction::RunCommand(cmd.into())) - .or_else(|| session.default_shell.clone()); - session - .senders + .or_else(|| default_shell.clone()); + senders .send_to_pty(PtyInstruction::SpawnTerminal( run_cmd, Some(should_float), @@ -362,7 +326,7 @@ pub(crate) fn route_action( let should_float = false; let run_cmd = run_command .map(|cmd| TerminalAction::RunCommand(cmd.into())) - .or_else(|| session.default_shell.clone()); + .or_else(|| default_shell.clone()); let pty_instr = match direction { Some(Direction::Left) => { PtyInstruction::SpawnTerminalVertically(run_cmd, name, client_id) @@ -384,35 +348,28 @@ pub(crate) fn route_action( ClientOrTabIndex::ClientId(client_id), ), }; - session - .senders - .send_to_pty(pty_instr) - .with_context(err_context)?; + senders.send_to_pty(pty_instr).with_context(err_context)?; }, Action::TogglePaneEmbedOrFloating => { - session - .senders + senders .send_to_screen(ScreenInstruction::TogglePaneEmbedOrFloating(client_id)) .with_context(err_context)?; }, Action::ToggleFloatingPanes => { - session - .senders + senders .send_to_screen(ScreenInstruction::ToggleFloatingPanes( client_id, - session.default_shell.clone(), + default_shell.clone(), )) .with_context(err_context)?; }, Action::PaneNameInput(c) => { - session - .senders + senders .send_to_screen(ScreenInstruction::UpdatePaneName(c, client_id)) .with_context(err_context)?; }, Action::UndoRenamePane => { - session - .senders + senders .send_to_screen(ScreenInstruction::UndoRenamePane(client_id)) .with_context(err_context)?; }, @@ -439,14 +396,10 @@ pub(crate) fn route_action( ClientOrTabIndex::ClientId(client_id), ), }; - session - .senders - .send_to_pty(pty_instr) - .with_context(err_context)?; + senders.send_to_pty(pty_instr).with_context(err_context)?; }, Action::CloseFocus => { - session - .senders + senders .send_to_screen(ScreenInstruction::CloseFocusedPane(client_id)) .with_context(err_context)?; }, @@ -457,13 +410,12 @@ pub(crate) fn route_action( swap_floating_layouts, tab_name, ) => { - let shell = session.default_shell.clone(); + let shell = default_shell.clone(); let swap_tiled_layouts = - swap_tiled_layouts.unwrap_or_else(|| session.layout.swap_tiled_layouts.clone()); + swap_tiled_layouts.unwrap_or_else(|| default_layout.swap_tiled_layouts.clone()); let swap_floating_layouts = swap_floating_layouts - .unwrap_or_else(|| session.layout.swap_floating_layouts.clone()); - session - .senders + .unwrap_or_else(|| default_layout.swap_floating_layouts.clone()); + senders .send_to_screen(ScreenInstruction::NewTab( None, shell, @@ -476,41 +428,35 @@ pub(crate) fn route_action( .with_context(err_context)?; }, Action::GoToNextTab => { - session - .senders + senders .send_to_screen(ScreenInstruction::SwitchTabNext(client_id)) .with_context(err_context)?; }, Action::GoToPreviousTab => { - session - .senders + senders .send_to_screen(ScreenInstruction::SwitchTabPrev(client_id)) .with_context(err_context)?; }, Action::ToggleActiveSyncTab => { - session - .senders + senders .send_to_screen(ScreenInstruction::ToggleActiveSyncTab(client_id)) .with_context(err_context)?; }, Action::CloseTab => { - session - .senders + senders .send_to_screen(ScreenInstruction::CloseTab(client_id)) .with_context(err_context)?; }, Action::GoToTab(i) => { - session - .senders + senders .send_to_screen(ScreenInstruction::GoToTab(i, Some(client_id))) .with_context(err_context)?; }, Action::GoToTabName(name, create) => { - let shell = session.default_shell.clone(); - let swap_tiled_layouts = session.layout.swap_tiled_layouts.clone(); - let swap_floating_layouts = session.layout.swap_floating_layouts.clone(); - session - .senders + let shell = default_shell.clone(); + let swap_tiled_layouts = default_layout.swap_tiled_layouts.clone(); + let swap_floating_layouts = default_layout.swap_floating_layouts.clone(); + senders .send_to_screen(ScreenInstruction::GoToTabName( name, (swap_tiled_layouts, swap_floating_layouts), @@ -521,106 +467,92 @@ pub(crate) fn route_action( .with_context(err_context)?; }, Action::TabNameInput(c) => { - session - .senders + senders .send_to_screen(ScreenInstruction::UpdateTabName(c, client_id)) .with_context(err_context)?; }, Action::UndoRenameTab => { - session - .senders + senders .send_to_screen(ScreenInstruction::UndoRenameTab(client_id)) .with_context(err_context)?; }, Action::Quit => { - to_server - .send(ServerInstruction::ClientExit(client_id)) + senders + .send_to_server(ServerInstruction::ClientExit(client_id)) .with_context(err_context)?; should_break = true; }, Action::Detach => { - to_server - .send(ServerInstruction::DetachSession(vec![client_id])) + senders + .send_to_server(ServerInstruction::DetachSession(vec![client_id])) .with_context(err_context)?; should_break = true; }, Action::LeftClick(point) => { - session - .senders + senders .send_to_screen(ScreenInstruction::LeftClick(point, client_id)) .with_context(err_context)?; }, Action::RightClick(point) => { - session - .senders + senders .send_to_screen(ScreenInstruction::RightClick(point, client_id)) .with_context(err_context)?; }, Action::MiddleClick(point) => { - session - .senders + senders .send_to_screen(ScreenInstruction::MiddleClick(point, client_id)) .with_context(err_context)?; }, Action::LeftMouseRelease(point) => { - session - .senders + senders .send_to_screen(ScreenInstruction::LeftMouseRelease(point, client_id)) .with_context(err_context)?; }, Action::RightMouseRelease(point) => { - session - .senders + senders .send_to_screen(ScreenInstruction::RightMouseRelease(point, client_id)) .with_context(err_context)?; }, Action::MiddleMouseRelease(point) => { - session - .senders + senders .send_to_screen(ScreenInstruction::MiddleMouseRelease(point, client_id)) .with_context(err_context)?; }, Action::MouseHoldLeft(point) => { - session - .senders + senders .send_to_screen(ScreenInstruction::MouseHoldLeft(point, client_id)) .with_context(err_context)?; }, Action::MouseHoldRight(point) => { - session - .senders + senders .send_to_screen(ScreenInstruction::MouseHoldRight(point, client_id)) .with_context(err_context)?; }, Action::MouseHoldMiddle(point) => { - session - .senders + senders .send_to_screen(ScreenInstruction::MouseHoldMiddle(point, client_id)) .with_context(err_context)?; }, Action::Copy => { - session - .senders + senders .send_to_screen(ScreenInstruction::Copy(client_id)) .with_context(err_context)?; }, Action::Confirm => { - session - .senders + senders .send_to_screen(ScreenInstruction::ConfirmPrompt(client_id)) .with_context(err_context)?; }, Action::Deny => { - session - .senders + senders .send_to_screen(ScreenInstruction::DenyPrompt(client_id)) .with_context(err_context)?; }, #[allow(clippy::single_match)] Action::SkipConfirm(action) => match *action { Action::Quit => { - to_server - .send(ServerInstruction::ClientExit(client_id)) + senders + .send_to_server(ServerInstruction::ClientExit(client_id)) .with_context(err_context)?; should_break = true; }, @@ -628,8 +560,7 @@ pub(crate) fn route_action( }, Action::NoOp => {}, Action::SearchInput(c) => { - session - .senders + senders .send_to_screen(ScreenInstruction::UpdateSearch(c, client_id)) .with_context(err_context)?; }, @@ -638,8 +569,7 @@ pub(crate) fn route_action( SearchDirection::Down => ScreenInstruction::SearchDown(client_id), SearchDirection::Up => ScreenInstruction::SearchUp(client_id), }; - session - .senders + senders .send_to_screen(instruction) .with_context(err_context)?; }, @@ -651,41 +581,35 @@ pub(crate) fn route_action( SearchOption::WholeWord => ScreenInstruction::SearchToggleWholeWord(client_id), SearchOption::Wrap => ScreenInstruction::SearchToggleWrap(client_id), }; - session - .senders + senders .send_to_screen(instruction) .with_context(err_context)?; }, Action::ToggleMouseMode => {}, // Handled client side Action::PreviousSwapLayout => { - session - .senders + senders .send_to_screen(ScreenInstruction::PreviousSwapLayout(client_id)) .with_context(err_context)?; }, Action::NextSwapLayout => { - session - .senders + senders .send_to_screen(ScreenInstruction::NextSwapLayout(client_id)) .with_context(err_context)?; }, Action::QueryTabNames => { - session - .senders + senders .send_to_screen(ScreenInstruction::QueryTabNames(client_id)) .with_context(err_context)?; }, Action::NewTiledPluginPane(run_plugin, name) => { - session - .senders + senders .send_to_screen(ScreenInstruction::NewTiledPluginPane( run_plugin, name, client_id, )) .with_context(err_context)?; }, Action::NewFloatingPluginPane(run_plugin, name) => { - session - .senders + senders .send_to_screen(ScreenInstruction::NewFloatingPluginPane( run_plugin, name, client_id, )) @@ -694,8 +618,7 @@ pub(crate) fn route_action( Action::StartOrReloadPlugin(url) => { let run_plugin_location = RunPluginLocation::parse(url.as_str()).with_context(err_context)?; - session - .senders + senders .send_to_screen(ScreenInstruction::StartOrReloadPluginPane( run_plugin_location, None, @@ -703,8 +626,7 @@ pub(crate) fn route_action( .with_context(err_context)?; }, Action::LaunchOrFocusPlugin(run_plugin, should_float) => { - session - .senders + senders .send_to_screen(ScreenInstruction::LaunchOrFocusPlugin( run_plugin, should_float, @@ -770,10 +692,12 @@ pub(crate) fn route_thread_main( } if route_action( action, - rlocked_sessions, - &*os_input, - &to_server, client_id, + rlocked_sessions.senders.clone(), + rlocked_sessions.capabilities.clone(), + rlocked_sessions.client_attributes.clone(), + rlocked_sessions.default_shell.clone(), + rlocked_sessions.layout.clone(), )? { should_break = true; } diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index e88baf29..920c9340 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -1364,6 +1364,12 @@ impl Screen { tab.change_mode_info(mode_info.clone(), client_id); tab.mark_active_pane_for_rerender(client_id); } + + if let Some(os_input) = &mut self.bus.os_input { + let _ = + os_input.send_to_client(client_id, ServerToClientMsg::SwitchToMode(mode_info.mode)); + } + Ok(()) } pub fn change_mode_for_all_clients(&mut self, mode_info: ModeInfo) -> Result<()> { @@ -1378,10 +1384,6 @@ impl Screen { for client_id in connected_client_ids { self.change_mode(mode_info.clone(), client_id) .with_context(err_context)?; - if let Some(os_input) = &mut self.bus.os_input { - let _ = os_input - .send_to_client(client_id, ServerToClientMsg::SwitchToMode(mode_info.mode)); - } } Ok(()) } diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index 8639970b..c8acdc63 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -99,20 +99,24 @@ fn take_snapshots_and_cursor_coordinates_from_render_events<'a>( fn send_cli_action_to_server( session_metadata: &SessionMetaData, cli_action: CliAction, - mock_screen: &mut MockScreen, client_id: ClientId, ) { - let os_input = Box::new(mock_screen.os_input.clone()); - let to_server = mock_screen.to_server.clone(); let get_current_dir = || PathBuf::from("."); let actions = Action::actions_from_cli(cli_action, Box::new(get_current_dir), None).unwrap(); + let senders = session_metadata.senders.clone(); + let capabilities = PluginCapabilities::default(); + let client_attributes = ClientAttributes::default(); + let default_shell = None; + let default_layout = Box::new(Layout::default()); for action in actions { route_action( action, - &session_metadata, - &*os_input, - &to_server.clone(), client_id, + senders.clone(), + capabilities, + client_attributes.clone(), + default_shell.clone(), + default_layout.clone(), ) .unwrap(); } @@ -1023,7 +1027,7 @@ pub fn send_cli_write_chars_action_to_screen() { let cli_action = CliAction::WriteChars { chars: "input from the cli".into(), }; - send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); + send_cli_action_to_server(&session_metadata, cli_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![pty_writer_thread, screen_thread]); assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); @@ -1049,7 +1053,7 @@ pub fn send_cli_write_action_to_screen() { let cli_action = CliAction::Write { bytes: vec![102, 111, 111], }; - send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); + send_cli_action_to_server(&session_metadata, cli_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![pty_writer_thread, screen_thread]); assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); @@ -1076,12 +1080,7 @@ pub fn send_cli_resize_action_to_screen() { resize: Resize::Increase, direction: Some(Direction::Left), }; - send_cli_action_to_server( - &session_metadata, - resize_cli_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, resize_cli_action, client_id); mock_screen.teardown(vec![pty_writer_thread, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( received_server_instructions.lock().unwrap().iter(), @@ -1112,12 +1111,7 @@ pub fn send_cli_focus_next_pane_action() { server_receiver ); let focus_next_pane_action = CliAction::FocusNextPane; - send_cli_action_to_server( - &session_metadata, - focus_next_pane_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, focus_next_pane_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1150,12 +1144,7 @@ pub fn send_cli_focus_previous_pane_action() { server_receiver ); let focus_next_pane_action = CliAction::FocusPreviousPane; - send_cli_action_to_server( - &session_metadata, - focus_next_pane_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, focus_next_pane_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1190,12 +1179,7 @@ pub fn send_cli_move_focus_pane_action() { let move_focus_action = CliAction::MoveFocus { direction: Direction::Right, }; - send_cli_action_to_server( - &session_metadata, - move_focus_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, move_focus_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1230,12 +1214,7 @@ pub fn send_cli_move_focus_or_tab_pane_action() { let move_focus_action = CliAction::MoveFocusOrTab { direction: Direction::Right, }; - send_cli_action_to_server( - &session_metadata, - move_focus_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, move_focus_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1270,7 +1249,7 @@ pub fn send_cli_move_pane_action() { let cli_action = CliAction::MovePane { direction: Some(Direction::Right), }; - send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); + send_cli_action_to_server(&session_metadata, cli_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1309,7 +1288,7 @@ pub fn send_cli_dump_screen_action() { 0, "fill pane up with something".as_bytes().to_vec(), )); - send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); + send_cli_action_to_server(&session_metadata, cli_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_thread, screen_thread]); assert_snapshot!(format!( @@ -1340,7 +1319,7 @@ pub fn send_cli_edit_scrollback_action() { 0, "fill pane up with something".as_bytes().to_vec(), )); - send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); + send_cli_action_to_server(&session_metadata, cli_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![pty_thread, screen_thread]); let dumped_file_name = mock_screen @@ -1395,18 +1374,8 @@ pub fn send_cli_scroll_up_action() { std::thread::sleep(std::time::Duration::from_millis(100)); // we send two actions here because only the last line in the pane is empty, so one action // won't show in a render - send_cli_action_to_server( - &session_metadata, - cli_action.clone(), - &mut mock_screen, - client_id, - ); - send_cli_action_to_server( - &session_metadata, - cli_action.clone(), - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, cli_action.clone(), client_id); + send_cli_action_to_server(&session_metadata, cli_action.clone(), client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1449,44 +1418,14 @@ pub fn send_cli_scroll_down_action() { )); std::thread::sleep(std::time::Duration::from_millis(100)); // scroll up some - send_cli_action_to_server( - &session_metadata, - scroll_up_cli_action.clone(), - &mut mock_screen, - client_id, - ); - send_cli_action_to_server( - &session_metadata, - scroll_up_cli_action.clone(), - &mut mock_screen, - client_id, - ); - send_cli_action_to_server( - &session_metadata, - scroll_up_cli_action.clone(), - &mut mock_screen, - client_id, - ); - send_cli_action_to_server( - &session_metadata, - scroll_up_cli_action.clone(), - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id); + send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id); + send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id); + send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id); // scroll down some - send_cli_action_to_server( - &session_metadata, - scroll_down_cli_action.clone(), - &mut mock_screen, - client_id, - ); - send_cli_action_to_server( - &session_metadata, - scroll_down_cli_action.clone(), - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, scroll_down_cli_action.clone(), client_id); + send_cli_action_to_server(&session_metadata, scroll_down_cli_action.clone(), client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1529,36 +1468,15 @@ pub fn send_cli_scroll_to_bottom_action() { )); std::thread::sleep(std::time::Duration::from_millis(100)); // scroll up some - send_cli_action_to_server( - &session_metadata, - scroll_up_cli_action.clone(), - &mut mock_screen, - client_id, - ); - send_cli_action_to_server( - &session_metadata, - scroll_up_cli_action.clone(), - &mut mock_screen, - client_id, - ); - send_cli_action_to_server( - &session_metadata, - scroll_up_cli_action.clone(), - &mut mock_screen, - client_id, - ); - send_cli_action_to_server( - &session_metadata, - scroll_up_cli_action.clone(), - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id); + send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id); + send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id); + send_cli_action_to_server(&session_metadata, scroll_up_cli_action.clone(), client_id); // scroll to bottom send_cli_action_to_server( &session_metadata, scroll_to_bottom_action.clone(), - &mut mock_screen, client_id, ); std::thread::sleep(std::time::Duration::from_millis(100)); @@ -1602,12 +1520,7 @@ pub fn send_cli_scroll_to_top_action() { )); std::thread::sleep(std::time::Duration::from_millis(100)); // scroll to top - send_cli_action_to_server( - &session_metadata, - scroll_to_top_action.clone(), - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, scroll_to_top_action.clone(), client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1648,12 +1561,7 @@ pub fn send_cli_page_scroll_up_action() { pane_contents.as_bytes().to_vec(), )); std::thread::sleep(std::time::Duration::from_millis(100)); - send_cli_action_to_server( - &session_metadata, - page_scroll_up_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, page_scroll_up_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1697,26 +1605,11 @@ pub fn send_cli_page_scroll_down_action() { std::thread::sleep(std::time::Duration::from_millis(100)); // scroll up some - send_cli_action_to_server( - &session_metadata, - page_scroll_up_action.clone(), - &mut mock_screen, - client_id, - ); - send_cli_action_to_server( - &session_metadata, - page_scroll_up_action.clone(), - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, page_scroll_up_action.clone(), client_id); + send_cli_action_to_server(&session_metadata, page_scroll_up_action.clone(), client_id); // scroll down - send_cli_action_to_server( - &session_metadata, - page_scroll_down_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, page_scroll_down_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1757,12 +1650,7 @@ pub fn send_cli_half_page_scroll_up_action() { pane_contents.as_bytes().to_vec(), )); std::thread::sleep(std::time::Duration::from_millis(100)); - send_cli_action_to_server( - &session_metadata, - half_page_scroll_up_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, half_page_scroll_up_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1809,23 +1697,16 @@ pub fn send_cli_half_page_scroll_down_action() { send_cli_action_to_server( &session_metadata, half_page_scroll_up_action.clone(), - &mut mock_screen, client_id, ); send_cli_action_to_server( &session_metadata, half_page_scroll_up_action.clone(), - &mut mock_screen, client_id, ); // scroll down - send_cli_action_to_server( - &session_metadata, - half_page_scroll_down_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, half_page_scroll_down_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1857,12 +1738,7 @@ pub fn send_cli_toggle_full_screen_action() { server_receiver ); let toggle_full_screen_action = CliAction::ToggleFullscreen; - send_cli_action_to_server( - &session_metadata, - toggle_full_screen_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, toggle_full_screen_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1894,12 +1770,7 @@ pub fn send_cli_toggle_pane_frames_action() { server_receiver ); let toggle_pane_frames_action = CliAction::TogglePaneFrames; - send_cli_action_to_server( - &session_metadata, - toggle_pane_frames_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, toggle_pane_frames_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -1940,15 +1811,9 @@ pub fn send_cli_toggle_active_tab_sync_action() { send_cli_action_to_server( &session_metadata, cli_toggle_active_tab_sync_action, - &mut mock_screen, - client_id, - ); - send_cli_action_to_server( - &session_metadata, - cli_write_action, - &mut mock_screen, client_id, ); + send_cli_action_to_server(&session_metadata, cli_write_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![pty_writer_thread, screen_thread]); assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); @@ -1984,12 +1849,7 @@ pub fn send_cli_new_pane_action_with_default_parameters() { close_on_exit: false, start_suspended: false, }; - send_cli_action_to_server( - &session_metadata, - cli_new_pane_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, cli_new_pane_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![pty_thread, screen_thread]); assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); @@ -2025,12 +1885,7 @@ pub fn send_cli_new_pane_action_with_split_direction() { close_on_exit: false, start_suspended: false, }; - send_cli_action_to_server( - &session_metadata, - cli_new_pane_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, cli_new_pane_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![pty_thread, screen_thread]); assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); @@ -2066,12 +1921,7 @@ pub fn send_cli_new_pane_action_with_command_and_cwd() { close_on_exit: false, start_suspended: false, }; - send_cli_action_to_server( - &session_metadata, - cli_new_pane_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, cli_new_pane_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![pty_thread, screen_thread]); assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); @@ -2104,12 +1954,7 @@ pub fn send_cli_edit_action_with_default_parameters() { floating: false, cwd: None, }; - send_cli_action_to_server( - &session_metadata, - cli_edit_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, cli_edit_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![pty_thread, screen_thread]); assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); @@ -2142,12 +1987,7 @@ pub fn send_cli_edit_action_with_line_number() { floating: false, cwd: None, }; - send_cli_action_to_server( - &session_metadata, - cli_edit_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, cli_edit_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![pty_thread, screen_thread]); assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); @@ -2180,12 +2020,7 @@ pub fn send_cli_edit_action_with_split_direction() { floating: false, cwd: None, }; - send_cli_action_to_server( - &session_metadata, - cli_edit_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, cli_edit_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![pty_thread, screen_thread]); assert_snapshot!(format!("{:?}", *received_pty_instructions.lock().unwrap())); @@ -2207,12 +2042,7 @@ pub fn send_cli_switch_mode_action() { let cli_switch_mode = CliAction::SwitchMode { input_mode: InputMode::Locked, }; - send_cli_action_to_server( - &session_metadata, - cli_switch_mode, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, cli_switch_mode, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![screen_thread]); assert_snapshot!(format!( @@ -2247,7 +2077,6 @@ pub fn send_cli_toggle_pane_embed_or_float() { send_cli_action_to_server( &session_metadata, toggle_pane_embed_or_floating.clone(), - &mut mock_screen, client_id, ); std::thread::sleep(std::time::Duration::from_millis(100)); @@ -2255,7 +2084,6 @@ pub fn send_cli_toggle_pane_embed_or_float() { send_cli_action_to_server( &session_metadata, toggle_pane_embed_or_floating.clone(), - &mut mock_screen, client_id, ); std::thread::sleep(std::time::Duration::from_millis(100)); @@ -2291,28 +2119,13 @@ pub fn send_cli_toggle_floating_panes() { let toggle_pane_embed_or_floating = CliAction::TogglePaneEmbedOrFloating; let toggle_floating_panes = CliAction::ToggleFloatingPanes; // float the focused pane - send_cli_action_to_server( - &session_metadata, - toggle_pane_embed_or_floating, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, toggle_pane_embed_or_floating, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // toggle floating panes (will hide the floated pane from the previous action) - send_cli_action_to_server( - &session_metadata, - toggle_floating_panes.clone(), - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, toggle_floating_panes.clone(), client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // toggle floating panes (will show the floated pane) - send_cli_action_to_server( - &session_metadata, - toggle_floating_panes.clone(), - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, toggle_floating_panes.clone(), client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -2344,12 +2157,7 @@ pub fn send_cli_close_pane_action() { server_receiver ); let close_pane_action = CliAction::ClosePane; - send_cli_action_to_server( - &session_metadata, - close_pane_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, close_pane_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_instruction, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -2386,12 +2194,7 @@ pub fn send_cli_new_tab_action_default_params() { layout_dir: None, cwd: None, }; - send_cli_action_to_server( - &session_metadata, - new_tab_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, new_tab_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![plugin_thread, screen_thread]); let received_plugin_instructions = received_plugin_instructions.lock().unwrap(); @@ -2431,12 +2234,7 @@ pub fn send_cli_new_tab_action_with_name_and_layout() { layout_dir: None, cwd: None, }; - send_cli_action_to_server( - &session_metadata, - new_tab_action, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, new_tab_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![plugin_thread, screen_thread]); let new_tab_instruction = received_plugin_instructions @@ -2478,12 +2276,7 @@ pub fn send_cli_next_tab_action() { server_receiver ); let goto_next_tab = CliAction::GoToNextTab; - send_cli_action_to_server( - &session_metadata, - goto_next_tab, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, goto_next_tab, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_thread, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -2519,12 +2312,7 @@ pub fn send_cli_previous_tab_action() { server_receiver ); let goto_previous_tab = CliAction::GoToPreviousTab; - send_cli_action_to_server( - &session_metadata, - goto_previous_tab, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, goto_previous_tab, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_thread, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -2560,7 +2348,7 @@ pub fn send_cli_goto_tab_action() { server_receiver ); let goto_tab = CliAction::GoToTab { index: 1 }; - send_cli_action_to_server(&session_metadata, goto_tab, &mut mock_screen, client_id); + send_cli_action_to_server(&session_metadata, goto_tab, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_thread, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -2596,7 +2384,7 @@ pub fn send_cli_close_tab_action() { server_receiver ); let close_tab = CliAction::CloseTab; - send_cli_action_to_server(&session_metadata, close_tab, &mut mock_screen, client_id); + send_cli_action_to_server(&session_metadata, close_tab, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_thread, screen_thread]); let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( @@ -2634,7 +2422,7 @@ pub fn send_cli_rename_tab() { let rename_tab = CliAction::RenameTab { name: "new-tab-name".into(), }; - send_cli_action_to_server(&session_metadata, rename_tab, &mut mock_screen, client_id); + send_cli_action_to_server(&session_metadata, rename_tab, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![plugin_thread, screen_thread]); assert_snapshot!(format!( @@ -2669,15 +2457,10 @@ pub fn send_cli_undo_rename_tab() { }; let undo_rename_tab = CliAction::UndoRenameTab; // first rename the tab - send_cli_action_to_server(&session_metadata, rename_tab, &mut mock_screen, client_id); + send_cli_action_to_server(&session_metadata, rename_tab, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // then undo the tab rename to go back to the default name - send_cli_action_to_server( - &session_metadata, - undo_rename_tab, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, undo_rename_tab, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![plugin_thread, screen_thread]); assert_snapshot!(format!( @@ -2702,12 +2485,7 @@ pub fn send_cli_query_tab_names_action() { server_receiver ); let query_tab_names = CliAction::QueryTabNames; - send_cli_action_to_server( - &session_metadata, - query_tab_names, - &mut mock_screen, - client_id, - ); + send_cli_action_to_server(&session_metadata, query_tab_names, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_thread, screen_thread]); let log_tab_names_instruction = received_server_instructions @@ -2743,7 +2521,7 @@ pub fn send_cli_launch_or_focus_plugin_action() { floating: true, url: url::Url::parse("file:/path/to/fake/plugin").unwrap(), }; - send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); + send_cli_action_to_server(&session_metadata, cli_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![plugin_thread, screen_thread]); @@ -2798,7 +2576,7 @@ pub fn send_cli_launch_or_focus_plugin_action_when_plugin_is_already_loaded() { floating: true, url: url::Url::parse("file:/path/to/fake/plugin").unwrap(), }; - send_cli_action_to_server(&session_metadata, cli_action, &mut mock_screen, client_id); + send_cli_action_to_server(&session_metadata, cli_action, client_id); std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be mock_screen.teardown(vec![plugin_thread, server_thread, screen_thread]); diff --git a/zellij-tile/src/shim.rs b/zellij-tile/src/shim.rs index c43fc8db..0a3102a1 100644 --- a/zellij-tile/src/shim.rs +++ b/zellij-tile/src/shim.rs @@ -64,6 +64,16 @@ pub fn open_terminal_floating(path: &Path) { unsafe { host_open_terminal_floating() }; } +pub fn open_command_pane(path: &Path, args: Vec) { + object_to_stdout(&(path, args)); + unsafe { host_open_command_pane() }; +} + +pub fn open_command_pane_floating(path: &Path, args: Vec) { + object_to_stdout(&(path, args)); + unsafe { host_open_command_pane_floating() }; +} + pub fn switch_tab_to(tab_idx: u32) { unsafe { host_switch_tab_to(tab_idx) }; } @@ -80,6 +90,28 @@ pub fn hide_self() { unsafe { host_hide_self() }; } +pub fn switch_to_input_mode(mode: &InputMode) { + object_to_stdout(&mode); + unsafe { host_switch_to_mode() }; +} + +pub fn new_tabs_with_layout(layout: &str) { + println!("{}", layout); + unsafe { host_new_tabs_with_layout() } +} + +pub fn new_tab() { + unsafe { host_new_tab() } +} + +pub fn go_to_next_tab() { + unsafe { host_go_to_next_tab() } +} + +pub fn go_to_previous_tab() { + unsafe { host_go_to_previous_tab() } +} + pub fn report_panic(info: &std::panic::PanicInfo) { println!(""); println!("A panic occured in a plugin"); @@ -87,6 +119,156 @@ pub fn report_panic(info: &std::panic::PanicInfo) { unsafe { host_report_panic() }; } +pub fn resize_focused_pane(resize: Resize) { + object_to_stdout(&resize); + unsafe { host_resize() }; +} + +pub fn resize_focused_pane_with_direction(resize: Resize, direction: Direction) { + object_to_stdout(&(resize, direction)); + unsafe { host_resize_with_direction() }; +} + +pub fn focus_next_pane() { + unsafe { host_focus_next_pane() }; +} + +pub fn focus_previous_pane() { + unsafe { host_focus_previous_pane() }; +} + +pub fn move_focus(direction: Direction) { + object_to_stdout(&direction); + unsafe { host_move_focus() }; +} + +pub fn move_focus_or_tab(direction: Direction) { + object_to_stdout(&direction); + unsafe { host_move_focus_or_tab() }; +} + +pub fn detach() { + unsafe { host_detach() }; +} + +pub fn edit_scrollback() { + unsafe { host_edit_scrollback() }; +} + +pub fn write(bytes: Vec) { + object_to_stdout(&bytes); + unsafe { host_write() }; +} + +pub fn write_chars(chars: &str) { + println!("{}", chars); + unsafe { host_write_chars() }; +} + +pub fn toggle_tab() { + unsafe { host_toggle_tab() }; +} + +pub fn move_pane() { + unsafe { host_move_pane() }; +} + +pub fn move_pane_with_direction(direction: Direction) { + object_to_stdout(&direction); + unsafe { host_move_pane_with_direction() }; +} + +pub fn clear_screen() { + unsafe { host_clear_screen() }; +} + +pub fn scroll_up() { + unsafe { host_scroll_up() }; +} + +pub fn scroll_down() { + unsafe { host_scroll_down() }; +} + +pub fn scroll_to_top() { + unsafe { host_scroll_to_top() }; +} + +pub fn scroll_to_bottom() { + unsafe { host_scroll_to_bottom() }; +} + +pub fn page_scroll_up() { + unsafe { host_page_scroll_up() }; +} + +pub fn page_scroll_down() { + unsafe { host_page_scroll_down() }; +} + +pub fn toggle_focus_fullscreen() { + unsafe { host_toggle_focus_fullscreen() }; +} + +pub fn toggle_pane_frames() { + unsafe { host_toggle_pane_frames() }; +} + +pub fn toggle_pane_embed_or_eject() { + unsafe { host_toggle_pane_embed_or_eject() }; +} + +pub fn undo_rename_pane() { + unsafe { host_undo_rename_pane() }; +} + +pub fn close_focus() { + unsafe { host_close_focus() }; +} + +pub fn toggle_active_tab_sync() { + unsafe { host_toggle_active_tab_sync() }; +} + +pub fn close_focused_tab() { + unsafe { host_close_focused_tab() }; +} + +pub fn undo_rename_tab() { + unsafe { host_undo_rename_tab() }; +} + +pub fn quit_zellij() { + unsafe { host_quit_zellij() }; +} + +pub fn previous_swap_layout() { + unsafe { host_previous_swap_layout() }; +} + +pub fn next_swap_layout() { + unsafe { host_next_swap_layout() }; +} + +pub fn go_to_tab_name(tab_name: &str) { + println!("{}", tab_name); + unsafe { host_go_to_tab_name() }; +} + +pub fn focus_or_create_tab(tab_name: &str) { + print!("{}", tab_name); + unsafe { host_focus_or_create_tab() }; +} + +pub fn go_to_tab(tab_index: i32) { + unsafe { host_go_to_tab(tab_index) }; +} + +pub fn start_or_reload_plugin(url: &str) { + println!("{}", url); + unsafe { host_start_or_reload_plugin() }; +} + // Internal Functions #[doc(hidden)] @@ -134,6 +316,8 @@ extern "C" { fn host_open_file_with_line_floating(); fn host_open_terminal(); fn host_open_terminal_floating(); + fn host_open_command_pane(); + fn host_open_command_pane_floating(); fn host_switch_tab_to(tab_idx: u32); fn host_set_timeout(secs: f64); fn host_exec_cmd(); @@ -141,4 +325,44 @@ extern "C" { fn host_post_message_to(); fn host_post_message_to_plugin(); fn host_hide_self(); + fn host_switch_to_mode(); + fn host_new_tabs_with_layout(); + fn host_new_tab(); + fn host_go_to_next_tab(); + fn host_go_to_previous_tab(); + fn host_resize(); + fn host_resize_with_direction(); + fn host_focus_next_pane(); + fn host_focus_previous_pane(); + fn host_move_focus(); + fn host_move_focus_or_tab(); + fn host_detach(); + fn host_edit_scrollback(); + fn host_write(); + fn host_write_chars(); + fn host_toggle_tab(); + fn host_move_pane(); + fn host_move_pane_with_direction(); + fn host_clear_screen(); + fn host_scroll_up(); + fn host_scroll_down(); + fn host_scroll_to_top(); + fn host_scroll_to_bottom(); + fn host_page_scroll_up(); + fn host_page_scroll_down(); + fn host_toggle_focus_fullscreen(); + fn host_toggle_pane_frames(); + fn host_toggle_pane_embed_or_eject(); + fn host_undo_rename_pane(); + fn host_close_focus(); + fn host_toggle_active_tab_sync(); + fn host_close_focused_tab(); + fn host_undo_rename_tab(); + fn host_quit_zellij(); + fn host_previous_swap_layout(); + fn host_next_swap_layout(); + fn host_go_to_tab_name(); + fn host_focus_or_create_tab(); + fn host_go_to_tab(tab_index: i32); + fn host_start_or_reload_plugin(); } diff --git a/zellij-utils/src/input/command.rs b/zellij-utils/src/input/command.rs index 3212d26e..c05aa644 100644 --- a/zellij-utils/src/input/command.rs +++ b/zellij-utils/src/input/command.rs @@ -10,6 +10,19 @@ pub enum TerminalAction { RunCommand(RunCommand), } +impl TerminalAction { + pub fn change_cwd(&mut self, new_cwd: PathBuf) { + match self { + TerminalAction::OpenFile(_, _, cwd) => { + *cwd = Some(new_cwd); + }, + TerminalAction::RunCommand(run_command) => { + run_command.cwd = Some(new_cwd); + }, + } + } +} + #[derive(Clone, Debug, Deserialize, Default, Serialize, PartialEq, Eq)] pub struct RunCommand { #[serde(alias = "cmd")] @@ -69,6 +82,19 @@ impl From for RunCommand { } } +impl From for RunCommandAction { + fn from(run_command: RunCommand) -> Self { + RunCommandAction { + command: run_command.command, + args: run_command.args, + cwd: run_command.cwd, + direction: None, + hold_on_close: run_command.hold_on_close, + hold_on_start: run_command.hold_on_start, + } + } +} + impl RunCommand { pub fn new(command: PathBuf) -> Self { RunCommand {