Skip to main content

embassy_shell/
command.rs

1use alloc::boxed::Box;
2use alloc::string::String;
3use alloc::vec::Vec;
4use core::fmt;
5
6use crate::Result;
7use crate::io::{BoxFuture, Io};
8
9/// Arguments of a command invocation: the whitespace-split, quote-unescaped
10/// tokens of the line, excluding the command name itself.
11#[derive(Clone, Copy)]
12pub struct Args<'a> {
13    parts: &'a [String],
14}
15
16impl<'a> Args<'a> {
17    pub(crate) fn new(parts: &'a [String]) -> Self {
18        Args { parts }
19    }
20
21    /// Number of arguments.
22    pub fn len(&self) -> usize {
23        self.parts.len()
24    }
25
26    /// Whether there are no arguments.
27    pub fn is_empty(&self) -> bool {
28        self.parts.is_empty()
29    }
30
31    /// Argument at index `i`, if present.
32    pub fn get(&self, i: usize) -> Option<&str> {
33        self.parts.get(i).map(|s| s.as_str())
34    }
35
36    /// Iterate over the arguments.
37    pub fn iter(&self) -> impl Iterator<Item = &str> {
38        self.parts.iter().map(|s| s.as_str())
39    }
40
41    /// The arguments joined back with single spaces (useful for commands like
42    /// `echo` that consume the rest of the line verbatim).
43    pub fn rest(&self) -> String {
44        let mut out = String::new();
45        for (i, part) in self.parts.iter().enumerate() {
46            if i > 0 {
47                out.push(' ');
48            }
49            out.push_str(part);
50        }
51        out
52    }
53}
54
55impl fmt::Debug for Args<'_> {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        f.debug_list().entries(self.parts).finish()
58    }
59}
60
61/// Signature of a command handler. See [`Shell::add_command`](crate::Shell::add_command).
62pub(crate) type Handler<'a> =
63    Box<dyn for<'x> Fn(Args<'x>, Io<'x>) -> BoxFuture<'x, Result<()>> + 'a>;
64
65/// Signature of a per-command tab completer: called with the index of the
66/// argument being completed (`>= 1`) and the current partial token, returns a
67/// list of candidate replacements for that token.
68pub(crate) type Completer<'a> = Box<dyn Fn(usize, &str) -> Vec<String> + 'a>;
69
70/// How a command completes its arguments. Fixed option lists are stored
71/// directly (no boxed closure, no heap candidates), keeping completion of
72/// `add_command_with_options` commands allocation-free.
73pub(crate) enum CompleterKind<'a> {
74    Options(&'static [&'static str]),
75    Custom(Completer<'a>),
76}
77
78pub(crate) struct Command<'a> {
79    pub name: String,
80    pub help: &'static str,
81    pub handler: Handler<'a>,
82    pub completer: Option<CompleterKind<'a>>,
83}