clap/completions/
powershell.rs
1use std::io::Write;
3
4use crate::{app::parser::Parser, INTERNAL_ERROR_MSG};
6
7pub struct PowerShellGen<'a, 'b>
8where
9 'a: 'b,
10{
11 p: &'b Parser<'a, 'b>,
12}
13
14impl<'a, 'b> PowerShellGen<'a, 'b> {
15 pub fn new(p: &'b Parser<'a, 'b>) -> Self {
16 PowerShellGen { p }
17 }
18
19 pub fn generate_to<W: Write>(&self, buf: &mut W) {
20 let bin_name = self.p.meta.bin_name.as_ref().unwrap();
21
22 let mut names = vec![];
23 let subcommands_cases = generate_inner(self.p, "", &mut names);
24
25 let result = format!(
26 r#"
27using namespace System.Management.Automation
28using namespace System.Management.Automation.Language
29
30Register-ArgumentCompleter -Native -CommandName '{bin_name}' -ScriptBlock {{
31 param($wordToComplete, $commandAst, $cursorPosition)
32
33 $commandElements = $commandAst.CommandElements
34 $command = @(
35 '{bin_name}'
36 for ($i = 1; $i -lt $commandElements.Count; $i++) {{
37 $element = $commandElements[$i]
38 if ($element -isnot [StringConstantExpressionAst] -or
39 $element.StringConstantType -ne [StringConstantType]::BareWord -or
40 $element.Value.StartsWith('-')) {{
41 break
42 }}
43 $element.Value
44 }}) -join ';'
45
46 $completions = @(switch ($command) {{{subcommands_cases}
47 }})
48
49 $completions.Where{{ $_.CompletionText -like "$wordToComplete*" }} |
50 Sort-Object -Property ListItemText
51}}
52"#,
53 bin_name = bin_name,
54 subcommands_cases = subcommands_cases
55 );
56
57 w!(buf, result.as_bytes());
58 }
59}
60
61fn escape_string(string: &str) -> String {
63 string.replace("'", "''")
64}
65
66fn get_tooltip<T: ToString>(help: Option<&str>, data: T) -> String {
67 match help {
68 Some(help) => escape_string(help),
69 _ => data.to_string(),
70 }
71}
72
73fn generate_inner<'a, 'b, 'p>(
74 p: &'p Parser<'a, 'b>,
75 previous_command_name: &str,
76 names: &mut Vec<&'p str>,
77) -> String {
78 debugln!("PowerShellGen::generate_inner;");
79 let command_name = if previous_command_name.is_empty() {
80 p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG).clone()
81 } else {
82 format!("{};{}", previous_command_name, &p.meta.name)
83 };
84
85 let mut completions = String::new();
86 let preamble = String::from("\n [CompletionResult]::new(");
87
88 for option in p.opts() {
89 if let Some(data) = option.s.short {
90 let tooltip = get_tooltip(option.b.help, data);
91 completions.push_str(&preamble);
92 completions.push_str(
93 format!(
94 "'-{}', '{}', {}, '{}')",
95 data, data, "[CompletionResultType]::ParameterName", tooltip
96 )
97 .as_str(),
98 );
99 }
100 if let Some(data) = option.s.long {
101 let tooltip = get_tooltip(option.b.help, data);
102 completions.push_str(&preamble);
103 completions.push_str(
104 format!(
105 "'--{}', '{}', {}, '{}')",
106 data, data, "[CompletionResultType]::ParameterName", tooltip
107 )
108 .as_str(),
109 );
110 }
111 }
112
113 for flag in p.flags() {
114 if let Some(data) = flag.s.short {
115 let tooltip = get_tooltip(flag.b.help, data);
116 completions.push_str(&preamble);
117 completions.push_str(
118 format!(
119 "'-{}', '{}', {}, '{}')",
120 data, data, "[CompletionResultType]::ParameterName", tooltip
121 )
122 .as_str(),
123 );
124 }
125 if let Some(data) = flag.s.long {
126 let tooltip = get_tooltip(flag.b.help, data);
127 completions.push_str(&preamble);
128 completions.push_str(
129 format!(
130 "'--{}', '{}', {}, '{}')",
131 data, data, "[CompletionResultType]::ParameterName", tooltip
132 )
133 .as_str(),
134 );
135 }
136 }
137
138 for subcommand in &p.subcommands {
139 let data = &subcommand.p.meta.name;
140 let tooltip = get_tooltip(subcommand.p.meta.about, data);
141 completions.push_str(&preamble);
142 completions.push_str(
143 format!(
144 "'{}', '{}', {}, '{}')",
145 data, data, "[CompletionResultType]::ParameterValue", tooltip
146 )
147 .as_str(),
148 );
149 }
150
151 let mut subcommands_cases = format!(
152 r"
153 '{}' {{{}
154 break
155 }}",
156 &command_name, completions
157 );
158
159 for subcommand in &p.subcommands {
160 let subcommand_subcommands_cases = generate_inner(&subcommand.p, &command_name, names);
161 subcommands_cases.push_str(&subcommand_subcommands_cases);
162 }
163
164 subcommands_cases
165}