Skip to content

Commit 99b6391

Browse files
committed
fix(complete): Fix PowerShell dynamic completion
PowerShell does not support inline syntax for assigning environment variables, so we must instead set the value before running the completer and restore it after it exits. The completer will often, if not always, be surrounded by double quotes. To avoid syntax errors, define the argument to Invoke-Expression as a here-string so the quotes don't create a syntax error. Updates the instructions for adding the argument completer to the profile. Piping a native command to Invoke-Expression invokes each line separately. Adding `Out-String` to the pipeline ensures that Invoke-Expression receives the whole script as a single value from the pipeline. Fixes: #5847
1 parent ed2360f commit 99b6391

File tree

2 files changed

+16
-2
lines changed

2 files changed

+16
-2
lines changed

clap_complete/src/env/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@
5252
//!
5353
//! Powershell
5454
//! ```powershell
55-
//! echo "COMPLETE=powershell your_program | Invoke-Expression" >> $PROFILE
55+
//! $env:COMPLETE = "powershell"
56+
//! echo "your_program | Out-String | Invoke-Expression" >> $PROFILE
57+
//! Remove-Item Env:\COMPLETE
5658
//! ```
5759
//!
5860
//! Zsh

clap_complete/src/env/shells.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,25 @@ impl EnvCompleter for Powershell {
274274
let completer =
275275
shlex::try_quote(completer).unwrap_or(std::borrow::Cow::Borrowed(completer));
276276

277+
// `completer` may or may not be surrounded by double quotes, enclosing
278+
// the expression in a here-string ensures the whole thing is
279+
// interpreted as the first argument to the call operator
277280
writeln!(
278281
buf,
279282
r#"
280283
Register-ArgumentCompleter -Native -CommandName {bin} -ScriptBlock {{
281284
param($wordToComplete, $commandAst, $cursorPosition)
282285
283-
$results = Invoke-Expression "{var}=powershell &{completer} -- $($commandAst.ToString())";
286+
$prev = $env:{var};
287+
$env:{var} = "powershell";
288+
$results = Invoke-Expression @"
289+
& {completer} -- $commandAst
290+
"@;
291+
if ($null -eq $prev) {{
292+
Remove-Item Env:\{var};
293+
}} else {{
294+
$env:{var} = $prev;
295+
}}
284296
$results | ForEach-Object {{
285297
$split = $_.Split("`t");
286298
$cmd = $split[0];

0 commit comments

Comments
 (0)