diff options
Diffstat (limited to 'clap/src/completions')
-rw-r--r-- | clap/src/completions/bash.rs | 219 | ||||
-rw-r--r-- | clap/src/completions/elvish.rs | 126 | ||||
-rw-r--r-- | clap/src/completions/fish.rs | 99 | ||||
-rw-r--r-- | clap/src/completions/macros.rs | 28 | ||||
-rw-r--r-- | clap/src/completions/mod.rs | 179 | ||||
-rw-r--r-- | clap/src/completions/powershell.rs | 139 | ||||
-rw-r--r-- | clap/src/completions/shell.rs | 52 | ||||
-rw-r--r-- | clap/src/completions/zsh.rs | 472 |
8 files changed, 0 insertions, 1314 deletions
diff --git a/clap/src/completions/bash.rs b/clap/src/completions/bash.rs deleted file mode 100644 index 37dfa66..0000000 --- a/clap/src/completions/bash.rs +++ /dev/null @@ -1,219 +0,0 @@ -// Std -use std::io::Write; - -// Internal -use app::parser::Parser; -use args::OptBuilder; -use completions; - -pub struct BashGen<'a, 'b> -where - 'a: 'b, -{ - p: &'b Parser<'a, 'b>, -} - -impl<'a, 'b> BashGen<'a, 'b> { - pub fn new(p: &'b Parser<'a, 'b>) -> Self { BashGen { p: p } } - - pub fn generate_to<W: Write>(&self, buf: &mut W) { - w!( - buf, - format!( - r#"_{name}() {{ - local i cur prev opts cmds - COMPREPLY=() - cur="${{COMP_WORDS[COMP_CWORD]}}" - prev="${{COMP_WORDS[COMP_CWORD-1]}}" - cmd="" - opts="" - - for i in ${{COMP_WORDS[@]}} - do - case "${{i}}" in - {name}) - cmd="{name}" - ;; - {subcmds} - *) - ;; - esac - done - - case "${{cmd}}" in - {name}) - opts="{name_opts}" - if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then - COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") ) - return 0 - fi - case "${{prev}}" in - {name_opts_details} - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") ) - return 0 - ;; - {subcmd_details} - esac -}} - -complete -F _{name} -o bashdefault -o default {name} -"#, - name = self.p.meta.bin_name.as_ref().unwrap(), - name_opts = self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()), - name_opts_details = - self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()), - subcmds = self.all_subcommands(), - subcmd_details = self.subcommand_details() - ).as_bytes() - ); - } - - fn all_subcommands(&self) -> String { - debugln!("BashGen::all_subcommands;"); - let mut subcmds = String::new(); - let scs = completions::all_subcommand_names(self.p); - - for sc in &scs { - subcmds = format!( - r#"{} - {name}) - cmd+="__{fn_name}" - ;;"#, - subcmds, - name = sc, - fn_name = sc.replace("-", "__") - ); - } - - subcmds - } - - fn subcommand_details(&self) -> String { - debugln!("BashGen::subcommand_details;"); - let mut subcmd_dets = String::new(); - let mut scs = completions::get_all_subcommand_paths(self.p, true); - scs.sort(); - scs.dedup(); - - for sc in &scs { - subcmd_dets = format!( - r#"{} - {subcmd}) - opts="{sc_opts}" - if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then - COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") ) - return 0 - fi - case "${{prev}}" in - {opts_details} - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${{opts}}" -- "${{cur}}") ) - return 0 - ;;"#, - subcmd_dets, - subcmd = sc.replace("-", "__"), - sc_opts = self.all_options_for_path(&*sc), - level = sc.split("__").map(|_| 1).fold(0, |acc, n| acc + n), - opts_details = self.option_details_for_path(&*sc) - ); - } - - subcmd_dets - } - - fn option_details_for_path(&self, path: &str) -> String { - debugln!("BashGen::option_details_for_path: path={}", path); - let mut p = self.p; - for sc in path.split("__").skip(1) { - debugln!("BashGen::option_details_for_path:iter: sc={}", sc); - p = &find_subcmd!(p, sc).unwrap().p; - } - let mut opts = String::new(); - for o in p.opts() { - if let Some(l) = o.s.long { - opts = format!( - "{} - --{}) - COMPREPLY=({}) - return 0 - ;;", - opts, - l, - self.vals_for(o) - ); - } - if let Some(s) = o.s.short { - opts = format!( - "{} - -{}) - COMPREPLY=({}) - return 0 - ;;", - opts, - s, - self.vals_for(o) - ); - } - } - opts - } - - fn vals_for(&self, o: &OptBuilder) -> String { - debugln!("BashGen::vals_for: o={}", o.b.name); - use args::AnyArg; - if let Some(vals) = o.possible_vals() { - format!(r#"$(compgen -W "{}" -- "${{cur}}")"#, vals.join(" ")) - } else { - String::from(r#"$(compgen -f "${cur}")"#) - } - } - - fn all_options_for_path(&self, path: &str) -> String { - debugln!("BashGen::all_options_for_path: path={}", path); - let mut p = self.p; - for sc in path.split("__").skip(1) { - debugln!("BashGen::all_options_for_path:iter: sc={}", sc); - p = &find_subcmd!(p, sc).unwrap().p; - } - let mut opts = shorts!(p).fold(String::new(), |acc, s| format!("{} -{}", acc, s)); - opts = format!( - "{} {}", - opts, - longs!(p).fold(String::new(), |acc, l| format!("{} --{}", acc, l)) - ); - opts = format!( - "{} {}", - opts, - p.positionals - .values() - .fold(String::new(), |acc, p| format!("{} {}", acc, p)) - ); - opts = format!( - "{} {}", - opts, - p.subcommands - .iter() - .fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name)) - ); - for sc in &p.subcommands { - if let Some(ref aliases) = sc.p.meta.aliases { - opts = format!( - "{} {}", - opts, - aliases - .iter() - .map(|&(n, _)| n) - .fold(String::new(), |acc, a| format!("{} {}", acc, a)) - ); - } - } - opts - } -} diff --git a/clap/src/completions/elvish.rs b/clap/src/completions/elvish.rs deleted file mode 100644 index 9a5f21a..0000000 --- a/clap/src/completions/elvish.rs +++ /dev/null @@ -1,126 +0,0 @@ -// Std -use std::io::Write; - -// Internal -use app::parser::Parser; -use INTERNAL_ERROR_MSG; - -pub struct ElvishGen<'a, 'b> -where - 'a: 'b, -{ - p: &'b Parser<'a, 'b>, -} - -impl<'a, 'b> ElvishGen<'a, 'b> { - pub fn new(p: &'b Parser<'a, 'b>) -> Self { ElvishGen { p: p } } - - pub fn generate_to<W: Write>(&self, buf: &mut W) { - let bin_name = self.p.meta.bin_name.as_ref().unwrap(); - - let mut names = vec![]; - let subcommands_cases = - generate_inner(self.p, "", &mut names); - - let result = format!(r#" -edit:completion:arg-completer[{bin_name}] = [@words]{{ - fn spaces [n]{{ - repeat $n ' ' | joins '' - }} - fn cand [text desc]{{ - edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc - }} - command = '{bin_name}' - for word $words[1:-1] {{ - if (has-prefix $word '-') {{ - break - }} - command = $command';'$word - }} - completions = [{subcommands_cases} - ] - $completions[$command] -}} -"#, - bin_name = bin_name, - subcommands_cases = subcommands_cases - ); - - w!(buf, result.as_bytes()); - } -} - -// Escape string inside single quotes -fn escape_string(string: &str) -> String { string.replace("'", "''") } - -fn get_tooltip<T : ToString>(help: Option<&str>, data: T) -> String { - match help { - Some(help) => escape_string(help), - _ => data.to_string() - } -} - -fn generate_inner<'a, 'b, 'p>( - p: &'p Parser<'a, 'b>, - previous_command_name: &str, - names: &mut Vec<&'p str>, -) -> String { - debugln!("ElvishGen::generate_inner;"); - let command_name = if previous_command_name.is_empty() { - p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG).clone() - } else { - format!("{};{}", previous_command_name, &p.meta.name) - }; - - let mut completions = String::new(); - let preamble = String::from("\n cand "); - - for option in p.opts() { - if let Some(data) = option.s.short { - let tooltip = get_tooltip(option.b.help, data); - completions.push_str(&preamble); - completions.push_str(format!("-{} '{}'", data, tooltip).as_str()); - } - if let Some(data) = option.s.long { - let tooltip = get_tooltip(option.b.help, data); - completions.push_str(&preamble); - completions.push_str(format!("--{} '{}'", data, tooltip).as_str()); - } - } - - for flag in p.flags() { - if let Some(data) = flag.s.short { - let tooltip = get_tooltip(flag.b.help, data); - completions.push_str(&preamble); - completions.push_str(format!("-{} '{}'", data, tooltip).as_str()); - } - if let Some(data) = flag.s.long { - let tooltip = get_tooltip(flag.b.help, data); - completions.push_str(&preamble); - completions.push_str(format!("--{} '{}'", data, tooltip).as_str()); - } - } - - for subcommand in &p.subcommands { - let data = &subcommand.p.meta.name; - let tooltip = get_tooltip(subcommand.p.meta.about, data); - completions.push_str(&preamble); - completions.push_str(format!("{} '{}'", data, tooltip).as_str()); - } - - let mut subcommands_cases = format!( - r" - &'{}'= {{{} - }}", - &command_name, - completions - ); - - for subcommand in &p.subcommands { - let subcommand_subcommands_cases = - generate_inner(&subcommand.p, &command_name, names); - subcommands_cases.push_str(&subcommand_subcommands_cases); - } - - subcommands_cases -} diff --git a/clap/src/completions/fish.rs b/clap/src/completions/fish.rs deleted file mode 100644 index c2c5a5e..0000000 --- a/clap/src/completions/fish.rs +++ /dev/null @@ -1,99 +0,0 @@ -// Std -use std::io::Write; - -// Internal -use app::parser::Parser; - -pub struct FishGen<'a, 'b> -where - 'a: 'b, -{ - p: &'b Parser<'a, 'b>, -} - -impl<'a, 'b> FishGen<'a, 'b> { - pub fn new(p: &'b Parser<'a, 'b>) -> Self { FishGen { p: p } } - - pub fn generate_to<W: Write>(&self, buf: &mut W) { - let command = self.p.meta.bin_name.as_ref().unwrap(); - let mut buffer = String::new(); - gen_fish_inner(command, self, command, &mut buffer); - w!(buf, buffer.as_bytes()); - } -} - -// Escape string inside single quotes -fn escape_string(string: &str) -> String { string.replace("\\", "\\\\").replace("'", "\\'") } - -fn gen_fish_inner(root_command: &str, comp_gen: &FishGen, subcommand: &str, buffer: &mut String) { - debugln!("FishGen::gen_fish_inner;"); - // example : - // - // complete - // -c {command} - // -d "{description}" - // -s {short} - // -l {long} - // -a "{possible_arguments}" - // -r # if require parameter - // -f # don't use file completion - // -n "__fish_use_subcommand" # complete for command "myprog" - // -n "__fish_seen_subcommand_from subcmd1" # complete for command "myprog subcmd1" - - let mut basic_template = format!("complete -c {} -n ", root_command); - if root_command == subcommand { - basic_template.push_str("\"__fish_use_subcommand\""); - } else { - basic_template.push_str(format!("\"__fish_seen_subcommand_from {}\"", subcommand).as_str()); - } - - for option in comp_gen.p.opts() { - let mut template = basic_template.clone(); - if let Some(data) = option.s.short { - template.push_str(format!(" -s {}", data).as_str()); - } - if let Some(data) = option.s.long { - template.push_str(format!(" -l {}", data).as_str()); - } - if let Some(data) = option.b.help { - template.push_str(format!(" -d '{}'", escape_string(data)).as_str()); - } - if let Some(ref data) = option.v.possible_vals { - template.push_str(format!(" -r -f -a \"{}\"", data.join(" ")).as_str()); - } - buffer.push_str(template.as_str()); - buffer.push_str("\n"); - } - - for flag in comp_gen.p.flags() { - let mut template = basic_template.clone(); - if let Some(data) = flag.s.short { - template.push_str(format!(" -s {}", data).as_str()); - } - if let Some(data) = flag.s.long { - template.push_str(format!(" -l {}", data).as_str()); - } - if let Some(data) = flag.b.help { - template.push_str(format!(" -d '{}'", escape_string(data)).as_str()); - } - buffer.push_str(template.as_str()); - buffer.push_str("\n"); - } - - for subcommand in &comp_gen.p.subcommands { - let mut template = basic_template.clone(); - template.push_str(" -f"); - template.push_str(format!(" -a \"{}\"", &subcommand.p.meta.name).as_str()); - if let Some(data) = subcommand.p.meta.about { - template.push_str(format!(" -d '{}'", escape_string(data)).as_str()) - } - buffer.push_str(template.as_str()); - buffer.push_str("\n"); - } - - // generate options of subcommands - for subcommand in &comp_gen.p.subcommands { - let sub_comp_gen = FishGen::new(&subcommand.p); - gen_fish_inner(root_command, &sub_comp_gen, &subcommand.to_string(), buffer); - } -} diff --git a/clap/src/completions/macros.rs b/clap/src/completions/macros.rs deleted file mode 100644 index 653c72c..0000000 --- a/clap/src/completions/macros.rs +++ /dev/null @@ -1,28 +0,0 @@ -macro_rules! w { - ($buf:expr, $to_w:expr) => { - match $buf.write_all($to_w) { - Ok(..) => (), - Err(..) => panic!("Failed to write to completions file"), - } - }; -} - -macro_rules! get_zsh_arg_conflicts { - ($p:ident, $arg:ident, $msg:ident) => { - if let Some(conf_vec) = $arg.blacklist() { - let mut v = vec![]; - for arg_name in conf_vec { - let arg = $p.find_any_arg(arg_name).expect($msg); - if let Some(s) = arg.short() { - v.push(format!("-{}", s)); - } - if let Some(l) = arg.long() { - v.push(format!("--{}", l)); - } - } - v.join(" ") - } else { - String::new() - } - } -} diff --git a/clap/src/completions/mod.rs b/clap/src/completions/mod.rs deleted file mode 100644 index a3306d7..0000000 --- a/clap/src/completions/mod.rs +++ /dev/null @@ -1,179 +0,0 @@ -#[macro_use] -mod macros; -mod bash; -mod fish; -mod zsh; -mod powershell; -mod elvish; -mod shell; - -// Std -use std::io::Write; - -// Internal -use app::parser::Parser; -use self::bash::BashGen; -use self::fish::FishGen; -use self::zsh::ZshGen; -use self::powershell::PowerShellGen; -use self::elvish::ElvishGen; -pub use self::shell::Shell; - -pub struct ComplGen<'a, 'b> -where - 'a: 'b, -{ - p: &'b Parser<'a, 'b>, -} - -impl<'a, 'b> ComplGen<'a, 'b> { - pub fn new(p: &'b Parser<'a, 'b>) -> Self { ComplGen { p: p } } - - pub fn generate<W: Write>(&self, for_shell: Shell, buf: &mut W) { - match for_shell { - Shell::Bash => BashGen::new(self.p).generate_to(buf), - Shell::Fish => FishGen::new(self.p).generate_to(buf), - Shell::Zsh => ZshGen::new(self.p).generate_to(buf), - Shell::PowerShell => PowerShellGen::new(self.p).generate_to(buf), - Shell::Elvish => ElvishGen::new(self.p).generate_to(buf), - } - } -} - -// Gets all subcommands including child subcommands in the form of 'name' where the name -// is a single word (i.e. "install") of the path to said subcommand (i.e. -// "rustup toolchain install") -// -// Also note, aliases are treated as their own subcommands but duplicates of whatever they're -// aliasing. -pub fn all_subcommand_names(p: &Parser) -> Vec<String> { - debugln!("all_subcommand_names;"); - let mut subcmds: Vec<_> = subcommands_of(p) - .iter() - .map(|&(ref n, _)| n.clone()) - .collect(); - for sc_v in p.subcommands.iter().map(|s| all_subcommand_names(&s.p)) { - subcmds.extend(sc_v); - } - subcmds.sort(); - subcmds.dedup(); - subcmds -} - -// Gets all subcommands including child subcommands in the form of ('name', 'bin_name') where the name -// is a single word (i.e. "install") of the path and full bin_name of said subcommand (i.e. -// "rustup toolchain install") -// -// Also note, aliases are treated as their own subcommands but duplicates of whatever they're -// aliasing. -pub fn all_subcommands(p: &Parser) -> Vec<(String, String)> { - debugln!("all_subcommands;"); - let mut subcmds: Vec<_> = subcommands_of(p); - for sc_v in p.subcommands.iter().map(|s| all_subcommands(&s.p)) { - subcmds.extend(sc_v); - } - subcmds -} - -// Gets all subcommands excluding child subcommands in the form of (name, bin_name) where the name -// is a single word (i.e. "install") and the bin_name is a space delineated list of the path to said -// subcommand (i.e. "rustup toolchain install") -// -// Also note, aliases are treated as their own subcommands but duplicates of whatever they're -// aliasing. -pub fn subcommands_of(p: &Parser) -> Vec<(String, String)> { - debugln!( - "subcommands_of: name={}, bin_name={}", - p.meta.name, - p.meta.bin_name.as_ref().unwrap() - ); - let mut subcmds = vec![]; - - debugln!( - "subcommands_of: Has subcommands...{:?}", - p.has_subcommands() - ); - if !p.has_subcommands() { - let mut ret = vec![]; - debugln!("subcommands_of: Looking for aliases..."); - if let Some(ref aliases) = p.meta.aliases { - for &(n, _) in aliases { - debugln!("subcommands_of:iter:iter: Found alias...{}", n); - let mut als_bin_name: Vec<_> = - p.meta.bin_name.as_ref().unwrap().split(' ').collect(); - als_bin_name.push(n); - let old = als_bin_name.len() - 2; - als_bin_name.swap_remove(old); - ret.push((n.to_owned(), als_bin_name.join(" "))); - } - } - return ret; - } - for sc in &p.subcommands { - debugln!( - "subcommands_of:iter: name={}, bin_name={}", - sc.p.meta.name, - sc.p.meta.bin_name.as_ref().unwrap() - ); - - debugln!("subcommands_of:iter: Looking for aliases..."); - if let Some(ref aliases) = sc.p.meta.aliases { - for &(n, _) in aliases { - debugln!("subcommands_of:iter:iter: Found alias...{}", n); - let mut als_bin_name: Vec<_> = - p.meta.bin_name.as_ref().unwrap().split(' ').collect(); - als_bin_name.push(n); - let old = als_bin_name.len() - 2; - als_bin_name.swap_remove(old); - subcmds.push((n.to_owned(), als_bin_name.join(" "))); - } - } - subcmds.push(( - sc.p.meta.name.clone(), - sc.p.meta.bin_name.as_ref().unwrap().clone(), - )); - } - subcmds -} - -pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> { - debugln!("get_all_subcommand_paths;"); - let mut subcmds = vec![]; - if !p.has_subcommands() { - if !first { - let name = &*p.meta.name; - let path = p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "__"); - let mut ret = vec![path.clone()]; - if let Some(ref aliases) = p.meta.aliases { - for &(n, _) in aliases { - ret.push(path.replace(name, n)); - } - } - return ret; - } - return vec![]; - } - for sc in &p.subcommands { - let name = &*sc.p.meta.name; - let path = sc.p - .meta - .bin_name - .as_ref() - .unwrap() - .clone() - .replace(" ", "__"); - subcmds.push(path.clone()); - if let Some(ref aliases) = sc.p.meta.aliases { - for &(n, _) in aliases { - subcmds.push(path.replace(name, n)); - } - } - } - for sc_v in p.subcommands - .iter() - .map(|s| get_all_subcommand_paths(&s.p, false)) - { - subcmds.extend(sc_v); - } - subcmds -} diff --git a/clap/src/completions/powershell.rs b/clap/src/completions/powershell.rs deleted file mode 100644 index 9fc77c7..0000000 --- a/clap/src/completions/powershell.rs +++ /dev/null @@ -1,139 +0,0 @@ -// Std -use std::io::Write; - -// Internal -use app::parser::Parser; -use INTERNAL_ERROR_MSG; - -pub struct PowerShellGen<'a, 'b> -where - 'a: 'b, -{ - p: &'b Parser<'a, 'b>, -} - -impl<'a, 'b> PowerShellGen<'a, 'b> { - pub fn new(p: &'b Parser<'a, 'b>) -> Self { PowerShellGen { p: p } } - - pub fn generate_to<W: Write>(&self, buf: &mut W) { - let bin_name = self.p.meta.bin_name.as_ref().unwrap(); - - let mut names = vec![]; - let subcommands_cases = - generate_inner(self.p, "", &mut names); - - let result = format!(r#" -using namespace System.Management.Automation -using namespace System.Management.Automation.Language - -Register-ArgumentCompleter -Native -CommandName '{bin_name}' -ScriptBlock {{ - param($wordToComplete, $commandAst, $cursorPosition) - - $commandElements = $commandAst.CommandElements - $command = @( - '{bin_name}' - for ($i = 1; $i -lt $commandElements.Count; $i++) {{ - $element = $commandElements[$i] - if ($element -isnot [StringConstantExpressionAst] -or - $element.StringConstantType -ne [StringConstantType]::BareWord -or - $element.Value.StartsWith('-')) {{ - break - }} - $element.Value - }}) -join ';' - - $completions = @(switch ($command) {{{subcommands_cases} - }}) - - $completions.Where{{ $_.CompletionText -like "$wordToComplete*" }} | - Sort-Object -Property ListItemText -}} -"#, - bin_name = bin_name, - subcommands_cases = subcommands_cases - ); - - w!(buf, result.as_bytes()); - } -} - -// Escape string inside single quotes -fn escape_string(string: &str) -> String { string.replace("'", "''") } - -fn get_tooltip<T : ToString>(help: Option<&str>, data: T) -> String { - match help { - Some(help) => escape_string(help), - _ => data.to_string() - } -} - -fn generate_inner<'a, 'b, 'p>( - p: &'p Parser<'a, 'b>, - previous_command_name: &str, - names: &mut Vec<&'p str>, -) -> String { - debugln!("PowerShellGen::generate_inner;"); - let command_name = if previous_command_name.is_empty() { - p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG).clone() - } else { - format!("{};{}", previous_command_name, &p.meta.name) - }; - - let mut completions = String::new(); - let preamble = String::from("\n [CompletionResult]::new("); - - for option in p.opts() { - if let Some(data) = option.s.short { - let tooltip = get_tooltip(option.b.help, data); - completions.push_str(&preamble); - completions.push_str(format!("'-{}', '{}', {}, '{}')", - data, data, "[CompletionResultType]::ParameterName", tooltip).as_str()); - } - if let Some(data) = option.s.long { - let tooltip = get_tooltip(option.b.help, data); - completions.push_str(&preamble); - completions.push_str(format!("'--{}', '{}', {}, '{}')", - data, data, "[CompletionResultType]::ParameterName", tooltip).as_str()); - } - } - - for flag in p.flags() { - if let Some(data) = flag.s.short { - let tooltip = get_tooltip(flag.b.help, data); - completions.push_str(&preamble); - completions.push_str(format!("'-{}', '{}', {}, '{}')", - data, data, "[CompletionResultType]::ParameterName", tooltip).as_str()); - } - if let Some(data) = flag.s.long { - let tooltip = get_tooltip(flag.b.help, data); - completions.push_str(&preamble); - completions.push_str(format!("'--{}', '{}', {}, '{}')", - data, data, "[CompletionResultType]::ParameterName", tooltip).as_str()); - } - } - - for subcommand in &p.subcommands { - let data = &subcommand.p.meta.name; - let tooltip = get_tooltip(subcommand.p.meta.about, data); - completions.push_str(&preamble); - completions.push_str(format!("'{}', '{}', {}, '{}')", - data, data, "[CompletionResultType]::ParameterValue", tooltip).as_str()); - } - - let mut subcommands_cases = format!( - r" - '{}' {{{} - break - }}", - &command_name, - completions - ); - - for subcommand in &p.subcommands { - let subcommand_subcommands_cases = - generate_inner(&subcommand.p, &command_name, names); - subcommands_cases.push_str(&subcommand_subcommands_cases); - } - - subcommands_cases -} diff --git a/clap/src/completions/shell.rs b/clap/src/completions/shell.rs deleted file mode 100644 index 19aab86..0000000 --- a/clap/src/completions/shell.rs +++ /dev/null @@ -1,52 +0,0 @@ -#[allow(deprecated, unused_imports)] -use std::ascii::AsciiExt; -use std::str::FromStr; -use std::fmt; - -/// Describes which shell to produce a completions file for -#[cfg_attr(feature = "lints", allow(enum_variant_names))] -#[derive(Debug, Copy, Clone)] -pub enum Shell { - /// Generates a .bash completion file for the Bourne Again SHell (BASH) - Bash, - /// Generates a .fish completion file for the Friendly Interactive SHell (fish) - Fish, - /// Generates a completion file for the Z SHell (ZSH) - Zsh, - /// Generates a completion file for PowerShell - PowerShell, - /// Generates a completion file for Elvish - Elvish, -} - -impl Shell { - /// A list of possible variants in `&'static str` form - pub fn variants() -> [&'static str; 5] { ["zsh", "bash", "fish", "powershell", "elvish"] } -} - -impl FromStr for Shell { - type Err = String; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - match s { - "ZSH" | _ if s.eq_ignore_ascii_case("zsh") => Ok(Shell::Zsh), - "FISH" | _ if s.eq_ignore_ascii_case("fish") => Ok(Shell::Fish), - "BASH" | _ if s.eq_ignore_ascii_case("bash") => Ok(Shell::Bash), - "POWERSHELL" | _ if s.eq_ignore_ascii_case("powershell") => Ok(Shell::PowerShell), - "ELVISH" | _ if s.eq_ignore_ascii_case("elvish") => Ok(Shell::Elvish), - _ => Err(String::from("[valid values: bash, fish, zsh, powershell, elvish]")), - } - } -} - -impl fmt::Display for Shell { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Shell::Bash => write!(f, "BASH"), - Shell::Fish => write!(f, "FISH"), - Shell::Zsh => write!(f, "ZSH"), - Shell::PowerShell => write!(f, "POWERSHELL"), - Shell::Elvish => write!(f, "ELVISH"), - } - } -} diff --git a/clap/src/completions/zsh.rs b/clap/src/completions/zsh.rs deleted file mode 100644 index 5d23fd2..0000000 --- a/clap/src/completions/zsh.rs +++ /dev/null @@ -1,472 +0,0 @@ -// Std -use std::io::Write; -#[allow(deprecated, unused_imports)] -use std::ascii::AsciiExt; - -// Internal -use app::App; -use app::parser::Parser; -use args::{AnyArg, ArgSettings}; -use completions; -use INTERNAL_ERROR_MSG; - -pub struct ZshGen<'a, 'b> -where - 'a: 'b, -{ - p: &'b Parser<'a, 'b>, -} - -impl<'a, 'b> ZshGen<'a, 'b> { - pub fn new(p: &'b Parser<'a, 'b>) -> Self { - debugln!("ZshGen::new;"); - ZshGen { p: p } - } - - pub fn generate_to<W: Write>(&self, buf: &mut W) { - debugln!("ZshGen::generate_to;"); - w!( - buf, - format!( - "\ -#compdef {name} - -autoload -U is-at-least - -_{name}() {{ - typeset -A opt_args - typeset -a _arguments_options - local ret=1 - - if is-at-least 5.2; then - _arguments_options=(-s -S -C) - else - _arguments_options=(-s -C) - fi - - local context curcontext=\"$curcontext\" state line - {initial_args} - {subcommands} -}} - -{subcommand_details} - -_{name} \"$@\"", - name = self.p.meta.bin_name.as_ref().unwrap(), - initial_args = get_args_of(self.p), - subcommands = get_subcommands_of(self.p), - subcommand_details = subcommand_details(self.p) - ).as_bytes() - ); - } -} - -// Displays the commands of a subcommand -// (( $+functions[_[bin_name_underscore]_commands] )) || -// _[bin_name_underscore]_commands() { -// local commands; commands=( -// '[arg_name]:[arg_help]' -// ) -// _describe -t commands '[bin_name] commands' commands "$@" -// -// Where the following variables are present: -// [bin_name_underscore]: The full space delineated bin_name, where spaces have been replaced by -// underscore characters -// [arg_name]: The name of the subcommand -// [arg_help]: The help message of the subcommand -// [bin_name]: The full space delineated bin_name -// -// Here's a snippet from rustup: -// -// (( $+functions[_rustup_commands] )) || -// _rustup_commands() { -// local commands; commands=( -// 'show:Show the active and installed toolchains' -// 'update:Update Rust toolchains' -// # ... snip for brevity -// 'help:Prints this message or the help of the given subcommand(s)' -// ) -// _describe -t commands 'rustup commands' commands "$@" -// -fn subcommand_details(p: &Parser) -> String { - debugln!("ZshGen::subcommand_details;"); - // First we do ourself - let mut ret = vec![ - format!( - "\ -(( $+functions[_{bin_name_underscore}_commands] )) || -_{bin_name_underscore}_commands() {{ - local commands; commands=( - {subcommands_and_args} - ) - _describe -t commands '{bin_name} commands' commands \"$@\" -}}", - bin_name_underscore = p.meta.bin_name.as_ref().unwrap().replace(" ", "__"), - bin_name = p.meta.bin_name.as_ref().unwrap(), - subcommands_and_args = subcommands_of(p) - ), - ]; - - // Next we start looping through all the children, grandchildren, etc. - let mut all_subcommands = completions::all_subcommands(p); - all_subcommands.sort(); - all_subcommands.dedup(); - for &(_, ref bin_name) in &all_subcommands { - debugln!("ZshGen::subcommand_details:iter: bin_name={}", bin_name); - ret.push(format!( - "\ -(( $+functions[_{bin_name_underscore}_commands] )) || -_{bin_name_underscore}_commands() {{ - local commands; commands=( - {subcommands_and_args} - ) - _describe -t commands '{bin_name} commands' commands \"$@\" -}}", - bin_name_underscore = bin_name.replace(" ", "__"), - bin_name = bin_name, - subcommands_and_args = subcommands_of(parser_of(p, bin_name)) - )); - } - - ret.join("\n") -} - -// Generates subcommand completions in form of -// -// '[arg_name]:[arg_help]' -// -// Where: -// [arg_name]: the subcommand's name -// [arg_help]: the help message of the subcommand -// -// A snippet from rustup: -// 'show:Show the active and installed toolchains' -// 'update:Update Rust toolchains' -fn subcommands_of(p: &Parser) -> String { - debugln!("ZshGen::subcommands_of;"); - let mut ret = vec![]; - fn add_sc(sc: &App, n: &str, ret: &mut Vec<String>) { - debugln!("ZshGen::add_sc;"); - let s = format!( - "\"{name}:{help}\" \\", - name = n, - help = sc.p - .meta - .about - .unwrap_or("") - .replace("[", "\\[") - .replace("]", "\\]") - ); - if !s.is_empty() { - ret.push(s); - } - } - - // The subcommands - for sc in p.subcommands() { - debugln!( - "ZshGen::subcommands_of:iter: subcommand={}", - sc.p.meta.name - ); - add_sc(sc, &sc.p.meta.name, &mut ret); - if let Some(ref v) = sc.p.meta.aliases { - for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) { - add_sc(sc, alias, &mut ret); - } - } - } - - ret.join("\n") -} - -// Get's the subcommand section of a completion file -// This looks roughly like: -// -// case $state in -// ([bin_name]_args) -// curcontext=\"${curcontext%:*:*}:[name_hyphen]-command-$words[1]:\" -// case $line[1] in -// -// ([name]) -// _arguments -C -s -S \ -// [subcommand_args] -// && ret=0 -// -// [RECURSIVE_CALLS] -// -// ;;", -// -// [repeat] -// -// esac -// ;; -// esac", -// -// Where the following variables are present: -// [name] = The subcommand name in the form of "install" for "rustup toolchain install" -// [bin_name] = The full space delineated bin_name such as "rustup toolchain install" -// [name_hyphen] = The full space delineated bin_name, but replace spaces with hyphens -// [repeat] = From the same recursive calls, but for all subcommands -// [subcommand_args] = The same as zsh::get_args_of -fn get_subcommands_of(p: &Parser) -> String { - debugln!("get_subcommands_of;"); - - debugln!( - "get_subcommands_of: Has subcommands...{:?}", - p.has_subcommands() - ); - if !p.has_subcommands() { - return String::new(); - } - - let sc_names = completions::subcommands_of(p); - - let mut subcmds = vec![]; - for &(ref name, ref bin_name) in &sc_names { - let mut v = vec![format!("({})", name)]; - let subcommand_args = get_args_of(parser_of(p, &*bin_name)); - if !subcommand_args.is_empty() { - v.push(subcommand_args); - } - let subcommands = get_subcommands_of(parser_of(p, &*bin_name)); - if !subcommands.is_empty() { - v.push(subcommands); - } - v.push(String::from(";;")); - subcmds.push(v.join("\n")); - } - - format!( - "case $state in - ({name}) - words=($line[{pos}] \"${{words[@]}}\") - (( CURRENT += 1 )) - curcontext=\"${{curcontext%:*:*}}:{name_hyphen}-command-$line[{pos}]:\" - case $line[{pos}] in - {subcommands} - esac - ;; -esac", - name = p.meta.name, - name_hyphen = p.meta.bin_name.as_ref().unwrap().replace(" ", "-"), - subcommands = subcmds.join("\n"), - pos = p.positionals().len() + 1 - ) -} - -fn parser_of<'a, 'b>(p: &'b Parser<'a, 'b>, sc: &str) -> &'b Parser<'a, 'b> { - debugln!("parser_of: sc={}", sc); - if sc == p.meta.bin_name.as_ref().unwrap_or(&String::new()) { - return p; - } - &p.find_subcommand(sc).expect(INTERNAL_ERROR_MSG).p -} - -// Writes out the args section, which ends up being the flags, opts and postionals, and a jump to -// another ZSH function if there are subcommands. -// The structer works like this: -// ([conflicting_args]) [multiple] arg [takes_value] [[help]] [: :(possible_values)] -// ^-- list '-v -h' ^--'*' ^--'+' ^-- list 'one two three' -// -// An example from the rustup command: -// -// _arguments -C -s -S \ -// '(-h --help --verbose)-v[Enable verbose output]' \ -// '(-V -v --version --verbose --help)-h[Prints help information]' \ -// # ... snip for brevity -// ':: :_rustup_commands' \ # <-- displays subcommands -// '*::: :->rustup' \ # <-- displays subcommand args and child subcommands -// && ret=0 -// -// The args used for _arguments are as follows: -// -C: modify the $context internal variable -// -s: Allow stacking of short args (i.e. -a -b -c => -abc) -// -S: Do not complete anything after '--' and treat those as argument values -fn get_args_of(p: &Parser) -> String { - debugln!("get_args_of;"); - let mut ret = vec![String::from("_arguments \"${_arguments_options[@]}\" \\")]; - let opts = write_opts_of(p); - let flags = write_flags_of(p); - let positionals = write_positionals_of(p); - let sc_or_a = if p.has_subcommands() { - format!( - "\":: :_{name}_commands\" \\", - name = p.meta.bin_name.as_ref().unwrap().replace(" ", "__") - ) - } else { - String::new() - }; - let sc = if p.has_subcommands() { - format!("\"*::: :->{name}\" \\", name = p.meta.name) - } else { - String::new() - }; - - if !opts.is_empty() { - ret.push(opts); - } - if !flags.is_empty() { - ret.push(flags); - } - if !positionals.is_empty() { - ret.push(positionals); - } - if !sc_or_a.is_empty() { - ret.push(sc_or_a); - } - if !sc.is_empty() { - ret.push(sc); - } - ret.push(String::from("&& ret=0")); - - ret.join("\n") -} - -// Escape help string inside single quotes and brackets -fn escape_help(string: &str) -> String { - string - .replace("\\", "\\\\") - .replace("'", "'\\''") - .replace("[", "\\[") - .replace("]", "\\]") -} - -// Escape value string inside single quotes and parentheses -fn escape_value(string: &str) -> String { - string - .replace("\\", "\\\\") - .replace("'", "'\\''") - .replace("(", "\\(") - .replace(")", "\\)") - .replace(" ", "\\ ") -} - -fn write_opts_of(p: &Parser) -> String { - debugln!("write_opts_of;"); - let mut ret = vec![]; - for o in p.opts() { - debugln!("write_opts_of:iter: o={}", o.name()); - let help = o.help().map_or(String::new(), escape_help); - let mut conflicts = get_zsh_arg_conflicts!(p, o, INTERNAL_ERROR_MSG); - conflicts = if conflicts.is_empty() { - String::new() - } else { - format!("({})", conflicts) - }; - - let multiple = if o.is_set(ArgSettings::Multiple) { - "*" - } else { - "" - }; - let pv = if let Some(pv_vec) = o.possible_vals() { - format!(": :({})", pv_vec.iter().map( - |v| escape_value(*v)).collect::<Vec<String>>().join(" ")) - } else { - String::new() - }; - if let Some(short) = o.short() { - let s = format!( - "'{conflicts}{multiple}-{arg}+[{help}]{possible_values}' \\", - conflicts = conflicts, - multiple = multiple, - arg = short, - possible_values = pv, - help = help - ); - - debugln!("write_opts_of:iter: Wrote...{}", &*s); - ret.push(s); - } - if let Some(long) = o.long() { - let l = format!( - "'{conflicts}{multiple}--{arg}=[{help}]{possible_values}' \\", - conflicts = conflicts, - multiple = multiple, - arg = long, - possible_values = pv, - help = help - ); - - debugln!("write_opts_of:iter: Wrote...{}", &*l); - ret.push(l); - } - } - - ret.join("\n") -} - -fn write_flags_of(p: &Parser) -> String { - debugln!("write_flags_of;"); - let mut ret = vec![]; - for f in p.flags() { - debugln!("write_flags_of:iter: f={}", f.name()); - let help = f.help().map_or(String::new(), escape_help); - let mut conflicts = get_zsh_arg_conflicts!(p, f, INTERNAL_ERROR_MSG); - conflicts = if conflicts.is_empty() { - String::new() - } else { - format!("({})", conflicts) - }; - - let multiple = if f.is_set(ArgSettings::Multiple) { - "*" - } else { - "" - }; - if let Some(short) = f.short() { - let s = format!( - "'{conflicts}{multiple}-{arg}[{help}]' \\", - multiple = multiple, - conflicts = conflicts, - arg = short, - help = help - ); - - debugln!("write_flags_of:iter: Wrote...{}", &*s); - ret.push(s); - } - - if let Some(long) = f.long() { - let l = format!( - "'{conflicts}{multiple}--{arg}[{help}]' \\", - conflicts = conflicts, - multiple = multiple, - arg = long, - help = help - ); - - debugln!("write_flags_of:iter: Wrote...{}", &*l); - ret.push(l); - } - } - - ret.join("\n") -} - -fn write_positionals_of(p: &Parser) -> String { - debugln!("write_positionals_of;"); - let mut ret = vec![]; - for arg in p.positionals() { - debugln!("write_positionals_of:iter: arg={}", arg.b.name); - let a = format!( - "'{optional}:{name}{help}:{action}' \\", - optional = if !arg.b.is_set(ArgSettings::Required) { ":" } else { "" }, - name = arg.b.name, - help = arg.b - .help - .map_or("".to_owned(), |v| " -- ".to_owned() + v) - .replace("[", "\\[") - .replace("]", "\\]"), - action = arg.possible_vals().map_or("_files".to_owned(), |values| { - format!("({})", - values.iter().map(|v| escape_value(*v)).collect::<Vec<String>>().join(" ")) - }) - ); - - debugln!("write_positionals_of:iter: Wrote...{}", a); - ret.push(a); - } - - ret.join("\n") -} |