1use cli_rs_command_gen::command;
2use std::fmt::Write;
3use std::str::FromStr;
4
5pub type Command<'a> = Command0<'a>;
6
7pub 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 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);