diff options
| author | Aram Drevekenin <aram@poor.dev> | 2026-05-08 18:25:37 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-05-08 18:25:37 +0200 |
| commit | 24f2173fbce61ca6234f4fe4b6ca83833bf3ae64 (patch) | |
| tree | 9e713d10952561889e45e0d3308fc65fa0a236e7 /zellij-server | |
| parent | fix: occasional stall when querying host terminal (introduced in 0.44.1) (#5149) (diff) | |
| download | sl0ppij-24f2173fbce61ca6234f4fe4b6ca83833bf3ae64.tar.gz sl0ppij-24f2173fbce61ca6234f4fe4b6ca83833bf3ae64.tar.xz sl0ppij-24f2173fbce61ca6234f4fe4b6ca83833bf3ae64.zip | |
fix: deadlock with blocking panes (#5152)
* fix: deadlock with blocking panes
* rustfmt
* add pr
Diffstat (limited to 'zellij-server')
18 files changed, 235 insertions, 796 deletions
diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs index 1cbd0208..29aabdd0 100644 --- a/zellij-server/src/lib.rs +++ b/zellij-server/src/lib.rs @@ -56,8 +56,8 @@ use zellij_utils::{ DEFAULT_SCROLL_BUFFER_SIZE, SCROLL_BUFFER_SIZE, ZELLIJ_SEEN_RELEASE_NOTES_CACHE_FILE, }, data::{ - ConnectToSession, InputMode, KeyWithModifier, LayoutInfo, LayoutWithError, - PluginCapabilities, Style, WebSharing, + ConnectToSession, InputMode, KeyWithModifier, LayoutInfo, LayoutWithError, Style, + WebSharing, }, errors::{prelude::*, ContextType, ErrorInstruction, FatalError, ServerContext}, home::{default_layout_dir, get_default_data_dir}, @@ -65,7 +65,6 @@ use zellij_utils::{ actions::Action, command::{RunCommand, TerminalAction}, config::{watch_config_file_changes, watch_layout_dir_changes, Config}, - get_mode_info, keybinds::Keybinds, layout::{FloatingPaneLayout, Layout, PluginAlias, Run, RunPluginOrAlias}, options::Options, @@ -322,10 +321,7 @@ impl SessionConfiguration { pub(crate) struct SessionMetaData { pub senders: ThreadSenders, - pub capabilities: PluginCapabilities, - pub client_attributes: ClientAttributes, pub default_shell: Option<TerminalAction>, - pub layout: Box<Layout>, pub current_input_modes: HashMap<ClientId, InputMode>, pub session_configuration: SessionConfiguration, pub web_sharing: WebSharing, // this is a special attribute explicitly set on session @@ -1038,8 +1034,8 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) { floating_panes_layout.clone(), tab_name, ( - layout.swap_tiled_layouts.clone(), - layout.swap_floating_layouts.clone(), + Some(layout.swap_tiled_layouts.clone()), + Some(layout.swap_floating_layouts.clone()), ), should_focus_tab, ); @@ -1070,8 +1066,8 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) { floating_panes, None, ( - layout.swap_tiled_layouts.clone(), - layout.swap_floating_layouts.clone(), + Some(layout.swap_tiled_layouts.clone()), + Some(layout.swap_floating_layouts.clone()), ), true, ); @@ -1142,20 +1138,16 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) { .send_to_plugin(PluginInstruction::AddClient(client_id)) .unwrap(); let default_mode = config.options.default_mode.unwrap_or_default(); - let mode_info = get_mode_info( - default_mode, - &client_attributes, - session_data.capabilities, - &session_data - .session_configuration - .get_client_keybinds(&client_id), - Some(default_mode), - ); // ModeUpdate broadcast is handled by the screen thread via // change_mode() -> update_input_modes() session_data .senders - .send_to_screen(ScreenInstruction::ChangeMode(mode_info, client_id, None)) + .send_to_screen(ScreenInstruction::ChangeMode( + default_mode, + Some(default_mode), + client_id, + None, + )) .unwrap(); }, ServerInstruction::AttachWatcherClient(client_id, terminal_size, is_web_client) => { @@ -1900,10 +1892,6 @@ fn init_session( // Determine and initialize the data directory let data_dir = cli_assets.data_dir.unwrap_or_else(get_default_data_dir); - let capabilities = PluginCapabilities { - arrow_fonts: config_options.simplified_ui.unwrap_or_default(), - }; - let serialization_interval = config_options.serialization_interval; let disable_session_metadata = config_options.disable_session_metadata.unwrap_or(false); let web_server_ip = config_options @@ -2008,9 +1996,7 @@ fn init_session( let engine = get_engine(); let layout = layout.clone(); - let client_attributes = client_attributes.clone(); let default_shell = default_shell.clone(); - let capabilities = capabilities.clone(); let layout_dir = config_options .layout_dir .clone() @@ -2029,8 +2015,6 @@ fn init_session( path_to_default_shell, zellij_cwd, session_env_vars, - capabilities, - client_attributes, default_shell, plugin_aliases, default_mode, @@ -2121,10 +2105,7 @@ fn init_session( to_server: Some(to_server), should_silently_fail: false, }, - capabilities, default_shell, - client_attributes, - layout, session_configuration: Default::default(), current_input_modes: HashMap::new(), screen_thread: Some(screen_thread), diff --git a/zellij-server/src/plugins/mod.rs b/zellij-server/src/plugins/mod.rs index bf11dbba..69c80e77 100644 --- a/zellij-server/src/plugins/mod.rs +++ b/zellij-server/src/plugins/mod.rs @@ -32,7 +32,7 @@ use zellij_utils::{ data::{ ClientInfo, CommandOrPlugin, Event, EventType, FloatingPaneCoordinates, InputMode, LayoutInfo, LayoutWithError, MessageToPlugin, PermissionStatus, PermissionType, - PipeMessage, PipeSource, PluginCapabilities, WebServerStatus, + PipeMessage, PipeSource, WebServerStatus, }, errors::{prelude::*, ContextType, PluginContext}, input::{ @@ -42,7 +42,6 @@ use zellij_utils::{ layout::{FloatingPaneLayout, Layout, Run, RunPlugin, RunPluginOrAlias, TiledPaneLayout}, plugins::PluginAliases, }, - ipc::ClientAttributes, pane_size::Size, session_serialization, }; @@ -300,8 +299,6 @@ pub(crate) fn plugin_thread_main( path_to_default_shell: PathBuf, zellij_cwd: PathBuf, session_env_vars: std::collections::BTreeMap<String, String>, - capabilities: PluginCapabilities, - client_attributes: ClientAttributes, default_shell: Option<TerminalAction>, plugin_aliases: PluginAliases, default_mode: InputMode, @@ -329,10 +326,7 @@ pub(crate) fn plugin_thread_main( path_to_default_shell, zellij_cwd.clone(), session_env_vars, - capabilities, - client_attributes, default_shell, - layout.clone(), layout_dir, available_layouts, available_layout_errors, diff --git a/zellij-server/src/plugins/pinned_executor.rs b/zellij-server/src/plugins/pinned_executor.rs index e02df637..9dfdba20 100644 --- a/zellij-server/src/plugins/pinned_executor.rs +++ b/zellij-server/src/plugins/pinned_executor.rs @@ -8,7 +8,6 @@ use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; use std::thread; use wasmi::Engine; -use zellij_utils::input::layout::Layout; /// A dynamic thread pool that pins jobs to specific threads based on plugin_id /// Starts with 1 thread and expands when threads are busy, shrinks when plugins unload @@ -32,7 +31,6 @@ pub struct PinnedExecutor { senders: ThreadSenders, plugin_map: Arc<Mutex<PluginMap>>, connected_clients: Arc<Mutex<Vec<ClientId>>>, - default_layout: Box<Layout>, plugin_cache: PluginCache, engine: Engine, } @@ -49,7 +47,6 @@ enum Job { ThreadSenders, Arc<Mutex<PluginMap>>, Arc<Mutex<Vec<ClientId>>>, - Box<Layout>, PluginCache, Engine, ) + Send @@ -67,7 +64,6 @@ impl PinnedExecutor { senders: &ThreadSenders, plugin_map: &Arc<Mutex<PluginMap>>, connected_clients: &Arc<Mutex<Vec<ClientId>>>, - default_layout: &Box<Layout>, plugin_cache: &PluginCache, engine: &Engine, ) -> Self { @@ -78,7 +74,6 @@ impl PinnedExecutor { senders.clone(), plugin_map.clone(), connected_clients.clone(), - default_layout.clone(), plugin_cache.clone(), engine.clone(), ); @@ -92,7 +87,6 @@ impl PinnedExecutor { senders: senders.clone(), plugin_map: plugin_map.clone(), connected_clients: connected_clients.clone(), - default_layout: default_layout.clone(), plugin_cache: plugin_cache.clone(), engine: engine.clone(), } @@ -103,7 +97,6 @@ impl PinnedExecutor { senders: ThreadSenders, plugin_map: Arc<Mutex<PluginMap>>, connected_clients: Arc<Mutex<Vec<ClientId>>>, - default_layout: Box<Layout>, plugin_cache: PluginCache, engine: Engine, ) -> ExecutionThread { @@ -118,7 +111,6 @@ impl PinnedExecutor { let senders = senders; let plugin_map = plugin_map; let connected_clients = connected_clients; - let default_layout = default_layout; let plugin_cache = plugin_cache; let engine = engine; while let Ok(job) = receiver.recv() { @@ -128,7 +120,6 @@ impl PinnedExecutor { senders.clone(), plugin_map.clone(), connected_clients.clone(), - default_layout.clone(), plugin_cache.clone(), engine.clone(), ); @@ -220,7 +211,6 @@ impl PinnedExecutor { self.senders.clone(), self.plugin_map.clone(), self.connected_clients.clone(), - self.default_layout.clone(), self.plugin_cache.clone(), self.engine.clone(), ); @@ -239,7 +229,6 @@ impl PinnedExecutor { ThreadSenders, Arc<Mutex<PluginMap>>, Arc<Mutex<Vec<ClientId>>>, - Box<Layout>, PluginCache, Engine, ) + Send @@ -283,7 +272,6 @@ impl PinnedExecutor { ThreadSenders, Arc<Mutex<PluginMap>>, Arc<Mutex<Vec<ClientId>>>, - Box<Layout>, PluginCache, Engine, ) + Send @@ -306,7 +294,6 @@ impl PinnedExecutor { ThreadSenders, Arc<Mutex<PluginMap>>, Arc<Mutex<Vec<ClientId>>>, - Box<Layout>, PluginCache, Engine, ) + Send @@ -315,16 +302,9 @@ impl PinnedExecutor { let executor = self.clone(); self.execute_for_plugin( plugin_id, - move |senders, plugin_map, connected_clients, default_layout, plugin_cache, engine| { + move |senders, plugin_map, connected_clients, plugin_cache, engine| { // Execute the cleanup work - f( - senders, - plugin_map, - connected_clients, - default_layout, - plugin_cache, - engine, - ); + f(senders, plugin_map, connected_clients, plugin_cache, engine); // Unregister plugin and potentially shrink the pool executor.unregister_plugin(plugin_id); @@ -423,7 +403,6 @@ mod tests { ThreadSenders, Arc<Mutex<PluginMap>>, Arc<Mutex<Vec<ClientId>>>, - Box<Layout>, PluginCache, Engine, ) { @@ -458,32 +437,22 @@ mod tests { let plugin_map = Arc::new(Mutex::new(PluginMap::default())); let connected_clients = Arc::new(Mutex::new(vec![])); - let layout = Box::new(Layout::default()); - let plugin_cache = Arc::new(Mutex::new( std::collections::HashMap::<PathBuf, Module>::new(), )); let engine = Engine::default(); - ( - senders, - plugin_map, - connected_clients, - layout, - plugin_cache, - engine, - ) + (senders, plugin_map, connected_clients, plugin_cache, engine) } fn create_test_executor(max_threads: usize) -> Arc<PinnedExecutor> { - let (senders, plugin_map, clients, layout, cache, engine) = create_test_dependencies(); + let (senders, plugin_map, clients, cache, engine) = create_test_dependencies(); Arc::new(PinnedExecutor::new( max_threads, &senders, &plugin_map, &clients, - &layout, &cache, &engine, )) @@ -496,12 +465,11 @@ mod tests { ThreadSenders, Arc<Mutex<PluginMap>>, Arc<Mutex<Vec<ClientId>>>, - Box<Layout>, PluginCache, Engine, ) + Send + 'static { - move |_senders, _plugin_map, _clients, _layout, _cache, _engine| { + move |_senders, _plugin_map, _clients, _cache, _engine| { tx.send(()).unwrap(); } } @@ -509,7 +477,7 @@ mod tests { // Helper to verify thread assignment by capturing thread name in job fn get_thread_name_for_plugin(executor: &Arc<PinnedExecutor>, plugin_id: u32) -> String { let (tx, rx) = channel(); - executor.execute_for_plugin(plugin_id, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(plugin_id, move |_s, _p, _c, _ca, _e| { let name = thread::current().name().unwrap().to_string(); tx.send(name).unwrap(); }); @@ -563,7 +531,7 @@ mod tests { // Make thread 0 busy with a barrier let barrier = Arc::new(Barrier::new(2)); let barrier_clone = barrier.clone(); - executor.execute_for_plugin(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(1, move |_s, _p, _c, _ca, _e| { barrier_clone.wait(); }); @@ -594,7 +562,7 @@ mod tests { // Make thread 0 busy let barrier1 = Arc::new(Barrier::new(2)); let barrier1_clone = barrier1.clone(); - executor.execute_for_plugin(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(1, move |_s, _p, _c, _ca, _e| { barrier1_clone.wait(); }); thread::sleep(Duration::from_millis(50)); @@ -605,7 +573,7 @@ mod tests { // Make thread 1 busy let barrier2 = Arc::new(Barrier::new(2)); let barrier2_clone = barrier2.clone(); - executor.execute_for_plugin(2, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(2, move |_s, _p, _c, _ca, _e| { barrier2_clone.wait(); }); thread::sleep(Duration::from_millis(50)); @@ -646,7 +614,7 @@ mod tests { // Make thread 0 busy let barrier = Arc::new(Barrier::new(2)); let barrier_clone = barrier.clone(); - executor.execute_for_plugin(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(1, move |_s, _p, _c, _ca, _e| { barrier_clone.wait(); }); thread::sleep(Duration::from_millis(50)); @@ -678,7 +646,7 @@ mod tests { // Make thread 0 busy to force plugin 2 to thread 1 let barrier = Arc::new(Barrier::new(2)); let barrier_clone = barrier.clone(); - executor.execute_for_plugin(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(1, move |_s, _p, _c, _ca, _e| { barrier_clone.wait(); }); thread::sleep(Duration::from_millis(50)); @@ -726,7 +694,7 @@ mod tests { for i in 1..=3 { let order_clone = order.clone(); let tx_clone = tx.clone(); - executor.execute_for_plugin(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(1, move |_s, _p, _c, _ca, _e| { order_clone.lock().unwrap().push(i); tx_clone.send(()).unwrap(); }); @@ -767,7 +735,7 @@ mod tests { // Make thread 0 busy to force plugin 2 to thread 1 let barrier = Arc::new(Barrier::new(2)); let barrier_clone = barrier.clone(); - executor.execute_for_plugin(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(1, move |_s, _p, _c, _ca, _e| { barrier_clone.wait(); }); thread::sleep(Duration::from_millis(50)); @@ -785,13 +753,13 @@ mod tests { let (tx2, rx2) = channel(); let barrier1 = sync_barrier.clone(); - executor.execute_for_plugin(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(1, move |_s, _p, _c, _ca, _e| { barrier1.wait(); tx1.send(()).unwrap(); }); let barrier2 = sync_barrier.clone(); - executor.execute_for_plugin(2, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(2, move |_s, _p, _c, _ca, _e| { barrier2.wait(); tx2.send(()).unwrap(); }); @@ -836,7 +804,7 @@ mod tests { let counter_clone = counter.clone(); let (tx_unload, rx_unload) = channel(); - executor.execute_plugin_unload(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_plugin_unload(1, move |_s, _p, _c, _ca, _e| { counter_clone.fetch_add(1, Ordering::SeqCst); tx_unload.send(()).unwrap(); }); @@ -873,7 +841,7 @@ mod tests { let sequence_clone = sequence.clone(); let (tx_unload, rx_unload) = channel(); - executor.execute_plugin_unload(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_plugin_unload(1, move |_s, _p, _c, _ca, _e| { sequence_clone.lock().unwrap().push("cleanup"); tx_unload.send(()).unwrap(); }); @@ -900,7 +868,7 @@ mod tests { // Make thread 0 busy to force plugin 2 to thread 1 let barrier = Arc::new(Barrier::new(2)); let barrier_clone = barrier.clone(); - executor.execute_for_plugin(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(1, move |_s, _p, _c, _ca, _e| { barrier_clone.wait(); }); thread::sleep(Duration::from_millis(50)); @@ -977,7 +945,7 @@ mod tests { // Force plugin 2 to thread 1 by making thread 0 busy let barrier = Arc::new(Barrier::new(2)); let barrier_clone = barrier.clone(); - executor.execute_for_plugin(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(1, move |_s, _p, _c, _ca, _e| { barrier_clone.wait(); }); thread::sleep(Duration::from_millis(50)); @@ -1035,7 +1003,7 @@ mod tests { // Force plugin 2 to thread 1 let barrier = Arc::new(Barrier::new(2)); let barrier_clone = barrier.clone(); - executor.execute_for_plugin(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(1, move |_s, _p, _c, _ca, _e| { barrier_clone.wait(); }); thread::sleep(Duration::from_millis(50)); @@ -1079,7 +1047,7 @@ mod tests { let barrier = Arc::new(Barrier::new(2)); let barrier_clone = barrier.clone(); - executor.execute_for_plugin(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(1, move |_s, _p, _c, _ca, _e| { barrier_clone.wait(); }); thread::sleep(Duration::from_millis(50)); @@ -1104,7 +1072,7 @@ mod tests { let barrier = Arc::new(Barrier::new(2)); let barrier_clone = barrier.clone(); - executor.execute_for_plugin(1, move |_s, _p, _c, _l, _ca, _e| { + executor.execute_for_plugin(1, move |_s, _p, _c, _ca, _e| { barrier_clone.wait(); }); diff --git a/zellij-server/src/plugins/plugin_loader.rs b/zellij-server/src/plugins/plugin_loader.rs index 31b54df7..8121fbe1 100644 --- a/zellij-server/src/plugins/plugin_loader.rs +++ b/zellij-server/src/plugins/plugin_loader.rs @@ -25,15 +25,8 @@ use crate::{ use zellij_utils::plugin_api::action::ProtobufPluginConfiguration; use zellij_utils::{ - consts::ZELLIJ_TMP_DIR, - data::{InputMode, PluginCapabilities}, - errors::prelude::*, - input::command::TerminalAction, - input::keybinds::Keybinds, - input::layout::Layout, - input::plugins::PluginConfig, - ipc::ClientAttributes, - pane_size::Size, + consts::ZELLIJ_TMP_DIR, data::InputMode, errors::prelude::*, input::command::TerminalAction, + input::keybinds::Keybinds, input::plugins::PluginConfig, pane_size::Size, }; /// Open a directory as a `File` handle for WASI pre-opening. @@ -77,8 +70,6 @@ pub struct PluginLoader<'a> { tab_index: Option<usize>, path_to_default_shell: PathBuf, session_env_vars: std::collections::BTreeMap<String, String>, - capabilities: PluginCapabilities, - client_attributes: ClientAttributes, default_shell: Option<TerminalAction>, layout_dir: Option<PathBuf>, default_mode: InputMode, @@ -88,7 +79,6 @@ pub struct PluginLoader<'a> { loading_indication: LoadingIndication, senders: ThreadSenders, engine: Engine, - default_layout: Box<Layout>, plugin_cache: PluginCache, plugin_map: &'a mut PluginMap, // we receive a mutable reference rather than the Arc so that it // will be held for the lifetime of this struct and thus loading @@ -102,7 +92,6 @@ impl<'a> PluginLoader<'a> { loading_context: LoadingContext, senders: ThreadSenders, engine: Engine, - default_layout: Box<Layout>, plugin_cache: PluginCache, plugin_map: &'a mut PluginMap, connected_clients: Arc<Mutex<Vec<ClientId>>>, @@ -122,8 +111,6 @@ impl<'a> PluginLoader<'a> { tab_index: loading_context.tab_index, path_to_default_shell: loading_context.path_to_default_shell, session_env_vars: loading_context.session_env_vars, - capabilities: loading_context.capabilities, - client_attributes: loading_context.client_attributes, default_shell: loading_context.default_shell, layout_dir: loading_context.layout_dir, default_mode: loading_context.default_mode, @@ -134,7 +121,6 @@ impl<'a> PluginLoader<'a> { skip_cache, senders, engine, - default_layout, plugin_cache, plugin_map, connected_clients: Some(connected_clients), @@ -282,10 +268,7 @@ impl<'a> PluginLoader<'a> { plugin_own_cache_dir: self.plugin_own_cache_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(), plugin_cwd: self.plugin_cwd.clone(), session_env_vars: self.session_env_vars.clone(), input_pipes_to_unblock: Arc::new(Mutex::new(HashSet::new())), @@ -397,10 +380,7 @@ impl<'a> PluginLoader<'a> { plugin_own_cache_dir: self.plugin_own_cache_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(), plugin_cwd: self.plugin_cwd.clone(), session_env_vars: self.session_env_vars.clone(), input_pipes_to_unblock: 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 f1459dc6..9539bef3 100644 --- a/zellij-server/src/plugins/plugin_map.rs +++ b/zellij-server/src/plugins/plugin_map.rs @@ -15,12 +15,10 @@ use tokio::sync::mpsc::UnboundedSender; use zellij_utils::{ data::EventType, data::InputMode, - data::PluginCapabilities, input::command::TerminalAction, input::keybinds::Keybinds, - input::layout::{Layout, PluginUserConfiguration, RunPlugin, RunPluginLocation}, + input::layout::{PluginUserConfiguration, RunPlugin, RunPluginLocation}, input::plugins::PluginConfig, - ipc::ClientAttributes, }; use zellij_utils::{data::PermissionType, errors::prelude::*}; @@ -285,10 +283,7 @@ pub struct PluginEnv { pub plugin_own_data_dir: PathBuf, pub plugin_own_cache_dir: PathBuf, pub path_to_default_shell: PathBuf, - pub capabilities: PluginCapabilities, - pub client_attributes: ClientAttributes, pub default_shell: Option<TerminalAction>, - pub default_layout: Box<Layout>, pub layout_dir: Option<PathBuf>, pub plugin_cwd: PathBuf, pub session_env_vars: std::collections::BTreeMap<String, String>, diff --git a/zellij-server/src/plugins/unit/plugin_tests.rs b/zellij-server/src/plugins/unit/plugin_tests.rs index 6e087db5..0e3b0637 100644 --- a/zellij-server/src/plugins/unit/plugin_tests.rs +++ b/zellij-server/src/plugins/unit/plugin_tests.rs @@ -9,7 +9,6 @@ use tempfile::tempdir; use wasmi::Engine; use zellij_utils::data::{ BareKey, Event, InputMode, KeyWithModifier, ModeInfo, PermissionStatus, PermissionType, - PluginCapabilities, }; use zellij_utils::errors::ErrorContext; use zellij_utils::input::actions::Action; @@ -19,7 +18,6 @@ use zellij_utils::input::layout::{ }; use zellij_utils::input::permission::PermissionCache; use zellij_utils::input::plugins::PluginAliases; -use zellij_utils::ipc::ClientAttributes; use zellij_utils::pane_size::Size; use crate::background_jobs::BackgroundJob; @@ -343,8 +341,6 @@ fn create_plugin_thread( let data_dir = PathBuf::from(tempdir().unwrap().path()); let layout_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 mut plugin_aliases = PluginAliases::default(); plugin_aliases.aliases.insert( @@ -372,8 +368,6 @@ fn create_plugin_thread( default_shell, zellij_cwd, session_env_vars, - plugin_capabilities, - client_attributes, default_shell_action, plugin_aliases, InputMode::Normal, @@ -445,8 +439,6 @@ fn create_plugin_thread_with_server_receiver( let engine = Engine::new(&config); 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 initiating_client_id = 1; let plugin_thread = std::thread::Builder::new() @@ -464,8 +456,6 @@ fn create_plugin_thread_with_server_receiver( default_shell, zellij_cwd, session_env_vars, - plugin_capabilities, - client_attributes, default_shell_action, PluginAliases::default(), InputMode::Normal, @@ -545,8 +535,6 @@ fn create_plugin_thread_with_pty_receiver( let data_dir = PathBuf::from(tempdir().unwrap().path()); let layout_dir = layout_dir.unwrap_or_else(|| 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 initiating_client_id = 1; let plugin_thread = std::thread::Builder::new() @@ -564,8 +552,6 @@ fn create_plugin_thread_with_pty_receiver( default_shell, zellij_cwd, session_env_vars, - plugin_capabilities, - client_attributes, default_shell_action, PluginAliases::default(), InputMode::Normal, @@ -638,8 +624,6 @@ fn create_plugin_thread_with_background_jobs_receiver( let engine = Engine::new(&config); 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 initiating_client_id = 1; let plugin_thread = std::thread::Builder::new() @@ -657,8 +641,6 @@ fn create_plugin_thread_with_background_jobs_receiver( default_shell, zellij_cwd, session_env_vars, - plugin_capabilities, - client_attributes, default_shell_action, PluginAliases::default(), InputMode::Normal, diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_or_create_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_or_create_tab_plugin_command.snap index cb2d7f0d..833815a3 100644 --- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_or_create_tab_plugin_command.snap +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__focus_or_create_tab_plugin_command.snap @@ -5,10 +5,6 @@ expression: "format!(\"{:#?}\", new_tab_event)" Some( GoToTabName( "my tab name", - ( - [], - [], - ), None, true, Some( diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab_name_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab_name_plugin_command.snap index f7968649..53e88889 100644 --- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab_name_plugin_command.snap +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__go_to_tab_name_plugin_command.snap @@ -5,10 +5,6 @@ expression: "format!(\"{:#?}\", new_tab_event)" Some( GoToTabName( "my tab name", - ( - [], - [], - ), None, false, Some( diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tab_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tab_plugin_command.snap index 3479f894..29315e57 100644 --- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tab_plugin_command.snap +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tab_plugin_command.snap @@ -14,8 +14,8 @@ Some( "new_tab_name", ), ( - [], - [], + None, + None, ), None, false, diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command-2.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command-2.snap index 69271b74..05830618 100644 --- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command-2.snap +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command-2.snap @@ -66,8 +66,12 @@ Some( [], None, ( - [], - [], + Some( + [], + ), + Some( + [], + ), ), None, false, diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command.snap index b650bbf3..54d7a13f 100644 --- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command.snap +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__new_tabs_with_layout_plugin_command.snap @@ -66,8 +66,12 @@ Some( [], None, ( - [], - [], + Some( + [], + ), + Some( + [], + ), ), None, false, diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__send_configuration_to_plugins.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__send_configuration_to_plugins.snap index e9e3f023..dadde052 100644 --- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__send_configuration_to_plugins.snap +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__send_configuration_to_plugins.snap @@ -5,10 +5,6 @@ expression: "format!(\"{:#?}\", go_to_tab_event)" Some( GoToTabName( "{\"fake_config_key_1\": \"fake_config_value_1\", \"fake_config_key_2\": \"fake_config_value_2\"}", - ( - [], - [], - ), None, false, Some( diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_mode_plugin_command.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_mode_plugin_command.snap index d8c94ff0..feaaebd7 100644 --- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_mode_plugin_command.snap +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__switch_to_mode_plugin_command.snap @@ -4,327 +4,10 @@ expression: "format!(\"{:#?}\", switch_to_mode_event)" --- Some( ChangeMode( - ModeInfo { - mode: Tab, - base_mode: Some( - Normal, - ), - keybinds: [], - style: Style { - colors: Styling { - text_unselected: StyleDeclaration { - base: EightBit( - 245, - ), - background: EightBit( - 238, - ), - emphasis_0: EightBit( - 166, - ), - emphasis_1: EightBit( - 51, - ), - emphasis_2: EightBit( - 154, - ), - emphasis_3: EightBit( - 201, - ), - }, - text_selected: StyleDeclaration { - base: EightBit( - 245, - ), - background: EightBit( - 238, - ), - emphasis_0: EightBit( - 166, - ), - emphasis_1: EightBit( - 51, - ), - emphasis_2: EightBit( - 154, - ), - emphasis_3: EightBit( - 201, - ), - }, - ribbon_unselected: StyleDeclaration { - base: EightBit( - 16, - ), - background: EightBit( - 238, - ), - emphasis_0: EightBit( - 124, - ), - emphasis_1: EightBit( - 255, - ), - emphasis_2: EightBit( - 45, - ), - emphasis_3: EightBit( - 201, - ), - }, - ribbon_selected: StyleDeclaration { - base: EightBit( - 16, - ), - background: EightBit( - 154, - ), - emphasis_0: EightBit( - 124, - ), - emphasis_1: EightBit( - 166, - ), - emphasis_2: EightBit( - 201, - ), - emphasis_3: EightBit( - 45, - ), - }, - table_title: StyleDeclaration { - base: EightBit( - 154, - ), - background: EightBit( - 238, - ), - emphasis_0: EightBit( - 166, - ), - emphasis_1: EightBit( - 51, - ), - emphasis_2: EightBit( - 154, - ), - emphasis_3: EightBit( - 201, - ), - }, - table_cell_unselected: StyleDeclaration { - base: EightBit( - 245, - ), - background: EightBit( - 238, - ), - emphasis_0: EightBit( - 166, - ), - emphasis_1: EightBit( - 51, - ), - emphasis_2: EightBit( - 154, - ), - emphasis_3: EightBit( - 201, - ), - }, - table_cell_selected: StyleDeclaration { - base: EightBit( - 154, - ), - background: EightBit( - 238, - ), - emphasis_0: EightBit( - 166, - ), - emphasis_1: EightBit( - 51, - ), - emphasis_2: EightBit( - 124, - ), - emphasis_3: EightBit( - 201, - ), - }, - list_unselected: StyleDeclaration { - base: EightBit( - 245, - ), - background: EightBit( - 238, - ), - emphasis_0: EightBit( - 166, - ), - emphasis_1: EightBit( - 51, - ), - emphasis_2: EightBit( - 154, - ), - emphasis_3: EightBit( - 201, - ), - }, - list_selected: StyleDeclaration { - base: EightBit( - 154, - ), - background: EightBit( - 238, - ), - emphasis_0: EightBit( - 166, - ), - emphasis_1: EightBit( - 51, - ), - emphasis_2: EightBit( - 124, - ), - emphasis_3: EightBit( - 201, - ), - }, - frame_unselected: None, - frame_selected: StyleDeclaration { - base: EightBit( - 154, - ), - background: EightBit( - 238, - ), - emphasis_0: EightBit( - 166, - ), - emphasis_1: EightBit( - 51, - ), - emphasis_2: EightBit( - 201, - ), - emphasis_3: EightBit( - 215, - ), - }, - frame_highlight: StyleDeclaration { - base: EightBit( - 166, - ), - background: EightBit( - 154, - ), - emphasis_0: EightBit( - 201, - ), - emphasis_1: EightBit( - 99, - ), - emphasis_2: EightBit( - 154, - ), - emphasis_3: EightBit( - 154, - ), - }, - exit_code_success: StyleDeclaration { - base: EightBit( - 154, - ), - background: EightBit( - 238, - ), - emphasis_0: EightBit( - 51, - ), - emphasis_1: EightBit( - 16, - ), - emphasis_2: EightBit( - 201, - ), - emphasis_3: EightBit( - 45, - ), - }, - exit_code_error: StyleDeclaration { - base: EightBit( - 124, - ), - background: EightBit( - 238, - ), - emphasis_0: EightBit( - 226, - ), - emphasis_1: EightBit( - 136, - ), - emphasis_2: EightBit( - 245, - ), - emphasis_3: EightBit( - 99, - ), - }, - multiplayer_user_colors: MultiplayerColors { - player_1: EightBit( - 201, - ), - player_2: EightBit( - 45, - ), - player_3: EightBit( - 99, - ), - player_4: EightBit( - 226, - ), - player_5: EightBit( - 51, - ), - player_6: EightBit( - 136, - ), - player_7: EightBit( - 124, - ), - player_8: EightBit( - 245, - ), - player_9: EightBit( - 207, - ), - player_10: EightBit( - 215, - ), - }, - }, - rounded_corners: false, - hide_session_name: false, - }, - capabilities: PluginCapabilities { - arrow_fonts: true, - }, - session_name: Some( - "zellij-test", - ), - editor: None, - shell: None, - web_clients_allowed: None, - web_sharing: None, - currently_marking_pane_group: None, - is_web_client: None, - web_server_ip: None, - web_server_port: None, - web_server_capability: None, - }, + Tab, + Some( + Normal, + ), 1, Some( NotificationEnd { diff --git a/zellij-server/src/plugins/wasm_bridge.rs b/zellij-server/src/plugins/wasm_bridge.rs index 86db429d..aaaf1971 100644 --- a/zellij-server/src/plugins/wasm_bridge.rs +++ b/zellij-server/src/plugins/wasm_bridge.rs @@ -40,14 +40,13 @@ use crate::{ ServerInstruction, }; use zellij_utils::{ - data::{Event, EventType, PluginCapabilities}, + data::{Event, EventType}, errors::prelude::*, input::{ command::TerminalAction, - layout::{Layout, PluginUserConfiguration, RunPlugin, RunPluginLocation, RunPluginOrAlias}, + layout::{PluginUserConfiguration, RunPlugin, RunPluginLocation, RunPluginOrAlias}, plugins::{PluginAliases, PluginConfig}, }, - ipc::ClientAttributes, pane_size::Size, }; @@ -104,8 +103,6 @@ pub struct LoadingContext { pub tab_index: Option<usize>, pub path_to_default_shell: PathBuf, pub session_env_vars: std::collections::BTreeMap<String, String>, - pub capabilities: PluginCapabilities, - pub client_attributes: ClientAttributes, pub default_shell: Option<TerminalAction>, pub layout_dir: Option<PathBuf>, pub default_mode: InputMode, @@ -151,8 +148,6 @@ impl LoadingContext { path_to_default_shell: wasm_bridge.path_to_default_shell.clone(), session_env_vars: wasm_bridge.session_env_vars.clone(), plugin_cwd: cwd.unwrap_or_else(|| wasm_bridge.zellij_cwd.clone()), - capabilities: wasm_bridge.capabilities.clone(), - client_attributes: wasm_bridge.client_attributes.clone(), default_shell: wasm_bridge.default_shell.clone(), layout_dir: wasm_bridge.layout_dir.clone(), keybinds, @@ -192,8 +187,6 @@ pub struct WasmBridge { watcher: Option<Debouncer<RecommendedWatcher, FileIdMap>>, zellij_cwd: PathBuf, session_env_vars: std::collections::BTreeMap<String, String>, - capabilities: PluginCapabilities, - client_attributes: ClientAttributes, default_shell: Option<TerminalAction>, cached_plugin_map: HashMap<RunPluginLocation, HashMap<PluginUserConfiguration, Vec<(PluginId, ClientId)>>>, @@ -218,10 +211,7 @@ impl WasmBridge { path_to_default_shell: PathBuf, zellij_cwd: PathBuf, session_env_vars: std::collections::BTreeMap<String, String>, - capabilities: PluginCapabilities, - client_attributes: ClientAttributes, default_shell: Option<TerminalAction>, - default_layout: Box<Layout>, layout_dir: Option<PathBuf>, available_layouts: Vec<LayoutInfo>, available_layout_errors: Vec<LayoutWithError>, @@ -240,7 +230,6 @@ impl WasmBridge { &senders, &plugin_map, &connected_clients, - &default_layout, &plugin_cache, &engine, )); @@ -261,8 +250,6 @@ impl WasmBridge { pending_plugin_reloads: HashSet::new(), zellij_cwd, session_env_vars, - capabilities, - client_attributes, default_shell, cached_plugin_map: HashMap::new(), pending_pipes: Default::default(), @@ -399,7 +386,6 @@ impl WasmBridge { move |senders: ThreadSenders, plugin_map: Arc<Mutex<PluginMap>>, connected_clients: Arc<Mutex<Vec<ClientId>>>, - default_layout: Box<Layout>, plugin_cache: PluginCache, engine| { let mut plugin_map = plugin_map.lock().unwrap(); @@ -408,7 +394,6 @@ impl WasmBridge { loading_context, senders.clone(), engine.clone(), - default_layout.clone(), plugin_cache.clone(), &mut plugin_map, connected_clients.clone(), @@ -450,7 +435,6 @@ impl WasmBridge { move |senders, plugin_map, connected_clients, - default_layout, plugin_cache: PluginCache, engine: Engine| { let mut plugin_map = plugin_map.lock().unwrap(); @@ -459,7 +443,6 @@ impl WasmBridge { loading_context, senders.clone(), engine.clone(), - default_layout.clone(), plugin_cache.clone(), &mut plugin_map, connected_clients.clone(), @@ -548,12 +531,7 @@ impl WasmBridge { self.plugin_executor.execute_plugin_unload( plugin_id, - move |senders, - _plugin_map, - _connected_clients, - _default_layout, - _plugin_cache, - _engine| { + move |senders, _plugin_map, _connected_clients, _plugin_cache, _engine| { let subscriptions_guard = subscriptions.lock().unwrap(); let needs_before_close = subscriptions_guard.contains(&EventType::BeforeClose); drop(subscriptions_guard); // Release lock before calling plugin @@ -671,7 +649,7 @@ impl WasmBridge { plugin_executor.execute_for_plugin( plugin_id, - move |senders, plugin_map, connected_clients, default_layout, plugin_cache, engine| { + move |senders, plugin_map, connected_clients, plugin_cache, engine| { let skip_cache = true; // we want to explicitly reload the plugin let mut plugin_map = plugin_map.lock().unwrap(); match PluginLoader::new( @@ -679,7 +657,6 @@ impl WasmBridge { loading_context, senders.clone(), engine.clone(), - default_layout.clone(), plugin_cache.clone(), &mut plugin_map, connected_clients.clone(), @@ -778,12 +755,7 @@ impl WasmBridge { plugin_executor.execute_for_plugin( plugin_id, - move |senders, - plugin_map, - connected_clients, - default_layout, - plugin_cache, - engine| { + move |senders, plugin_map, connected_clients, plugin_cache, engine| { let skip_cache = false; let mut plugin_map = plugin_map.lock().unwrap(); match PluginLoader::new( @@ -791,7 +763,6 @@ impl WasmBridge { loading_context, senders.clone(), engine.clone(), - default_layout.clone(), plugin_cache.clone(), &mut plugin_map, connected_clients.clone(), @@ -853,12 +824,7 @@ impl WasmBridge { // let senders = self.senders.clone(); let running_plugin = running_plugin.clone(); let _s = shutdown_sender.clone(); - move |senders, - _plugin_map, - _connected_clients, - _default_layout, - _plugin_cache, - _engine| { + move |senders, _plugin_map, _connected_clients, _plugin_cache, _engine| { let mut running_plugin = running_plugin.lock().unwrap(); let _s = _s; // guard to allow the task to complete before cleanup/shutdown if running_plugin.apply_event_id(AtomicEvent::Resize, event_id) { @@ -965,7 +931,6 @@ impl WasmBridge { move |senders, _plugin_map, _connected_clients, - _default_layout, _plugin_cache, _engine| { let _s = _s; // guard to allow the task to complete before cleanup/shutdown @@ -1061,12 +1026,7 @@ impl WasmBridge { // Execute directly on pinned thread (no async I/O needed for directory check/change) self.plugin_executor .execute_for_plugin(plugin_id_to_update, { - move |senders, - _plugin_map, - _connected_clients, - _default_layout, - _plugin_cache, - _engine| { + move |senders, _plugin_map, _connected_clients, _plugin_cache, _engine| { match new_host_dir.try_exists() { Ok(false) => { log::error!( @@ -1190,12 +1150,7 @@ impl WasmBridge { let client_id = *client_id; let _s = shutdown_sender.clone(); let notification_end = notification_end.take(); - move |senders, - _plugin_map, - _connected_clients, - _default_layout, - _plugin_cache, - _engine| { + move |senders, _plugin_map, _connected_clients, _plugin_cache, _engine| { let mut running_plugin = running_plugin.lock().unwrap(); let mut plugin_render_assets = vec![]; let _s = _s; // guard to allow the task to complete before cleanup/shutdown @@ -1525,12 +1480,7 @@ impl WasmBridge { let keybinds = keybinds.clone(); let default_shell = default_shell.clone(); let layout_dir = layout_dir.clone(); - move |_senders, - _plugin_map, - _connected_clients, - _default_layout, - _plugin_cache, - _engine| { + move |_senders, _plugin_map, _connected_clients, _plugin_cache, _engine| { let mut running_plugin = running_plugin.lock().unwrap(); if let Some(keybinds) = keybinds { running_plugin.update_keybinds(keybinds); @@ -1578,12 +1528,7 @@ impl WasmBridge { let client_id = *client_id; let _s = shutdown_sender.clone(); let events_or_pipe_messages = events_or_pipe_messages.clone(); - move |senders, - _plugin_map, - _connected_clients, - _default_layout, - _plugin_cache, - _engine| { + move |senders, _plugin_map, _connected_clients, _plugin_cache, _engine| { let _s = _s; // guard to allow the task to complete before cleanup/shutdown for event_or_pipe_message in events_or_pipe_messages { match event_or_pipe_message { diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs index 1a941026..e586404f 100644 --- a/zellij-server/src/plugins/zellij_exports.rs +++ b/zellij-server/src/plugins/zellij_exports.rs @@ -121,12 +121,8 @@ macro_rules! apply_action { None, Some(PaneId::Plugin($env.plugin_id)), $env.senders.clone(), - $env.capabilities.clone(), - $env.client_attributes.clone(), $env.default_shell.clone(), - &$env.default_layout, None, - &$env.keybinds, $env.default_mode.clone(), None, ) { @@ -1430,11 +1426,7 @@ fn run_action(env: &PluginEnv, mut action: Action, context: BTreeMap<String, Str let client_id = env.client_id; let plugin_id = env.plugin_id; let senders = env.senders.clone(); - let capabilities = env.capabilities.clone(); - let client_attributes = env.client_attributes.clone(); let default_shell = env.default_shell.clone(); - let default_layout = env.default_layout.clone(); - let keybinds = env.keybinds.clone(); let default_mode = env.default_mode.clone(); let plugin_name = env.name().to_string(); @@ -1447,12 +1439,8 @@ fn run_action(env: &PluginEnv, mut action: Action, context: BTreeMap<String, Str None, Some(PaneId::Plugin(plugin_id)), senders.clone(), - capabilities, - client_attributes, default_shell, - &default_layout, None, - &keybinds, default_mode, None, ) { @@ -4482,12 +4470,8 @@ fn try_edit_layout( None, Some(PaneId::Plugin(env.plugin_id)), env.senders.clone(), - env.capabilities.clone(), - env.client_attributes.clone(), env.default_shell.clone(), - &env.default_layout, None, - &env.keybinds, env.default_mode.clone(), None, ) diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index 9fad8ddc..fa359d2c 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -19,21 +19,16 @@ use zellij_utils::{ channels::SenderWithContext, data::{ BareKey, ConnectToSession, Direction, Event, InputMode, KeyModifier, ListPanesResponse, - ListTabsResponse, NewPanePlacement, PaneListEntry, PluginCapabilities, ResizeStrategy, - TabInfo, UnblockCondition, + ListTabsResponse, NewPanePlacement, PaneListEntry, ResizeStrategy, TabInfo, + UnblockCondition, }, envs, errors::prelude::*, input::{ actions::{Action, SearchDirection, SearchOption}, command::TerminalAction, - get_mode_info, - keybinds::Keybinds, - layout::Layout, - }, - ipc::{ - ClientAttributes, ClientToServerMsg, ExitReason, IpcReceiverWithContext, ServerToClientMsg, }, + ipc::{ClientToServerMsg, ExitReason, IpcReceiverWithContext, ServerToClientMsg}, }; use crate::ClientId; @@ -194,18 +189,18 @@ impl Drop for NotificationEnd { } } +// `route_action` must not borrow from the `session_data` read guard. +// otherwise blocking-CLI actions +// (`wait_forever=true`) park this function while still holding the guard, +// deadlocking concurrent `session_data.write()`s. pub(crate) fn route_action( action: Action, client_id: ClientId, cli_client_id: Option<ClientId>, pane_id: Option<PaneId>, senders: ThreadSenders, - capabilities: PluginCapabilities, - client_attributes: ClientAttributes, default_shell: Option<TerminalAction>, - default_layout: &Layout, mut seen_cli_pipes: Option<&mut HashSet<String>>, - client_keybinds: &Keybinds, default_mode: InputMode, os_input: Option<Box<dyn ServerOsApi>>, ) -> Result<(bool, Option<ActionCompletionResult>)> { @@ -326,19 +321,13 @@ pub(crate) fn route_action( .with_context(err_context)?; }, Action::SwitchToMode { input_mode } => { - let attrs = &client_attributes; senders .send_to_server(ServerInstruction::ChangeMode(client_id, input_mode)) .with_context(err_context)?; senders .send_to_screen(ScreenInstruction::ChangeMode( - get_mode_info( - input_mode, - attrs, - capabilities, - &client_keybinds, - Some(default_mode), - ), + input_mode, + Some(default_mode), client_id, Some(NotificationEnd::new(completion_tx)), )) @@ -743,7 +732,6 @@ pub(crate) fn route_action( senders.send_to_pty(pty_instr).with_context(err_context)?; }, Action::SwitchModeForAllClients { input_mode } => { - let attrs = &client_attributes; // ModeUpdate broadcast is handled by the screen thread via // change_mode_for_all_clients() -> change_mode() -> update_input_modes() senders @@ -752,13 +740,8 @@ pub(crate) fn route_action( senders .send_to_screen(ScreenInstruction::ChangeModeForAllClients( - get_mode_info( - input_mode, - attrs, - capabilities, - &client_keybinds, - Some(default_mode), - ), + input_mode, + Some(default_mode), Some(NotificationEnd::new(completion_tx)), )) .with_context(err_context)?; @@ -984,10 +967,6 @@ pub(crate) fn route_action( first_pane_unblock_condition, } => { let shell = default_shell.clone(); - let swap_tiled_layouts = - swap_tiled_layouts.unwrap_or_else(|| default_layout.swap_tiled_layouts.clone()); - let swap_floating_layouts = swap_floating_layouts - .unwrap_or_else(|| default_layout.swap_floating_layouts.clone()); let is_web_client = false; // actions cannot be initiated directly from the web // Construct completion_tx conditionally @@ -1060,12 +1039,9 @@ pub(crate) fn route_action( }, Action::GoToTabName { name, create } => { 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), shell, create, Some(client_id), @@ -1538,7 +1514,6 @@ pub(crate) fn route_action( Action::BreakPane => { senders .send_to_screen(ScreenInstruction::BreakPane( - Box::new(default_layout.clone()), default_shell.clone(), client_id, Some(NotificationEnd::new(completion_tx)), @@ -2251,74 +2226,60 @@ pub(crate) fn route_thread_main( .unwrap() .set_last_active_client(client_id); - let session_data_guard = session_data.read().unwrap(); - let session_data_assets = session_data_guard.as_ref().map(|s| { - ( - s.senders.clone(), - s.capabilities.clone(), - s.client_attributes.clone(), - s.default_shell.clone(), - &*s.layout, - s.session_configuration - .get_client_default_input_mode(&client_id), - ) - }); - if let Some((keybinds, input_mode, default_input_mode)) = - session_data_guard - .as_ref() - .and_then(|s| s.get_client_keybinds_and_mode(&client_id)) - { - if let Some(( - senders, - capabilities, - client_attributes, - default_shell, - layout, - client_input_mode, - )) = session_data_assets - { - for action in keybinds + // The read guard ends as a temporary in this expression so + // `route_action` runs without holding `session_data.read()` — + // see the doc comment on `route_action` for why this matters. + let dispatch_inputs = + session_data.read().unwrap().as_ref().and_then(|s| { + let (kb, im, dim) = + s.get_client_keybinds_and_mode(&client_id)?; + let actions: Vec<Action> = kb .get_actions_for_key_in_mode_or_default_action( - &input_mode, + im, &key, raw_bytes, - default_input_mode, + dim, is_kitty_keyboard_protocol, - ) - { - // Send user input to plugin thread for logging - let _ = - senders.send_to_plugin(PluginInstruction::UserInput { - client_id, - action: action.clone(), - terminal_id: None, - cli_client_id: None, - }); + ); + Some(( + s.senders.clone(), + s.default_shell.clone(), + s.session_configuration + .get_client_default_input_mode(&client_id), + actions, + )) + }); + if let Some((senders, default_shell, client_input_mode, actions)) = + dispatch_inputs + { + for action in actions { + // Send user input to plugin thread for logging + let _ = senders.send_to_plugin(PluginInstruction::UserInput { + client_id, + action: action.clone(), + terminal_id: None, + cli_client_id: None, + }); - match route_action( - action, - client_id, - None, - None, - senders.clone(), - capabilities, - client_attributes.clone(), - default_shell.clone(), - layout, - Some(&mut seen_cli_pipes), - keybinds, - client_input_mode, - Some(os_input.clone()), - ) { - Ok(route_action_should_break) => { - if route_action_should_break.0 { - should_break = true; - } - }, - Err(e) => { - log::error!("{}", e); - }, - } + match route_action( + action, + client_id, + None, + None, + senders.clone(), + default_shell.clone(), + Some(&mut seen_cli_pipes), + client_input_mode, + Some(os_input.clone()), + ) { + Ok(route_action_should_break) => { + if route_action_should_break.0 { + should_break = true; + } + }, + Err(e) => { + log::error!("{}", e); + }, } } } @@ -2361,28 +2322,20 @@ pub(crate) fn route_thread_main( }); } - let session_data_guard = session_data.read().unwrap(); - let session_data_assets = session_data_guard.as_ref().map(|s| { - ( - s.senders.clone(), - s.capabilities.clone(), - s.client_attributes.clone(), - s.default_shell.clone(), - &*s.layout, - s.session_configuration - .get_client_default_input_mode(&client_id), - s.session_configuration.get_client_keybinds(&client_id), - ) - }); - if let Some(( - senders, - capabilities, - client_attributes, - default_shell, - layout, - client_input_mode, - client_keybinds, - )) = session_data_assets + // The read guard ends as a temporary in this expression so + // `route_action` runs without holding `session_data.read()` — + // see the doc comment on `route_action` for why this matters. + let session_data_assets = + session_data.read().unwrap().as_ref().map(|s| { + ( + s.senders.clone(), + s.default_shell.clone(), + s.session_configuration + .get_client_default_input_mode(&client_id), + ) + }); + if let Some((senders, default_shell, client_input_mode)) = + session_data_assets { match route_action( action, @@ -2390,12 +2343,8 @@ pub(crate) fn route_thread_main( Some(cli_client_id), maybe_pane_id.map(|p| PaneId::Terminal(p)), senders, - capabilities, - client_attributes, default_shell, - layout, Some(&mut seen_cli_pipes), - client_keybinds, client_input_mode, Some(os_input.clone()), ) { diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index c12b060d..ea2ca4a3 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -445,12 +445,16 @@ pub enum ScreenInstruction { Option<TiledPaneLayout>, Vec<FloatingPaneLayout>, Option<String>, - (Vec<SwapTiledLayout>, Vec<SwapFloatingLayout>), // swap layouts - Option<Vec<CommandOrPlugin>>, // initial_panes - bool, // block_on_first_terminal - bool, // should_change_focus_to_new_tab - (ClientId, bool), // bool -> is_web_client - Option<NotificationEnd>, // completion signal + // `None` falls back to `Screen::default_layout`'s swap layouts. + ( + Option<Vec<SwapTiledLayout>>, + Option<Vec<SwapFloatingLayout>>, + ), + Option<Vec<CommandOrPlugin>>, // initial_panes + bool, // block_on_first_terminal + bool, // should_change_focus_to_new_tab + (ClientId, bool), // bool -> is_web_client + Option<NotificationEnd>, // completion signal ), /// Apply layout to tab with given stable ID. /// @@ -475,8 +479,7 @@ pub enum ScreenInstruction { GoToTab(u32, Option<ClientId>, Option<NotificationEnd>), // this Option is a hacky workaround, please do not copy this behaviour GoToTabName( String, - (Vec<SwapTiledLayout>, Vec<SwapFloatingLayout>), // swap layouts - Option<TerminalAction>, // default_shell + Option<TerminalAction>, // default_shell bool, Option<ClientId>, Option<NotificationEnd>, @@ -547,8 +550,13 @@ pub enum ScreenInstruction { SetDarkTheme(Option<NotificationEnd>), SetLightTheme(Option<NotificationEnd>), ToggleTheme(Option<NotificationEnd>), - ChangeMode(ModeInfo, ClientId, Option<NotificationEnd>), - ChangeModeForAllClients(ModeInfo, Option<NotificationEnd>), + ChangeMode( + InputMode, + Option<InputMode>, + ClientId, + Option<NotificationEnd>, + ), + ChangeModeForAllClients(InputMode, Option<InputMode>, Option<NotificationEnd>), MouseEvent(MouseEvent, ClientId, Option<NotificationEnd>), Copy(ClientId, Option<NotificationEnd>), AddClient( @@ -679,12 +687,7 @@ pub enum ScreenInstruction { u32, // u32 - plugin_id PluginPermission, ), - BreakPane( - Box<Layout>, - Option<TerminalAction>, - ClientId, - Option<NotificationEnd>, - ), + BreakPane(Option<TerminalAction>, ClientId, Option<NotificationEnd>), BreakPaneRight(ClientId, Option<NotificationEnd>), BreakPaneLeft(ClientId, Option<NotificationEnd>), UpdateSessionInfos( @@ -3749,23 +3752,28 @@ impl Screen { Ok(()) } - pub fn change_mode(&mut self, mut mode_info: ModeInfo, client_id: ClientId) -> Result<()> { + pub fn change_mode( + &mut self, + new_mode: InputMode, + base_mode: Option<InputMode>, + client_id: ClientId, + ) -> Result<()> { + let mut mode_info = self + .mode_info + .get(&client_id) + .cloned() + .unwrap_or_else(|| self.default_mode_info.clone()); + let previous_mode = mode_info.mode; + mode_info.mode = new_mode; + mode_info.base_mode = base_mode; if mode_info.session_name.as_ref() != Some(&self.session_name) { mode_info.session_name = Some(self.session_name.clone()); } - let previous_mode_info = self - .mode_info - .get(&client_id) - .unwrap_or(&self.default_mode_info); - let previous_mode = previous_mode_info.mode; - mode_info.style = previous_mode_info.style; - mode_info.capabilities = previous_mode_info.capabilities; - let err_context = || { format!( "failed to change from mode '{:?}' to mode '{:?}' for client {client_id}", - previous_mode, mode_info.mode + previous_mode, new_mode ) }; @@ -3829,17 +3837,21 @@ impl Screen { } Ok(()) } - pub fn change_mode_for_all_clients(&mut self, mode_info: ModeInfo) -> Result<()> { + pub fn change_mode_for_all_clients( + &mut self, + new_mode: InputMode, + base_mode: Option<InputMode>, + ) -> Result<()> { let err_context = || { format!( "failed to change input mode to {:?} for all clients", - mode_info.mode + new_mode ) }; let connected_client_ids: Vec<ClientId> = self.active_tab_ids.keys().copied().collect(); for client_id in connected_client_ids { - self.change_mode(mode_info.clone(), client_id) + self.change_mode(new_mode, base_mode, client_id) .with_context(err_context)?; } Ok(()) @@ -4561,6 +4573,11 @@ impl Screen { self.default_mode_info.update_theme(theme); self.default_mode_info .update_rounded_corners(rounded_corners); + // `default_mode_info` is the fallback used by `change_mode` for + // clients that don't yet have a per-client `mode_info` entry, so its + // keybinds and base mode must be kept in sync with reconfigures. + self.default_mode_info.update_keybinds(new_keybinds.clone()); + self.default_mode_info.update_default_mode(new_default_mode); self.default_shell = default_shell.clone().unwrap_or_else(|| get_default_shell()); self.default_editor = default_editor.clone().or_else(|| get_default_editor()); self.auto_layout = auto_layout; @@ -7017,7 +7034,7 @@ pub(crate) fn screen_thread_main( layout, floating_panes_layout, tab_name, - swap_layouts, + (swap_tiled_layouts, swap_floating_layouts), initial_panes, block_on_first_terminal, should_change_focus_to_new_tab, @@ -7031,9 +7048,15 @@ pub(crate) fn screen_thread_main( } else { None }; + let resolved_swap_layouts = ( + swap_tiled_layouts + .unwrap_or_else(|| screen.default_layout.swap_tiled_layouts.clone()), + swap_floating_layouts + .unwrap_or_else(|| screen.default_layout.swap_floating_layouts.clone()), + ); screen.new_tab( tab_index, - swap_layouts, + resolved_swap_layouts, tab_name.clone(), client_id_for_new_tab, )?; @@ -7194,12 +7217,15 @@ pub(crate) fn screen_thread_main( }, ScreenInstruction::GoToTabName( tab_name, - swap_layouts, default_shell, create, client_id, mut completion_tx, ) => { + let swap_layouts = ( + screen.default_layout.swap_tiled_layouts.clone(), + screen.default_layout.swap_floating_layouts.clone(), + ); let client_id = if client_id.is_none() { None } else if screen @@ -7358,20 +7384,22 @@ pub(crate) fn screen_thread_main( screen.apply_manual_host_terminal_theme_mode(next, &mut completion_tx)?; }, ScreenInstruction::ChangeMode( - mode_info, + input_mode, + base_mode, client_id, _completion_tx, // the action ends here, dropping this will release anything // waiting for it ) => { - screen.change_mode(mode_info, client_id)?; + screen.change_mode(input_mode, base_mode, client_id)?; screen.render(None)?; }, ScreenInstruction::ChangeModeForAllClients( - mode_info, + input_mode, + base_mode, _completion_tx, // the action ends here, dropping this will release anything // waiting for it ) => { - screen.change_mode_for_all_clients(mode_info)?; + screen.change_mode_for_all_clients(input_mode, base_mode)?; screen.render(None)?; }, ScreenInstruction::ToggleActiveSyncTab( @@ -8552,12 +8580,12 @@ pub(crate) fn screen_thread_main( } }, ScreenInstruction::BreakPane( - default_layout, default_shell, client_id, _completion_tx, // the action ends here, dropping this will release anything // waiting for it ) => { + let default_layout = screen.default_layout.clone(); screen.break_pane(default_shell, default_layout, client_id)?; }, ScreenInstruction::BreakPaneRight( diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index e31816d3..3d2efa8a 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -39,10 +39,7 @@ use zellij_utils::ipc::PixelDimensions; use interprocess::local_socket::Stream as LocalSocketStream; use zellij_utils::{ channels::{self, ChannelWithContext, Receiver}, - data::{ - Direction, FloatingPaneCoordinates, InputMode, ModeInfo, NewPanePlacement, Palette, - PluginCapabilities, - }, + data::{Direction, FloatingPaneCoordinates, InputMode, ModeInfo, NewPanePlacement, Palette}, ipc::{ClientAttributes, ClientToServerMsg, ServerToClientMsg}, }; @@ -128,20 +125,13 @@ fn send_cli_action_to_server( 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()); let default_mode = session_metadata .session_configuration .get_client_configuration(&client_id) .options .default_mode .unwrap_or(InputMode::Normal); - let client_keybinds = session_metadata - .session_configuration - .get_client_keybinds(&client_id) - .clone(); for action in actions { route_action( action, @@ -149,12 +139,8 @@ fn send_cli_action_to_server( None, None, senders.clone(), - capabilities, - client_attributes.clone(), default_shell.clone(), - &default_layout, None, - &client_keybinds, default_mode, None, ) @@ -424,8 +410,8 @@ impl MockScreen { Some(pane_layout.clone()), initial_floating_panes_layout.clone(), tab_name, - (vec![], vec![]), // swap layouts - None, // initial_panes + (Some(vec![]), Some(vec![])), // swap layouts (None would fall back to Screen::default_layout) + None, // initial_panes false, should_change_focus_to_new_tab, (self.main_client_id, false), @@ -517,8 +503,8 @@ impl MockScreen { Some(pane_layout.clone()), initial_floating_panes_layout.clone(), tab_name, - (vec![], vec![]), // swap layouts - None, // initial_panes + (Some(vec![]), Some(vec![])), // swap layouts (None would fall back to Screen::default_layout) + None, // initial_panes false, should_change_focus_to_new_tab, (self.main_client_id, false), @@ -556,8 +542,8 @@ impl MockScreen { Some(tab_layout.clone()), vec![], // floating_panes_layout tab_name, - (vec![], vec![]), // swap layouts - None, // initial_panes + (Some(vec![]), Some(vec![])), // swap layouts (None would fall back to Screen::default_layout) + None, // initial_panes false, should_change_focus_to_new_tab, (self.main_client_id, false), @@ -604,8 +590,8 @@ impl MockScreen { Some(tab_layout.clone()), vec![], // floating_panes_layout tab_name, - (vec![], vec![]), // swap layouts - None, // initial_panes + (Some(vec![]), Some(vec![])), // swap layouts (None would fall back to Screen::default_layout) + None, // initial_panes false, should_change_focus_to_new_tab, (self.main_client_id, false), @@ -638,11 +624,8 @@ impl MockScreen { } pub fn clone_session_metadata(&self) -> SessionMetaData { // hack that only clones the clonable parts of SessionMetaData - let layout = Box::new(Layout::default()); // this is not actually correct!! SessionMetaData { senders: self.session_metadata.senders.clone(), - capabilities: self.session_metadata.capabilities.clone(), - client_attributes: self.session_metadata.client_attributes.clone(), default_shell: self.session_metadata.default_shell.clone(), screen_thread: None, pty_thread: None, @@ -650,7 +633,6 @@ impl MockScreen { pty_writer_thread: None, background_jobs_thread: None, session_configuration: self.session_metadata.session_configuration.clone(), - layout, current_input_modes: self.session_metadata.current_input_modes.clone(), web_sharing: WebSharing::Off, config_file_path: self.session_metadata.config_file_path.clone(), @@ -686,11 +668,7 @@ impl MockScreen { size, ..Default::default() }; - let capabilities = PluginCapabilities { - arrow_fonts: Default::default(), - }; - let layout = Box::new(Layout::default()); // this is not actually correct!! let session_metadata = SessionMetaData { senders: ThreadSenders { to_screen: Some(to_screen.clone()), @@ -701,15 +679,12 @@ impl MockScreen { to_server: Some(to_server.clone()), should_silently_fail: true, }, - capabilities, default_shell: None, - client_attributes: client_attributes.clone(), screen_thread: None, pty_thread: None, plugin_thread: None, pty_writer_thread: None, background_jobs_thread: None, - layout, session_configuration: Default::default(), current_input_modes: HashMap::new(), web_sharing: WebSharing::Off, @@ -4277,12 +4252,9 @@ pub fn screen_can_break_pane_to_a_new_tab() { server_receiver ); - let _ = mock_screen.to_screen.send(ScreenInstruction::BreakPane( - Box::new(Layout::default()), - Default::default(), - 1, - None, - )); + let _ = mock_screen + .to_screen + .send(ScreenInstruction::BreakPane(Default::default(), 1, None)); std::thread::sleep(std::time::Duration::from_millis(100)); // we send ApplyLayout, because in prod this is eventually received after the message traverses // through the plugin and pty threads (to open extra stuff we need in the layout, eg. the @@ -4338,12 +4310,9 @@ pub fn screen_cannot_break_last_selectable_pane_to_a_new_tab() { server_receiver ); - let _ = mock_screen.to_screen.send(ScreenInstruction::BreakPane( - Box::new(Layout::default()), - Default::default(), - 1, - None, - )); + let _ = mock_screen + .to_screen + .send(ScreenInstruction::BreakPane(Default::default(), 1, None)); std::thread::sleep(std::time::Duration::from_millis(100)); mock_screen.teardown(vec![server_thread, screen_thread]); @@ -4382,12 +4351,9 @@ pub fn screen_can_break_floating_pane_to_a_new_tab() { server_receiver ); - let _ = mock_screen.to_screen.send(ScreenInstruction::BreakPane( - Box::new(Layout::default()), - Default::default(), - 1, - None, - )); + let _ = mock_screen + .to_screen + .send(ScreenInstruction::BreakPane(Default::default(), 1, None)); std::thread::sleep(std::time::Duration::from_millis(100)); // we send ApplyLayout, because in prod this is eventually received after the message traverses // through the plugin and pty threads (to open extra stuff we need in the layout, eg. the @@ -4547,12 +4513,9 @@ pub fn screen_can_break_plugin_pane_to_a_new_tab() { server_receiver ); - let _ = mock_screen.to_screen.send(ScreenInstruction::BreakPane( - Box::new(Layout::default()), - Default::default(), - 1, - None, - )); + let _ = mock_screen + .to_screen + .send(ScreenInstruction::BreakPane(Default::default(), 1, None)); std::thread::sleep(std::time::Duration::from_millis(100)); // we send ApplyLayout, because in prod this is eventually received after the message traverses // through the plugin and pty threads (to open extra stuff we need in the layout, eg. the @@ -4623,12 +4586,9 @@ pub fn screen_can_break_floating_plugin_pane_to_a_new_tab() { server_receiver ); - let _ = mock_screen.to_screen.send(ScreenInstruction::BreakPane( - Box::new(Layout::default()), - Default::default(), - 1, - None, - )); + let _ = mock_screen + .to_screen + .send(ScreenInstruction::BreakPane(Default::default(), 1, None)); std::thread::sleep(std::time::Duration::from_millis(100)); // we send ApplyLayout, because in prod this is eventually received after the message traverses // through the plugin and pty threads (to open extra stuff we need in the layout, eg. the @@ -4691,12 +4651,9 @@ pub fn screen_can_move_pane_to_a_new_tab_right() { server_receiver ); - let _ = mock_screen.to_screen.send(ScreenInstruction::BreakPane( - Box::new(Layout::default()), - Default::default(), - 1, - None, - )); + let _ = mock_screen + .to_screen + .send(ScreenInstruction::BreakPane(Default::default(), 1, None)); std::thread::sleep(std::time::Duration::from_millis(100)); let _ = mock_screen.to_screen.send(ScreenInstruction::ApplyLayout( @@ -4754,12 +4711,9 @@ pub fn screen_can_move_pane_to_a_new_tab_left() { server_receiver ); - let _ = mock_screen.to_screen.send(ScreenInstruction::BreakPane( - Box::new(Layout::default()), - Default::default(), - 1, - None, - )); + let _ = mock_screen + .to_screen + .send(ScreenInstruction::BreakPane(Default::default(), 1, None)); let _ = mock_screen.to_screen.send(ScreenInstruction::ApplyLayout( TiledPaneLayout::default(), Default::default(), |
