diff --git a/zellij-server/src/plugins/mod.rs b/zellij-server/src/plugins/mod.rs index 55e97f0319..7791880f27 100644 --- a/zellij-server/src/plugins/mod.rs +++ b/zellij-server/src/plugins/mod.rs @@ -5,7 +5,11 @@ mod wasm_bridge; mod watch_filesystem; mod zellij_exports; use log::info; -use std::{collections::HashMap, fs, path::PathBuf}; +use std::{ + collections::{HashMap, HashSet}, + fs, + path::PathBuf, +}; use wasmer::Store; use crate::screen::ScreenInstruction; @@ -14,7 +18,7 @@ use crate::{pty::PtyInstruction, thread_bus::Bus, ClientId, ServerInstruction}; use wasm_bridge::WasmBridge; use zellij_utils::{ - data::{Event, PluginCapabilities}, + data::{Event, EventType, PluginCapabilities}, errors::{prelude::*, ContextType, PluginContext}, input::{ command::TerminalAction, @@ -74,6 +78,7 @@ pub enum PluginInstruction { String, // serialized message String, // serialized payload ), + PluginSubscribedToEvents(PluginId, ClientId, HashSet), Exit, } @@ -97,6 +102,9 @@ impl From<&PluginInstruction> for PluginContext { PluginContext::PostMessageToPluginWorker }, PluginInstruction::PostMessageToPlugin(..) => PluginContext::PostMessageToPlugin, + PluginInstruction::PluginSubscribedToEvents(..) => { + PluginContext::PluginSubscribedToEvents + }, } } } @@ -267,6 +275,17 @@ pub(crate) fn plugin_thread_main( )]; wasm_bridge.update_plugins(updates)?; }, + PluginInstruction::PluginSubscribedToEvents(_plugin_id, _client_id, events) => { + for event in events { + if let EventType::FileSystemCreate + | EventType::FileSystemRead + | EventType::FileSystemUpdate + | EventType::FileSystemDelete = event + { + wasm_bridge.start_fs_watcher_if_not_started(); + } + } + }, PluginInstruction::Exit => { wasm_bridge.cleanup(); break; diff --git a/zellij-server/src/plugins/unit/plugin_tests.rs b/zellij-server/src/plugins/unit/plugin_tests.rs index f15ac1262a..6084c9fe97 100644 --- a/zellij-server/src/plugins/unit/plugin_tests.rs +++ b/zellij-server/src/plugins/unit/plugin_tests.rs @@ -553,7 +553,7 @@ pub fn can_subscribe_to_hd_events() { received_screen_instructions, ScreenInstruction::PluginBytes, screen_receiver, - 3 + 2 ); let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); @@ -565,12 +565,8 @@ pub fn can_subscribe_to_hd_events() { client_id, size, )); - let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( - None, - Some(client_id), - Event::InputReceived, - )])); // will be cached and sent to the plugin once it's loaded - std::thread::sleep(std::time::Duration::from_millis(100)); + // extra long time because we only start the fs watcher on plugin load + std::thread::sleep(std::time::Duration::from_millis(5000)); std::fs::OpenOptions::new() .create(true) .write(true) diff --git a/zellij-server/src/plugins/wasm_bridge.rs b/zellij-server/src/plugins/wasm_bridge.rs index 319b26cd2d..0e53ce41e5 100644 --- a/zellij-server/src/plugins/wasm_bridge.rs +++ b/zellij-server/src/plugins/wasm_bridge.rs @@ -75,13 +75,7 @@ impl WasmBridge { let connected_clients: Arc>> = Arc::new(Mutex::new(vec![])); let plugin_cache: Arc>> = Arc::new(Mutex::new(HashMap::new())); - let watcher = match watch_filesystem(senders.clone(), &zellij_cwd) { - Ok(watcher) => Some(watcher), - Err(e) => { - log::error!("Failed to watch filesystem: {:?}", e); - None - }, - }; + let watcher = None; WasmBridge { connected_clients, plugins, @@ -697,6 +691,17 @@ impl WasmBridge { } Ok(()) } + pub fn start_fs_watcher_if_not_started(&mut self) { + if self.watcher.is_none() { + self.watcher = match watch_filesystem(self.senders.clone(), &self.zellij_cwd) { + Ok(watcher) => Some(watcher), + Err(e) => { + log::error!("Failed to watch filesystem: {:?}", e); + None + }, + }; + } + } } fn handle_plugin_successful_loading(senders: &ThreadSenders, plugin_id: PluginId) { diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs index f0c7ba1b9d..d4153ec8a0 100644 --- a/zellij-server/src/plugins/zellij_exports.rs +++ b/zellij-server/src/plugins/zellij_exports.rs @@ -26,7 +26,7 @@ use zellij_utils::{ input::{ actions::Action, command::{RunCommand, RunCommandAction, TerminalAction}, - layout::{Layout, RunPlugin, RunPluginLocation}, + layout::Layout, plugins::PluginType, }, serde, @@ -146,8 +146,17 @@ impl ForeignFunctionEnv { fn host_subscribe(env: &ForeignFunctionEnv) { wasi_read_object::>(&env.plugin_env.wasi_env) .and_then(|new| { - env.subscriptions.lock().to_anyhow()?.extend(new); - Ok(()) + env.subscriptions.lock().to_anyhow()?.extend(new.clone()); + Ok(new) + }) + .and_then(|new| { + env.plugin_env + .senders + .send_to_plugin(PluginInstruction::PluginSubscribedToEvents( + env.plugin_env.plugin_id, + env.plugin_env.client_id, + new, + )) }) .with_context(|| format!("failed to subscribe for plugin {}", env.plugin_env.name())) .fatal(); diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index de53d0276b..b70ac4399b 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -929,7 +929,6 @@ impl Screen { self.character_cell_size.clone(), ); let mut tabs_to_close = vec![]; - let size = self.size; for (tab_index, tab) in &mut self.tabs { if tab.has_selectable_tiled_panes() { tab.render(&mut output).context(err_context)?; diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index 239cf5ab8c..78468891d0 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -370,6 +370,7 @@ pub enum PluginContext { ApplyCachedWorkerMessages, PostMessageToPluginWorker, PostMessageToPlugin, + PluginSubscribedToEvents, } /// Stack call representations corresponding to the different types of [`ClientInstruction`]s.