2023-03-06 02:28:31 +00:00
// Copyright 2013-2023 The Cobra Authors
2022-09-16 13:55:56 +02:00
//
// Licensed under the Apache License, Version 2.0 ( the "License" ) ;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2021-06-30 17:24:58 -04:00
package cobra
import (
"bytes"
"fmt"
"io"
"os"
)
2025-04-26 20:13:18 +00:00
// genBashCompletion generates Bash completion script for the command.
// It writes the completion script to the provided writer and includes descriptions if specified.
// Returns an error if the operation fails.
2021-06-30 17:24:58 -04:00
func ( c *Command) genBashCompletion( w io.Writer, includeDesc bool) error {
buf := new( bytes.Buffer)
genBashComp( buf, c.Name( ) , includeDesc)
_, err := buf.WriteTo( w)
return err
}
func genBashComp( buf io.StringWriter, name string, includeDesc bool) {
compCmd := ShellCompRequestCmd
if !includeDesc {
compCmd = ShellCompNoDescRequestCmd
}
WriteStringAndCheck( buf, fmt.Sprintf( ` # bash completion V2 for %-36[1]s -*- shell-script -*-
__%[ 1] s_debug( )
{
2022-10-17 22:24:27 +03:00
if [ [ -n ${ BASH_COMP_DEBUG_FILE - } ] ] ; then
2021-06-30 17:24:58 -04:00
echo " $* " >> " ${ BASH_COMP_DEBUG_FILE } "
fi
}
# Macs have bash3 for which the bash-completion package doesn't include
# _init_completion. This is a minimal version of that function.
__%[ 1] s_init_completion( )
{
COMPREPLY = ( )
_get_comp_words_by_ref " $@ " cur prev words cword
}
# This function calls the %[1]s program to obtain the completion
# results and the directive. It fills the 'out' and 'directive' vars.
__%[ 1] s_get_completion_results( ) {
local requestComp lastParam lastChar args
# Prepare the command to request completions for the program.
2023-06-13 18:12:49 +03:00
# Calling ${words[0]} instead of directly %[1]s allows handling aliases
2021-06-30 17:24:58 -04:00
args = ( " ${ words [@] : 1 } " )
requestComp = " ${ words [0] } %[2]s ${ args [*] } "
lastParam = ${ words [ $(( ${# words [@] } - 1 )) ] }
lastChar = ${ lastParam : $(( ${# lastParam } - 1 )) : 1 }
__%[ 1] s_debug " lastParam ${ lastParam } , lastChar ${ lastChar } "
2022-10-17 22:24:27 +03:00
if [ [ -z ${ cur } && ${ lastChar } != = ] ] ; then
2021-06-30 17:24:58 -04:00
# 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.
__%[ 1] s_debug "Adding extra empty parameter"
requestComp = " ${ requestComp } '' "
fi
# When completing a flag with an = (e.g., %[1]s -n=<TAB>)
# bash focuses on the part after the =, so we need to remove
# the flag part from $cur
2022-10-17 22:24:27 +03:00
if [ [ ${ cur } = = -*= * ] ] ; then
2021-06-30 17:24:58 -04:00
cur = " ${ cur #*= } "
fi
__%[ 1] s_debug " Calling ${ requestComp } "
# Use eval to handle any environment variables and such
out = $( eval " ${ requestComp } " 2>/dev/null)
# Extract the directive integer at the very end of the output following a colon (:)
directive = ${ out ##* : }
# Remove the directive
out = ${ out %% : * }
2022-10-17 22:24:27 +03:00
if [ [ ${ directive } = = " ${ out } " ] ] ; then
2021-06-30 17:24:58 -04:00
# There is not directive specified
directive = 0
fi
__%[ 1] s_debug " The completion directive is: ${ directive } "
2022-04-28 05:27:52 +03:00
__%[ 1] s_debug " The completions are: ${ out } "
2021-06-30 17:24:58 -04:00
}
__%[ 1] s_process_completion_results( ) {
local shellCompDirectiveError = %[ 3] d
local shellCompDirectiveNoSpace = %[ 4] d
local shellCompDirectiveNoFileComp = %[ 5] d
local shellCompDirectiveFilterFileExt = %[ 6] d
local shellCompDirectiveFilterDirs = %[ 7] d
2023-02-25 20:57:12 +00:00
local shellCompDirectiveKeepOrder = %[ 8] d
2021-06-30 17:24:58 -04:00
2022-10-17 22:24:27 +03:00
if ( ( ( directive & shellCompDirectiveError) != 0) ) ; then
2021-06-30 17:24:58 -04:00
# Error code. No completion.
__%[ 1] s_debug "Received error from custom completion go code"
return
else
2022-10-17 22:24:27 +03:00
if ( ( ( directive & shellCompDirectiveNoSpace) != 0) ) ; then
if [ [ $( type -t compopt) = = builtin ] ] ; then
2021-06-30 17:24:58 -04:00
__%[ 1] s_debug "Activating no space"
compopt -o nospace
else
__%[ 1] s_debug "No space directive not supported in this version of bash"
fi
fi
2023-02-25 20:57:12 +00:00
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
2022-10-17 22:24:27 +03:00
if ( ( ( directive & shellCompDirectiveNoFileComp) != 0) ) ; then
if [ [ $( type -t compopt) = = builtin ] ] ; then
2021-06-30 17:24:58 -04:00
__%[ 1] s_debug "Activating no file completion"
compopt +o default
else
__%[ 1] s_debug "No file completion directive not supported in this version of bash"
fi
fi
fi
2022-06-15 20:08:16 -04:00
# Separate activeHelp from normal completions
local completions = ( )
local activeHelp = ( )
__%[ 1] s_extract_activeHelp
2022-10-17 22:24:27 +03:00
if ( ( ( directive & shellCompDirectiveFilterFileExt) != 0) ) ; then
2021-06-30 17:24:58 -04:00
# File extension filtering
2025-02-01 23:35:34 -01:00
local fullFilter = "" filter filteringCmd
2021-06-30 17:24:58 -04:00
2022-06-15 20:08:16 -04:00
# Do not use quotes around the $completions variable or else newline
2021-06-30 17:24:58 -04:00
# characters will be kept.
2022-06-15 20:08:16 -04:00
for filter in ${ completions [*] } ; do
2021-06-30 17:24:58 -04:00
fullFilter += " $filter | "
done
filteringCmd = " _filedir $fullFilter "
__%[ 1] s_debug " File filtering command: $filteringCmd "
$filteringCmd
2022-10-17 22:24:27 +03:00
elif ( ( ( directive & shellCompDirectiveFilterDirs) != 0) ) ; then
2021-06-30 17:24:58 -04:00
# File completion for directories only
local subdir
2022-10-17 22:24:27 +03:00
subdir = ${ completions [0] }
if [ [ -n $subdir ] ] ; then
2021-06-30 17:24:58 -04:00
__%[ 1] s_debug " Listing directories in $subdir "
pushd " $subdir " >/dev/null 2>& 1 && _filedir -d && popd >/dev/null 2>& 1 || return
else
__%[ 1] s_debug "Listing directories in ."
_filedir -d
fi
else
2021-12-07 17:59:41 -05:00
__%[ 1] s_handle_completion_types
2021-06-30 17:24:58 -04:00
fi
__%[ 1] s_handle_special_char " $cur " :
__%[ 1] s_handle_special_char " $cur " =
2022-06-15 20:08:16 -04:00
# Print the activeHelp statements before we finish
Print ActiveHelp for bash along other completions (#2076)
In the bash shell we used to print ActiveHelp messages on every
tab-press. In the example below, notice the "Command help" line which is
ActiveHelp:
bash-5.1$ tanzu context u[tab]
Command help: Configure and manage contexts for the Tanzu CLI
bash-5.1$ tanzu context u[tab]
Command help: Configure and manage contexts for the Tanzu CLI
bash-5.1$ tanzu context u
unset (Unset the active context so that it is not used by default.)
use (Set the context to be used by default)
bash-5.1$ tanzu context u
Above, on the first [tab] press, only the ActiveHelp is printed.
On the second [tab] press, the ActiveHelp is printed again, followed
by a re-print of the command-line, followed by the completions choices.
The separation between ActiveHelp and completion choices makes the
ActiveHelp harder to see. Furthermore, I find the double printing of the
ActiveHelp string to look bad.
Note that for zsh, the UX is different and that ActiveHelp messages are
printed at the same time as the completion choices.
This commit aligns the UX for ActiveHelp in bash with the one for zsh:
if there are other completions to be shown, the ActiveHelp messages are
printed at the same time.
New behaviour:
1- ActiveHelp is no longer printed on the first [tab] press. This is
better aligned with bash's standard approach.
2- ActiveHelp is printed on the second [tab] press, above the completion
choices, with a `--` delimiter.
3- If there are no completion choices, the `--` delimiter is omitted.
This behaviour is the same as what is done for zsh (except that for zsh
the first [tab] press immediately shows completion choices).
Below is the above example, but using this commit.
Notice the more concise and easier to read completion output:
bash-5.1$ tanzu context u[tab][tab]
Command help: Configure and manage contexts for the Tanzu CLI
--
unset (Unset the active context so that it is not used by default.)
use (Set the context to be used by default)
bash-5.1$ tanzu context u
Signed-off-by: Marc Khouzam <marc.khouzam@gmail.com>
2025-01-29 19:28:46 -05:00
__%[ 1] s_handle_activeHelp
}
__%[ 1] s_handle_activeHelp( ) {
# Print the activeHelp statements
2022-10-17 22:24:27 +03:00
if ( ( ${# activeHelp [*] } != 0) ) ; then
Print ActiveHelp for bash along other completions (#2076)
In the bash shell we used to print ActiveHelp messages on every
tab-press. In the example below, notice the "Command help" line which is
ActiveHelp:
bash-5.1$ tanzu context u[tab]
Command help: Configure and manage contexts for the Tanzu CLI
bash-5.1$ tanzu context u[tab]
Command help: Configure and manage contexts for the Tanzu CLI
bash-5.1$ tanzu context u
unset (Unset the active context so that it is not used by default.)
use (Set the context to be used by default)
bash-5.1$ tanzu context u
Above, on the first [tab] press, only the ActiveHelp is printed.
On the second [tab] press, the ActiveHelp is printed again, followed
by a re-print of the command-line, followed by the completions choices.
The separation between ActiveHelp and completion choices makes the
ActiveHelp harder to see. Furthermore, I find the double printing of the
ActiveHelp string to look bad.
Note that for zsh, the UX is different and that ActiveHelp messages are
printed at the same time as the completion choices.
This commit aligns the UX for ActiveHelp in bash with the one for zsh:
if there are other completions to be shown, the ActiveHelp messages are
printed at the same time.
New behaviour:
1- ActiveHelp is no longer printed on the first [tab] press. This is
better aligned with bash's standard approach.
2- ActiveHelp is printed on the second [tab] press, above the completion
choices, with a `--` delimiter.
3- If there are no completion choices, the `--` delimiter is omitted.
This behaviour is the same as what is done for zsh (except that for zsh
the first [tab] press immediately shows completion choices).
Below is the above example, but using this commit.
Notice the more concise and easier to read completion output:
bash-5.1$ tanzu context u[tab][tab]
Command help: Configure and manage contexts for the Tanzu CLI
--
unset (Unset the active context so that it is not used by default.)
use (Set the context to be used by default)
bash-5.1$ tanzu context u
Signed-off-by: Marc Khouzam <marc.khouzam@gmail.com>
2025-01-29 19:28:46 -05:00
if [ -z $COMP_TYPE ] ; then
# Bash v3 does not set the COMP_TYPE variable.
printf "\n" ;
printf "%%s\n" " ${ activeHelp [@] } "
printf "\n"
__%[ 1] s_reprint_commandLine
return
fi
# Only print ActiveHelp on the second TAB press
if [ $COMP_TYPE -eq 63 ] ; then
printf "\n"
printf "%%s\n" " ${ activeHelp [@] } "
if ( ( ${# COMPREPLY [*] } = = 0) ) ; then
# When there are no completion choices from the program, file completion
# may kick in if the program has not disabled it; in such a case, we want
# to know if any files will match what the user typed, so that we know if
# there will be completions presented, so that we know how to handle ActiveHelp.
# To find out, we actually trigger the file completion ourselves;
# the call to _filedir will fill COMPREPLY if files match.
if ( ( ( directive & shellCompDirectiveNoFileComp) = = 0) ) ; then
__%[ 1] s_debug "Listing files"
_filedir
fi
fi
if ( ( ${# COMPREPLY [*] } != 0) ) ; then
# If there are completion choices to be shown, print a delimiter.
# Re-printing the command-line will automatically be done
# by the shell when it prints the completion choices.
printf -- "--"
else
# When there are no completion choices at all, we need
# to re-print the command-line since the shell will
# not be doing it itself.
__%[ 1] s_reprint_commandLine
fi
elif [ $COMP_TYPE -eq 37 ] || [ $COMP_TYPE -eq 42 ] ; then
# For completion type: menu-complete/menu-complete-backward and insert-completions
# the completions are immediately inserted into the command-line, so we first
# print the activeHelp message and reprint the command-line since the shell won't.
printf "\n"
printf "%%s\n" " ${ activeHelp [@] } "
__%[ 1] s_reprint_commandLine
2022-06-15 20:08:16 -04:00
fi
fi
}
Print ActiveHelp for bash along other completions (#2076)
In the bash shell we used to print ActiveHelp messages on every
tab-press. In the example below, notice the "Command help" line which is
ActiveHelp:
bash-5.1$ tanzu context u[tab]
Command help: Configure and manage contexts for the Tanzu CLI
bash-5.1$ tanzu context u[tab]
Command help: Configure and manage contexts for the Tanzu CLI
bash-5.1$ tanzu context u
unset (Unset the active context so that it is not used by default.)
use (Set the context to be used by default)
bash-5.1$ tanzu context u
Above, on the first [tab] press, only the ActiveHelp is printed.
On the second [tab] press, the ActiveHelp is printed again, followed
by a re-print of the command-line, followed by the completions choices.
The separation between ActiveHelp and completion choices makes the
ActiveHelp harder to see. Furthermore, I find the double printing of the
ActiveHelp string to look bad.
Note that for zsh, the UX is different and that ActiveHelp messages are
printed at the same time as the completion choices.
This commit aligns the UX for ActiveHelp in bash with the one for zsh:
if there are other completions to be shown, the ActiveHelp messages are
printed at the same time.
New behaviour:
1- ActiveHelp is no longer printed on the first [tab] press. This is
better aligned with bash's standard approach.
2- ActiveHelp is printed on the second [tab] press, above the completion
choices, with a `--` delimiter.
3- If there are no completion choices, the `--` delimiter is omitted.
This behaviour is the same as what is done for zsh (except that for zsh
the first [tab] press immediately shows completion choices).
Below is the above example, but using this commit.
Notice the more concise and easier to read completion output:
bash-5.1$ tanzu context u[tab][tab]
Command help: Configure and manage contexts for the Tanzu CLI
--
unset (Unset the active context so that it is not used by default.)
use (Set the context to be used by default)
bash-5.1$ tanzu context u
Signed-off-by: Marc Khouzam <marc.khouzam@gmail.com>
2025-01-29 19:28:46 -05:00
__%[ 1] s_reprint_commandLine( ) {
# The prompt format is only available from bash 4.4.
# We test if it is available before using it.
if ( x = ${ PS1 @P } ) 2> /dev/null; then
printf "%%s" " ${ PS1 @P } ${ COMP_LINE [@] } "
else
# Can't print the prompt. Just print the
# text the user had typed, it is workable enough.
printf "%%s" " ${ COMP_LINE [@] } "
fi
}
2022-06-15 20:08:16 -04:00
# Separate activeHelp lines from real completions.
# Fills the $activeHelp and $completions arrays.
__%[ 1] s_extract_activeHelp( ) {
2023-02-25 20:57:12 +00:00
local activeHelpMarker = "%[9]s"
2022-06-15 20:08:16 -04:00
local endIndex = ${# activeHelpMarker }
while IFS = '' read -r comp; do
2025-01-23 04:28:30 +02:00
[ [ -z $comp ] ] && continue
2022-10-17 22:24:27 +03:00
if [ [ ${ comp : 0 : endIndex } = = $activeHelpMarker ] ] ; then
2022-06-15 20:08:16 -04:00
comp = ${ comp : endIndex }
__%[ 1] s_debug " ActiveHelp found: $comp "
2022-10-17 22:24:27 +03:00
if [ [ -n $comp ] ] ; then
2022-06-15 20:08:16 -04:00
activeHelp += ( " $comp " )
fi
else
# Not an activeHelp line but a normal completion
completions += ( " $comp " )
fi
2022-10-17 22:24:27 +03:00
done <<< " ${ out } "
2021-06-30 17:24:58 -04:00
}
2021-12-07 17:59:41 -05:00
__%[ 1] s_handle_completion_types( ) {
__%[ 1] s_debug " __%[1]s_handle_completion_types: COMP_TYPE is $COMP_TYPE "
case $COMP_TYPE in
37| 42)
# Type: menu-complete/menu-complete-backward and insert-completions
# If the user requested inserting one completion at a time, or all
# completions at once on the command-line we must remove the descriptions.
# https://github.com/spf13/cobra/issues/1508
2025-01-23 04:28:30 +02:00
# If there are no completions, we don't need to do anything
( ( ${# completions [@] } = = 0 ) ) && return 0
local tab = $'\t'
# Strip any description and escape the completion to handled special characters
IFS = $'\n' read -ra completions -d '' < <( printf "%%q\n" " ${ completions [@]%%%% $tab * } " )
# Only consider the completions that match
IFS = $'\n' read -ra COMPREPLY -d '' < <( IFS = $'\n' ; compgen -W " ${ completions [*] } " -- " ${ cur } " )
# compgen looses the escaping so we need to escape all completions again since they will
# all be inserted on the command-line.
IFS = $'\n' read -ra COMPREPLY -d '' < <( printf "%%q\n" " ${ COMPREPLY [@] } " )
2021-12-07 17:59:41 -05:00
; ;
*)
# Type: complete (normal completion)
__%[ 1] s_handle_standard_completion_case
; ;
esac
}
2021-06-30 17:24:58 -04:00
__%[ 1] s_handle_standard_completion_case( ) {
2025-01-23 04:28:30 +02:00
local tab = $'\t'
# If there are no completions, we don't need to do anything
( ( ${# completions [@] } = = 0 ) ) && return 0
2021-06-30 17:24:58 -04:00
2022-05-04 04:16:07 +03:00
# Short circuit to optimize if we don't have descriptions
2022-06-20 00:11:21 -04:00
if [ [ " ${ completions [*] } " != *$tab * ] ] ; then
2025-01-23 04:28:30 +02:00
# First, escape the completions to handle special characters
IFS = $'\n' read -ra completions -d '' < <( printf "%%q\n" " ${ completions [@] } " )
# Only consider the completions that match what the user typed
IFS = $'\n' read -ra COMPREPLY -d '' < <( IFS = $'\n' ; compgen -W " ${ completions [*] } " -- " ${ cur } " )
# compgen looses the escaping so, if there is only a single completion, we need to
# escape it again because it will be inserted on the command-line. If there are multiple
# completions, we don't want to escape them because they will be printed in a list
# and we don't want to show escape characters in that list.
if ( ( ${# COMPREPLY [@] } = = 1 ) ) ; then
COMPREPLY[ 0] = $( printf "%%q" " ${ COMPREPLY [0] } " )
fi
2022-05-04 04:16:07 +03:00
return 0
fi
2021-06-30 17:24:58 -04:00
local longest = 0
2022-05-03 04:00:51 +03:00
local compline
2021-06-30 17:24:58 -04:00
# Look for the longest completion so that we can format things nicely
2022-05-03 04:00:51 +03:00
while IFS = '' read -r compline; do
2022-05-17 20:47:47 +03:00
[ [ -z $compline ] ] && continue
2025-01-23 04:28:30 +02:00
# Before checking if the completion matches what the user typed,
# we need to strip any description and escape the completion to handle special
# characters because those escape characters are part of what the user typed.
# Don't call "printf" in a sub-shell because it will be much slower
# since we are in a loop.
printf -v comp "%%q" " ${ compline %%%% $tab * } " & >/dev/null || comp = $( printf "%%q" " ${ compline %%%% $tab * } " )
2021-06-30 17:24:58 -04:00
# Only consider the completions that match
2022-05-04 04:34:55 +03:00
[ [ $comp = = " $cur " * ] ] || continue
2025-01-23 04:28:30 +02:00
# The completions matches. Add it to the list of full completions including
# its description. We don't escape the completion because it may get printed
# in a list if there are more than one and we don't want show escape characters
# in that list.
2022-05-03 04:00:51 +03:00
COMPREPLY += ( " $compline " )
2025-01-23 04:28:30 +02:00
# Strip any description before checking the length, and again, don't escape
# the completion because this length is only used when printing the completions
# in a list and we don't want show escape characters in that list.
comp = ${ compline %%%% $tab * }
2021-06-30 17:24:58 -04:00
if ( ( ${# comp } >longest) ) ; then
longest = ${# comp }
fi
2022-06-15 20:08:16 -04:00
done < <( printf "%%s\n" " ${ completions [@] } " )
2021-06-30 17:24:58 -04:00
2025-01-23 04:28:30 +02:00
# If there is a single completion left, remove the description text and escape any special characters
2022-10-17 22:24:27 +03:00
if ( ( ${# COMPREPLY [*] } = = 1) ) ; then
2021-06-30 17:24:58 -04:00
__%[ 1] s_debug " COMPREPLY[0]: ${ COMPREPLY [0] } "
2025-01-23 04:28:30 +02:00
COMPREPLY[ 0] = $( printf "%%q" " ${ COMPREPLY [0]%%%% $tab * } " )
__%[ 1] s_debug " Removed description from single completion, which is now: ${ COMPREPLY [0] } "
else
# Format the descriptions
2022-05-03 04:00:51 +03:00
__%[ 1] s_format_comp_descriptions $longest
2021-06-30 17:24:58 -04:00
fi
}
__%[ 1] s_handle_special_char( )
{
local comp = " $1 "
local char = $2
if [ [ " $comp " = = *${ char } * && " $COMP_WORDBREAKS " = = *${ char } * ] ] ; then
local word = ${ comp %% " ${ comp ##* ${ char } } " }
local idx = ${# COMPREPLY [*] }
2022-10-17 22:24:27 +03:00
while ( ( --idx >= 0) ) ; do
COMPREPLY[ idx] = ${ COMPREPLY [idx]# " $word " }
2021-06-30 17:24:58 -04:00
done
fi
}
__%[ 1] s_format_comp_descriptions( )
{
2022-04-28 05:02:30 +03:00
local tab = $'\t'
2022-05-03 04:00:51 +03:00
local comp desc maxdesclength
local longest = $1
local i ci
for ci in ${ !COMPREPLY[*] } ; do
comp = ${ COMPREPLY [ci] }
# Properly format the description string which follows a tab character if there is one
if [ [ " $comp " = = *$tab * ] ] ; then
__%[ 1] s_debug " Original comp: $comp "
desc = ${ comp #* $tab }
comp = ${ comp %%%% $tab * }
2021-06-30 17:24:58 -04:00
2022-05-03 04:00:51 +03:00
# $COLUMNS stores the current shell width.
# Remove an extra 4 because we add 2 spaces and 2 parentheses.
maxdesclength = $(( COLUMNS - longest - 4 ))
# Make sure we can fit a description of at least 8 characters
# if we are to align the descriptions.
2022-10-17 22:24:27 +03:00
if ( ( maxdesclength > 8) ) ; then
2022-05-03 04:00:51 +03:00
# Add the proper number of spaces to align the descriptions
for ( ( i = ${# comp } ; i < longest ; i++) ) ; do
comp += " "
done
else
# Don't pad the descriptions so we can fit more text after the completion
maxdesclength = $(( COLUMNS - ${# comp } - 4 ))
2021-06-30 17:24:58 -04:00
fi
2022-05-03 04:00:51 +03:00
# If there is enough space for any description text,
# truncate the descriptions that are too long for the shell width
2022-10-17 22:24:27 +03:00
if ( ( maxdesclength > 0) ) ; then
if ( ( ${# desc } > maxdesclength) ) ; then
2022-05-03 04:00:51 +03:00
desc = ${ desc : 0 : $(( maxdesclength - 1 )) }
desc += "…"
fi
comp += " ( $desc ) "
fi
COMPREPLY[ ci] = $comp
__%[ 1] s_debug " Final comp: $comp "
fi
done
2021-06-30 17:24:58 -04:00
}
__start_%[ 1] s( )
{
local cur prev words cword split
COMPREPLY = ( )
# Call _init_completion from the bash-completion package
# to prepare the arguments properly
if declare -F _init_completion >/dev/null 2>& 1; then
2022-10-17 22:24:27 +03:00
_init_completion -n = : || return
2021-06-30 17:24:58 -04:00
else
2022-10-17 22:24:27 +03:00
__%[ 1] s_init_completion -n = : || return
2021-06-30 17:24:58 -04:00
fi
__%[ 1] s_debug
__%[ 1] s_debug "========= starting completion logic =========="
__%[ 1] s_debug " cur is ${ cur } , words[*] is ${ words [*] } , #words[@] is ${# words [@] } , cword is $cword "
# The user could have moved the cursor backwards on the command-line.
# We need to trigger completion from the $cword location, so we need
# to truncate the command-line ($words) up to the $cword location.
words = ( " ${ words [@] : 0 : $cword +1 } " )
__%[ 1] s_debug " Truncated words[*]: ${ words [*] } , "
local out directive
__%[ 1] s_get_completion_results
__%[ 1] s_process_completion_results
}
if [ [ $( type -t compopt) = "builtin" ] ] ; then
complete -o default -F __start_%[ 1] s %[ 1] s
else
complete -o default -o nospace -F __start_%[ 1] s %[ 1] s
fi
# ex: ts=4 sw=4 et filetype=sh
` , name, compCmd,
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
2023-02-25 20:57:12 +00:00
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, ShellCompDirectiveKeepOrder,
2022-06-15 20:08:16 -04:00
activeHelpMarker) )
2021-06-30 17:24:58 -04:00
}
2025-04-26 20:13:18 +00:00
// GenBashCompletionFileV2 generates a Bash completion file for version 2.
//
// Parameters:
// - filename: The name of the file to be created.
// - includeDesc: A boolean indicating whether to include descriptions in the completion file.
//
// Returns:
// - error: An error if any occurs during file creation or generation.
2021-06-30 17:24:58 -04:00
func ( c *Command) GenBashCompletionFileV2( filename string, includeDesc bool) error {
outFile, err := os.Create( filename)
if err != nil {
return err
}
defer outFile.Close( )
return c.GenBashCompletionV2( outFile, includeDesc)
}
2025-04-26 20:13:18 +00:00
// GenBashCompletionV2 generates Bash completion file version 2 and writes it to the provided writer. It includes a description of each command if includeDesc is true.
//
// Parameters:
// - w: The writer where the Bash completion file will be written.
// - includeDesc: A boolean indicating whether to include descriptions in the completion file.
//
// Returns:
// - An error if there was an issue generating or writing the completion file.
2021-06-30 17:24:58 -04:00
func ( c *Command) GenBashCompletionV2( w io.Writer, includeDesc bool) error {
return c.genBashCompletion( w, includeDesc)
}