embedded_cli/
help.rs

1use crate::{arguments::Arg, command::RawCommand};
2
3#[derive(Clone, Debug, Eq, PartialEq)]
4pub enum HelpRequest<'a> {
5    /// Show list of all available commands
6    All,
7
8    /// Show help for specific command with arguments
9    /// One of command arguments might be -h or --help
10    Command(RawCommand<'a>),
11}
12
13impl<'a> HelpRequest<'a> {
14    /// Tries to create new help request from raw command
15    pub fn from_command(command: &RawCommand<'a>) -> Option<Self> {
16        let mut args = command.args().args();
17        if command.name() == "help" {
18            match args.next() {
19                Some(Ok(Arg::Value(name))) => {
20                    let command = RawCommand::new(name, args.into_args());
21                    Some(HelpRequest::Command(command))
22                }
23                None => Some(HelpRequest::All),
24                _ => None,
25            }
26        }
27        // check if any other option is -h or --help
28        else if args
29            .any(|arg| arg == Ok(Arg::LongOption("help")) || arg == Ok(Arg::ShortOption('h')))
30        {
31            Some(HelpRequest::Command(command.clone()))
32        } else {
33            None
34        }
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use rstest::rstest;
41
42    use crate::{arguments::ArgList, command::RawCommand, token::Tokens};
43
44    use super::HelpRequest;
45
46    fn help_command(name: &'static str, args: &'static str) -> HelpRequest<'static> {
47        HelpRequest::Command(RawCommand::new(
48            name,
49            ArgList::new(Tokens::from_raw(args, args.is_empty())),
50        ))
51    }
52
53    #[rstest]
54    #[case("help", HelpRequest::All)]
55    #[case("help cmd1", help_command("cmd1", ""))]
56    #[case("cmd2 --help", help_command("cmd2", "--help"))]
57    #[case(
58        "cmd3 -v --opt --help --some",
59        help_command("cmd3", "-v\0--opt\0--help\0--some")
60    )]
61    #[case("cmd3 -vh --opt --some", help_command("cmd3", "-vh\0--opt\0--some"))]
62    #[case("cmd3 -hv --opt --some", help_command("cmd3", "-hv\0--opt\0--some"))]
63    fn parsing_ok(#[case] input: &str, #[case] expected: HelpRequest<'_>) {
64        let mut input = input.as_bytes().to_vec();
65        let input = core::str::from_utf8_mut(&mut input).unwrap();
66        let tokens = Tokens::new(input);
67        let command = RawCommand::from_tokens(&tokens).unwrap();
68
69        assert_eq!(HelpRequest::from_command(&command), Some(expected));
70    }
71
72    #[rstest]
73    #[case("cmd1")]
74    #[case("cmd1 help")]
75    #[case("--help")]
76    fn parsing_err(#[case] input: &str) {
77        let mut input = input.as_bytes().to_vec();
78        let input = core::str::from_utf8_mut(&mut input).unwrap();
79        let tokens = Tokens::new(input);
80        let command = RawCommand::from_tokens(&tokens).unwrap();
81        let res = HelpRequest::from_command(&command);
82
83        assert!(res.is_none());
84    }
85}