summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2024-08-21 15:54:02 +0200
committerAram Drevekenin <aram@poor.dev>2024-08-21 15:54:02 +0200
commit7aab852cc8489dd638ba59611ba3a02970203607 (patch)
tree582ad115cf186ec3a4c47ca2e9bfcf3854652ac0
parent905ce0a27d8079b128a860eabf8692dca5911674 (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.rs79
-rw-r--r--zellij-server/src/route.rs4
-rw-r--r--zellij-utils/src/input/actions.rs1
-rw-r--r--zellij-utils/src/kdl/mod.rs66
-rw-r--r--zellij-utils/src/plugin_api/action.rs1
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"),