cli_rs/command/
mod.rs

1use cli_rs_command_gen::command;
2use std::fmt::Write;
3use std::str::FromStr;
4
5pub type Command<'a> = Command0<'a>;
6
7// todo: use CliResult, also in macro
8pub trait ParserInfo {
9    fn docs(&self) -> &DocInfo;
10    fn symbols(&mut self) -> Vec<&mut dyn Input>;
11    fn subcommand_docs(&self) -> Vec<DocInfo>;
12    fn parse_subcommand(&mut self, sub_idx: usize, tokens: &[String]) -> Result<(), CliError>;
13    fn complete_subcommand(
14        &mut self,
15        sub_idx: usize,
16        tokens: &[String],
17    ) -> Result<Vec<CompOut>, CliError>;
18    fn call_handler(&mut self) -> CliResult<()>;
19    fn push_parent(&mut self, parents: &[String]);
20}
21
22#[derive(Default, Debug, Clone)]
23pub struct DocInfo {
24    pub(crate) name: String,
25    pub(crate) version: Option<String>,
26    pub(crate) description: Option<String>,
27    pub(crate) parents: Vec<String>,
28}
29
30impl DocInfo {
31    pub fn cmd_path(&self) -> String {
32        let mut path = String::new();
33        for parent in &self.parents {
34            write!(path, "{parent} ").unwrap();
35        }
36
37        write!(path, "{}", self.name).unwrap();
38        path
39    }
40}
41
42#[derive(PartialEq, Copy, Clone, Debug)]
43pub enum CompletionMode {
44    Bash,
45    Fish,
46    Zsh,
47}
48
49impl FromStr for CompletionMode {
50    type Err = ();
51
52    fn from_str(s: &str) -> Result<Self, Self::Err> {
53        match s.to_lowercase().as_str() {
54            "bash" => Ok(Self::Bash),
55            "zsh" => Ok(Self::Zsh),
56            "fish" => Ok(Self::Fish),
57            _ => panic!("unsuppored shell, choices are bash, zsh, and fish"),
58        }
59    }
60}
61
62impl CompletionMode {
63    // thanks @ad-tra
64    pub fn print_completion(&self, name: &str) {
65        let adapter = match self {
66            CompletionMode::Bash => {
67                format!(
68                    r#"
69_{name}_complete_()
70{{
71    _COMP_OUTPUTSTR="$( {name} complete bash ${{COMP_CWORD}} "${{COMP_WORDS[*]}}" )"
72    if test $? -ne 0; then
73        return 1
74    fi
75    COMPREPLY=($( echo -n "$_COMP_OUTPUTSTR" ))
76}}
77complete -o nospace -F _{name}_complete_ {name} -E
78                        "#
79                )
80            }
81            CompletionMode::Fish => format!(
82                r#"complete -c {name} -f --condition "not __fish_seen_subcommand_from file-command non-file-command" -a '({name} complete fish 0 (commandline -cp))'"#
83            ),
84            CompletionMode::Zsh => format!(
85                r#"#compdef {name}
86function _{name} {{
87    comp_output=$( {name} complete zsh "$(($CURRENT - 1))" "${{words[*]}}" )
88    eval ${{comp_output}}
89}}
90"#
91            ),
92        };
93
94        println!("{adapter}");
95    }
96}
97
98use crate::{
99    arg::Arg,
100    cli_error::{CliError, CliResult},
101    input::Input,
102    parser::{Cmd, CompOut},
103};
104
105command!(0);
106command!(1);
107command!(2);
108command!(3);
109command!(4);
110command!(5);
111command!(6);