diff --git a/docs/man/git-lfs-completion.adoc b/docs/man/git-lfs-completion.adoc index 32532fd081..21ff620b53 100644 --- a/docs/man/git-lfs-completion.adoc +++ b/docs/man/git-lfs-completion.adoc @@ -211,7 +211,6 @@ tab-completion, as described in the <<_shells>> section. + .... % source <(git lfs completion zsh) -% compdef _git-lfs git-lfs .... === Automatically loading completions for future shell sessions diff --git a/go.mod b/go.mod index 83dc168d05..b7fbd5e820 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 github.com/pkg/errors v0.0.0-20170505043639-c605e284fe17 github.com/rubyist/tracerx v0.0.0-20170927163412-787959303086 - github.com/spf13/cobra v1.6.0 + github.com/spf13/cobra v1.7.0 github.com/ssgelm/cookiejarparser v1.0.1 github.com/stretchr/testify v1.6.1 github.com/xeipuuv/gojsonschema v0.0.0-20170210233622-6b67b3fab74d @@ -27,7 +27,7 @@ require ( github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.2 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.0.0 // indirect diff --git a/go.sum b/go.sum index 4a0ac71d8b..3015505698 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,8 @@ github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7Fsg github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= @@ -49,8 +49,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rubyist/tracerx v0.0.0-20170927163412-787959303086 h1:mncRSDOqYCng7jOD+Y6+IivdRI6Kzv2BLWYkWkdQfu0= github.com/rubyist/tracerx v0.0.0-20170927163412-787959303086/go.mod h1:YpdgDXpumPB/+EGmGTYHeiW/0QVFRzBYTNFaxWfPDk4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= -github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/ssgelm/cookiejarparser v1.0.1 h1:cRdXauUbOTFzTPJFaeiWbHnQ+tRGlpKKzvIK9PUekE4= diff --git a/t/fixtures/completions/git-lfs-completion.bash b/t/fixtures/completions/git-lfs-completion.bash index 128493da16..384d9b41e5 100644 --- a/t/fixtures/completions/git-lfs-completion.bash +++ b/t/fixtures/completions/git-lfs-completion.bash @@ -2,7 +2,7 @@ __git-lfs_debug() { - if [[ -n ${BASH_COMP_DEBUG_FILE:-} ]]; then + if [[ -n ${BASH_COMP_DEBUG_FILE-} ]]; then echo "$*" >> "${BASH_COMP_DEBUG_FILE}" fi } @@ -29,7 +29,7 @@ __git-lfs_get_completion_results() { lastChar=${lastParam:$((${#lastParam}-1)):1} __git-lfs_debug "lastParam ${lastParam}, lastChar ${lastChar}" - if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then + if [[ -z ${cur} && ${lastChar} != = ]]; then # If the last parameter is complete (there is a space following it) # We add an extra empty parameter so we can indicate this to the go method. __git-lfs_debug "Adding extra empty parameter" @@ -39,7 +39,7 @@ __git-lfs_get_completion_results() { # When completing a flag with an = (e.g., git-lfs -n=) # bash focuses on the part after the =, so we need to remove # the flag part from $cur - if [[ "${cur}" == -*=* ]]; then + if [[ ${cur} == -*=* ]]; then cur="${cur#*=}" fi @@ -51,7 +51,7 @@ __git-lfs_get_completion_results() { directive=${out##*:} # Remove the directive out=${out%:*} - if [ "${directive}" = "${out}" ]; then + if [[ ${directive} == "${out}" ]]; then # There is not directive specified directive=0 fi @@ -65,22 +65,36 @@ __git-lfs_process_completion_results() { local shellCompDirectiveNoFileComp=4 local shellCompDirectiveFilterFileExt=8 local shellCompDirectiveFilterDirs=16 + local shellCompDirectiveKeepOrder=32 - if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then + if (((directive & shellCompDirectiveError) != 0)); then # Error code. No completion. __git-lfs_debug "Received error from custom completion go code" return else - if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then - if [[ $(type -t compopt) = "builtin" ]]; then + if (((directive & shellCompDirectiveNoSpace) != 0)); then + if [[ $(type -t compopt) == builtin ]]; then __git-lfs_debug "Activating no space" compopt -o nospace else __git-lfs_debug "No space directive not supported in this version of bash" fi fi - if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then - if [[ $(type -t compopt) = "builtin" ]]; then + 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 + __git-lfs_debug "No sort directive not supported in this version of bash" + else + __git-lfs_debug "Activating keep order" + compopt -o nosort + fi + else + __git-lfs_debug "No sort directive not supported in this version of bash" + fi + fi + if (((directive & shellCompDirectiveNoFileComp) != 0)); then + if [[ $(type -t compopt) == builtin ]]; then __git-lfs_debug "Activating no file completion" compopt +o default else @@ -94,7 +108,7 @@ __git-lfs_process_completion_results() { local activeHelp=() __git-lfs_extract_activeHelp - if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then + if (((directive & shellCompDirectiveFilterFileExt) != 0)); then # File extension filtering local fullFilter filter filteringCmd @@ -107,13 +121,12 @@ __git-lfs_process_completion_results() { filteringCmd="_filedir $fullFilter" __git-lfs_debug "File filtering command: $filteringCmd" $filteringCmd - elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then + elif (((directive & shellCompDirectiveFilterDirs) != 0)); then # File completion for directories only - # Use printf to strip any trailing newline local subdir - subdir=$(printf "%s" "${completions[0]}") - if [ -n "$subdir" ]; then + subdir=${completions[0]} + if [[ -n $subdir ]]; then __git-lfs_debug "Listing directories in $subdir" pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return else @@ -128,7 +141,7 @@ __git-lfs_process_completion_results() { __git-lfs_handle_special_char "$cur" = # Print the activeHelp statements before we finish - if [ ${#activeHelp[*]} -ne 0 ]; then + if ((${#activeHelp[*]} != 0)); then printf "\n"; printf "%s\n" "${activeHelp[@]}" printf "\n" @@ -152,17 +165,17 @@ __git-lfs_extract_activeHelp() { local endIndex=${#activeHelpMarker} while IFS='' read -r comp; do - if [ "${comp:0:endIndex}" = "$activeHelpMarker" ]; then + if [[ ${comp:0:endIndex} == $activeHelpMarker ]]; then comp=${comp:endIndex} __git-lfs_debug "ActiveHelp found: $comp" - if [ -n "$comp" ]; then + if [[ -n $comp ]]; then activeHelp+=("$comp") fi else # Not an activeHelp line but a normal completion completions+=("$comp") fi - done < <(printf "%s\n" "${out}") + done <<<"${out}" } __git-lfs_handle_completion_types() { @@ -218,7 +231,7 @@ __git-lfs_handle_standard_completion_case() { done < <(printf "%s\n" "${completions[@]}") # If there is a single completion left, remove the description text - if [ ${#COMPREPLY[*]} -eq 1 ]; then + if ((${#COMPREPLY[*]} == 1)); then __git-lfs_debug "COMPREPLY[0]: ${COMPREPLY[0]}" comp="${COMPREPLY[0]%%$tab*}" __git-lfs_debug "Removed description from single completion, which is now: ${comp}" @@ -235,8 +248,8 @@ __git-lfs_handle_special_char() if [[ "$comp" == *${char}* && "$COMP_WORDBREAKS" == *${char}* ]]; then local word=${comp%"${comp##*${char}}"} local idx=${#COMPREPLY[*]} - while [[ $((--idx)) -ge 0 ]]; do - COMPREPLY[$idx]=${COMPREPLY[$idx]#"$word"} + while ((--idx >= 0)); do + COMPREPLY[idx]=${COMPREPLY[idx]#"$word"} done fi } @@ -262,7 +275,7 @@ __git-lfs_format_comp_descriptions() # Make sure we can fit a description of at least 8 characters # if we are to align the descriptions. - if [[ $maxdesclength -gt 8 ]]; then + if ((maxdesclength > 8)); then # Add the proper number of spaces to align the descriptions for ((i = ${#comp} ; i < longest ; i++)); do comp+=" " @@ -274,8 +287,8 @@ __git-lfs_format_comp_descriptions() # If there is enough space for any description text, # truncate the descriptions that are too long for the shell width - if [ $maxdesclength -gt 0 ]; then - if [ ${#desc} -gt $maxdesclength ]; then + if ((maxdesclength > 0)); then + if ((${#desc} > maxdesclength)); then desc=${desc:0:$(( maxdesclength - 1 ))} desc+="…" fi @@ -296,9 +309,9 @@ __start_git-lfs() # Call _init_completion from the bash-completion package # to prepare the arguments properly if declare -F _init_completion >/dev/null 2>&1; then - _init_completion -n "=:" || return + _init_completion -n =: || return else - __git-lfs_init_completion -n "=:" || return + __git-lfs_init_completion -n =: || return fi __git-lfs_debug diff --git a/t/fixtures/completions/git-lfs-completion.fish b/t/fixtures/completions/git-lfs-completion.fish index fcdd0ed751..b4a3a9a14d 100644 --- a/t/fixtures/completions/git-lfs-completion.fish +++ b/t/fixtures/completions/git-lfs-completion.fish @@ -55,6 +55,60 @@ function __git_lfs_perform_completion printf "%s\n" "$directiveLine" end +# this function limits calls to __git_lfs_perform_completion, by caching the result behind $__git_lfs_perform_completion_once_result +function __git_lfs_perform_completion_once + __git_lfs_debug "Starting __git_lfs_perform_completion_once" + + if test -n "$__git_lfs_perform_completion_once_result" + __git_lfs_debug "Seems like a valid result already exists, skipping __git_lfs_perform_completion" + return 0 + end + + set --global __git_lfs_perform_completion_once_result (__git_lfs_perform_completion) + if test -z "$__git_lfs_perform_completion_once_result" + __git_lfs_debug "No completions, probably due to a failure" + return 1 + end + + __git_lfs_debug "Performed completions and set __git_lfs_perform_completion_once_result" + return 0 +end + +# this function is used to clear the $__git_lfs_perform_completion_once_result variable after completions are run +function __git_lfs_clear_perform_completion_once_result + __git_lfs_debug "" + __git_lfs_debug "========= clearing previously set __git_lfs_perform_completion_once_result variable ==========" + set --erase __git_lfs_perform_completion_once_result + __git_lfs_debug "Succesfully erased the variable __git_lfs_perform_completion_once_result" +end + +function __git_lfs_requires_order_preservation + __git_lfs_debug "" + __git_lfs_debug "========= checking if order preservation is required ==========" + + __git_lfs_perform_completion_once + if test -z "$__git_lfs_perform_completion_once_result" + __git_lfs_debug "Error determining if order preservation is required" + return 1 + end + + set -l directive (string sub --start 2 $__git_lfs_perform_completion_once_result[-1]) + __git_lfs_debug "Directive is: $directive" + + set -l shellCompDirectiveKeepOrder 32 + set -l keeporder (math (math --scale 0 $directive / $shellCompDirectiveKeepOrder) % 2) + __git_lfs_debug "Keeporder is: $keeporder" + + if test $keeporder -ne 0 + __git_lfs_debug "This does require order preservation" + return 0 + end + + __git_lfs_debug "This doesn't require order preservation" + return 1 +end + + # This function does two things: # - Obtain the completions and store them in the global __git_lfs_comp_results # - Return false if file completion should be performed @@ -65,17 +119,17 @@ function __git_lfs_prepare_completions # Start fresh set --erase __git_lfs_comp_results - set -l results (__git_lfs_perform_completion) - __git_lfs_debug "Completion results: $results" + __git_lfs_perform_completion_once + __git_lfs_debug "Completion results: $__git_lfs_perform_completion_once_result" - if test -z "$results" + if test -z "$__git_lfs_perform_completion_once_result" __git_lfs_debug "No completion, probably due to a failure" # Might as well do file completion, in case it helps return 1 end - set -l directive (string sub --start 2 $results[-1]) - set --global __git_lfs_comp_results $results[1..-2] + set -l directive (string sub --start 2 $__git_lfs_perform_completion_once_result[-1]) + set --global __git_lfs_comp_results $__git_lfs_perform_completion_once_result[1..-2] __git_lfs_debug "Completions are: $__git_lfs_comp_results" __git_lfs_debug "Directive is: $directive" @@ -171,7 +225,11 @@ end # Remove any pre-existing completions for the program since we will be handling all of them. complete -c git-lfs -e +# this will get called after the two calls below and clear the $__git_lfs_perform_completion_once_result global +complete -c git-lfs -n '__git_lfs_clear_perform_completion_once_result' # The call to __git_lfs_prepare_completions will setup __git_lfs_comp_results # which provides the program's completion choices. -complete -c git-lfs -n '__git_lfs_prepare_completions' -f -a '$__git_lfs_comp_results' - +# If this doesn't require order preservation, we don't use the -k flag +complete -c git-lfs -n 'not __git_lfs_requires_order_preservation && __git_lfs_prepare_completions' -f -a '$__git_lfs_comp_results' +# otherwise we use the -k flag +complete -k -c git-lfs -n '__git_lfs_requires_order_preservation && __git_lfs_prepare_completions' -f -a '$__git_lfs_comp_results' diff --git a/t/fixtures/completions/git-lfs-completion.zsh b/t/fixtures/completions/git-lfs-completion.zsh index e3d8cab523..9603af7782 100644 --- a/t/fixtures/completions/git-lfs-completion.zsh +++ b/t/fixtures/completions/git-lfs-completion.zsh @@ -1,4 +1,5 @@ #compdef git-lfs +compdef _git-lfs git-lfs # zsh completion for git-lfs -*- shell-script -*- @@ -17,8 +18,9 @@ _git-lfs() local shellCompDirectiveNoFileComp=4 local shellCompDirectiveFilterFileExt=8 local shellCompDirectiveFilterDirs=16 + local shellCompDirectiveKeepOrder=32 - local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace + local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace keepOrder local -a completions __git-lfs_debug "\n========= starting completion logic ==========" @@ -136,6 +138,11 @@ _git-lfs() noSpace="-S ''" fi + if [ $((directive & shellCompDirectiveKeepOrder)) -ne 0 ]; then + __git-lfs_debug "Activating keep order." + keepOrder="-V" + fi + if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then # File extension filtering local filteringCmd @@ -171,7 +178,7 @@ _git-lfs() return $result else __git-lfs_debug "Calling _describe" - if eval _describe "completions" completions $flagPrefix $noSpace; then + if eval _describe $keepOrder "completions" completions $flagPrefix $noSpace; then __git-lfs_debug "_describe found some completions" # Return the success of having called _describe