diff options
author | Aram Drevekenin <aram@poor.dev> | 2024-08-21 15:54:02 +0200 |
---|---|---|
committer | Aram Drevekenin <aram@poor.dev> | 2024-08-21 15:54:02 +0200 |
commit | 7aab852cc8489dd638ba59611ba3a02970203607 (patch) | |
tree | 582ad115cf186ec3a4c47ca2e9bfcf3854652ac0 | |
parent | 905ce0a27d8079b128a860eabf8692dca5911674 (diff) |
feat(plugins): API to temporarily bind keys to send a message to a specific plugin idbind-key-to-message-plugin-id
-rw-r--r-- | zellij-server/src/plugins/mod.rs | 79 | ||||
-rw-r--r-- | zellij-server/src/route.rs | 4 | ||||
-rw-r--r-- | zellij-utils/src/input/actions.rs | 1 | ||||
-rw-r--r-- | zellij-utils/src/kdl/mod.rs | 66 | ||||
-rw-r--r-- | zellij-utils/src/plugin_api/action.rs | 1 |
5 files changed, 117 insertions, 34 deletions
diff --git a/zellij-server/src/plugins/mod.rs b/zellij-server/src/plugins/mod.rs index e1b807ce0..62cc89161 100644 --- a/zellij-server/src/plugins/mod.rs +++ b/zellij-server/src/plugins/mod.rs @@ -134,6 +134,7 @@ pub enum PluginInstruction { cwd: Option<PathBuf>, skip_cache: bool, cli_client_id: ClientId, + plugin_and_client_id: Option<(u32, ClientId)>, }, CachePluginEvents { plugin_id: PluginId, @@ -624,42 +625,52 @@ pub(crate) fn plugin_thread_main( cwd, skip_cache, cli_client_id, + plugin_and_client_id, } => { let should_float = floating.unwrap_or(true); let mut pipe_messages = vec![]; - match plugin { - Some(plugin_url) => { - // send to specific plugin(s) - pipe_to_specific_plugins( - PipeSource::Keybind, - &plugin_url, - &configuration, - &cwd, - skip_cache, - should_float, - &pane_id_to_replace, - &pane_title, - Some(cli_client_id), - &mut pipe_messages, - &name, - &payload, - &args, - &bus, - &mut wasm_bridge, - &plugin_aliases, - ); - }, - None => { - // no specific destination, send to all plugins - pipe_to_all_plugins( - PipeSource::Keybind, - &name, - &payload, - &args, - &mut wasm_bridge, - &mut pipe_messages, - ); - }, + if let Some((plugin_id, client_id)) = plugin_and_client_id { + let is_private = true; + pipe_messages.push(( + Some(plugin_id), + Some(client_id), + PipeMessage::new(PipeSource::Keybind, name, &payload, &args, is_private), + )); + } else { + match plugin { + Some(plugin_url) => { + // send to specific plugin(s) + pipe_to_specific_plugins( + PipeSource::Keybind, + &plugin_url, + &configuration, + &cwd, + skip_cache, + should_float, + &pane_id_to_replace, + &pane_title, + Some(cli_client_id), + &mut pipe_messages, + &name, + &payload, + &args, + &bus, + &mut wasm_bridge, + &plugin_aliases, + ); + }, + None => { + // no specific destination, send to all plugins + pipe_to_all_plugins( + PipeSource::Keybind, + &name, + &payload, + &args, + &mut wasm_bridge, + &mut pipe_messages, + ); + }, + } } wasm_bridge.pipe_messages(pipe_messages, shutdown_send.clone())?; }, @@ -768,6 +779,8 @@ pub(crate) fn plugin_thread_main( keybinds, default_mode, } => { + // TODO: notify plugins that this happened so that they can eg. rebind temporary keys that + // were lost wasm_bridge .reconfigure(client_id, keybinds, default_mode) .non_fatal(); diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index f27266e0e..9da11259a 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -921,12 +921,13 @@ pub(crate) fn route_action( cwd, pane_title, launch_new, + plugin_id, .. } => { if let Some(name) = name.take() { let should_open_in_place = in_place.unwrap_or(false); let pane_id_to_replace = if should_open_in_place { pane_id } else { None }; - if launch_new { + if launch_new && plugin_id.is_none() { // we do this to make sure the plugin is unique (has a unique configuration parameter) configuration .get_or_insert_with(BTreeMap::new) @@ -945,6 +946,7 @@ pub(crate) fn route_action( pane_title, skip_cache, cli_client_id: client_id, + plugin_and_client_id: plugin_id.map(|plugin_id| (plugin_id, client_id)), }) .with_context(err_context)?; } else { diff --git a/zellij-utils/src/input/actions.rs b/zellij-utils/src/input/actions.rs index 81572995b..da1244d3c 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -289,6 +289,7 @@ pub enum Action { payload: Option<String>, args: Option<BTreeMap<String, String>>, plugin: Option<String>, + plugin_id: Option<u32>, // supercedes plugin if present configuration: Option<BTreeMap<String, String>>, launch_new: bool, skip_cache: bool, diff --git a/zellij-utils/src/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs index bfb01c782..dfa1f9ad7 100644 --- a/zellij-utils/src/kdl/mod.rs +++ b/zellij-utils/src/kdl/mod.rs @@ -363,6 +363,27 @@ pub fn kdl_arguments_that_are_strings<'a>( Ok(args) } +pub fn kdl_arguments_that_are_digits<'a>( + arguments: impl Iterator<Item = &'a KdlEntry>, +) -> Result<Vec<i64>, ConfigError> { + let mut args: Vec<i64> = vec![]; + for kdl_entry in arguments { + match kdl_entry.value().as_i64() { + Some(digit_value) => { + args.push(digit_value); + }, + None => { + return Err(ConfigError::new_kdl_error( + format!("Argument must be a digit"), + kdl_entry.span().offset(), + kdl_entry.span().len(), + )); + }, + } + } + Ok(args) +} + pub fn kdl_child_string_value_for_entry<'a>( command_metadata: &'a KdlDocument, entry_name: &'a str, @@ -1010,7 +1031,12 @@ impl Action { in_place, cwd, pane_title, + plugin_id, } => { + if plugin_id.is_some() { + log::warn!("Not serializing temporary keybinding MessagePluginId"); + return None; + } let mut node = KdlNode::new("MessagePlugin"); let mut node_children = KdlDocument::new(); if let Some(plugin) = plugin { @@ -1678,6 +1704,46 @@ impl TryFrom<(&KdlNode, &Options)> for Action { in_place: None, // TODO: support this cwd, pane_title: title, + plugin_id: None, + }) + }, + "MessagePluginId" => { + let arguments = action_arguments.iter().copied(); + let mut args = kdl_arguments_that_are_digits(arguments)?; + let plugin_id = if args.is_empty() { + None + } else { + Some(args.remove(0) as u32) + }; + + let command_metadata = action_children.iter().next(); + let launch_new = false; + let skip_cache = false; + let name = command_metadata + .and_then(|c_m| kdl_child_string_value_for_entry(c_m, "name")) + .map(|n| n.to_owned()); + let payload = command_metadata + .and_then(|c_m| kdl_child_string_value_for_entry(c_m, "payload")) + .map(|p| p.to_owned()); + let configuration = None; + + let name = name + // if no name is provided, we use a uuid to at least have some sort of identifier for this message + .or_else(|| Some(Uuid::new_v4().to_string())); + + Ok(Action::KeybindPipe { + name, + payload, + args: None, // TODO: consider supporting this if there's a need + plugin: None, + configuration, + launch_new, + skip_cache, + floating: None, + in_place: None, // TODO: support this + cwd: None, + pane_title: None, + plugin_id, }) }, _ => Err(ConfigError::new_kdl_error( diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs index a2f5bd760..d61ddcb8d 100644 --- a/zellij-utils/src/plugin_api/action.rs +++ b/zellij-utils/src/plugin_api/action.rs @@ -703,6 +703,7 @@ impl TryFrom<ProtobufAction> for Action { in_place: None, cwd: None, pane_title: None, + plugin_id: None, }), }, _ => Err("Unknown Action"), |