1 #[macro_use]
2 mod macros;
3 mod bash;
4 mod elvish;
5 mod fish;
6 mod powershell;
7 mod shell;
8 mod zsh;
9 
10 // Std
11 use std::io::Write;
12 
13 // Internal
14 pub use crate::completions::shell::Shell;
15 use crate::{
16     app::parser::Parser,
17     completions::{
18         bash::BashGen, elvish::ElvishGen, fish::FishGen, powershell::PowerShellGen, zsh::ZshGen,
19     },
20 };
21 
22 pub struct ComplGen<'a, 'b>
23 where
24     'a: 'b,
25 {
26     p: &'b Parser<'a, 'b>,
27 }
28 
29 impl<'a, 'b> ComplGen<'a, 'b> {
new(p: &'b Parser<'a, 'b>) -> Self30     pub fn new(p: &'b Parser<'a, 'b>) -> Self {
31         ComplGen { p }
32     }
33 
generate<W: Write>(&self, for_shell: Shell, buf: &mut W)34     pub fn generate<W: Write>(&self, for_shell: Shell, buf: &mut W) {
35         match for_shell {
36             Shell::Bash => BashGen::new(self.p).generate_to(buf),
37             Shell::Fish => FishGen::new(self.p).generate_to(buf),
38             Shell::Zsh => ZshGen::new(self.p).generate_to(buf),
39             Shell::PowerShell => PowerShellGen::new(self.p).generate_to(buf),
40             Shell::Elvish => ElvishGen::new(self.p).generate_to(buf),
41         }
42     }
43 }
44 
45 // Gets all subcommands including child subcommands in the form of 'name' where the name
46 // is a single word (i.e. "install")  of the path to said subcommand (i.e.
47 // "rustup toolchain install")
48 //
49 // Also note, aliases are treated as their own subcommands but duplicates of whatever they're
50 // aliasing.
all_subcommand_names(p: &Parser) -> Vec<String>51 pub fn all_subcommand_names(p: &Parser) -> Vec<String> {
52     debugln!("all_subcommand_names;");
53     let mut subcmds: Vec<_> = subcommands_of(p)
54         .iter()
55         .map(|&(ref n, _)| n.clone())
56         .collect();
57     for sc_v in p.subcommands.iter().map(|s| all_subcommand_names(&s.p)) {
58         subcmds.extend(sc_v);
59     }
60     subcmds.sort();
61     subcmds.dedup();
62     subcmds
63 }
64 
65 // Gets all subcommands including child subcommands in the form of ('name', 'bin_name') where the name
66 // is a single word (i.e. "install") of the path and full bin_name of said subcommand (i.e.
67 // "rustup toolchain install")
68 //
69 // Also note, aliases are treated as their own subcommands but duplicates of whatever they're
70 // aliasing.
all_subcommands(p: &Parser) -> Vec<(String, String)>71 pub fn all_subcommands(p: &Parser) -> Vec<(String, String)> {
72     debugln!("all_subcommands;");
73     let mut subcmds: Vec<_> = subcommands_of(p);
74     for sc_v in p.subcommands.iter().map(|s| all_subcommands(&s.p)) {
75         subcmds.extend(sc_v);
76     }
77     subcmds
78 }
79 
80 // Gets all subcommands excluding child subcommands in the form of (name, bin_name) where the name
81 // is a single word (i.e. "install") and the bin_name is a space delineated list of the path to said
82 // subcommand (i.e. "rustup toolchain install")
83 //
84 // Also note, aliases are treated as their own subcommands but duplicates of whatever they're
85 // aliasing.
subcommands_of(p: &Parser) -> Vec<(String, String)>86 pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> {
87     debugln!(
88         "subcommands_of: name={}, bin_name={}",
89         p.meta.name,
90         p.meta.bin_name.as_ref().unwrap()
91     );
92     let mut subcmds = vec![];
93 
94     debugln!(
95         "subcommands_of: Has subcommands...{:?}",
96         p.has_subcommands()
97     );
98     if !p.has_subcommands() {
99         let mut ret = vec![];
100         debugln!("subcommands_of: Looking for aliases...");
101         if let Some(ref aliases) = p.meta.aliases {
102             for &(n, _) in aliases {
103                 debugln!("subcommands_of:iter:iter: Found alias...{}", n);
104                 let mut als_bin_name: Vec<_> =
105                     p.meta.bin_name.as_ref().unwrap().split(' ').collect();
106                 als_bin_name.push(n);
107                 let old = als_bin_name.len() - 2;
108                 als_bin_name.swap_remove(old);
109                 ret.push((n.to_owned(), als_bin_name.join(" ")));
110             }
111         }
112         return ret;
113     }
114     for sc in &p.subcommands {
115         debugln!(
116             "subcommands_of:iter: name={}, bin_name={}",
117             sc.p.meta.name,
118             sc.p.meta.bin_name.as_ref().unwrap()
119         );
120 
121         debugln!("subcommands_of:iter: Looking for aliases...");
122         if let Some(ref aliases) = sc.p.meta.aliases {
123             for &(n, _) in aliases {
124                 debugln!("subcommands_of:iter:iter: Found alias...{}", n);
125                 let mut als_bin_name: Vec<_> =
126                     p.meta.bin_name.as_ref().unwrap().split(' ').collect();
127                 als_bin_name.push(n);
128                 let old = als_bin_name.len() - 2;
129                 als_bin_name.swap_remove(old);
130                 subcmds.push((n.to_owned(), als_bin_name.join(" ")));
131             }
132         }
133         subcmds.push((
134             sc.p.meta.name.clone(),
135             sc.p.meta.bin_name.as_ref().unwrap().clone(),
136         ));
137     }
138     subcmds
139 }
140 
get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String>141 pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
142     debugln!("get_all_subcommand_paths;");
143     let mut subcmds = vec![];
144     if !p.has_subcommands() {
145         if !first {
146             let name = &*p.meta.name;
147             let path = p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "__");
148             let mut ret = vec![path.clone()];
149             if let Some(ref aliases) = p.meta.aliases {
150                 for &(n, _) in aliases {
151                     ret.push(path.replace(name, n));
152                 }
153             }
154             return ret;
155         }
156         return vec![];
157     }
158     for sc in &p.subcommands {
159         let name = &*sc.p.meta.name;
160         let path =
161             sc.p.meta
162                 .bin_name
163                 .as_ref()
164                 .unwrap()
165                 .clone()
166                 .replace(" ", "__");
167         subcmds.push(path.clone());
168         if let Some(ref aliases) = sc.p.meta.aliases {
169             for &(n, _) in aliases {
170                 subcmds.push(path.replace(name, n));
171             }
172         }
173     }
174     for sc_v in p
175         .subcommands
176         .iter()
177         .map(|s| get_all_subcommand_paths(&s.p, false))
178     {
179         subcmds.extend(sc_v);
180     }
181     subcmds
182 }
183