diff options
Diffstat (limited to 'clap/src/completions/powershell.rs')
-rw-r--r-- | clap/src/completions/powershell.rs | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/clap/src/completions/powershell.rs b/clap/src/completions/powershell.rs new file mode 100644 index 0000000..9fc77c7 --- /dev/null +++ b/clap/src/completions/powershell.rs @@ -0,0 +1,139 @@ +// 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 +} |