Skip to main content

agent_air_tui/commands/
custom.rs

1//! Custom command helper for closure-based commands.
2
3use super::context::CommandContext;
4use super::result::CommandResult;
5use super::traits::SlashCommand;
6
7/// Closure type for custom command handlers.
8pub type CommandHandlerFn = Box<dyn Fn(&str, &mut CommandContext) -> CommandResult + Send + Sync>;
9
10/// A simple custom command using a closure.
11///
12/// Use this for commands that don't need internal state.
13/// For stateful commands, implement [`SlashCommand`] directly.
14///
15/// # Example
16///
17/// ```ignore
18/// use agent_air::tui::commands::{CustomCommand, CommandResult};
19///
20/// let cmd = CustomCommand::new(
21///     "greet",
22///     "Say hello to someone",
23///     |args, ctx| {
24///         let name = if args.is_empty() { "World" } else { args };
25///         CommandResult::Message(format!("Hello, {}!", name))
26///     },
27/// );
28/// ```
29pub struct CustomCommand {
30    name: String,
31    description: String,
32    handler: CommandHandlerFn,
33}
34
35impl CustomCommand {
36    /// Create a new custom command.
37    ///
38    /// # Arguments
39    /// * `name` - Command name without the leading slash
40    /// * `description` - Short description shown in the popup
41    /// * `handler` - Closure that executes the command
42    pub fn new<F>(name: impl Into<String>, description: impl Into<String>, handler: F) -> Self
43    where
44        F: Fn(&str, &mut CommandContext) -> CommandResult + Send + Sync + 'static,
45    {
46        Self {
47            name: name.into(),
48            description: description.into(),
49            handler: Box::new(handler),
50        }
51    }
52}
53
54impl SlashCommand for CustomCommand {
55    fn name(&self) -> &str {
56        &self.name
57    }
58
59    fn description(&self) -> &str {
60        &self.description
61    }
62
63    fn execute(&self, args: &str, ctx: &mut CommandContext) -> CommandResult {
64        (self.handler)(args, ctx)
65    }
66}