mirror of
https://github.com/spf13/cobra
synced 2024-11-24 14:47:12 +00:00
Add keeporder to shell completion (#1903)
This allows programs to request the shell to maintain the order of completions that was returned by the program
This commit is contained in:
parent
a516d4132c
commit
3daa4b9c36
6 changed files with 112 additions and 17 deletions
|
@ -101,6 +101,7 @@ __%[1]s_process_completion_results() {
|
||||||
local shellCompDirectiveNoFileComp=%[5]d
|
local shellCompDirectiveNoFileComp=%[5]d
|
||||||
local shellCompDirectiveFilterFileExt=%[6]d
|
local shellCompDirectiveFilterFileExt=%[6]d
|
||||||
local shellCompDirectiveFilterDirs=%[7]d
|
local shellCompDirectiveFilterDirs=%[7]d
|
||||||
|
local shellCompDirectiveKeepOrder=%[8]d
|
||||||
|
|
||||||
if (((directive & shellCompDirectiveError) != 0)); then
|
if (((directive & shellCompDirectiveError) != 0)); then
|
||||||
# Error code. No completion.
|
# Error code. No completion.
|
||||||
|
@ -115,6 +116,19 @@ __%[1]s_process_completion_results() {
|
||||||
__%[1]s_debug "No space directive not supported in this version of bash"
|
__%[1]s_debug "No space directive not supported in this version of bash"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
if (((directive & shellCompDirectiveKeepOrder) != 0)); then
|
||||||
|
if [[ $(type -t compopt) == builtin ]]; then
|
||||||
|
# no sort isn't supported for bash less than < 4.4
|
||||||
|
if [[ ${BASH_VERSINFO[0]} -lt 4 || ( ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -lt 4 ) ]]; then
|
||||||
|
__%[1]s_debug "No sort directive not supported in this version of bash"
|
||||||
|
else
|
||||||
|
__%[1]s_debug "Activating keep order"
|
||||||
|
compopt -o nosort
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
__%[1]s_debug "No sort directive not supported in this version of bash"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
if (((directive & shellCompDirectiveNoFileComp) != 0)); then
|
if (((directive & shellCompDirectiveNoFileComp) != 0)); then
|
||||||
if [[ $(type -t compopt) == builtin ]]; then
|
if [[ $(type -t compopt) == builtin ]]; then
|
||||||
__%[1]s_debug "Activating no file completion"
|
__%[1]s_debug "Activating no file completion"
|
||||||
|
@ -183,7 +197,7 @@ __%[1]s_process_completion_results() {
|
||||||
# Separate activeHelp lines from real completions.
|
# Separate activeHelp lines from real completions.
|
||||||
# Fills the $activeHelp and $completions arrays.
|
# Fills the $activeHelp and $completions arrays.
|
||||||
__%[1]s_extract_activeHelp() {
|
__%[1]s_extract_activeHelp() {
|
||||||
local activeHelpMarker="%[8]s"
|
local activeHelpMarker="%[9]s"
|
||||||
local endIndex=${#activeHelpMarker}
|
local endIndex=${#activeHelpMarker}
|
||||||
|
|
||||||
while IFS='' read -r comp; do
|
while IFS='' read -r comp; do
|
||||||
|
@ -360,7 +374,7 @@ fi
|
||||||
# ex: ts=4 sw=4 et filetype=sh
|
# ex: ts=4 sw=4 et filetype=sh
|
||||||
`, name, compCmd,
|
`, name, compCmd,
|
||||||
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
|
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
|
||||||
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs,
|
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder,
|
||||||
activeHelpMarker))
|
activeHelpMarker))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,10 @@ const (
|
||||||
// obtain the same behavior but only for flags.
|
// obtain the same behavior but only for flags.
|
||||||
ShellCompDirectiveFilterDirs
|
ShellCompDirectiveFilterDirs
|
||||||
|
|
||||||
|
// ShellCompDirectiveKeepOrder indicates that the shell should preserve the order
|
||||||
|
// in which the completions are provided
|
||||||
|
ShellCompDirectiveKeepOrder
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|
||||||
// All directives using iota should be above this one.
|
// All directives using iota should be above this one.
|
||||||
|
@ -159,6 +163,9 @@ func (d ShellCompDirective) string() string {
|
||||||
if d&ShellCompDirectiveFilterDirs != 0 {
|
if d&ShellCompDirectiveFilterDirs != 0 {
|
||||||
directives = append(directives, "ShellCompDirectiveFilterDirs")
|
directives = append(directives, "ShellCompDirectiveFilterDirs")
|
||||||
}
|
}
|
||||||
|
if d&ShellCompDirectiveKeepOrder != 0 {
|
||||||
|
directives = append(directives, "ShellCompDirectiveKeepOrder")
|
||||||
|
}
|
||||||
if len(directives) == 0 {
|
if len(directives) == 0 {
|
||||||
directives = append(directives, "ShellCompDirectiveDefault")
|
directives = append(directives, "ShellCompDirectiveDefault")
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ function __%[1]s_perform_completion
|
||||||
__%[1]s_debug "last arg: $lastArg"
|
__%[1]s_debug "last arg: $lastArg"
|
||||||
|
|
||||||
# Disable ActiveHelp which is not supported for fish shell
|
# Disable ActiveHelp which is not supported for fish shell
|
||||||
set -l requestComp "%[9]s=0 $args[1] %[3]s $args[2..-1] $lastArg"
|
set -l requestComp "%[10]s=0 $args[1] %[3]s $args[2..-1] $lastArg"
|
||||||
|
|
||||||
__%[1]s_debug "Calling $requestComp"
|
__%[1]s_debug "Calling $requestComp"
|
||||||
set -l results (eval $requestComp 2> /dev/null)
|
set -l results (eval $requestComp 2> /dev/null)
|
||||||
|
@ -89,6 +89,60 @@ function __%[1]s_perform_completion
|
||||||
printf "%%s\n" "$directiveLine"
|
printf "%%s\n" "$directiveLine"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# this function limits calls to __%[1]s_perform_completion, by caching the result behind $__%[1]s_perform_completion_once_result
|
||||||
|
function __%[1]s_perform_completion_once
|
||||||
|
__%[1]s_debug "Starting __%[1]s_perform_completion_once"
|
||||||
|
|
||||||
|
if test -n "$__%[1]s_perform_completion_once_result"
|
||||||
|
__%[1]s_debug "Seems like a valid result already exists, skipping __%[1]s_perform_completion"
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
set --global __%[1]s_perform_completion_once_result (__%[1]s_perform_completion)
|
||||||
|
if test -z "$__%[1]s_perform_completion_once_result"
|
||||||
|
__%[1]s_debug "No completions, probably due to a failure"
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
__%[1]s_debug "Performed completions and set __%[1]s_perform_completion_once_result"
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
# this function is used to clear the $__%[1]s_perform_completion_once_result variable after completions are run
|
||||||
|
function __%[1]s_clear_perform_completion_once_result
|
||||||
|
__%[1]s_debug ""
|
||||||
|
__%[1]s_debug "========= clearing previously set __%[1]s_perform_completion_once_result variable =========="
|
||||||
|
set --erase __%[1]s_perform_completion_once_result
|
||||||
|
__%[1]s_debug "Succesfully erased the variable __%[1]s_perform_completion_once_result"
|
||||||
|
end
|
||||||
|
|
||||||
|
function __%[1]s_requires_order_preservation
|
||||||
|
__%[1]s_debug ""
|
||||||
|
__%[1]s_debug "========= checking if order preservation is required =========="
|
||||||
|
|
||||||
|
__%[1]s_perform_completion_once
|
||||||
|
if test -z "$__%[1]s_perform_completion_once_result"
|
||||||
|
__%[1]s_debug "Error determining if order preservation is required"
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
set -l directive (string sub --start 2 $__%[1]s_perform_completion_once_result[-1])
|
||||||
|
__%[1]s_debug "Directive is: $directive"
|
||||||
|
|
||||||
|
set -l shellCompDirectiveKeepOrder %[9]d
|
||||||
|
set -l keeporder (math (math --scale 0 $directive / $shellCompDirectiveKeepOrder) %% 2)
|
||||||
|
__%[1]s_debug "Keeporder is: $keeporder"
|
||||||
|
|
||||||
|
if test $keeporder -ne 0
|
||||||
|
__%[1]s_debug "This does require order preservation"
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
__%[1]s_debug "This doesn't require order preservation"
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
# This function does two things:
|
# This function does two things:
|
||||||
# - Obtain the completions and store them in the global __%[1]s_comp_results
|
# - Obtain the completions and store them in the global __%[1]s_comp_results
|
||||||
# - Return false if file completion should be performed
|
# - Return false if file completion should be performed
|
||||||
|
@ -99,17 +153,17 @@ function __%[1]s_prepare_completions
|
||||||
# Start fresh
|
# Start fresh
|
||||||
set --erase __%[1]s_comp_results
|
set --erase __%[1]s_comp_results
|
||||||
|
|
||||||
set -l results (__%[1]s_perform_completion)
|
__%[1]s_perform_completion_once
|
||||||
__%[1]s_debug "Completion results: $results"
|
__%[1]s_debug "Completion results: $__%[1]s_perform_completion_once_result"
|
||||||
|
|
||||||
if test -z "$results"
|
if test -z "$__%[1]s_perform_completion_once_result"
|
||||||
__%[1]s_debug "No completion, probably due to a failure"
|
__%[1]s_debug "No completion, probably due to a failure"
|
||||||
# Might as well do file completion, in case it helps
|
# Might as well do file completion, in case it helps
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
set -l directive (string sub --start 2 $results[-1])
|
set -l directive (string sub --start 2 $__%[1]s_perform_completion_once_result[-1])
|
||||||
set --global __%[1]s_comp_results $results[1..-2]
|
set --global __%[1]s_comp_results $__%[1]s_perform_completion_once_result[1..-2]
|
||||||
|
|
||||||
__%[1]s_debug "Completions are: $__%[1]s_comp_results"
|
__%[1]s_debug "Completions are: $__%[1]s_comp_results"
|
||||||
__%[1]s_debug "Directive is: $directive"
|
__%[1]s_debug "Directive is: $directive"
|
||||||
|
@ -205,13 +259,17 @@ end
|
||||||
# Remove any pre-existing completions for the program since we will be handling all of them.
|
# Remove any pre-existing completions for the program since we will be handling all of them.
|
||||||
complete -c %[2]s -e
|
complete -c %[2]s -e
|
||||||
|
|
||||||
|
# this will get called after the two calls below and clear the $__%[1]s_perform_completion_once_result global
|
||||||
|
complete -c %[2]s -n '__%[1]s_clear_perform_completion_once_result'
|
||||||
# The call to __%[1]s_prepare_completions will setup __%[1]s_comp_results
|
# The call to __%[1]s_prepare_completions will setup __%[1]s_comp_results
|
||||||
# which provides the program's completion choices.
|
# which provides the program's completion choices.
|
||||||
complete -c %[2]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results'
|
# If this doesn't require order preservation, we don't use the -k flag
|
||||||
|
complete -c %[2]s -n 'not __%[1]s_requires_order_preservation && __%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results'
|
||||||
|
# otherwise we use the -k flag
|
||||||
|
complete -k -c %[2]s -n '__%[1]s_requires_order_preservation && __%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results'
|
||||||
`, nameForVar, name, compCmd,
|
`, nameForVar, name, compCmd,
|
||||||
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
|
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
|
||||||
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name)))
|
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder, activeHelpEnvVar(name)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenFishCompletion generates fish completion file and writes to the passed writer.
|
// GenFishCompletion generates fish completion file and writes to the passed writer.
|
||||||
|
|
|
@ -77,6 +77,7 @@ filter __%[1]s_escapeStringWithSpecialChars {
|
||||||
$ShellCompDirectiveNoFileComp=%[6]d
|
$ShellCompDirectiveNoFileComp=%[6]d
|
||||||
$ShellCompDirectiveFilterFileExt=%[7]d
|
$ShellCompDirectiveFilterFileExt=%[7]d
|
||||||
$ShellCompDirectiveFilterDirs=%[8]d
|
$ShellCompDirectiveFilterDirs=%[8]d
|
||||||
|
$ShellCompDirectiveKeepOrder=%[9]d
|
||||||
|
|
||||||
# Prepare the command to request completions for the program.
|
# Prepare the command to request completions for the program.
|
||||||
# Split the command at the first space to separate the program and arguments.
|
# Split the command at the first space to separate the program and arguments.
|
||||||
|
@ -112,7 +113,7 @@ filter __%[1]s_escapeStringWithSpecialChars {
|
||||||
|
|
||||||
__%[1]s_debug "Calling $RequestComp"
|
__%[1]s_debug "Calling $RequestComp"
|
||||||
# First disable ActiveHelp which is not supported for Powershell
|
# First disable ActiveHelp which is not supported for Powershell
|
||||||
$env:%[9]s=0
|
$env:%[10]s=0
|
||||||
|
|
||||||
#call the command store the output in $out and redirect stderr and stdout to null
|
#call the command store the output in $out and redirect stderr and stdout to null
|
||||||
# $Out is an array contains each line per element
|
# $Out is an array contains each line per element
|
||||||
|
@ -182,6 +183,11 @@ filter __%[1]s_escapeStringWithSpecialChars {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# we sort the values in ascending order by name if keep order isn't passed
|
||||||
|
if (($Directive -band $ShellCompDirectiveKeepOrder) -eq 0 ) {
|
||||||
|
$Values = $Values | Sort-Object -Property Name
|
||||||
|
}
|
||||||
|
|
||||||
if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) {
|
if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) {
|
||||||
__%[1]s_debug "ShellCompDirectiveNoFileComp is called"
|
__%[1]s_debug "ShellCompDirectiveNoFileComp is called"
|
||||||
|
|
||||||
|
@ -267,7 +273,7 @@ filter __%[1]s_escapeStringWithSpecialChars {
|
||||||
Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock $__%[2]sCompleterBlock
|
Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock $__%[2]sCompleterBlock
|
||||||
`, name, nameForVar, compCmd,
|
`, name, nameForVar, compCmd,
|
||||||
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
|
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
|
||||||
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name)))
|
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder, activeHelpEnvVar(name)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Command) genPowerShellCompletion(w io.Writer, includeDesc bool) error {
|
func (c *Command) genPowerShellCompletion(w io.Writer, includeDesc bool) error {
|
||||||
|
|
|
@ -228,6 +228,10 @@ ShellCompDirectiveFilterFileExt
|
||||||
// return []string{"themes"}, ShellCompDirectiveFilterDirs
|
// return []string{"themes"}, ShellCompDirectiveFilterDirs
|
||||||
//
|
//
|
||||||
ShellCompDirectiveFilterDirs
|
ShellCompDirectiveFilterDirs
|
||||||
|
|
||||||
|
// ShellCompDirectiveKeepOrder indicates that the shell should preserve the order
|
||||||
|
// in which the completions are provided
|
||||||
|
ShellCompDirectiveKeepOrder
|
||||||
```
|
```
|
||||||
|
|
||||||
***Note***: When using the `ValidArgsFunction`, Cobra will call your registered function after having parsed all flags and arguments provided in the command-line. You therefore don't need to do this parsing yourself. For example, when a user calls `helm status --namespace my-rook-ns [tab][tab]`, Cobra will call your registered `ValidArgsFunction` after having parsed the `--namespace` flag, as it would have done when calling the `RunE` function.
|
***Note***: When using the `ValidArgsFunction`, Cobra will call your registered function after having parsed all flags and arguments provided in the command-line. You therefore don't need to do this parsing yourself. For example, when a user calls `helm status --namespace my-rook-ns [tab][tab]`, Cobra will call your registered `ValidArgsFunction` after having parsed the `--namespace` flag, as it would have done when calling the `RunE` function.
|
||||||
|
|
|
@ -108,8 +108,9 @@ _%[1]s()
|
||||||
local shellCompDirectiveNoFileComp=%[5]d
|
local shellCompDirectiveNoFileComp=%[5]d
|
||||||
local shellCompDirectiveFilterFileExt=%[6]d
|
local shellCompDirectiveFilterFileExt=%[6]d
|
||||||
local shellCompDirectiveFilterDirs=%[7]d
|
local shellCompDirectiveFilterDirs=%[7]d
|
||||||
|
local shellCompDirectiveKeepOrder=%[8]d
|
||||||
|
|
||||||
local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace
|
local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace keepOrder
|
||||||
local -a completions
|
local -a completions
|
||||||
|
|
||||||
__%[1]s_debug "\n========= starting completion logic =========="
|
__%[1]s_debug "\n========= starting completion logic =========="
|
||||||
|
@ -177,7 +178,7 @@ _%[1]s()
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local activeHelpMarker="%[8]s"
|
local activeHelpMarker="%[9]s"
|
||||||
local endIndex=${#activeHelpMarker}
|
local endIndex=${#activeHelpMarker}
|
||||||
local startIndex=$((${#activeHelpMarker}+1))
|
local startIndex=$((${#activeHelpMarker}+1))
|
||||||
local hasActiveHelp=0
|
local hasActiveHelp=0
|
||||||
|
@ -227,6 +228,11 @@ _%[1]s()
|
||||||
noSpace="-S ''"
|
noSpace="-S ''"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ $((directive & shellCompDirectiveKeepOrder)) -ne 0 ]; then
|
||||||
|
__%[1]s_debug "Activating keep order."
|
||||||
|
keepOrder="-V"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
|
if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
|
||||||
# File extension filtering
|
# File extension filtering
|
||||||
local filteringCmd
|
local filteringCmd
|
||||||
|
@ -262,7 +268,7 @@ _%[1]s()
|
||||||
return $result
|
return $result
|
||||||
else
|
else
|
||||||
__%[1]s_debug "Calling _describe"
|
__%[1]s_debug "Calling _describe"
|
||||||
if eval _describe "completions" completions $flagPrefix $noSpace; then
|
if eval _describe $keepOrder "completions" completions $flagPrefix $noSpace; then
|
||||||
__%[1]s_debug "_describe found some completions"
|
__%[1]s_debug "_describe found some completions"
|
||||||
|
|
||||||
# Return the success of having called _describe
|
# Return the success of having called _describe
|
||||||
|
@ -296,6 +302,6 @@ if [ "$funcstack[1]" = "_%[1]s" ]; then
|
||||||
fi
|
fi
|
||||||
`, name, compCmd,
|
`, name, compCmd,
|
||||||
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
|
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
|
||||||
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs,
|
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder,
|
||||||
activeHelpMarker))
|
activeHelpMarker))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue