vendor/github.com/spf13/cobra/bash_completionsV2.go
changeset 260 445e01aede7e
parent 256 6d9efbef00a9
child 265 05c40b36d3b2
equal deleted inserted replaced
259:db4911b0c721 260:445e01aede7e
    76     if [ "${directive}" = "${out}" ]; then
    76     if [ "${directive}" = "${out}" ]; then
    77         # There is not directive specified
    77         # There is not directive specified
    78         directive=0
    78         directive=0
    79     fi
    79     fi
    80     __%[1]s_debug "The completion directive is: ${directive}"
    80     __%[1]s_debug "The completion directive is: ${directive}"
    81     __%[1]s_debug "The completions are: ${out[*]}"
    81     __%[1]s_debug "The completions are: ${out}"
    82 }
    82 }
    83 
    83 
    84 __%[1]s_process_completion_results() {
    84 __%[1]s_process_completion_results() {
    85     local shellCompDirectiveError=%[3]d
    85     local shellCompDirectiveError=%[3]d
    86     local shellCompDirectiveNoSpace=%[4]d
    86     local shellCompDirectiveNoSpace=%[4]d
   109                 __%[1]s_debug "No file completion directive not supported in this version of bash"
   109                 __%[1]s_debug "No file completion directive not supported in this version of bash"
   110             fi
   110             fi
   111         fi
   111         fi
   112     fi
   112     fi
   113 
   113 
       
   114     # Separate activeHelp from normal completions
       
   115     local completions=()
       
   116     local activeHelp=()
       
   117     __%[1]s_extract_activeHelp
       
   118 
   114     if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
   119     if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
   115         # File extension filtering
   120         # File extension filtering
   116         local fullFilter filter filteringCmd
   121         local fullFilter filter filteringCmd
   117 
   122 
   118         # Do not use quotes around the $out variable or else newline
   123         # Do not use quotes around the $completions variable or else newline
   119         # characters will be kept.
   124         # characters will be kept.
   120         for filter in ${out[*]}; do
   125         for filter in ${completions[*]}; do
   121             fullFilter+="$filter|"
   126             fullFilter+="$filter|"
   122         done
   127         done
   123 
   128 
   124         filteringCmd="_filedir $fullFilter"
   129         filteringCmd="_filedir $fullFilter"
   125         __%[1]s_debug "File filtering command: $filteringCmd"
   130         __%[1]s_debug "File filtering command: $filteringCmd"
   127     elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then
   132     elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then
   128         # File completion for directories only
   133         # File completion for directories only
   129 
   134 
   130         # Use printf to strip any trailing newline
   135         # Use printf to strip any trailing newline
   131         local subdir
   136         local subdir
   132         subdir=$(printf "%%s" "${out[0]}")
   137         subdir=$(printf "%%s" "${completions[0]}")
   133         if [ -n "$subdir" ]; then
   138         if [ -n "$subdir" ]; then
   134             __%[1]s_debug "Listing directories in $subdir"
   139             __%[1]s_debug "Listing directories in $subdir"
   135             pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return
   140             pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return
   136         else
   141         else
   137             __%[1]s_debug "Listing directories in ."
   142             __%[1]s_debug "Listing directories in ."
   138             _filedir -d
   143             _filedir -d
   139         fi
   144         fi
   140     else
   145     else
   141         __%[1]s_handle_standard_completion_case
   146         __%[1]s_handle_completion_types
   142     fi
   147     fi
   143 
   148 
   144     __%[1]s_handle_special_char "$cur" :
   149     __%[1]s_handle_special_char "$cur" :
   145     __%[1]s_handle_special_char "$cur" =
   150     __%[1]s_handle_special_char "$cur" =
       
   151 
       
   152     # Print the activeHelp statements before we finish
       
   153     if [ ${#activeHelp} -ne 0 ]; then
       
   154         printf "\n";
       
   155         printf "%%s\n" "${activeHelp[@]}"
       
   156         printf "\n"
       
   157 
       
   158         # The prompt format is only available from bash 4.4.
       
   159         # We test if it is available before using it.
       
   160         if (x=${PS1@P}) 2> /dev/null; then
       
   161             printf "%%s" "${PS1@P}${COMP_LINE[@]}"
       
   162         else
       
   163             # Can't print the prompt.  Just print the
       
   164             # text the user had typed, it is workable enough.
       
   165             printf "%%s" "${COMP_LINE[@]}"
       
   166         fi
       
   167     fi
       
   168 }
       
   169 
       
   170 # Separate activeHelp lines from real completions.
       
   171 # Fills the $activeHelp and $completions arrays.
       
   172 __%[1]s_extract_activeHelp() {
       
   173     local activeHelpMarker="%[8]s"
       
   174     local endIndex=${#activeHelpMarker}
       
   175 
       
   176     while IFS='' read -r comp; do
       
   177         if [ "${comp:0:endIndex}" = "$activeHelpMarker" ]; then
       
   178             comp=${comp:endIndex}
       
   179             __%[1]s_debug "ActiveHelp found: $comp"
       
   180             if [ -n "$comp" ]; then
       
   181                 activeHelp+=("$comp")
       
   182             fi
       
   183         else
       
   184             # Not an activeHelp line but a normal completion
       
   185             completions+=("$comp")
       
   186         fi
       
   187     done < <(printf "%%s\n" "${out}")
       
   188 }
       
   189 
       
   190 __%[1]s_handle_completion_types() {
       
   191     __%[1]s_debug "__%[1]s_handle_completion_types: COMP_TYPE is $COMP_TYPE"
       
   192 
       
   193     case $COMP_TYPE in
       
   194     37|42)
       
   195         # Type: menu-complete/menu-complete-backward and insert-completions
       
   196         # If the user requested inserting one completion at a time, or all
       
   197         # completions at once on the command-line we must remove the descriptions.
       
   198         # https://github.com/spf13/cobra/issues/1508
       
   199         local tab=$'\t' comp
       
   200         while IFS='' read -r comp; do
       
   201             [[ -z $comp ]] && continue
       
   202             # Strip any description
       
   203             comp=${comp%%%%$tab*}
       
   204             # Only consider the completions that match
       
   205             if [[ $comp == "$cur"* ]]; then
       
   206                 COMPREPLY+=("$comp")
       
   207             fi
       
   208         done < <(printf "%%s\n" "${completions[@]}")
       
   209         ;;
       
   210 
       
   211     *)
       
   212         # Type: complete (normal completion)
       
   213         __%[1]s_handle_standard_completion_case
       
   214         ;;
       
   215     esac
   146 }
   216 }
   147 
   217 
   148 __%[1]s_handle_standard_completion_case() {
   218 __%[1]s_handle_standard_completion_case() {
   149     local tab comp
   219     local tab=$'\t' comp
   150     tab=$(printf '\t')
   220 
       
   221     # Short circuit to optimize if we don't have descriptions
       
   222     if [[ "${completions[*]}" != *$tab* ]]; then
       
   223         IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur")
       
   224         return 0
       
   225     fi
   151 
   226 
   152     local longest=0
   227     local longest=0
       
   228     local compline
   153     # Look for the longest completion so that we can format things nicely
   229     # Look for the longest completion so that we can format things nicely
   154     while IFS='' read -r comp; do
   230     while IFS='' read -r compline; do
       
   231         [[ -z $compline ]] && continue
   155         # Strip any description before checking the length
   232         # Strip any description before checking the length
   156         comp=${comp%%%%$tab*}
   233         comp=${compline%%%%$tab*}
   157         # Only consider the completions that match
   234         # Only consider the completions that match
   158         comp=$(compgen -W "$comp" -- "$cur")
   235         [[ $comp == "$cur"* ]] || continue
       
   236         COMPREPLY+=("$compline")
   159         if ((${#comp}>longest)); then
   237         if ((${#comp}>longest)); then
   160             longest=${#comp}
   238             longest=${#comp}
   161         fi
   239         fi
   162     done < <(printf "%%s\n" "${out[@]}")
   240     done < <(printf "%%s\n" "${completions[@]}")
   163 
       
   164     local completions=()
       
   165     while IFS='' read -r comp; do
       
   166         if [ -z "$comp" ]; then
       
   167             continue
       
   168         fi
       
   169 
       
   170         __%[1]s_debug "Original comp: $comp"
       
   171         comp="$(__%[1]s_format_comp_descriptions "$comp" "$longest")"
       
   172         __%[1]s_debug "Final comp: $comp"
       
   173         completions+=("$comp")
       
   174     done < <(printf "%%s\n" "${out[@]}")
       
   175 
       
   176     while IFS='' read -r comp; do
       
   177         COMPREPLY+=("$comp")
       
   178     done < <(compgen -W "${completions[*]}" -- "$cur")
       
   179 
   241 
   180     # If there is a single completion left, remove the description text
   242     # If there is a single completion left, remove the description text
   181     if [ ${#COMPREPLY[*]} -eq 1 ]; then
   243     if [ ${#COMPREPLY[*]} -eq 1 ]; then
   182         __%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
   244         __%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
   183         comp="${COMPREPLY[0]%%%% *}"
   245         comp="${COMPREPLY[0]%%%%$tab*}"
   184         __%[1]s_debug "Removed description from single completion, which is now: ${comp}"
   246         __%[1]s_debug "Removed description from single completion, which is now: ${comp}"
   185         COMPREPLY=()
   247         COMPREPLY[0]=$comp
   186         COMPREPLY+=("$comp")
   248     else # Format the descriptions
       
   249         __%[1]s_format_comp_descriptions $longest
   187     fi
   250     fi
   188 }
   251 }
   189 
   252 
   190 __%[1]s_handle_special_char()
   253 __%[1]s_handle_special_char()
   191 {
   254 {
   200     fi
   263     fi
   201 }
   264 }
   202 
   265 
   203 __%[1]s_format_comp_descriptions()
   266 __%[1]s_format_comp_descriptions()
   204 {
   267 {
   205     local tab
   268     local tab=$'\t'
   206     tab=$(printf '\t')
   269     local comp desc maxdesclength
   207     local comp="$1"
   270     local longest=$1
   208     local longest=$2
   271 
   209 
   272     local i ci
   210     # Properly format the description string which follows a tab character if there is one
   273     for ci in ${!COMPREPLY[*]}; do
   211     if [[ "$comp" == *$tab* ]]; then
   274         comp=${COMPREPLY[ci]}
   212         desc=${comp#*$tab}
   275         # Properly format the description string which follows a tab character if there is one
   213         comp=${comp%%%%$tab*}
   276         if [[ "$comp" == *$tab* ]]; then
   214 
   277             __%[1]s_debug "Original comp: $comp"
   215         # $COLUMNS stores the current shell width.
   278             desc=${comp#*$tab}
   216         # Remove an extra 4 because we add 2 spaces and 2 parentheses.
   279             comp=${comp%%%%$tab*}
   217         maxdesclength=$(( COLUMNS - longest - 4 ))
   280 
   218 
   281             # $COLUMNS stores the current shell width.
   219         # Make sure we can fit a description of at least 8 characters
   282             # Remove an extra 4 because we add 2 spaces and 2 parentheses.
   220         # if we are to align the descriptions.
   283             maxdesclength=$(( COLUMNS - longest - 4 ))
   221         if [[ $maxdesclength -gt 8 ]]; then
   284 
   222             # Add the proper number of spaces to align the descriptions
   285             # Make sure we can fit a description of at least 8 characters
   223             for ((i = ${#comp} ; i < longest ; i++)); do
   286             # if we are to align the descriptions.
   224                 comp+=" "
   287             if [[ $maxdesclength -gt 8 ]]; then
   225             done
   288                 # Add the proper number of spaces to align the descriptions
   226         else
   289                 for ((i = ${#comp} ; i < longest ; i++)); do
   227             # Don't pad the descriptions so we can fit more text after the completion
   290                     comp+=" "
   228             maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
   291                 done
   229         fi
   292             else
   230 
   293                 # Don't pad the descriptions so we can fit more text after the completion
   231         # If there is enough space for any description text,
   294                 maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
   232         # truncate the descriptions that are too long for the shell width
   295             fi
   233         if [ $maxdesclength -gt 0 ]; then
   296 
   234             if [ ${#desc} -gt $maxdesclength ]; then
   297             # If there is enough space for any description text,
   235                 desc=${desc:0:$(( maxdesclength - 1 ))}
   298             # truncate the descriptions that are too long for the shell width
   236                 desc+="…"
   299             if [ $maxdesclength -gt 0 ]; then
   237             fi
   300                 if [ ${#desc} -gt $maxdesclength ]; then
   238             comp+="  ($desc)"
   301                     desc=${desc:0:$(( maxdesclength - 1 ))}
   239         fi
   302                     desc+="…"
   240     fi
   303                 fi
   241 
   304                 comp+="  ($desc)"
   242     # Must use printf to escape all special characters
   305             fi
   243     printf "%%q" "${comp}"
   306             COMPREPLY[ci]=$comp
       
   307             __%[1]s_debug "Final comp: $comp"
       
   308         fi
       
   309     done
   244 }
   310 }
   245 
   311 
   246 __start_%[1]s()
   312 __start_%[1]s()
   247 {
   313 {
   248     local cur prev words cword split
   314     local cur prev words cword split
   279 fi
   345 fi
   280 
   346 
   281 # ex: ts=4 sw=4 et filetype=sh
   347 # ex: ts=4 sw=4 et filetype=sh
   282 `, name, compCmd,
   348 `, name, compCmd,
   283 		ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
   349 		ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
   284 		ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
   350 		ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs,
       
   351 		activeHelpMarker))
   285 }
   352 }
   286 
   353 
   287 // GenBashCompletionFileV2 generates Bash completion version 2.
   354 // GenBashCompletionFileV2 generates Bash completion version 2.
   288 func (c *Command) GenBashCompletionFileV2(filename string, includeDesc bool) error {
   355 func (c *Command) GenBashCompletionFileV2(filename string, includeDesc bool) error {
   289 	outFile, err := os.Create(filename)
   356 	outFile, err := os.Create(filename)