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