Skip to main content

ratatui_action/
invocation.rs

1//! Resolved arguments and invocation requests.
2//!
3//! Use this module at the dispatch boundary:
4//!
5//! - [`ActionArgs`] stores resolved input values keyed by [`InputId`].
6//! - [`ActionInvocation`] names the action, carries resolved arguments, and records source.
7//! - [`InvocationSource`] identifies the UI or integration that requested the action.
8
9use std::collections::BTreeMap;
10
11use crate::id::{ActionId, InputId};
12
13/// Resolved arguments for an action invocation.
14///
15/// Arguments are keyed by [`InputId`] so dispatch code can read values without
16/// knowing which UI surface collected them.
17///
18/// Method groups:
19///
20/// - **Construction and mutation:** [`new`](Self::new) and [`insert`](Self::insert).
21/// - **Inspection:** [`get`](Self::get), [`iter`](Self::iter), and [`is_empty`](Self::is_empty).
22///
23/// # Examples
24///
25/// ```
26/// use ratatui_action::id::InputId;
27/// use ratatui_action::invocation::ActionArgs;
28///
29/// let mut args = ActionArgs::new();
30/// args.insert("theme", "github-dark");
31///
32/// assert_eq!(args.get(&InputId::new("theme")), Some("github-dark"));
33/// assert!(!args.is_empty());
34/// ```
35#[derive(Clone, Debug, Default, PartialEq, Eq)]
36pub struct ActionArgs {
37    values: BTreeMap<InputId, String>,
38}
39
40impl ActionArgs {
41    /// Creates an empty argument set.
42    pub fn new() -> Self {
43        Self::default()
44    }
45
46    /// Inserts or replaces an argument value.
47    pub fn insert(&mut self, id: impl Into<InputId>, value: impl Into<String>) -> Option<String> {
48        self.values.insert(id.into(), value.into())
49    }
50
51    /// Returns an argument value by input id.
52    pub fn get(&self, id: &InputId) -> Option<&str> {
53        self.values.get(id).map(String::as_str)
54    }
55
56    /// Iterates over resolved argument values in input-id order.
57    pub fn iter(&self) -> impl Iterator<Item = (&InputId, &str)> {
58        self.values
59            .iter()
60            .map(|(input, value)| (input, value.as_str()))
61    }
62
63    /// Returns true when no argument values have been resolved.
64    pub fn is_empty(&self) -> bool {
65        self.values.is_empty()
66    }
67}
68
69/// A request for the application to run an action.
70///
71/// Invocation is the handoff point between a UI surface and application-owned
72/// dispatch. The action crate does not execute callbacks or mutate application
73/// state.
74///
75/// Use [`new`](Self::new) for actions without arguments and [`with_args`](Self::with_args) when a
76/// UI surface has collected inputs. Dispatch code usually reads [`id`](Self::id),
77/// [`args`](Self::args), and [`source`](Self::source).
78///
79/// # Examples
80///
81/// ```
82/// use ratatui_action::id::InputId;
83/// use ratatui_action::invocation::{ActionArgs, ActionInvocation, InvocationSource};
84///
85/// let mut args = ActionArgs::new();
86/// args.insert(InputId::new("theme"), "github-dark");
87///
88/// let invocation = ActionInvocation::with_args("theme.switch", args, InvocationSource::Palette);
89///
90/// assert_eq!(invocation.id().as_str(), "theme.switch");
91/// assert_eq!(invocation.source(), InvocationSource::Palette);
92/// ```
93#[derive(Clone, Debug, PartialEq, Eq)]
94pub struct ActionInvocation {
95    id: ActionId,
96    args: ActionArgs,
97    source: InvocationSource,
98}
99
100impl ActionInvocation {
101    /// Creates an invocation with no arguments.
102    pub fn new(id: impl Into<ActionId>, source: InvocationSource) -> Self {
103        Self {
104            id: id.into(),
105            args: ActionArgs::new(),
106            source,
107        }
108    }
109
110    /// Creates an invocation with resolved arguments.
111    pub fn with_args(id: impl Into<ActionId>, args: ActionArgs, source: InvocationSource) -> Self {
112        Self {
113            id: id.into(),
114            args,
115            source,
116        }
117    }
118
119    /// Returns the action identifier to invoke.
120    pub fn id(&self) -> &ActionId {
121        &self.id
122    }
123
124    /// Returns resolved invocation arguments.
125    pub fn args(&self) -> &ActionArgs {
126        &self.args
127    }
128
129    /// Returns the surface that requested this invocation.
130    pub fn source(&self) -> InvocationSource {
131        self.source
132    }
133}
134
135/// UI or integration surface that requested an action invocation.
136///
137/// The source lets dispatch code distinguish user intent from a palette,
138/// keybinding, menu, mouse action, or automation path when that distinction
139/// affects behavior or telemetry.
140///
141/// Match this enum when dispatch needs different policy for palette, keybinding,
142/// menu, mouse, or automation callers.
143#[derive(Clone, Copy, Debug, PartialEq, Eq)]
144pub enum InvocationSource {
145    /// Invocation came from a command palette.
146    Palette,
147    /// Invocation came from a keybinding.
148    KeyBinding,
149    /// Invocation came from a menu item.
150    Menu,
151    /// Invocation came from a mouse interaction.
152    Mouse,
153    /// Invocation came from automation or a non-interactive integration.
154    Automation,
155}