Skip to content

Commit 5c68aec

Browse files
authored
Merge branch 'main' into fix/fish-dynamic-completions
2 parents 5bbe3e3 + d525e78 commit 5c68aec

5 files changed

Lines changed: 53 additions & 21 deletions

File tree

autocomplete/bash_autocomplete

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,40 @@ __%[1]s_bash_autocomplete() {
2626
requestComp="${words[*]} --generate-shell-completion"
2727
fi
2828
opts=$(eval "${requestComp}" 2>/dev/null)
29-
COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
29+
30+
# Separate completions and descriptions
31+
local completions=()
32+
local descriptions=()
33+
local longest=0
34+
while IFS=$'\n' read -r line; do
35+
local comp_part desc_part
36+
if [[ "$line" == *:* ]]; then
37+
comp_part="${line%%:*}"
38+
desc_part="${line#*:}"
39+
else
40+
comp_part="$line"
41+
desc_part=""
42+
fi
43+
completions+=("$comp_part")
44+
descriptions+=("$desc_part")
45+
(( ${#comp_part} > longest )) && longest=${#comp_part}
46+
done <<< "$opts"
47+
48+
# Format completions with aligned descriptions
49+
for i in "${!completions[@]}"; do
50+
local padded_completion="${completions[i]}"
51+
local pad_len=$((longest - ${#padded_completion}))
52+
if (( pad_len > 0 )); then
53+
padded_completion="${padded_completion}$(head -c $pad_len < /dev/zero | tr '\0' ' ')"
54+
fi
55+
56+
if [[ -n "${descriptions[i]}" ]]; then
57+
COMPREPLY+=("${padded_completion} -- ${descriptions[i]}")
58+
else
59+
COMPREPLY+=("${padded_completion}")
60+
fi
61+
done
62+
3063
return 0
3164
fi
3265
}
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
$fn = $($MyInvocation.MyCommand.Name)
22
$name = $fn -replace "(.*)\.ps1$", '$1'
33
Register-ArgumentCompleter -Native -CommandName $name -ScriptBlock {
4-
param($commandName, $wordToComplete, $cursorPosition)
5-
$other = "$wordToComplete --generate-shell-completion"
6-
Invoke-Expression $other | ForEach-Object {
4+
param($commandName, $wordToComplete, $cursorPosition)
5+
$other = "$wordToComplete --generate-shell-completion"
6+
Invoke-Expression $other | ForEach-Object {
7+
$parts = $_.Split(':', 2)
8+
if ($parts.Count -eq 2) {
9+
$completion = $parts[0].Trim()
10+
$description = $parts[1].Trim()
11+
[System.Management.Automation.CompletionResult]::new($completion, $completion, 'ParameterValue', $description)
12+
} else {
713
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
8-
}
9-
}
14+
}
15+
}
16+
}

docs/v3/examples/completions/shell-completions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ search:
66
---
77

88
The urfave/cli v3 library supports programmable completion for apps utilizing its framework. This means
9-
that the completion is generated dynamically at runtime by invokiong the app itself with a special hidden
9+
that the completion is generated dynamically at runtime by invoking the app itself with a special hidden
1010
flag. The urfave/cli searches for this flag and activates a different flow for command paths than regular flow
1111
The following shells are supported
1212

examples_test.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -258,14 +258,13 @@ func ExampleCommand_Run_shellComplete_bash_withShortFlag() {
258258
}
259259

260260
// Simulate a bash environment and command line arguments
261-
os.Setenv("SHELL", "bash")
262261
os.Args = []string{"greet", "-", "--generate-shell-completion"}
263262

264263
_ = cmd.Run(context.Background(), os.Args)
265264
// Output:
266265
// --other
267266
// --xyz
268-
// --help
267+
// --help:show help
269268
}
270269

271270
func ExampleCommand_Run_shellComplete_bash_withLongFlag() {
@@ -291,7 +290,6 @@ func ExampleCommand_Run_shellComplete_bash_withLongFlag() {
291290
}
292291

293292
// Simulate a bash environment and command line arguments
294-
os.Setenv("SHELL", "bash")
295293
os.Args = []string{"greet", "--s", "--generate-shell-completion"}
296294

297295
_ = cmd.Run(context.Background(), os.Args)
@@ -326,7 +324,6 @@ func ExampleCommand_Run_shellComplete_bash_withMultipleLongFlag() {
326324
}
327325

328326
// Simulate a bash environment and command line arguments
329-
os.Setenv("SHELL", "bash")
330327
os.Args = []string{"greet", "--st", "--generate-shell-completion"}
331328

332329
_ = cmd.Run(context.Background(), os.Args)
@@ -362,14 +359,13 @@ func ExampleCommand_Run_shellComplete_bash() {
362359
}
363360

364361
// Simulate a bash environment and command line arguments
365-
os.Setenv("SHELL", "bash")
366362
os.Args = []string{"greet", "--generate-shell-completion"}
367363

368364
_ = cmd.Run(context.Background(), os.Args)
369365
// Output:
370-
// describeit
371-
// next
372-
// help
366+
// describeit:use it to see a description
367+
// next:next example
368+
// help:Shows a list of commands or help for one command
373369
}
374370

375371
func ExampleCommand_Run_shellComplete_zsh() {
@@ -400,7 +396,6 @@ func ExampleCommand_Run_shellComplete_zsh() {
400396

401397
// Simulate a zsh environment and command line arguments
402398
os.Args = []string{"greet", "--generate-shell-completion"}
403-
os.Setenv("SHELL", "/usr/bin/zsh")
404399

405400
_ = cmd.Run(context.Background(), os.Args)
406401
// Output:
@@ -437,7 +432,6 @@ func ExampleCommand_Run_shellComplete_fish() {
437432

438433
// Simulate a fish environment and command line arguments
439434
os.Args = []string{"greet", "--generate-shell-completion"}
440-
os.Setenv("SHELL", "/usr/bin/fish")
441435

442436
_ = cmd.Run(context.Background(), os.Args)
443437
// Output:

help.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,11 @@ func DefaultRootCommandComplete(ctx context.Context, cmd *Command) {
184184
var DefaultAppComplete = DefaultRootCommandComplete
185185

186186
func printCommandSuggestions(commands []*Command, writer io.Writer) {
187-
shell := os.Getenv("SHELL")
188187
for _, command := range commands {
189188
if command.Hidden {
190189
continue
191190
}
192-
if (strings.HasSuffix(shell, "zsh") || strings.HasSuffix(shell, "fish")) && len(command.Usage) > 0 {
191+
if len(command.Usage) > 0 {
193192
_, _ = fmt.Fprintf(writer, "%s:%s\n", command.Name, command.Usage)
194193
} else {
195194
_, _ = fmt.Fprintf(writer, "%s\n", command.Name)
@@ -239,8 +238,7 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) {
239238
// match if last argument matches this flag and it is not repeated
240239
if strings.HasPrefix(name, cur) && cur != name /* && !cliArgContains(name, os.Args)*/ {
241240
flagCompletion := fmt.Sprintf("%s%s", strings.Repeat("-", count), name)
242-
shell := os.Getenv("SHELL")
243-
if usage != "" && (strings.HasSuffix(shell, "zsh") || strings.HasSuffix(shell, "fish")) {
241+
if usage != "" {
244242
flagCompletion = fmt.Sprintf("%s:%s", flagCompletion, usage)
245243
}
246244
fmt.Fprintln(writer, flagCompletion)

0 commit comments

Comments
 (0)