diff --git a/Cargo.lock b/Cargo.lock index 457a6a7f32..152c1db510 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4177,9 +4177,9 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "usage-lib" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1f5bb4a03f9084a6bf27f3f561f76522f1c65fcff6815a193b0a5fd4304cbe" +checksum = "bd75b195d7d5e9232b7b0f5a76d2e13ca4b8ac765180aa37737adec4baa28ad1" dependencies = [ "clap", "heck 0.5.0", diff --git a/completions/mise.bash b/completions/mise.bash index eaa18858c8..bb22726934 100644 --- a/completions/mise.bash +++ b/completions/mise.bash @@ -1,3479 +1,3 @@ -# -*- shell-script -*- -# -# bash_completion - programmable completion functions for bash 4.2+ -# -# Copyright © 2006-2008, Ian Macdonald -# © 2009-2020, Bash Completion Maintainers -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# The latest version of this software can be obtained here: -# -# https://github.com/scop/bash-completion - -BASH_COMPLETION_VERSINFO=( - 2 # x-release-please-major - 15 # x-release-please-minor - 0 # x-release-please-patch -) - -if [[ $- == *v* ]]; then - _comp__init_original_set_v="-v" -else - _comp__init_original_set_v="+v" -fi - -if [[ ${BASH_COMPLETION_DEBUG-} ]]; then - set -v -else - set +v -fi - -# Turn on extended globbing and programmable completion -shopt -s extglob progcomp - -# Declare a compatibility function name -# @param $1 Version of bash-completion where the deprecation occurred -# @param $2 Old function name -# @param $3 New function name -# @since 2.12 -_comp_deprecate_func() -{ - if (($# != 3)); then - printf 'bash_completion: %s: usage: %s DEPRECATION_VERSION OLD_NAME NEW_NAME\n' "$FUNCNAME" "$FUNCNAME" - return 2 - fi - if [[ $2 != [a-zA-Z_]*([a-zA-Z_0-9]) ]]; then - printf 'bash_completion: %s: %s\n' "$FUNCNAME" "\$2: invalid function name '$1'" >&2 - return 2 - elif [[ $3 != [a-zA-Z_]*([a-zA-Z_0-9]) ]]; then - printf 'bash_completion: %s: %s\n' "$FUNCNAME" "\$3: invalid function name '$2'" >&2 - return 2 - fi - eval -- "$2() { $3 \"\$@\"; }" -} - -# Declare a compatibility variable name. -# For bash 4.3+, a real name alias is created, allowing value changes to -# "apply through" when the variables are set later. For bash versions earlier -# than that, the operation is once-only; the value of the new variable -# (if it's unset) is set to that of the old (if set) at call time. -# -# @param $1 Version of bash-completion where the deprecation occurred -# @param $2 Old variable name -# @param $3 New variable name -# @since 2.12 -_comp_deprecate_var() -{ - if (($# != 3)); then - printf 'bash_completion: %s: usage: %s DEPRECATION_VERSION OLD_NAME NEW_NAME\n' "$FUNCNAME" "$FUNCNAME" - return 2 - fi - if [[ $2 != [a-zA-Z_]*([a-zA-Z_0-9]) ]]; then - printf 'bash_completion: %s: %s\n' "$FUNCNAME" "\$2: invalid variable name '$1'" >&2 - return 2 - elif [[ $3 != [a-zA-Z_]*([a-zA-Z_0-9]) ]]; then - printf 'bash_completion: %s: %s\n' "$FUNCNAME" "\$3: invalid variable name '$2'" >&2 - return 2 - fi - if ((BASH_VERSINFO[0] >= 5 || BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] >= 3)); then - eval "declare -gn $2=$3" - elif [[ -v $2 && ! -v $3 ]]; then - printf -v "$3" %s "$2" - fi -} - -# A lot of the following one-liners were taken directly from the -# completion examples provided with the bash 2.04 source distribution - -# start of section containing compspecs that can be handled within bash - -# user commands see only users -complete -u groups slay w sux - -# bg completes with stopped jobs -complete -A stopped -P '"%' -S '"' bg - -# other job commands -complete -j -P '"%' -S '"' fg jobs disown - -# readonly and unset complete with shell variables -complete -v readonly unset - -# shopt completes with shopt options -complete -A shopt shopt - -# unalias completes with aliases -complete -a unalias - -# type and which complete on commands -complete -c command type which - -# builtin completes on builtins -complete -b builtin - -# start of section containing completion functions called by other functions - -# Check if we're running on the given userland -# @param $1 userland to check for -# @since 2.12 -_comp_userland() -{ - local userland=$(uname -s) - [[ $userland == @(Linux|GNU/*) ]] && userland=GNU - [[ $userland == "$1" ]] -} - -# This function sets correct SysV init directories -# -# @since 2.12 -_comp_sysvdirs() -{ - sysvdirs=() - [[ -d /etc/rc.d/init.d ]] && sysvdirs+=(/etc/rc.d/init.d) - [[ -d /etc/init.d ]] && sysvdirs+=(/etc/init.d) - # Slackware uses /etc/rc.d - [[ -f /etc/slackware-version ]] && sysvdirs=(/etc/rc.d) - ((${#sysvdirs[@]})) -} - -# This function checks whether we have a given program on the system. -# -# @since 2.12 -_comp_have_command() -{ - # Completions for system administrator commands are installed as well in - # case completion is attempted via `sudo command ...'. - PATH=$PATH:/usr/sbin:/sbin:/usr/local/sbin type "$1" &>/dev/null -} - -# This function checks whether a given readline variable -# is `on'. -# -# @since 2.12 -_comp_readline_variable_on() -{ - [[ $(bind -v) == *$1+([[:space:]])on* ]] -} - -# This function shell-quotes the argument -# @param $1 String to be quoted -# @var[out] REPLY Resulting string -# @since 2.12 -_comp_quote() -{ - REPLY=\'${1//\'/\'\\\'\'}\' -} - -# shellcheck disable=SC1003 -_comp_dequote__initialize() -{ - local regex_param='\$([_a-zA-Z][_a-zA-Z0-9]*|[-*@#?$!0-9_])|\$\{[!#]?([_a-zA-Z][_a-zA-Z0-9]*(\[([0-9]+|[*@])\])?|[-*@#?$!0-9_])\}' - local regex_quoted='\\.|'\''[^'\'']*'\''|\$?"([^\"$`!]|'$regex_param'|\\.)*"|\$'\''([^\'\'']|\\.)*'\''' - _comp_dequote__regex_safe_word='^([^\'\''"$`;&|<>()!]|'$regex_quoted'|'$regex_param')*$' - unset -f "$FUNCNAME" -} -_comp_dequote__initialize - -# This function expands a word using `eval` in a safe way. This function can -# be typically used to get the expanded value of `${word[i]}` as -# `_comp_dequote "${word[i]}"`. When the word contains unquoted shell special -# characters, command substitutions, and other unsafe strings, the function -# call fails before applying `eval`. Otherwise, `eval` is applied to the -# string to generate the result. -# -# @param $1 String to be expanded. A safe word consists of the following -# sequence of substrings: -# -# - Shell non-special characters: [^\'"$`;&|<>()!]. -# - Parameter expansions of the forms $PARAM, ${!PARAM}, -# ${#PARAM}, ${NAME[INDEX]}, ${!NAME[INDEX]}, ${#NAME[INDEX]} -# where INDEX is an integer, `*` or `@`, NAME is a valid -# variable name [_a-zA-Z][_a-zA-Z0-9]*, and PARAM is NAME or a -# parameter [-*@#?$!0-9_]. -# - Quotes \?, '...', "...", $'...', and $"...". In the double -# quotations, parameter expansions are allowed. -# -# @var[out] REPLY Array that contains the expanded results. Multiple words or -# no words may be generated through pathname expansions. -# -# Note: This function allows parameter expansions as safe strings, which might -# cause unexpected results: -# -# * This allows execution of arbitrary commands through extra expansions of -# array subscripts in name references. For example, -# -# declare -n v='dummy[$(echo xxx >/dev/tty)]' -# echo "$v" # This line executes the command 'echo xxx'. -# _comp_dequote '"$v"' # This line also executes it. -# -# * This may change the internal state of the variable that has side effects. -# For example, the state of the random number generator of RANDOM can change: -# -# RANDOM=1234 # Set seed -# echo "$RANDOM" # This produces 30658. -# RANDOM=1234 # Reset seed -# _comp_dequote '"$RANDOM"' # This line changes the internal state. -# echo "$RANDOM" # This fails to reproduce 30658. -# -# We allow these parameter expansions as a part of safe strings assuming the -# referential transparency of the simple parameter expansions and the sane -# setup of the variables by the user or other frameworks that the user loads. -# @since 2.12 -_comp_dequote() -{ - REPLY=() # fallback value for unsafe word and failglob - [[ $1 =~ $_comp_dequote__regex_safe_word ]] || return 1 - eval "REPLY=($1)" 2>/dev/null # may produce failglob -} - -# Unset the given variables across a scope boundary. Useful for unshadowing -# global scoped variables. Note that simply calling unset on a local variable -# will not unshadow the global variable. Rather, the result will be a local -# variable in an unset state. -# Usage: local IFS='|'; _comp_unlocal IFS -# @param $* Variable names to be unset -# @since 2.12 -_comp_unlocal() -{ - if ((BASH_VERSINFO[0] >= 5)) && shopt -q localvar_unset; then - shopt -u localvar_unset - unset -v "$@" - shopt -s localvar_unset - else - unset -v "$@" - fi -} - -# Assign variables one scope above the caller -# Usage: local varname [varname ...] && -# _comp_upvars [-v varname value] | [-aN varname [value ...]] ... -# Available OPTIONS: -# -aN Assign next N values to varname as array -# -v Assign single value to varname -# @return 1 if error occurs -# @see https://fvue.nl/wiki/Bash:_Passing_variables_by_reference -# @since 2.12 -_comp_upvars() -{ - if ! (($#)); then - echo "bash_completion: $FUNCNAME: usage: $FUNCNAME" \ - "[-v varname value] | [-aN varname [value ...]] ..." >&2 - return 2 - fi - while (($#)); do - case $1 in - -a*) - # Error checking - [[ ${1#-a} ]] || { - echo "bash_completion: $FUNCNAME:" \ - "\`$1': missing number specifier" >&2 - return 1 - } - printf %d "${1#-a}" &>/dev/null || { - echo bash_completion: \ - "$FUNCNAME: \`$1': invalid number specifier" >&2 - return 1 - } - # Assign array of -aN elements - # shellcheck disable=SC2015,SC2140 # TODO - [[ $2 ]] && unset -v "$2" && eval "$2"=\(\"\$"{@:3:${1#-a}}"\"\) && - shift $((${1#-a} + 2)) || { - echo bash_completion: \ - "$FUNCNAME: \`$1${2+ }$2': missing argument(s)" \ - >&2 - return 1 - } - ;; - -v) - # Assign single value - # shellcheck disable=SC2015 # TODO - [[ $2 ]] && unset -v "$2" && eval "$2"=\"\$3\" && - shift 3 || { - echo "bash_completion: $FUNCNAME: $1:" \ - "missing argument(s)" >&2 - return 1 - } - ;; - *) - echo "bash_completion: $FUNCNAME: $1: invalid option" >&2 - return 1 - ;; - esac - done -} - -# Get the list of filenames that match with the specified glob pattern. -# This function does the globbing in a controlled environment, avoiding -# interference from user's shell options/settings or environment variables. -# @param $1 array_name Array name -# The array name should not start with an underscore "_", which is internally -# used. The array name should not be "GLOBIGNORE" or "GLOBSORT". -# @param $2 pattern Pattern string to be evaluated. -# This pattern string will be evaluated using "eval", so brace expansions, -# parameter expansions, command substitutions, and other expansions will be -# processed. The user-provided strings should not be directly specified to -# this argument. -# @return 0 if at least one path is generated, 1 if no path is generated, or 2 -# if the usage is incorrect. -# @since 2.12 -_comp_expand_glob() -{ - if (($# != 2)); then - printf 'bash-completion: %s: unexpected number of arguments\n' "$FUNCNAME" >&2 - printf 'usage: %s ARRAY_NAME PATTERN\n' "$FUNCNAME" >&2 - return 2 - elif [[ $1 == @(GLOBIGNORE|GLOBSORT|_*|*[^_a-zA-Z0-9]*|[0-9]*|'') ]]; then - printf 'bash-completion: %s: invalid array name "%s"\n' "$FUNCNAME" "$1" >&2 - return 2 - fi - - # Save and adjust the settings. - local _original_opts=$SHELLOPTS:$BASHOPTS - set +o noglob - shopt -s nullglob - shopt -u failglob dotglob - - # Also the user's GLOBIGNORE and GLOBSORT (bash >= 5.3) may affect the - # result of pathname expansions. - local GLOBIGNORE="" GLOBSORT=name - - # To canonicalize the sorting order of the generated paths, we set - # LC_COLLATE=C and unset LC_ALL while preserving LC_CTYPE. - local LC_COLLATE=C LC_CTYPE=${LC_ALL:-${LC_CTYPE:-${LANG-}}} LC_ALL= - - eval -- "$1=()" # a fallback in case that the next line fails. - eval -- "$1=($2)" - - # Restore the settings. Note: Changing GLOBIGNORE affects the state of - # "shopt -q dotglob", so we need to explicitly restore the original state - # of "shopt -q dotglob". - _comp_unlocal GLOBIGNORE - if [[ :$_original_opts: == *:dotglob:* ]]; then - shopt -s dotglob - else - shopt -u dotglob - fi - [[ :$_original_opts: == *:nullglob:* ]] || shopt -u nullglob - [[ :$_original_opts: == *:failglob:* ]] && shopt -s failglob - [[ :$_original_opts: == *:noglob:* ]] && set -o noglob - eval "((\${#$1[@]}))" -} - -# Split a string and assign to an array. This function basically performs -# `IFS=; =()` but properly handles saving/restoring the -# state of `IFS` and the shell option `noglob`. A naive splitting by -# `arr=(...)` suffers from unexpected IFS and pathname expansions, so one -# should prefer this function to such naive splitting. -# OPTIONS -# -a Append to the array -# -F sep Set a set of separator characters (used as IFS). The default -# separator is $' \t\n' -# -l The same as -F $'\n' -# @param $1 array_name The array name -# The array name should not start with an underscores "_", which is -# internally used. The array name should not be either "IFS" or -# "OPT{IND,ARG,ERR}". -# @param $2 text The string to split -# @return 2 when the usage is wrong, 0 when one or more completions are -# generated, or 1 when the execution succeeds but no candidates are -# generated. -# @since 2.12 -_comp_split() -{ - local _append="" IFS=$' \t\n' - - local OPTIND=1 OPTARG="" OPTERR=0 _opt - while getopts ':alF:' _opt "$@"; do - case $_opt in - a) _append=set ;; - l) IFS=$'\n' ;; - F) IFS=$OPTARG ;; - *) - echo "bash_completion: $FUNCNAME: usage error" >&2 - return 2 - ;; - esac - done - shift "$((OPTIND - 1))" - if (($# != 2)); then - printf '%s\n' "bash_completion: $FUNCNAME: unexpected number of arguments" >&2 - printf '%s\n' "usage: $FUNCNAME [-al] [-F SEP] ARRAY_NAME TEXT" >&2 - return 2 - elif [[ $1 == @(*[^_a-zA-Z0-9]*|[0-9]*|''|_*|IFS|OPTIND|OPTARG|OPTERR) ]]; then - printf '%s\n' "bash_completion: $FUNCNAME: invalid array name '$1'" >&2 - return 2 - fi - - local _original_opts=$SHELLOPTS - set -o noglob - - local _old_size _new_size - if [[ $_append ]]; then - eval "$1+=()" # in case $1 is unset - eval "_old_size=\${#$1[@]}" - eval "$1+=(\$2)" - else - _old_size=0 - eval "$1=(\$2)" - fi - eval "_new_size=\${#$1[@]}" - - [[ :$_original_opts: == *:noglob:* ]] || set +o noglob - ((_new_size > _old_size)) -} - -# Helper function for _comp_compgen -# @var[in] $? -# @var[in] _var -# @var[in] _append -# @return original $? -_comp_compgen__error_fallback() -{ - local _status=$? - if [[ $_append ]]; then - # make sure existence of variable - eval -- "$_var+=()" - else - eval -- "$_var=()" - fi - return "$_status" -} - -# Provide a common interface to generate completion candidates in COMPREPLY or -# in a specified array. -# OPTIONS -# -a Append to the array -# -v arr Store the results to the array ARR. The default is `COMPREPLY`. -# The array name should not start with an underscores "_", which is -# internally used. The array name should not be any of "cur", "IFS" -# or "OPT{IND,ARG,ERR}". -# -U var Unlocalize VAR before performing the assignments. This option can -# be specified multiple times to register multiple variables. This -# option is supposed to be used in implementing a generator (G1) when -# G1 defines a local variable name that does not start with `_`. In -# such a case, when the target variable specified to G1 by `-v VAR1` -# conflicts with the local variable, the assignment to the target -# variable fails to propagate outside G1. To avoid such a situation, -# G1 can call `_comp_compgen` with `-U VAR` to unlocalize `VAR` -# before accessing the target variable. For a builtin compgen call -# (i.e., _comp_compgen [options] -- options), VAR is unlocalized -# after calling the builtin `compgen` but before assigning results to -# the target array. For a generator call (i.e., _comp_compgen -# [options] G2 ...), VAR is unlocalized before calling the child -# generator function `_comp_compgen_G2`. -# -c cur Set a word used as a prefix to filter the completions. The default -# is ${cur-}. -# -R The same as -c ''. Use raw outputs without filtering. -# -C dir Evaluate compgen/generator in the specified directory. -# @var[in,opt] cur Used as the default value of a prefix to filter the -# completions. -# -# Usage #1: _comp_compgen [-alR|-F sep|-v arr|-c cur|-C dir] -- options... -# Call `compgen` with the specified arguments and store the results in the -# specified array. This function essentially performs arr=($(compgen args...)) -# but properly handles shell options, IFS, etc. using _comp_split. This -# function is equivalent to `_comp_split [-a] -l arr "$(IFS=sep; compgen -# args... -- cur)"`, but this pattern is frequent in the codebase and is good -# to separate out as a function for the possible future implementation change. -# OPTIONS -# -F sep Set a set of separator characters (used as IFS in evaluating -# `compgen'). The default separator is $' \t\n'. Note that this is -# not the set of separators to delimit output of `compgen', but the -# separators in evaluating the expansions of `-W '...'`, etc. The -# delimiter of the output of `compgen` is always a newline. -# -l The same as -F $'\n'. Use lines as words in evaluating compgen. -# @param $1... options Arguments that are passed to compgen (if $1 starts with -# a hyphen `-`). -# -# Note: References to positional parameters $1, $2, ... (such as -W '$1') -# will not work as expected because these reference the arguments of -# `_comp_compgen' instead of those of the caller function. When there are -# needs to reference them, save the arguments to an array and reference the -# array instead. -# -# Note: The array option `-V arr` in bash >= 5.3 should be instead specified -# as `-v arr` as a part of the `_comp_compgen` options. -# @return True (0) if at least one completion is generated, False (1) if no -# completion is generated, or 2 with an incorrect usage. -# -# Usage #2: _comp_compgen [-aR|-v arr|-c cur|-C dir|-i cmd|-x cmd] name args... -# Call the generator `_comp_compgen_NAME ARGS...` with the specified options. -# This provides a common interface to call the functions `_comp_compgen_NAME`, -# which produce completion candidates, with custom options [-alR|-v arr|-c -# cur]. The option `-F sep` is not used with this usage. -# OPTIONS -# -x cmd Call exported generator `_comp_xfunc_CMD_compgen_NAME` -# -i cmd Call internal generator `_comp_cmd_CMD__compgen_NAME` -# @param $1... name args Calls the function _comp_compgen_NAME with the -# specified ARGS (if $1 does not start with a hyphen `-`). The options -# [-alR|-v arr|-c cur] are inherited by the child calls of `_comp_compgen` -# inside `_comp_compgen_NAME` unless the child call `_comp_compgen` receives -# overriding options. -# @var[in,opt,internal] _comp_compgen__append -# @var[in,opt,internal] _comp_compgen__var -# @var[in,opt,internal] _comp_compgen__cur -# These variables are internally used to pass the effect of the options -# [-alR|-v arr|-c cur] to the child calls of `_comp_compgen` in -# `_comp_compgen_NAME`. -# @return Exit status of the generator. -# -# @remarks When no options are supplied to _comp_compgen, `_comp_compgen NAME -# args` is equivalent to the direct call `_comp_compgen_NAME args`. As the -# direct call is slightly more efficient, the direct call is preferred over -# calling it through `_comp_compgen`. -# -# @remarks Design `_comp_compgen_NAME`: a function that produce completions can -# be defined with the name _comp_compgen_NAME. The function is supposed to -# generate completions by calling `_comp_compgen`. To reflect the options -# specified to the outer calls of `_comp_compgen`, the function should not -# directly modify `COMPREPLY`. To add words, one can call -# -# _comp_compgen -- -W '"${words[@]}"' -# -# To directly add words without filtering by `cur`, one can call -# -# _comp_compgen -R -- -W '"${words[@]}"' -# -# or use the utility `_comp_compgen_set`: -# -# _comp_compgen_set "${words[@]}" -# -# Other nested calls of _comp_compgen can also be used. The function is -# supposed to replace the existing content of the array by default to allow the -# caller control whether to replace or append by the option `-a`. -# -# @since 2.12 -_comp_compgen() -{ - local _append= - local _var= - local _cur=${_comp_compgen__cur-${cur-}} - local _dir="" - local _ifs=$' \t\n' _has_ifs="" - local _icmd="" _xcmd="" - local -a _upvars=() - - local _old_nocasematch="" - if shopt -q nocasematch; then - _old_nocasematch=set - shopt -u nocasematch - fi - local OPTIND=1 OPTARG="" OPTERR=0 _opt - while getopts ':av:U:Rc:C:lF:i:x:' _opt "$@"; do - case $_opt in - a) _append=set ;; - v) - if [[ $OPTARG == @(*[^_a-zA-Z0-9]*|[0-9]*|''|_*|IFS|OPTIND|OPTARG|OPTERR|cur) ]]; then - printf 'bash_completion: %s: -v: invalid array name `%s'\''\n' "$FUNCNAME" "$OPTARG" >&2 - return 2 - fi - _var=$OPTARG - ;; - U) - if [[ $OPTARG == @(*[^_a-zA-Z0-9]*|[0-9]*|'') ]]; then - printf 'bash_completion: %s: -U: invalid variable name `%s'\''\n' "$FUNCNAME" "$OPTARG" >&2 - return 2 - elif [[ $OPTARG == @(_*|IFS|OPTIND|OPTARG|OPTERR|cur) ]]; then - printf 'bash_completion: %s: -U: unnecessary to mark `%s'\'' as upvar\n' "$FUNCNAME" "$OPTARG" >&2 - return 2 - fi - _upvars+=("$OPTARG") - ;; - c) _cur=$OPTARG ;; - R) _cur="" ;; - C) - if [[ ! $OPTARG ]]; then - printf 'bash_completion: %s: -C: invalid directory name `%s'\''\n' "$FUNCNAME" "$OPTARG" >&2 - return 2 - fi - _dir=$OPTARG - ;; - l) _has_ifs=set _ifs=$'\n' ;; - F) _has_ifs=set _ifs=$OPTARG ;; - [ix]) - if [[ ! $OPTARG ]]; then - printf 'bash_completion: %s: -%s: invalid command name `%s'\''\n' "$FUNCNAME" "$_opt" "$OPTARG" >&2 - return 2 - elif [[ $_icmd ]]; then - printf 'bash_completion: %s: -%s: `-i %s'\'' is already specified\n' "$FUNCNAME" "$_opt" "$_icmd" >&2 - return 2 - elif [[ $_xcmd ]]; then - printf 'bash_completion: %s: -%s: `-x %s'\'' is already specified\n' "$FUNCNAME" "$_opt" "$_xcmd" >&2 - return 2 - fi - ;;& - i) _icmd=$OPTARG ;; - x) _xcmd=$OPTARG ;; - *) - printf 'bash_completion: %s: usage error\n' "$FUNCNAME" >&2 - return 2 - ;; - esac - done - [[ $_old_nocasematch ]] && shopt -s nocasematch - shift "$((OPTIND - 1))" - if (($# == 0)); then - printf 'bash_completion: %s: unexpected number of arguments\n' "$FUNCNAME" >&2 - printf 'usage: %s [-alR|-F SEP|-v ARR|-c CUR] -- ARGS...' "$FUNCNAME" >&2 - return 2 - fi - if [[ ! $_var ]]; then - # Inherit _append and _var only when -v var is unspecified. - _var=${_comp_compgen__var-COMPREPLY} - [[ $_append ]] || _append=${_comp_compgen__append-} - fi - - if [[ $1 != -* ]]; then - # usage: _comp_compgen [options] NAME args - if [[ $_has_ifs ]]; then - printf 'bash_completion: %s: `-l'\'' and `-F sep'\'' are not supported for generators\n' "$FUNCNAME" >&2 - return 2 - fi - - local -a _generator - if [[ $_icmd ]]; then - _generator=("_comp_cmd_${_icmd//[^a-zA-Z0-9_]/_}__compgen_$1") - elif [[ $_xcmd ]]; then - _generator=(_comp_xfunc "$_xcmd" "compgen_$1") - else - _generator=("_comp_compgen_$1") - fi - if ! declare -F -- "${_generator[0]}" &>/dev/null; then - printf 'bash_completion: %s: unrecognized generator `%s'\'' (function %s not found)\n' "$FUNCNAME" "$1" "${_generator[0]}" >&2 - return 2 - fi - shift - - _comp_compgen__call_generator "$@" - else - # usage: _comp_compgen [options] -- [compgen_options] - if [[ $_icmd || $_xcmd ]]; then - printf 'bash_completion: %s: generator name is unspecified for `%s'\''\n' "$FUNCNAME" "${_icmd:+-i $_icmd}${_xcmd:+x $_xcmd}" >&2 - return 2 - fi - - # Note: $* in the below checks would be affected by uncontrolled IFS in - # bash >= 5.0, so we need to set IFS to the normal value. The behavior - # in bash < 5.0, where unquoted $* in conditional command did not honor - # IFS, was a bug. - # Note: Also, ${_cur:+-- "$_cur"} and ${_append:+-a} would be affected - # by uncontrolled IFS. - local IFS=$' \t\n' - # Note: extglob *\$?(\{)[0-9]* can be extremely slow when the string - # "${*:2:_nopt}" becomes longer, so we test \$[0-9] and \$\{[0-9] - # separately. - if [[ $* == *\$[0-9]* || $* == *\$\{[0-9]* ]]; then - printf 'bash_completion: %s: positional parameter $1, $2, ... do not work inside this function\n' "$FUNCNAME" >&2 - return 2 - fi - - _comp_compgen__call_builtin "$@" - fi -} - -# Helper function for _comp_compgen. This function calls a generator. -# @param $1... generator_args -# @var[in] _dir -# @var[in] _cur -# @arr[in] _generator -# @arr[in] _upvars -# @var[in] _append -# @var[in] _var -_comp_compgen__call_generator() -{ - ((${#_upvars[@]})) && _comp_unlocal "${_upvars[@]}" - - if [[ $_dir ]]; then - local _original_pwd=$PWD - local PWD=${PWD-} OLDPWD=${OLDPWD-} - # Note: We also redirect stdout because `cd` may output the target - # directory to stdout when CDPATH is set. - command cd -- "$_dir" &>/dev/null || - { - _comp_compgen__error_fallback - return - } - fi - - local _comp_compgen__append=$_append - local _comp_compgen__var=$_var - local _comp_compgen__cur=$_cur cur=$_cur - # Note: we use $1 as a part of a function name, and we use $2... as - # arguments to the function if any. - # shellcheck disable=SC2145 - "${_generator[@]}" "$@" - local _status=$? - - # Go back to the original directory. - # Note: Failure of this line results in the change of the current - # directory visible to the user. We intentionally do not redirect - # stderr so that the error message appear in the terminal. - # shellcheck disable=SC2164 - [[ $_dir ]] && command cd -- "$_original_pwd" - - return "$_status" -} - -# Helper function for _comp_compgen. This function calls the builtin compgen. -# @param $1... compgen_args -# @var[in] _dir -# @var[in] _ifs -# @var[in] _cur -# @arr[in] _upvars -# @var[in] _append -# @var[in] _var -if ((BASH_VERSINFO[0] > 5 || BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] >= 3)); then - # bash >= 5.3 has `compgen -V array_name` - _comp_compgen__call_builtin() - { - if [[ $_dir ]]; then - local _original_pwd=$PWD - local PWD=${PWD-} OLDPWD=${OLDPWD-} - # Note: We also redirect stdout because `cd` may output the target - # directory to stdout when CDPATH is set. - command cd -- "$_dir" &>/dev/null || { - _comp_compgen__error_fallback - return - } - fi - - local -a _result=() - - # Note: We specify -X '' to exclude empty completions to make the - # behavior consistent with the implementation for Bash < 5.3 where - # `_comp_split -l` removes empty lines. If the caller specifies -X - # pat, the effect of -X '' is overwritten by the specified one. - IFS=$_ifs compgen -V _result -X '' "$@" ${_cur:+-- "$_cur"} || { - _comp_compgen__error_fallback - return - } - - # Go back to the original directory. - # Note: Failure of this line results in the change of the current - # directory visible to the user. We intentionally do not redirect - # stderr so that the error message appear in the terminal. - # shellcheck disable=SC2164 - [[ $_dir ]] && command cd -- "$_original_pwd" - - ((${#_upvars[@]})) && _comp_unlocal "${_upvars[@]}" - ((${#_result[@]})) || return - if [[ $_append ]]; then - eval -- "$_var+=(\"\${_result[@]}\")" - else - eval -- "$_var=(\"\${_result[@]}\")" - fi - return - } -else - _comp_compgen__call_builtin() - { - local _result - _result=$( - if [[ $_dir ]]; then - # Note: We also redirect stdout because `cd` may output the target - # directory to stdout when CDPATH is set. - command cd -- "$_dir" &>/dev/null || return - fi - IFS=$_ifs compgen "$@" ${_cur:+-- "$_cur"} - ) || { - _comp_compgen__error_fallback - return - } - - ((${#_upvars[@]})) && _comp_unlocal "${_upvars[@]}" - _comp_split -l ${_append:+-a} "$_var" "$_result" - } -fi - -# usage: _comp_compgen_set [words...] -# Reset COMPREPLY with the specified WORDS. If no arguments are specified, the -# array is cleared. -# -# When an array name is specified by `-v VAR` in a caller _comp_compgen, the -# array is reset instead of COMPREPLY. When the `-a` flag is specified in a -# caller _comp_compgen, the words are appended to the existing elements of the -# array instead of replacing the existing elements. This function ignores -# ${cur-} or the prefix specified by `-v CUR`. -# @return 0 if at least one completion is generated, or 1 otherwise. -# @since 2.12 -_comp_compgen_set() -{ - local _append=${_comp_compgen__append-} - local _var=${_comp_compgen__var-COMPREPLY} - eval -- "$_var${_append:++}=(\"\$@\")" - (($#)) -} - -# Simply split the text and generate completions. This function should be used -# instead of `_comp_compgen -- -W "$(command)"`, which is vulnerable because -# option -W evaluates the shell expansions included in the option argument. -# Options: -# -F sep Specify the separators. The default is $' \t\n' -# -l The same as -F $'\n' -# -X arg The same as the compgen option -X. -# -S arg The same as the compgen option -S. -# -P arg The same as the compgen option -P. -# -o arg The same as the compgen option -o. -# @param $1 String to split -# @return 0 if at least one completion is generated, or 1 otherwise. -# @since 2.12 -_comp_compgen_split() -{ - local _ifs=$' \t\n' - local -a _compgen_options=() - - local OPTIND=1 OPTARG="" OPTERR=0 _opt - while getopts ':lF:X:S:P:o:' _opt "$@"; do - case $_opt in - l) _ifs=$'\n' ;; - F) _ifs=$OPTARG ;; - [XSPo]) _compgen_options+=("-$_opt" "$OPTARG") ;; - *) - printf 'bash_completion: usage: %s [-l|-F sep] [--] str\n' "$FUNCNAME" >&2 - return 2 - ;; - esac - done - shift "$((OPTIND - 1))" - if (($# != 1)); then - printf 'bash_completion: %s: unexpected number of arguments.\n' "$FUNCNAME" >&2 - printf 'usage: %s [-l|-F sep] [--] str' "$FUNCNAME" >&2 - return 2 - fi - - local input=$1 IFS=$' \t\n' - _comp_compgen -F "$_ifs" -U input -- ${_compgen_options[@]+"${_compgen_options[@]}"} -W '$input' -} - -# Check if the argument looks like a path. -# @param $1 thing to check -# @return True (0) if it does, False (> 0) otherwise -# @since 2.12 -_comp_looks_like_path() -{ - [[ ${1-} == @(*/|[.~])* ]] -} - -# Reassemble command line words, excluding specified characters from the -# list of word completion separators (COMP_WORDBREAKS). -# @param $1 chars Characters out of $COMP_WORDBREAKS which should -# NOT be considered word breaks. This is useful for things like scp where -# we want to return host:path and not only path, so we would pass the -# colon (:) as $1 here. -# @param $2 words Name of variable to return words to -# @param $3 cword Name of variable to return cword to -# -_comp__reassemble_words() -{ - local exclude="" i j line ref - # Exclude word separator characters? - if [[ $1 ]]; then - # Yes, exclude word separator characters; - # Exclude only those characters, which were really included - exclude="[${1//[^$COMP_WORDBREAKS]/}]" - fi - - # Default to cword unchanged - printf -v "$3" %s "$COMP_CWORD" - # Are characters excluded which were former included? - if [[ $exclude ]]; then - # Yes, list of word completion separators has shrunk; - line=$COMP_LINE - # Re-assemble words to complete - for ((i = 0, j = 0; i < ${#COMP_WORDS[@]}; i++, j++)); do - # Is current word not word 0 (the command itself) and is word not - # empty and is word made up of just word separator characters to - # be excluded and is current word not preceded by whitespace in - # original line? - while [[ $i -gt 0 && ${COMP_WORDS[i]} == +($exclude) ]]; do - # Is word separator not preceded by whitespace in original line - # and are we not going to append to word 0 (the command - # itself), then append to current word. - [[ $line != [[:blank:]]* ]] && ((j >= 2)) && ((j--)) - # Append word separator to current or new word - ref="$2[$j]" - printf -v "$ref" %s "${!ref-}${COMP_WORDS[i]}" - # Indicate new cword - ((i == COMP_CWORD)) && printf -v "$3" %s "$j" - # Remove optional whitespace + word separator from line copy - line=${line#*"${COMP_WORDS[i]}"} - # Indicate next word if available, else end *both* while and - # for loop - if ((i < ${#COMP_WORDS[@]} - 1)); then - ((i++)) - else - break 2 - fi - # Start new word if word separator in original line is - # followed by whitespace. - [[ $line == [[:blank:]]* ]] && ((j++)) - done - # Append word to current word - ref="$2[$j]" - printf -v "$ref" %s "${!ref-}${COMP_WORDS[i]}" - # Remove optional whitespace + word from line copy - line=${line#*"${COMP_WORDS[i]}"} - # Indicate new cword - ((i == COMP_CWORD)) && printf -v "$3" %s "$j" - done - ((i == COMP_CWORD)) && printf -v "$3" %s "$j" - else - # No, list of word completions separators hasn't changed; - for i in "${!COMP_WORDS[@]}"; do - printf -v "$2[i]" %s "${COMP_WORDS[i]}" - done - fi -} - -# @param $1 exclude Characters out of $COMP_WORDBREAKS which should NOT be -# considered word breaks. This is useful for things like scp where -# we want to return host:path and not only path, so we would pass the -# colon (:) as $1 in this case. -# @param $2 words Name of variable to return words to -# @param $3 cword Name of variable to return cword to -# @param $4 cur Name of variable to return current word to complete to -# @see _comp__reassemble_words() -_comp__get_cword_at_cursor() -{ - local cword words=() - _comp__reassemble_words "$1" words cword - - local i cur="" index=$COMP_POINT lead=${COMP_LINE:0:COMP_POINT} - # Cursor not at position 0 and not led by just space(s)? - if [[ $index -gt 0 && ($lead && ${lead//[[:space:]]/}) ]]; then - cur=$COMP_LINE - for ((i = 0; i <= cword; ++i)); do - # Current word fits in $cur, and $cur doesn't match cword? - while [[ ${#cur} -ge ${#words[i]} && - ${cur:0:${#words[i]}} != "${words[i]-}" ]]; do - # Strip first character - cur=${cur:1} - # Decrease cursor position, staying >= 0 - ((index > 0)) && ((index--)) - done - - # Does found word match cword? - if ((i < cword)); then - # No, cword lies further; - local old_size=${#cur} - cur=${cur#"${words[i]}"} - local new_size=${#cur} - ((index -= old_size - new_size)) - fi - done - # Clear $cur if just space(s) - [[ $cur && ! ${cur//[[:space:]]/} ]] && cur= - # Zero $index if negative - ((index < 0)) && index=0 - fi - - local IFS=$' \t\n' - local "$2" "$3" "$4" && _comp_upvars -a"${#words[@]}" "$2" ${words[@]+"${words[@]}"} \ - -v "$3" "$cword" -v "$4" "${cur:0:index}" -} - -# Get the word to complete and optional previous words. -# This is nicer than ${COMP_WORDS[COMP_CWORD]}, since it handles cases -# where the user is completing in the middle of a word. -# (For example, if the line is "ls foobar", -# and the cursor is here --------> ^ -# Also one is able to cross over possible wordbreak characters. -# Usage: _comp_get_words [OPTIONS] [VARNAMES] -# Available VARNAMES: -# cur Return cur via $cur -# prev Return prev via $prev -# words Return words via $words -# cword Return cword via $cword -# -# Available OPTIONS: -# -n EXCLUDE Characters out of $COMP_WORDBREAKS which should NOT be -# considered word breaks. This is useful for things like scp -# where we want to return host:path and not only path, so we -# would pass the colon (:) as -n option in this case. -# -c VARNAME Return cur via $VARNAME -# -p VARNAME Return prev via $VARNAME -# -w VARNAME Return words via $VARNAME -# -i VARNAME Return cword via $VARNAME -# -# Example usage: -# -# $ _comp_get_words -n : cur prev -# -# @since 2.12 -_comp_get_words() -{ - local exclude="" flag i OPTIND=1 - local cur cword words=() - local upargs=() upvars=() vcur="" vcword="" vprev="" vwords="" - - while getopts "c:i:n:p:w:" flag "$@"; do - case $flag in - [cipw]) - if [[ $OPTARG != [a-zA-Z_]*([a-zA-Z_0-9])?(\[*\]) ]]; then - echo "bash_completion: $FUNCNAME: -$flag: invalid variable name \`$OPTARG'" >&2 - return 1 - fi - ;;& - c) vcur=$OPTARG ;; - i) vcword=$OPTARG ;; - n) exclude=$OPTARG ;; - p) vprev=$OPTARG ;; - w) vwords=$OPTARG ;; - *) - echo "bash_completion: $FUNCNAME: usage error" >&2 - return 1 - ;; - esac - done - while [[ $# -ge $OPTIND ]]; do - case ${!OPTIND} in - cur) vcur=cur ;; - prev) vprev=prev ;; - cword) vcword=cword ;; - words) vwords=words ;; - *) - echo "bash_completion: $FUNCNAME: \`${!OPTIND}':" \ - "unknown argument" >&2 - return 1 - ;; - esac - ((OPTIND += 1)) - done - - _comp__get_cword_at_cursor "${exclude-}" words cword cur - - [[ $vcur ]] && { - upvars+=("$vcur") - upargs+=(-v "$vcur" "$cur") - } - [[ $vcword ]] && { - upvars+=("$vcword") - upargs+=(-v "$vcword" "$cword") - } - [[ $vprev ]] && { - local value="" - ((cword >= 1)) && value=${words[cword - 1]} - upvars+=("$vprev") - upargs+=(-v "$vprev" "$value") - } - [[ $vwords ]] && { - # Note: bash < 4.4 has a bug that all the elements are connected with - # ${v+"$@"} when IFS does not contain whitespace. - local IFS=$' \t\n' - upvars+=("$vwords") - upargs+=(-a"${#words[@]}" "$vwords" ${words+"${words[@]}"}) - } - - ((${#upvars[@]})) && local "${upvars[@]}" && _comp_upvars "${upargs[@]}" -} - -# Generate the specified items after left-trimming with the word-to-complete -# containing a colon (:). If the word-to-complete does not contain a colon, -# this generates the specified items without modifications. -# @param $@ items to generate -# @var[in] cur current word to complete -# -# @remarks In Bash, with a colon in COMP_WORDBREAKS, words containing colons -# are always completed as entire words if the word to complete contains a -# colon. This function fixes this behavior by removing the -# colon-containing-prefix from the items. -# -# The preferred solution is to remove the colon (:) from COMP_WORDBREAKS in -# your .bashrc: -# -# # Remove colon (:) from list of word completion separators -# COMP_WORDBREAKS=${COMP_WORDBREAKS//:} -# -# See also: Bash FAQ - E13) Why does filename completion misbehave if a colon -# appears in the filename? - https://tiswww.case.edu/php/chet/bash/FAQ -# -# @since 2.12 -_comp_compgen_ltrim_colon() -{ - (($#)) || return 0 - local -a _tmp - _tmp=("$@") - if [[ $cur == *:* && $COMP_WORDBREAKS == *:* ]]; then - # Remove colon-word prefix from items - local _colon_word=${cur%"${cur##*:}"} - _tmp=("${_tmp[@]#"$_colon_word"}") - fi - _comp_compgen_set "${_tmp[@]}" -} - -# If the word-to-complete contains a colon (:), left-trim COMPREPLY items with -# word-to-complete. -# -# @param $1 current word to complete (cur) -# @var[in,out] COMPREPLY -# -# @since 2.12 -_comp_ltrim_colon_completions() -{ - ((${#COMPREPLY[@]})) || return 0 - _comp_compgen -c "$1" ltrim_colon "${COMPREPLY[@]}" -} - -# This function quotes the argument in a way so that readline dequoting -# results in the original argument. This is necessary for at least -# `compgen` which requires its arguments quoted/escaped: -# -# $ ls "a'b/" -# c -# $ compgen -f "a'b/" # Wrong, doesn't return output -# $ compgen -f "a\'b/" # Good -# a\'b/c -# -# See also: -# - https://lists.gnu.org/archive/html/bug-bash/2009-03/msg00155.html -# - https://www.mail-archive.com/bash-completion-devel@lists.alioth.debian.org/msg01944.html -# @param $1 Argument to quote -# @var[out] REPLY Quoted result is stored in this variable -# @since 2.12 -# shellcheck disable=SC2178 # The assignment is not intended for the global "REPLY" -_comp_quote_compgen() -{ - if [[ $1 == \'* ]]; then - # Leave out first character - REPLY=${1:1} - else - printf -v REPLY %q "$1" - - # If result becomes quoted like this: $'string', re-evaluate in order - # to drop the additional quoting. See also: - # https://www.mail-archive.com/bash-completion-devel@lists.alioth.debian.org/msg01942.html - if [[ $REPLY == \$\'*\' ]]; then - local value=${REPLY:2:-1} # Strip beginning $' and ending '. - value=${value//'%'/%%} # Escape % for printf format. - # shellcheck disable=SC2059 - printf -v REPLY "$value" # Decode escape sequences of \.... - fi - fi -} - -# This function performs file and directory completion. It's better than -# simply using 'compgen -f', because it honours spaces in filenames. -# @param $1 If `-d', complete only on directories. Otherwise filter/pick only -# completions with `.$1' and the uppercase version of it as file -# extension. -# @return 0 if at least one completion is generated, or 1 otherwise. -# -# @since 2.12 -_comp_compgen_filedir() -{ - _comp_compgen_tilde && return - - local -a toks - local _arg=${1-} - - if [[ $_arg == -d ]]; then - _comp_compgen -v toks -- -d - else - local REPLY - _comp_quote_compgen "${cur-}" - local _quoted=$REPLY - _comp_unlocal REPLY - - # work around bash-4.2 where compgen -f "''" produces nothing. - [[ $_quoted == "''" ]] && _quoted="" - - # Munge xspec to contain uppercase version too - # https://lists.gnu.org/archive/html/bug-bash/2010-09/msg00036.html - # news://news.gmane.io/4C940E1C.1010304@case.edu - local _xspec=${_arg:+"!*.@($_arg|${_arg^^})"} _plusdirs=() - - # Use plusdirs to get dir completions if we have a xspec; if we don't, - # there's no need, dirs come along with other completions. Don't use - # plusdirs quite yet if fallback is in use though, in order to not ruin - # the fallback condition with the "plus" dirs. - local _opts=(-f -X "$_xspec") - [[ $_xspec ]] && _plusdirs=(-o plusdirs) - [[ ${BASH_COMPLETION_FILEDIR_FALLBACK-} || ! ${_plusdirs-} ]] || - _opts+=("${_plusdirs[@]}") - - _comp_compgen -v toks -c "$_quoted" -- "${_opts[@]}" - - # Try without filter if it failed to produce anything and configured to - [[ ${BASH_COMPLETION_FILEDIR_FALLBACK-} && - $_arg && ${#toks[@]} -lt 1 ]] && - _comp_compgen -av toks -c "$_quoted" -- \ - -f ${_plusdirs+"${_plusdirs[@]}"} - fi - - if ((${#toks[@]} != 0)); then - # Remove . and .. (as well as */. and */..) from suggestions, unless - # .. or */.. was typed explicitly by the user (for users who use - # tab-completion to append a slash after '..') - if [[ $cur != ?(*/).. ]]; then - _comp_compgen -Rv toks -- -X '?(*/)@(.|..)' -W '"${toks[@]}"' - fi - fi - - if ((${#toks[@]} != 0)); then - # 2>/dev/null for direct invocation, e.g. in the _comp_compgen_filedir - # unit test - compopt -o filenames 2>/dev/null - fi - - # Note: bash < 4.4 has a bug that all the elements are connected with - # ${v+"${a[@]}"} when IFS does not contain whitespace. - local IFS=$' \t\n' - _comp_compgen -U toks set ${toks[@]+"${toks[@]}"} -} - -# This function splits $cur=--foo=bar into $prev=--foo, $cur=bar, making it -# easier to support both "--foo bar" and "--foo=bar" style completions. -# `=' should have been removed from COMP_WORDBREAKS when setting $cur for -# this to be useful. -# Returns 0 if current option was split, 1 otherwise. -# -_comp__split_longopt() -{ - if [[ $cur == --?*=* ]]; then - # Cut also backslash before '=' in case it ended up there - # for some reason. - prev=${cur%%?(\\)=*} - cur=${cur#*=} - return 0 - fi - - return 1 -} - -# Complete variables. -# @return True (0) if variables were completed, -# False (> 0) if not. -# @since 2.12 -_comp_compgen_variables() -{ - if [[ $cur =~ ^(\$(\{[!#]?)?)([A-Za-z0-9_]*)$ ]]; then - # Completing $var / ${var / ${!var / ${#var - if [[ $cur == '${'* ]]; then - local arrs vars - _comp_compgen -v vars -c "${BASH_REMATCH[3]}" -- -A variable -P "${BASH_REMATCH[1]}" -S '}' - _comp_compgen -v arrs -c "${BASH_REMATCH[3]}" -- -A arrayvar -P "${BASH_REMATCH[1]}" -S '[' - if ((${#vars[@]} == 1 && ${#arrs[@]} != 0)); then - # Complete ${arr with ${array[ if there is only one match, and that match is an array variable - compopt -o nospace - _comp_compgen -U vars -U arrs -R -- -W '"${arrs[@]}"' - else - # Complete ${var with ${variable} - _comp_compgen -U vars -U arrs -R -- -W '"${vars[@]}"' - fi - else - # Complete $var with $variable - _comp_compgen -ac "${BASH_REMATCH[3]}" -- -A variable -P '$' - fi - return 0 - elif [[ $cur =~ ^(\$\{[#!]?)([A-Za-z0-9_]*)\[([^]]*)$ ]]; then - # Complete ${array[i with ${array[idx]} - local vars - _comp_compgen -v vars -c "${BASH_REMATCH[3]}" -- -W '"${!'"${BASH_REMATCH[2]}"'[@]}"' \ - -P "${BASH_REMATCH[1]}${BASH_REMATCH[2]}[" -S ']}' - # Complete ${arr[@ and ${arr[* - if [[ ${BASH_REMATCH[3]} == [@*] ]]; then - vars+=("${BASH_REMATCH[1]}${BASH_REMATCH[2]}[${BASH_REMATCH[3]}]}") - fi - # array indexes may have colons - if ((${#vars[@]})); then - _comp_compgen -U vars -c "$cur" ltrim_colon "${vars[@]}" - else - _comp_compgen_set - fi - return 0 - elif [[ $cur =~ ^\$\{[#!]?[A-Za-z0-9_]*\[.*\]$ ]]; then - # Complete ${array[idx] with ${array[idx]} - _comp_compgen -c "$cur" ltrim_colon "$cur}" - return 0 - fi - return 1 -} - -# Complete a delimited value. -# -# Usage: [-k] DELIMITER COMPGEN_ARG... -# -k: do not filter out already present tokens in value -# @since 2.12 -_comp_delimited() -{ - local prefix="" delimiter=$1 deduplicate=set - shift - if [[ $delimiter == -k ]]; then - deduplicate="" - delimiter=$1 - shift - fi - [[ $cur == *"$delimiter"* ]] && prefix=${cur%"$delimiter"*}$delimiter - - if [[ $deduplicate ]]; then - # We could construct a -X pattern to feed to compgen, but that'd - # conflict with possibly already set -X in $@, as well as have - # glob char escaping issues to deal with. Do removals by hand instead. - _comp_compgen -R -- "$@" - local -a existing - _comp_split -F "$delimiter" existing "$cur" - # Do not remove the last from existing if it's not followed by the - # delimiter so we get space appended. - [[ ! $cur || $cur == *"$delimiter" ]] || unset -v "existing[${#existing[@]}-1]" - if ((${#COMPREPLY[@]})); then - local x i - for x in ${existing+"${existing[@]}"}; do - for i in "${!COMPREPLY[@]}"; do - if [[ $x == "${COMPREPLY[i]}" ]]; then - unset -v 'COMPREPLY[i]' - continue 2 # assume no dupes in COMPREPLY - fi - done - done - ((${#COMPREPLY[@]})) && - _comp_compgen -c "${cur##*"$delimiter"}" -- -W '"${COMPREPLY[@]}"' - fi - else - _comp_compgen -c "${cur##*"$delimiter"}" -- "$@" - fi - - # It would seem that in some specific cases we could avoid adding the - # prefix to all completions, thereby making the list of suggestions - # cleaner, and only adding it when there's exactly one completion. - # The cases where this opportunity has been observed involve having - # `show-all-if-ambiguous` on, but even that has cases where it fails - # and the last separator including everything before it is lost. - # https://github.com/scop/bash-completion/pull/913#issuecomment-1490140309 - local i - for i in "${!COMPREPLY[@]}"; do - COMPREPLY[i]="$prefix${COMPREPLY[i]}" - done - - [[ $delimiter != : ]] || _comp_ltrim_colon_completions "$cur" -} - -# Complete assignment of various known environment variables. -# -# The word to be completed is expected to contain the entire assignment, -# including the variable name and the "=". Some known variables are completed -# with colon separated values; for those to work, colon should not have been -# used to split words. See related parameters to _comp_initialize. -# -# @param $1 variable assignment to be completed -# @return True (0) if variable value completion was attempted, -# False (> 0) if not. -# @since 2.12 -_comp_variable_assignments() -{ - local cur=${1-} i - - if [[ $cur =~ ^([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]]; then - prev=${BASH_REMATCH[1]} - cur=${BASH_REMATCH[2]} - else - return 1 - fi - - case $prev in - TZ) - cur=/usr/share/zoneinfo/$cur - _comp_compgen_filedir - if ((${#COMPREPLY[@]})); then - for i in "${!COMPREPLY[@]}"; do - if [[ ${COMPREPLY[i]} == *.tab ]]; then - unset -v 'COMPREPLY[i]' - continue - elif [[ -d ${COMPREPLY[i]} ]]; then - COMPREPLY[i]+=/ - compopt -o nospace - fi - COMPREPLY[i]=${COMPREPLY[i]#/usr/share/zoneinfo/} - done - fi - ;; - TERM) - _comp_compgen_terms - ;; - LANG | LC_*) - _comp_compgen_split -- "$(locale -a 2>/dev/null)" - ;; - LANGUAGE) - _comp_delimited : -W '$(locale -a 2>/dev/null)' - ;; - *) - _comp_compgen_variables && return 0 - _comp_compgen -a filedir - ;; - esac - - return 0 -} - -# Initialize completion and deal with various general things: do file -# and variable completion where appropriate, and adjust prev, words, -# and cword as if no redirections exist so that completions do not -# need to deal with them. Before calling this function, make sure -# cur, prev, words, and cword are local, ditto split if you use -s. -# -# Options: -# -n EXCLUDE Passed to _comp_get_words -n with redirection chars -# -e XSPEC Passed to _comp_compgen_filedir as first arg for stderr -# redirections -# -o XSPEC Passed to _comp_compgen_filedir as first arg for other output -# redirections -# -i XSPEC Passed to _comp_compgen_filedir as first arg for stdin -# redirections -# -s Split long options with _comp__split_longopt, implies -n = -# @param $1...$3 args Original arguments specified to the completion function. -# The first argument $1 is command name. The second -# argument $2 is the string before the cursor in the -# current word. The third argument $3 is the previous -# word. -# @var[out] cur Reconstructed current word -# @var[out] prev Reconstructed previous word -# @var[out] words Reconstructed words -# @var[out] cword Current word index in `words` -# @var[out] comp_args Original arguments specified to the completion -# function are saved in this array, if the arguments -# $1...$3 is specified. -# @var[out,opt] was_split When "-s" is specified, `"set"/""` is set depending -# on whether the split happened. -# @return True (0) if completion needs further processing, -# False (> 0) no further processing is necessary. -# -# @since 2.12 -_comp_initialize() -{ - local exclude="" opt_split="" outx="" errx="" inx="" - - local flag OPTIND=1 OPTARG="" OPTERR=0 - while getopts "n:e:o:i:s" flag "$@"; do - case $flag in - n) exclude+=$OPTARG ;; - e) errx=$OPTARG ;; - o) outx=$OPTARG ;; - i) inx=$OPTARG ;; - s) - opt_split="set" - was_split="" - exclude+="=" - ;; - *) - echo "bash_completion: $FUNCNAME: usage error" >&2 - return 1 - ;; - esac - done - shift "$((OPTIND - 1))" - (($#)) && comp_args=("$@") - - COMPREPLY=() - local redir='@(?(+([0-9])|{[a-zA-Z_]*([a-zA-Z_0-9])})@(>?([>|&])|&])|<?(>))' - _comp_get_words -n "$exclude<>&" cur prev words cword - - # Complete variable names. - _comp_compgen_variables && return 1 - - # Complete on files if current is a redirect possibly followed by a - # filename, e.g. ">foo", or previous is a "bare" redirect, e.g. ">". - # shellcheck disable=SC2053 - if [[ $cur == $redir* || ${prev-} == $redir ]]; then - local xspec - case $cur in - 2'>'*) xspec=${errx-} ;; - *'>'*) xspec=${outx-} ;; - *'<'*) xspec=${inx-} ;; - *) - case $prev in - 2'>'*) xspec=${errx-} ;; - *'>'*) xspec=${outx-} ;; - *'<'*) xspec=${inx-} ;; - esac - ;; - esac - # shellcheck disable=SC2295 # redir is a pattern - cur=${cur##$redir} - _comp_compgen_filedir "$xspec" - return 1 - fi - - # Remove all redirections so completions don't have to deal with them. - local i skip - for ((i = 1; i < ${#words[@]}; )); do - if [[ ${words[i]} == $redir* ]]; then - # If "bare" redirect, remove also the next word (skip=2). - # shellcheck disable=SC2053 - [[ ${words[i]} == $redir ]] && skip=2 || skip=1 - words=("${words[@]:0:i}" "${words[@]:i+skip}") - ((i <= cword)) && ((cword -= skip)) - else - ((i++)) - fi - done - - ((cword <= 0)) && return 1 - prev=${words[cword - 1]} - - [[ $opt_split ]] && _comp__split_longopt && was_split="set" - - return 0 -} - -# Helper function for _comp_compgen_help and _comp_compgen_usage. -# Obtain the help output based on the arguments. -# @param $@ args Arguments specified to the caller. -# @var[out] _lines -# @return 2 if the usage is wrong, 1 if no output is obtained, or otherwise 0. -_comp_compgen_help__get_help_lines() -{ - local -a help_cmd - case ${1-} in - -) - if (($# > 1)); then - printf 'bash_completion: %s -: extra arguments for -\n' "${FUNCNAME[1]}" >&2 - printf 'usage: %s -\n' "${FUNCNAME[1]}" >&2 - printf 'usage: %s -c cmd args...\n' "${FUNCNAME[1]}" >&2 - printf 'usage: %s [-- args...]\n' "${FUNCNAME[1]}" >&2 - return 2 - fi - help_cmd=(exec cat) - ;; - -c) - if (($# < 2)); then - printf 'bash_completion: %s -c: no command is specified\n' "${FUNCNAME[1]}" >&2 - printf 'usage: %s -\n' "${FUNCNAME[1]}" >&2 - printf 'usage: %s -c cmd args...\n' "${FUNCNAME[1]}" >&2 - printf 'usage: %s [-- args...]\n' "${FUNCNAME[1]}" >&2 - return 2 - fi - help_cmd=("${@:2}") - ;; - --) shift 1 ;& - *) - local REPLY - _comp_dequote "${comp_args[0]-}" || REPLY=${comp_args[0]-} - help_cmd=("${REPLY:-false}" "$@") - ;; - esac - - local REPLY - _comp_split -l REPLY "$(LC_ALL=C "${help_cmd[@]}" 2>&1)" && - _lines=("${REPLY[@]}") -} - -# Helper function for _comp_compgen_help and _comp_compgen_usage. -# @var[in,out] options Add options -# @return True (0) if an option was found, False (> 0) otherwise -_comp_compgen_help__parse() -{ - local option option2 i - - # Take first found long option, or first one (short) if not found. - option= - local -a array - if _comp_split -F $' \t\n,/|' array "$1"; then - for i in "${array[@]}"; do - case "$i" in - ---*) break ;; - --?*) - option=$i - break - ;; - -?*) [[ $option ]] || option=$i ;; - *) break ;; - esac - done - fi - [[ $option ]] || return 1 - - # Expand --[no]foo to --foo and --nofoo etc - if [[ $option =~ (\[((no|dont)-?)\]). ]]; then - option2=${option/"${BASH_REMATCH[1]}"/} - option2=${option2%%[<{().[]*} - options+=("${option2/=*/=}") - option=${option/"${BASH_REMATCH[1]}"/"${BASH_REMATCH[2]}"} - fi - - [[ $option =~ ^([^=<{().[]|\.[A-Za-z0-9])+=? ]] && - options+=("$BASH_REMATCH") -} - -# Parse GNU style help output of the given command and generate and store -# completions in an array. The help output is produced in the way depending on -# the usage: -# usage: _comp_compgen_help - # read from stdin -# usage: _comp_compgen_help -c cmd args... # run "cmd args..." -# usage: _comp_compgen_help [[--] args...] # run "${comp_args[0]} args..." -# When no arguments are specified, `--help` is assumed. -# -# @var[in] comp_args[0] -# @since 2.12 -_comp_compgen_help() -{ - (($#)) || set -- -- --help - - local -a _lines - _comp_compgen_help__get_help_lines "$@" || return "$?" - - local -a options=() - local _line - for _line in "${_lines[@]}"; do - [[ $_line == *([[:blank:]])-* ]] || continue - # transform "-f FOO, --foo=FOO" to "-f , --foo=FOO" etc - while [[ $_line =~ ((^|[^-])-[A-Za-z0-9?][[:space:]]+)\[?[A-Z0-9]+([,_-]+[A-Z0-9]+)?(\.\.+)?\]? ]]; do - _line=${_line/"${BASH_REMATCH[0]}"/"${BASH_REMATCH[1]}"} - done - _comp_compgen_help__parse "${_line// or /, }" - done - ((${#options[@]})) || return 1 - - _comp_compgen -U options -- -W '"${options[@]}"' - return 0 -} - -# Parse BSD style usage output (options in brackets) of the given command. The -# help output is produced in the way depending on the usage: -# usage: _comp_compgen_usage - # read from stdin -# usage: _comp_compgen_usage -c cmd args... # run "cmd args..." -# usage: _comp_compgen_usage [[--] args...] # run "${comp_args[0]} args..." -# When no arguments are specified, `--usage` is assumed. -# -# @var[in] comp_args[0] -# @since 2.12 -_comp_compgen_usage() -{ - (($#)) || set -- -- --usage - - local -a _lines - _comp_compgen_help__get_help_lines "$@" || return "$?" - - local -a options=() - local _line _match _option _i _char - for _line in "${_lines[@]}"; do - while [[ $_line =~ \[[[:space:]]*(-[^]]+)[[:space:]]*\] ]]; do - _match=${BASH_REMATCH[0]} - _option=${BASH_REMATCH[1]} - case $_option in - -?(\[)+([a-zA-Z0-9?])) - # Treat as bundled short options - for ((_i = 1; _i < ${#_option}; _i++)); do - _char=${_option:_i:1} - [[ $_char != '[' ]] && options+=("-$_char") - done - ;; - *) - _comp_compgen_help__parse "$_option" - ;; - esac - _line=${_line#*"$_match"} - done - done - ((${#options[@]})) || return 1 - - _comp_compgen -U options -- -W '"${options[@]}"' - return 0 -} - -# This function completes on signal names (minus the SIG prefix) -# @param $1 prefix -# -# @since 2.12 -_comp_compgen_signals() -{ - local -a sigs - _comp_compgen -v sigs -c "SIG${cur#"${1-}"}" -- -A signal && - _comp_compgen -RU sigs -- -P "${1-}" -W '"${sigs[@]#SIG}"' -} - -# This function completes on known mac addresses -# -# @since 2.12 -_comp_compgen_mac_addresses() -{ - local _re='\([A-Fa-f0-9]\{2\}:\)\{5\}[A-Fa-f0-9]\{2\}' - local PATH="$PATH:/sbin:/usr/sbin" - local -a addresses - - # Local interfaces - # - ifconfig on Linux: HWaddr or ether - # - ifconfig on FreeBSD: ether - # - ip link: link/ether - _comp_compgen -v addresses split -- "$( - { - ip -c=never link show || ip link show || LC_ALL=C ifconfig -a - } 2>/dev/null | command sed -ne \ - "s/.*[[:space:]]HWaddr[[:space:]]\{1,\}\($_re\)[[:space:]].*/\1/p" -ne \ - "s/.*[[:space:]]HWaddr[[:space:]]\{1,\}\($_re\)[[:space:]]*$/\1/p" -ne \ - "s|.*[[:space:]]\(link/\)\{0,1\}ether[[:space:]]\{1,\}\($_re\)[[:space:]].*|\2|p" -ne \ - "s|.*[[:space:]]\(link/\)\{0,1\}ether[[:space:]]\{1,\}\($_re\)[[:space:]]*$|\2|p" - )" - - # ARP cache - _comp_compgen -av addresses split -- "$( - { - arp -an || ip -c=never neigh show || ip neigh show - } 2>/dev/null | command sed -ne \ - "s/.*[[:space:]]\($_re\)[[:space:]].*/\1/p" -ne \ - "s/.*[[:space:]]\($_re\)[[:space:]]*$/\1/p" - )" - - # /etc/ethers - _comp_compgen -av addresses split -- "$(command sed -ne \ - "s/^[[:space:]]*\($_re\)[[:space:]].*/\1/p" /etc/ethers 2>/dev/null)" - - _comp_compgen -U addresses ltrim_colon "${addresses[@]}" -} - -# This function completes on configured network interfaces -# -# @since 2.12 -_comp_compgen_configured_interfaces() -{ - local -a files - if [[ -f /etc/debian_version ]]; then - # Debian system - _comp_expand_glob files '/etc/network/interfaces /etc/network/interfaces.d/*' || return 0 - _comp_compgen -U files split -- "$(command sed -ne \ - 's|^iface \([^ ]\{1,\}\).*$|\1|p' "${files[@]}" 2>/dev/null)" - elif [[ -f /etc/SuSE-release ]]; then - # SuSE system - _comp_expand_glob files '/etc/sysconfig/network/ifcfg-*' || return 0 - _comp_compgen -U files split -- "$(printf '%s\n' "${files[@]}" | - command sed -ne 's|.*ifcfg-\([^*].*\)$|\1|p')" - elif [[ -f /etc/pld-release ]]; then - # PLD Linux - _comp_compgen -U files split -- "$(command ls -B /etc/sysconfig/interfaces | - command sed -ne 's|.*ifcfg-\([^*].*\)$|\1|p')" - else - # Assume Red Hat - _comp_expand_glob files '/etc/sysconfig/network-scripts/ifcfg-*' || return 0 - _comp_compgen -U files split -- "$(printf '%s\n' "${files[@]}" | - command sed -ne 's|.*ifcfg-\([^*].*\)$|\1|p')" - fi -} - -# Local IP addresses. -# If producing IPv6 completions, `_comp_initialize` with `-n :`. -# -# -4: IPv4 addresses only (default) -# -6: IPv6 addresses only -# -a: All addresses -# -# @since 2.12 -_comp_compgen_ip_addresses() -{ - local _n - case ${1-} in - -a) _n='6\{0,1\}' ;; - -6) _n='6' ;; - *) _n= ;; - esac - local PATH=$PATH:/sbin - local addrs - _comp_compgen -v addrs split -- "$({ - ip -c=never addr show || ip addr show || LC_ALL=C ifconfig -a - } 2>/dev/null | - command sed -e 's/[[:space:]]addr:/ /' -ne \ - "s|.*inet${_n}[[:space:]]\{1,\}\([^[:space:]/]*\).*|\1|p")" || - return - - if [[ ! $_n ]]; then - _comp_compgen -U addrs set "${addrs[@]}" - else - _comp_compgen -U addrs ltrim_colon "${addrs[@]}" - fi -} - -# This function completes on available kernel versions -# -# @since 2.12 -_comp_compgen_kernel_versions() -{ - _comp_compgen_split -- "$(command ls /lib/modules)" -} - -# This function completes on all available network interfaces -# -a: restrict to active interfaces only -# -w: restrict to wireless interfaces only -# -# @since 2.12 -_comp_compgen_available_interfaces() -{ - local PATH=$PATH:/sbin - local generated - _comp_compgen -v generated split -- "$({ - if [[ ${1-} == -w ]]; then - iwconfig - elif [[ ${1-} == -a ]]; then - # Note: we prefer ip (iproute2) to ifconfig (inetutils) since long - # interface names will be truncated by ifconfig [1]. - # [1]: https://github.com/scop/bash-completion/issues/1089 - ip -c=never link show up || ip link show up || ifconfig - else - ip -c=never link show || ip link show || ifconfig -a - fi - } 2>/dev/null | _comp_awk \ - '/^[^ \t]/ { if ($1 ~ /^[0-9]+:/) { print $2 } else { print $1 } }')" && - _comp_compgen -U generated set "${generated[@]%:}" -} - -# Echo number of CPUs, falling back to 1 on failure. -# @var[out] REPLY -# @return 0 if it successfully obtained the number of CPUs, or otherwise 1 -# @since 2.12 -_comp_get_ncpus() -{ - local var=NPROCESSORS_ONLN - [[ $OSTYPE == *@(linux|msys|cygwin)* ]] && var=_$var - if REPLY=$(getconf $var 2>/dev/null) && ((REPLY >= 1)); then - return 0 - else - REPLY=1 - return 1 - fi -} - -# Perform tilde (~) completion -# @return False (1) if completion needs further processing, -# True (0) if tilde is followed by a valid username, completions are -# put in COMPREPLY and no further processing is necessary. -# @since 2.12 -_comp_compgen_tilde() -{ - if [[ ${cur-} == \~* && $cur != */* ]]; then - # Try generate ~username completions - if _comp_compgen -c "${cur#\~}" -- -P '~' -u; then - # 2>/dev/null for direct invocation, e.g. in the - # _comp_compgen_tilde unit test - compopt -o filenames 2>/dev/null - return 0 - fi - fi - return 1 -} - -# Expand string starting with tilde (~) -# We want to expand ~foo/... to /home/foo/... to avoid problems when -# word-to-complete starting with a tilde is fed to commands and ending up -# quoted instead of expanded. -# Only the first portion of the variable from the tilde up to the first slash -# (~../) is expanded. The remainder of the variable, containing for example -# a dollar sign variable ($) or asterisk (*) is not expanded. -# Example usage: -# -# $ _comp_expand_tilde "~"; echo "$REPLY" -# -# Example output: -# -# $1 REPLY -# -------- ---------------- -# ~ /home/user -# ~foo/bar /home/foo/bar -# ~foo/$HOME /home/foo/$HOME -# ~foo/a b /home/foo/a b -# ~foo/* /home/foo/* -# -# @param $1 Value to expand -# @var[out] REPLY Expanded result -# @since 2.12 -_comp_expand_tilde() -{ - REPLY=$1 - if [[ $1 == \~* ]]; then - printf -v REPLY '~%q' "${1#\~}" - eval "REPLY=$REPLY" - fi -} - -# This function expands tildes in pathnames -# -# @since 2.12 -_comp_expand() -{ - # Expand ~username type directory specifications. We want to expand - # ~foo/... to /home/foo/... to avoid problems when $cur starting with - # a tilde is fed to commands and ending up quoted instead of expanded. - - case ${cur-} in - ~*/*) - local REPLY - _comp_expand_tilde "$cur" - cur=$REPLY - ;; - ~*) - _comp_compgen -v COMPREPLY tilde && - eval "COMPREPLY[0]=$(printf ~%q "${COMPREPLY[0]#\~}")" && - return 1 - ;; - esac - return 0 -} - -# Process ID related functions. -# for AIX and Solaris we use X/Open syntax, BSD for others. -# -# @since 2.12 -if [[ $OSTYPE == *@(solaris|aix)* ]]; then - # This function completes on process IDs. - _comp_compgen_pids() - { - _comp_compgen_split -- "$(command ps -efo pid | command sed 1d)" - } - - _comp_compgen_pgids() - { - _comp_compgen_split -- "$(command ps -efo pgid | command sed 1d)" - } - _comp_compgen_pnames() - { - _comp_compgen_split -X '' -- "$(command ps -efo comm | - command sed -e 1d -e 's:.*/::' -e 's/^-//' | sort -u)" - } -else - _comp_compgen_pids() - { - _comp_compgen_split -- "$(command ps ax -o pid=)" - } - _comp_compgen_pgids() - { - _comp_compgen_split -- "$(command ps ax -o pgid=)" - } - # @param $1 if -s, don't try to avoid truncated command names - _comp_compgen_pnames() - { - local -a procs=() - if [[ ${1-} == -s ]]; then - _comp_split procs "$(command ps ax -o comm | command sed -e 1d)" - else - # Some versions of ps don't support "command", but do "comm", e.g. - # some busybox ones. Fall back - local -a psout - _comp_split -l psout "$({ - command ps ax -o command= || command ps ax -o comm= - } 2>/dev/null)" - local line i=-1 - for line in "${psout[@]}"; do - if ((i == -1)); then - # First line, see if it has COMMAND column header. For - # example some busybox ps versions do that, i.e. don't - # respect command= - if [[ $line =~ ^(.*[[:space:]])COMMAND([[:space:]]|$) ]]; then - # It does; store its index. - i=${#BASH_REMATCH[1]} - else - # Nope, fall through to "regular axo command=" parsing. - break - fi - else - # - line=${line:i} # take command starting from found index - line=${line%% *} # trim arguments - [[ $line ]] && procs+=("$line") - fi - done - if ((i == -1)); then - # Regular command= parsing - for line in "${psout[@]}"; do - if [[ $line =~ ^[[(](.+)[])]$ ]]; then - procs+=("${BASH_REMATCH[1]}") - else - line=${line%% *} # trim arguments - line=${line##@(*/|-)} # trim leading path and - - [[ $line ]] && procs+=("$line") - fi - done - fi - fi - ((${#procs[@]})) && - _comp_compgen -U procs -- -X "" -W '"${procs[@]}"' - } -fi - -# This function completes on user IDs -# -# @since 2.12 -_comp_compgen_uids() -{ - if type getent &>/dev/null; then - _comp_compgen_split -- "$(getent passwd | cut -d: -f3)" - elif type perl &>/dev/null; then - _comp_compgen_split -- "$(perl -e 'while (($uid) = (getpwent)[2]) { print $uid . "\n" }')" - else - # make do with /etc/passwd - _comp_compgen_split -- "$(cut -d: -f3 /etc/passwd)" - fi -} - -# This function completes on group IDs -# -# @since 2.12 -_comp_compgen_gids() -{ - if type getent &>/dev/null; then - _comp_compgen_split -- "$(getent group | cut -d: -f3)" - elif type perl &>/dev/null; then - _comp_compgen_split -- "$(perl -e 'while (($gid) = (getgrent)[2]) { print $gid . "\n" }')" - else - # make do with /etc/group - _comp_compgen_split -- "$(cut -d: -f3 /etc/group)" - fi -} - -# Glob for matching various backup files. -# -_comp_backup_glob='@(#*#|*@(~|.@(bak|orig|rej|swp|@(dpkg|ucf)-*|rpm@(orig|new|save))))' - -# Complete on xinetd services -# -# @since 2.12 -_comp_compgen_xinetd_services() -{ - local xinetddir=${_comp__test_xinetd_dir:-/etc/xinetd.d} - if [[ -d $xinetddir ]]; then - local -a svcs - if _comp_expand_glob svcs '$xinetddir/!($_comp_backup_glob)'; then - _comp_compgen -U svcs -U xinetddir -- -W '"${svcs[@]#$xinetddir/}"' - fi - fi -} - -# This function completes on services -# -# @since 2.12 -_comp_compgen_services() -{ - local sysvdirs - _comp_sysvdirs || return 1 - - local services - _comp_expand_glob services '${sysvdirs[0]}/!($_comp_backup_glob|functions|README)' - - local _generated=$({ - systemctl list-units --full --all || - systemctl list-unit-files - } 2>/dev/null | - _comp_awk '$1 ~ /\.service$/ { sub("\\.service$", "", $1); print $1 }') - _comp_split -la services "$_generated" - - if [[ -x /sbin/upstart-udev-bridge ]]; then - _comp_split -la services "$(initctl list 2>/dev/null | cut -d' ' -f1)" - fi - - ((${#services[@]})) || return 1 - _comp_compgen -U services -U sysvdirs -- -W '"${services[@]#${sysvdirs[0]}/}"' -} - -# This completes on a list of all available service scripts for the -# 'service' command and/or the SysV init.d directory, followed by -# that script's available commands -# This function is in the main bash_completion file rather than in a separate -# one, because we set it up eagerly as completer for scripts in sysv init dirs -# below. -# -# @since 2.12 -_comp_complete_service() -{ - local cur prev words cword comp_args - _comp_initialize -- "$@" || return - - # don't complete past 2nd token - ((cword > 2)) && return - - if [[ $cword -eq 1 && $prev == ?(*/)service ]]; then - _comp_compgen_services - [[ -e /etc/mandrake-release ]] && _comp_compgen_xinetd_services - else - local sysvdirs - _comp_sysvdirs || return 1 - _comp_compgen_split -l -- "$(command sed -e 'y/|/ /' \ - -ne 's/^.*\(U\|msg_u\)sage.*{\(.*\)}.*$/\2/p' \ - "${sysvdirs[0]}/${prev##*/}" 2>/dev/null) start stop" - fi -} && - complete -F _comp_complete_service service - -_comp__init_set_up_service_completions() -{ - local sysvdirs svc svcdir svcs - _comp_sysvdirs && - for svcdir in "${sysvdirs[@]}"; do - if _comp_expand_glob svcs '"$svcdir"/!($_comp_backup_glob)'; then - for svc in "${svcs[@]}"; do - [[ -x $svc ]] && complete -F _comp_complete_service "$svc" - done - fi - done - unset -f "$FUNCNAME" -} -_comp__init_set_up_service_completions - -# This function completes on kernel modules -# @param $1 kernel version -# -# @since 2.12 -_comp_compgen_kernel_modules() -{ - local _modpath=/lib/modules/$1 - _comp_compgen_split -- "$(command ls -RL "$_modpath" 2>/dev/null | - command sed -ne 's/^\(.*\)\.k\{0,1\}o\(\.[gx]z\)\{0,1\}$/\1/p' \ - -e 's/^\(.*\)\.ko\.zst$/\1/p')" -} - -# This function completes on inserted kernel modules -# @param $1 prefix to filter with, default $cur -# -# @since 2.12 -_comp_compgen_inserted_kernel_modules() -{ - _comp_compgen -c "${1:-$cur}" split -- "$(PATH="$PATH:/sbin" lsmod | - _comp_awk '{if (NR != 1) print $1}')" -} - -# This function completes on user or user:group format; as for chown and cpio. -# -# The : must be added manually; it will only complete usernames initially. -# The legacy user.group format is not supported. -# -# @param $1 If -u, only return users/groups the user has access to in -# context of current completion. -# -# @since 2.12 -_comp_compgen_usergroups() -{ - if [[ $cur == *\\\\* || $cur == *:*:* ]]; then - # Give up early on if something seems horribly wrong. - return - elif [[ $cur == *\\:* ]]; then - # Completing group after 'user\:gr'. - # Reply with a list of groups prefixed with 'user:', readline will - # escape to the colon. - local tmp - if [[ ${1-} == -u ]]; then - _comp_compgen -v tmp -c "${cur#*:}" allowed_groups - else - _comp_compgen -v tmp -c "${cur#*:}" -- -g - fi - if ((${#tmp[@]})); then - local _prefix=${cur%%*([^:])} - _prefix=${_prefix//\\/} - _comp_compgen -Rv tmp -- -P "$_prefix" -W '"${tmp[@]}"' - _comp_compgen -U tmp set "${tmp[@]}" - fi - elif [[ $cur == *:* ]]; then - # Completing group after 'user:gr'. - # Reply with a list of unprefixed groups since readline with split on : - # and only replace the 'gr' part - if [[ ${1-} == -u ]]; then - _comp_compgen -c "${cur#*:}" allowed_groups - else - _comp_compgen -c "${cur#*:}" -- -g - fi - else - # Completing a partial 'usernam'. - # - # Don't suffix with a : because readline will escape it and add a - # slash. It's better to complete into 'chown username ' than 'chown - # username\:'. - if [[ ${1-} == -u ]]; then - _comp_compgen_allowed_users - else - _comp_compgen -- -u - fi - fi -} - -# @since 2.12 -_comp_compgen_allowed_users() -{ - if _comp_as_root; then - _comp_compgen -- -u - else - _comp_compgen_split -- "$(id -un 2>/dev/null || whoami 2>/dev/null)" - fi -} - -# @since 2.12 -_comp_compgen_allowed_groups() -{ - if _comp_as_root; then - _comp_compgen -- -g - else - _comp_compgen_split -- "$(id -Gn 2>/dev/null || groups 2>/dev/null)" - fi -} - -# @since 2.12 -_comp_compgen_selinux_users() -{ - _comp_compgen_split -- "$(semanage user -nl 2>/dev/null | - _comp_awk '{ print $1 }')" -} - -# This function completes on valid shells -# @param $1 chroot to search from -# -# @since 2.12 -_comp_compgen_shells() -{ - local -a shells=() - local _shell _rest - while read -r _shell _rest; do - [[ $_shell == /* ]] && shells+=("$_shell") - done 2>/dev/null <"${1-}"/etc/shells - _comp_compgen -U shells -- -W '"${shells[@]}"' -} - -# This function completes on valid filesystem types -# -# @since 2.12 -_comp_compgen_fstypes() -{ - local _fss - - if [[ -e /proc/filesystems ]]; then - # Linux - _fss="$(cut -d$'\t' -f2 /proc/filesystems) - $(_comp_awk '! /\*/ { print $NF }' /etc/filesystems 2>/dev/null)" - else - # Generic - _fss="$(_comp_awk '/^[ \t]*[^#]/ { print $3 }' /etc/fstab 2>/dev/null) - $(_comp_awk '/^[ \t]*[^#]/ { print $3 }' /etc/mnttab 2>/dev/null) - $(_comp_awk '/^[ \t]*[^#]/ { print $4 }' /etc/vfstab 2>/dev/null) - $(_comp_awk '{ print $1 }' /etc/dfs/fstypes 2>/dev/null) - $(lsvfs 2>/dev/null | _comp_awk '$1 !~ /^(Filesystem|[^a-zA-Z])/ { print $1 }') - $([[ -d /etc/fs ]] && command ls /etc/fs)" - fi - - [[ $_fss ]] && _comp_compgen_split -- "$_fss" -} - -# Get absolute path to a file, with rudimentary canonicalization. -# No symlink resolution or existence checks are done; -# see `_comp_realcommand` for those. -# @param $1 The file -# @var[out] REPLY The path -# @since 2.12 -_comp_abspath() -{ - REPLY=$1 - [[ $REPLY == /* ]] || REPLY=$PWD/$REPLY - REPLY=${REPLY//+(\/)/\/} - while true; do - # Process "." and "..". To avoid reducing "/../../ => /", we convert - # "/*/../" one by one. "/.." at the beginning is ignored. Then, /*/../ - # in the middle is processed. Finally, /*/.. at the end is removed. - case $REPLY in - */./*) REPLY=${REPLY//\/.\//\/} ;; - */.) REPLY=${REPLY%/.} ;; - /..?(/*)) REPLY=${REPLY#/..} ;; - */+([^/])/../*) REPLY=${REPLY/\/+([^\/])\/..\//\/} ;; - */+([^/])/..) REPLY=${REPLY%/+([^/])/..} ;; - *) break ;; - esac - done - [[ $REPLY ]] || REPLY=/ -} - -# Get real command. -# Command is the filename of command in PATH with possible symlinks resolved -# (if resolve tooling available), empty string if command not found. -# @param $1 Command -# @var[out] REPLY Resulting string -# @return True (0) if command found, False (> 0) if not. -# @since 2.12 -_comp_realcommand() -{ - REPLY="" - local file - file=$(type -P -- "$1") || return $? - if type -p realpath >/dev/null; then - REPLY=$(realpath "$file") - elif type -p greadlink >/dev/null; then - REPLY=$(greadlink -f "$file") - elif type -p readlink >/dev/null; then - REPLY=$(readlink -f "$file") - else - _comp_abspath "$file" - fi -} - -# This function returns the position of the first argument, excluding options -# -# Options: -# -a GLOB Pattern of options that take an option argument -# -# @var[out] REPLY Position of the first argument before the current one being -# completed if any, or otherwise an empty string -# @return True (0) if any argument is found, False (> 0) otherwise. -# @since 2.12 -_comp_locate_first_arg() -{ - local has_optarg="" - local OPTIND=1 OPTARG="" OPTERR=0 _opt - while getopts ':a:' _opt "$@"; do - case $_opt in - a) has_optarg=$OPTARG ;; - *) - echo "bash_completion: $FUNCNAME: usage error" >&2 - return 2 - ;; - esac - done - shift "$((OPTIND - 1))" - - local i - REPLY= - for ((i = 1; i < cword; i++)); do - # shellcheck disable=SC2053 - if [[ $has_optarg && ${words[i]} == $has_optarg ]]; then - ((i++)) - elif [[ ${words[i]} != -?* ]]; then - REPLY=$i - return 0 - elif [[ ${words[i]} == -- ]]; then - ((i + 1 < cword)) && REPLY=$((i + 1)) && return 0 - break - fi - done - return 1 -} - -# This function returns the first argument, excluding options -# -# Options: -# -a GLOB Pattern of options that take an option argument -# -# @var[out] REPLY First argument before the current one being completed if any, -# or otherwise an empty string -# @return True (0) if any argument is found, False (> 0) otherwise. -# @since 2.12 -_comp_get_first_arg() -{ - _comp_locate_first_arg "$@" && REPLY=${words[REPLY]} -} - -# This function counts the number of args, excluding options -# -# Options: -# -n CHARS Characters out of $COMP_WORDBREAKS which should -# NOT be considered word breaks. See -# _comp__reassemble_words. -# -a GLOB Options whose following argument should not be counted -# -i GLOB Options that should be counted as args -# -# @var[out] REPLY Return the number of arguments -# @since 2.12 -_comp_count_args() -{ - local has_optarg="" has_exclude="" exclude="" glob_include="" - local OPTIND=1 OPTARG="" OPTERR=0 _opt - while getopts ':a:n:i:' _opt "$@"; do - case $_opt in - a) has_optarg=$OPTARG ;; - n) has_exclude=set exclude+=$OPTARG ;; - i) glob_include=$OPTARG ;; - *) - echo "bash_completion: $FUNCNAME: usage error" >&2 - return 2 - ;; - esac - done - shift "$((OPTIND - 1))" - - if [[ $has_exclude ]]; then - local cword words - _comp__reassemble_words "$exclude<>&" words cword - fi - - local i - REPLY=1 - for ((i = 1; i < cword; i++)); do - # shellcheck disable=SC2053 - if [[ $has_optarg && ${words[i]} == $has_optarg ]]; then - ((i++)) - elif [[ ${words[i]} != -?* || $glob_include && ${words[i]} == $glob_include ]]; then - ((REPLY++)) - elif [[ ${words[i]} == -- ]]; then - ((REPLY += cword - i - 1)) - break - fi - done -} - -# This function completes on PCI IDs -# -# @since 2.12 -_comp_compgen_pci_ids() -{ - _comp_compgen_split -- "$(PATH="$PATH:/sbin" lspci -n | _comp_awk '{print $3}')" -} - -# This function completes on USB IDs -# -# @since 2.12 -_comp_compgen_usb_ids() -{ - _comp_compgen_split -- "$(PATH="$PATH:/sbin" lsusb | _comp_awk '{print $6}')" -} - -# CD device names -# -# @since 2.12 -_comp_compgen_cd_devices() -{ - _comp_compgen -c "${cur:-/dev/}" -- -f -d -X "!*/?([amrs])cd!(c-*)" -} - -# DVD device names -# -# @since 2.12 -_comp_compgen_dvd_devices() -{ - _comp_compgen -c "${cur:-/dev/}" -- -f -d -X "!*/?(r)dvd*" -} - -# TERM environment variable values -# -# @since 2.12 -_comp_compgen_terms() -{ - _comp_compgen_split -- "$({ - command sed -ne 's/^\([^[:space:]#|]\{2,\}\)|.*/\1/p' /etc/termcap - { - toe -a || toe - } | _comp_awk '{ print $1 }' - _comp_expand_glob dirs '/{etc,lib,usr/lib,usr/share}/terminfo/?' && - find "${dirs[@]}" -type f -maxdepth 1 | - _comp_awk -F / '{ print $NF }' - } 2>/dev/null)" -} - -# @since 2.12 -_comp_try_faketty() -{ - if type unbuffer &>/dev/null; then - unbuffer -p "$@" - elif script --version 2>&1 | command grep -qF util-linux; then - # BSD and Solaris "script" do not seem to have required features - script -qaefc "$*" /dev/null - else - "$@" # no can do, fallback - fi -} - -# a little help for FreeBSD ports users -[[ $OSTYPE == *freebsd* ]] && complete -W 'index search fetch fetch-list - extract patch configure build install reinstall deinstall clean - clean-depends kernel buildworld' make - -# This function provides simple user@host completion -# -# @since 2.12 -_comp_complete_user_at_host() -{ - local cur prev words cword comp_args - _comp_initialize -n : -- "$@" || return - - if [[ $cur == *@* ]]; then - _comp_compgen_known_hosts "$cur" - else - _comp_compgen -- -u -S @ - compopt -o nospace - fi -} -shopt -u hostcomplete && complete -F _comp_complete_user_at_host talk ytalk finger - -# NOTE: Using this function as a helper function is deprecated. Use -# `_comp_compgen_known_hosts' instead. -# @since 2.12 -_comp_complete_known_hosts() -{ - local cur prev words cword comp_args - _comp_initialize -n : -- "$@" || return - - # NOTE: Using `_known_hosts' (the old name of `_comp_complete_known_hosts') - # as a helper function and passing options to `_known_hosts' is - # deprecated: Use `_comp_compgen_known_hosts' instead. - local -a options=() - [[ ${1-} == -a || ${2-} == -a ]] && options+=(-a) - [[ ${1-} == -c || ${2-} == -c ]] && options+=(-c) - local IFS=$' \t\n' # Workaround for connected ${v+"$@"} in bash < 4.4 - _comp_compgen_known_hosts ${options[@]+"${options[@]}"} -- "$cur" -} - -# Helper function to locate ssh included files in configs -# This function looks for the "Include" keyword in ssh config files and -# includes them recursively, adding each result to the config variable. -_comp__included_ssh_config_files() -{ - (($# < 1)) && - echo "bash_completion: $FUNCNAME: missing mandatory argument CONFIG" >&2 - local configfile i files f REPLY - configfile=$1 - - # From man ssh_config: - # "Files without absolute paths are assumed to be in ~/.ssh if included - # in a user configuration file or /etc/ssh if included from the system - # configuration file." - # This behavior is not affected by the the including file location - - # if the system configuration file is included from the user's config, - # relative includes are still resolved in the user's ssh config directory. - local relative_include_base - if [[ $configfile == /etc/ssh* ]]; then - relative_include_base="/etc/ssh" - else - relative_include_base="$HOME/.ssh" - fi - - local depth=1 - local -a included - local -a include_files - included=("$configfile") - - # Max recursion depth per openssh's READCONF_MAX_DEPTH: - # https://github.com/openssh/openssh-portable/blob/5ec5504f1d328d5bfa64280cd617c3efec4f78f3/readconf.c#L2240 - local max_depth=16 - while ((${#included[@]} > 0 && depth++ < max_depth)); do - _comp_split include_files "$(command sed -ne 's/^[[:blank:]]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][[:blank:]]\(.*\)$/\1/p' "${included[@]}")" || return - included=() - for i in "${include_files[@]}"; do - if [[ $i != [~/]* ]]; then - i="${relative_include_base}/${i}" - fi - _comp_expand_tilde "$i" - if _comp_expand_glob files '$REPLY'; then - # In case the expanded variable contains multiple paths - for f in "${files[@]}"; do - if [[ -r $f && ! -d $f ]]; then - config+=("$f") - included+=("$f") - fi - done - fi - done - done -} - -# Helper function for completing _comp_complete_known_hosts. -# This function performs host completion based on ssh's config and known_hosts -# files, as well as hostnames reported by avahi-browse if -# BASH_COMPLETION_KNOWN_HOSTS_WITH_AVAHI is set to a non-empty value. -# Also hosts from HOSTFILE (compgen -A hostname) are added, unless -# BASH_COMPLETION_KNOWN_HOSTS_WITH_HOSTFILE is set to an empty value. -# Usage: _comp_compgen_known_hosts [OPTIONS] CWORD -# Options: -# -a Use aliases from ssh config files -# -c Use `:' suffix -# -F configfile Use `configfile' for configuration settings -# -p PREFIX Use PREFIX -# -4 Filter IPv6 addresses from results -# -6 Filter IPv4 addresses from results -# @var[out] COMPREPLY Completions, starting with CWORD, are added -# @return True (0) if one or more completions are generated, or otherwise False -# (1). -# @since 2.12 -_comp_compgen_known_hosts() -{ - local known_hosts - _comp_compgen_known_hosts__impl "$@" || return "$?" - _comp_compgen -U known_hosts set "${known_hosts[@]}" -} -_comp_compgen_known_hosts__impl() -{ - known_hosts=() - - local configfile="" flag prefix="" - local cur suffix="" aliases="" i host ipv4="" ipv6="" - local -a kh tmpkh=() khd=() config=() - - # TODO remove trailing %foo from entries - - local OPTIND=1 - while getopts "ac46F:p:" flag "$@"; do - case $flag in - a) aliases=set ;; - c) suffix=':' ;; - F) - if [[ ! $OPTARG ]]; then - echo "bash_completion: $FUNCNAME: -F: an empty filename is specified" >&2 - return 2 - fi - configfile=$OPTARG - ;; - p) prefix=$OPTARG ;; - 4) ipv4=set ;; - 6) ipv6=set ;; - *) - echo "bash_completion: $FUNCNAME: usage error" >&2 - return 2 - ;; - esac - done - if (($# < OPTIND)); then - echo "bash_completion: $FUNCNAME: missing mandatory argument CWORD" >&2 - return 2 - fi - cur=${!OPTIND} - ((OPTIND += 1)) - if (($# >= OPTIND)); then - echo "bash_completion: $FUNCNAME($*): unprocessed arguments:" \ - "$(while (($# >= OPTIND)); do - printf '%s ' ${!OPTIND} - shift - done)" >&2 - return 2 - fi - - [[ $cur == *@* ]] && prefix=$prefix${cur%@*}@ && cur=${cur#*@} - kh=() - - # ssh config files - if [[ $configfile ]]; then - [[ -r $configfile && ! -d $configfile ]] && config+=("$configfile") - else - for i in /etc/ssh/ssh_config ~/.ssh/config ~/.ssh2/config; do - [[ -r $i && ! -d $i ]] && config+=("$i") - done - fi - - # "Include" keyword in ssh config files - if ((${#config[@]} > 0)); then - for i in "${config[@]}"; do - _comp__included_ssh_config_files "$i" - done - fi - - # Known hosts files from configs - if ((${#config[@]} > 0)); then - # expand paths (if present) to global and user known hosts files - # TODO(?): try to make known hosts files with more than one consecutive - # spaces in their name work (watch out for ~ expansion - # breakage! Alioth#311595) - if _comp_split -l tmpkh "$(_comp_awk 'sub("^[ \t]*([Gg][Ll][Oo][Bb][Aa][Ll]|[Uu][Ss][Ee][Rr])[Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee][ \t=]+", "") { print $0 }' "${config[@]}" | sort -u)"; then - local tmpkh2 j REPLY - for i in "${tmpkh[@]}"; do - # First deal with quoted entries... - while [[ $i =~ ^([^\"]*)\"([^\"]*)\"(.*)$ ]]; do - i=${BASH_REMATCH[1]}${BASH_REMATCH[3]} - _comp_expand_tilde "${BASH_REMATCH[2]}" # Eval/expand possible `~' or `~user' - [[ -r $REPLY ]] && kh+=("$REPLY") - done - # ...and then the rest. - _comp_split tmpkh2 "$i" || continue - for j in "${tmpkh2[@]}"; do - _comp_expand_tilde "$j" # Eval/expand possible `~' or `~user' - [[ -r $REPLY ]] && kh+=("$REPLY") - done - done - fi - fi - - if [[ ! $configfile ]]; then - # Global and user known_hosts files - for i in /etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2 \ - /etc/known_hosts /etc/known_hosts2 ~/.ssh/known_hosts \ - ~/.ssh/known_hosts2; do - [[ -r $i && ! -d $i ]] && kh+=("$i") - done - for i in /etc/ssh2/knownhosts ~/.ssh2/hostkeys; do - [[ -d $i ]] || continue - _comp_expand_glob tmpkh '"$i"/*.pub' && khd+=("${tmpkh[@]}") - done - fi - - # If we have known_hosts files to use - if ((${#kh[@]} + ${#khd[@]} > 0)); then - if ((${#kh[@]} > 0)); then - # https://man.openbsd.org/sshd.8#SSH_KNOWN_HOSTS_FILE_FORMAT - for i in "${kh[@]}"; do - while read -ra tmpkh; do - ((${#tmpkh[@]} == 0)) && continue - # Skip entries starting with | (hashed) and # (comment) - [[ ${tmpkh[0]} == [\|\#]* ]] && continue - # Ignore leading @foo (markers) - local host_list=${tmpkh[0]} - [[ ${tmpkh[0]} == @* ]] && host_list=${tmpkh[1]-} - # Split entry on commas - local -a hosts - if _comp_split -F , hosts "$host_list"; then - for host in "${hosts[@]}"; do - # Skip hosts containing wildcards - [[ $host == *[*?]* ]] && continue - # Remove leading [ - host=${host#[} - # Remove trailing ] + optional :port - host=${host%]?(:+([0-9]))} - # Add host to candidates - [[ $host ]] && known_hosts+=("$host") - done - fi - done <"$i" - done - fi - if ((${#khd[@]} > 0)); then - # Needs to look for files called - # .../.ssh2/key_22_.pub - # dont fork any processes, because in a cluster environment, - # there can be hundreds of hostkeys - for i in "${khd[@]}"; do - if [[ $i == *key_22_*.pub && -r $i ]]; then - host=${i/#*key_22_/} - host=${host/%.pub/} - [[ $host ]] && known_hosts+=("$host") - fi - done - fi - - # apply suffix and prefix - ((${#known_hosts[@]})) && - _comp_compgen -v known_hosts -- -W '"${known_hosts[@]}"' -P "$prefix" -S "$suffix" - fi - - # append any available aliases from ssh config files - if [[ ${#config[@]} -gt 0 && $aliases ]]; then - local -a hosts - if _comp_split hosts "$(command sed -ne 's/^[[:blank:]]*[Hh][Oo][Ss][Tt][[:blank:]=]\{1,\}\(.*\)$/\1/p' "${config[@]}")"; then - _comp_compgen -av known_hosts -- -P "$prefix" \ - -S "$suffix" -W '"${hosts[@]%%[*?%]*}"' -X '@(\!*|)' - fi - fi - - # Add hosts reported by avahi-browse, if desired and it's available. - if [[ ${BASH_COMPLETION_KNOWN_HOSTS_WITH_AVAHI-} ]] && - type avahi-browse &>/dev/null; then - # Some old versions of avahi-browse reportedly didn't have -k - # (even if mentioned in the manpage); those we do not support any more. - local generated=$(avahi-browse -cprak 2>/dev/null | _comp_awk -F ';' \ - '/^=/ && $5 ~ /^_(ssh|workstation)\._tcp$/ { print $7 }' | - sort -u) - _comp_compgen -av known_hosts -- -P "$prefix" -S "$suffix" -W '$generated' - fi - - # Add hosts reported by ruptime. - if type ruptime &>/dev/null; then - local generated=$(ruptime 2>/dev/null | _comp_awk '!/^ruptime:/ { print $1 }') - _comp_compgen -av known_hosts -- -W '$generated' - fi - - # Add results of normal hostname completion, unless - # `BASH_COMPLETION_KNOWN_HOSTS_WITH_HOSTFILE' is set to an empty value. - if [[ ${BASH_COMPLETION_KNOWN_HOSTS_WITH_HOSTFILE-set} ]]; then - _comp_compgen -av known_hosts -- -A hostname -P "$prefix" -S "$suffix" - fi - - ((${#known_hosts[@]})) || return 1 - - if [[ $ipv4 ]]; then - known_hosts=("${known_hosts[@]/*:*$suffix/}") - fi - if [[ $ipv6 ]]; then - known_hosts=("${known_hosts[@]/+([0-9]).+([0-9]).+([0-9]).+([0-9])$suffix/}") - fi - if [[ $ipv4 || $ipv6 ]]; then - for i in "${!known_hosts[@]}"; do - [[ ${known_hosts[i]} ]] || unset -v 'known_hosts[i]' - done - fi - ((${#known_hosts[@]})) || return 1 - - _comp_compgen -v known_hosts -c "$prefix$cur" ltrim_colon "${known_hosts[@]}" -} -complete -F _comp_complete_known_hosts traceroute traceroute6 \ - fping fping6 telnet rsh rlogin ftp dig drill ssh-installkeys showmount - -# Convert the word index in `words` to the index in `COMP_WORDS`. -# @param $1 Index in the array WORDS. -# @var[in,opt] words Words that contain reassmbled words. -# @var[in,opt] cword Current word index in WORDS. -# WORDS and CWORD, if any, are expected to be created by -# _comp__reassemble_words. -# -_comp__find_original_word() -{ - REPLY=$1 - - # If CWORD or WORDS are undefined, we return the first argument without any - # processing. - [[ -v cword && -v words ]] || return 0 - - local reassembled_offset=$1 i=0 j - for ((j = 0; j < reassembled_offset; j++)); do - local word=${words[j]} - while [[ $word && i -lt ${#COMP_WORDS[@]} && $word == *"${COMP_WORDS[i]}"* ]]; do - word=${word#*"${COMP_WORDS[i++]}"} - done - done - REPLY=$i -} -# A meta-command completion function for commands like sudo(8), which need to -# first complete on a command, then complete according to that command's own -# completion definition. -# -# @since 2.12 -_comp_command_offset() -{ - # rewrite current completion context before invoking - # actual command completion - - # obtain the word index in COMP_WORDS - local REPLY - _comp__find_original_word "$1" - local word_offset=$REPLY - - # make changes to COMP_* local. Note that bash-4.3..5.0 have a - # bug that `local -a arr=("${arr[@]}")` fails. We instead first - # assign the values of `COMP_WORDS` to another array `comp_words`. - local COMP_LINE=$COMP_LINE COMP_POINT=$COMP_POINT COMP_CWORD=$COMP_CWORD - local -a comp_words=("${COMP_WORDS[@]}") - local -a COMP_WORDS=("${comp_words[@]}") - - # find new first word position, then - # rewrite COMP_LINE and adjust COMP_POINT - local i tail - for ((i = 0; i < word_offset; i++)); do - tail=${COMP_LINE#*"${COMP_WORDS[i]}"} - ((COMP_POINT -= ${#COMP_LINE} - ${#tail})) - COMP_LINE=$tail - done - - # shift COMP_WORDS elements and adjust COMP_CWORD - COMP_WORDS=("${COMP_WORDS[@]:word_offset}") - ((COMP_CWORD -= word_offset)) - - COMPREPLY=() - local cur - _comp_get_words cur - - if ((COMP_CWORD == 0)); then - _comp_compgen_commands - else - _comp_dequote "${COMP_WORDS[0]}" || REPLY=${COMP_WORDS[0]} - local cmd=$REPLY compcmd=$REPLY - local cspec=$(complete -p -- "$cmd" 2>/dev/null) - - # If we have no completion for $cmd yet, see if we have for basename - if [[ ! $cspec && $cmd == */* ]]; then - cspec=$(complete -p -- "${cmd##*/}" 2>/dev/null) - [[ $cspec ]] && compcmd=${cmd##*/} - fi - # If still nothing, just load it for the basename - if [[ ! $cspec ]]; then - compcmd=${cmd##*/} - _comp_load -D -- "$compcmd" - cspec=$(complete -p -- "$compcmd" 2>/dev/null) - fi - - local retry_count=0 - while true; do # loop for the retry request by status 124 - local args original_cur=${comp_args[1]-$cur} - if ((${#COMP_WORDS[@]} >= 2)); then - args=("$cmd" "$original_cur" "${COMP_WORDS[-2]}") - else - args=("$cmd" "$original_cur") - fi - - if [[ ! $cspec ]]; then - if ((${#COMPREPLY[@]} == 0)); then - # XXX will probably never happen as long as completion loader loads - # *something* for every command thrown at it ($cspec != empty) - _comp_complete_minimal "${args[@]}" - fi - elif [[ $cspec == *\ -[CF]\ * ]]; then - if [[ $cspec == *' -F '* ]]; then - # complete -F - - # get function name - local func=${cspec#* -F } - func=${func%% *} - $func "${args[@]}" - - # restart completion (once) if function exited with 124 - if (($? == 124 && retry_count++ == 0)); then - # Note: When the completion function returns 124, the - # state of COMPREPLY is discarded. - COMPREPLY=() - - cspec=$(complete -p -- "$compcmd" 2>/dev/null) - - # Note: When completion spec is removed after 124, we - # do not generate any completions including the default - # ones. This is the behavior of the original Bash - # progcomp. - [[ $cspec ]] || break - - continue - fi - else - # complete -C - - # get command name - local completer=${cspec#* -C \'} - - # completer commands are always single-quoted - if ! _comp_dequote "'$completer"; then - _minimal "${args[@]}" - break - fi - completer=${REPLY[0]} - - local -a suggestions - - local IFS=$' \t\n' - local reset_monitor=$(shopt -po monitor) reset_lastpipe=$(shopt -p lastpipe) reset_noglob=$(shopt -po noglob) - set +o monitor - shopt -s lastpipe - set -o noglob - - COMP_KEY="$COMP_KEY" COMP_LINE="$COMP_LINE" \ - COMP_POINT="$COMP_POINT" COMP_TYPE="$COMP_TYPE" \ - $completer "${args[@]}" | mapfile -t suggestions - - $reset_monitor - $reset_lastpipe - $reset_noglob - _comp_unlocal IFS - - local suggestion - local i=0 - COMPREPLY=() - for suggestion in "${suggestions[@]}"; do - COMPREPLY[i]+=${COMPREPLY[i]+$'\n'}$suggestion - - if [[ $suggestion != *\\ ]]; then - ((i++)) - fi - done - fi - - # restore initial compopts - local opt - while [[ $cspec == *" -o "* ]]; do - # FIXME: should we take "+o opt" into account? - cspec=${cspec#*-o } - opt=${cspec%% *} - compopt -o "$opt" - cspec=${cspec#"$opt"} - done - else - cspec=${cspec#complete} - cspec=${cspec%%@("$compcmd"|"'${compcmd//\'/\'\\\'\'}'")} - eval "_comp_compgen -- $cspec" - fi - break - done - fi -} - -# A _comp_command_offset wrapper function for use when the offset is unknown. -# Only intended to be used as a completion function directly associated -# with a command, not to be invoked from within other completion functions. -# -# @since 2.12 -_comp_command() -{ - # We unset the shell variable `words` locally to tell - # `_comp_command_offset` that the index is intended to be that in - # `COMP_WORDS` instead of `words`. - local words - unset -v words - - local offset i - - # find actual offset, as position of the first non-option - offset=1 - for ((i = 1; i <= COMP_CWORD; i++)); do - if [[ ${COMP_WORDS[i]} != -* ]]; then - offset=$i - break - fi - done - _comp_command_offset $offset -} -complete -F _comp_command aoss command "do" else eval exec ltrace nice nohup padsp \ - "then" time tsocks vsound xargs - -# @since 2.12 -_comp_root_command() -{ - local PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin - local _comp_root_command=$1 - _comp_command -} -complete -F _comp_root_command fakeroot gksu gksudo kdesudo really - -# Return true if the completion should be treated as running as root -# -# @since 2.12 -_comp_as_root() -{ - [[ $EUID -eq 0 || ${_comp_root_command-} ]] -} - -# Complete on available commands, subject to `no_empty_cmd_completion`. -# @return True (0) if one or more completions are generated, or otherwise False -# (1). Note that it returns 1 even when the completion generation is canceled -# by `shopt -s no_empty_cmd_completion`. -# -# @since 2.12 -_comp_compgen_commands() -{ - [[ ! ${cur-} ]] && shopt -q no_empty_cmd_completion && return 1 - # -o filenames for e.g. spaces in paths to and in command names - _comp_compgen -- -c -o plusdirs && compopt -o filenames -} - -# @since 2.12 -_comp_complete_longopt() -{ - local cur prev words cword was_split comp_args - _comp_initialize -s -- "$@" || return - - case "${prev,,}" in - --help | --usage | --version) - return - ;; - --!(no-*)dir*) - _comp_compgen -a filedir -d - return - ;; - --!(no-*)@(file|path)*) - _comp_compgen -a filedir - return - ;; - --+([-a-z0-9_])) - local argtype=$(LC_ALL=C $1 --help 2>&1 | command sed -ne \ - "s|.*$prev\[\{0,1\}=[<[]\{0,1\}\([-A-Za-z0-9_]\{1,\}\).*|\1|p") - case ${argtype,,} in - *dir*) - _comp_compgen -a filedir -d - return - ;; - *file* | *path*) - _comp_compgen -a filedir - return - ;; - esac - ;; - esac - - [[ $was_split ]] && return - - if [[ $cur == -* ]]; then - _comp_compgen_split -- "$(LC_ALL=C $1 --help 2>&1 | - while read -r line; do - [[ $line =~ --[A-Za-z0-9]+([-_][A-Za-z0-9]+)*=? ]] && - printf '%s\n' "${BASH_REMATCH[0]}" - done)" - [[ ${COMPREPLY-} == *= ]] && compopt -o nospace - elif [[ $1 == *@(rmdir|chroot) ]]; then - _comp_compgen -a filedir -d - else - [[ $1 == *mkdir ]] && compopt -o nospace - _comp_compgen -a filedir - fi -} -# makeinfo and texi2dvi are defined elsewhere. -complete -F _comp_complete_longopt \ - a2ps awk base64 bash bc bison cat chroot colordiff cp \ - csplit cut date df diff dir du enscript expand fmt fold gperf \ - grep grub head irb ld ldd less ln ls m4 mkdir mkfifo mknod \ - mv netstat nl nm objcopy objdump od paste pr ptx readelf rm rmdir \ - sed seq shar sort split strip sum tac tail tee \ - texindex touch tr uname unexpand uniq units vdir wc who - -# @since 2.12 -declare -Ag _comp_xspecs - -# @since 2.12 -_comp_complete_filedir_xspec() -{ - local cur prev words cword comp_args - _comp_initialize -- "$@" || return - _comp_compgen_filedir_xspec "$1" -} - -# @since 2.12 -_comp_compgen_filedir_xspec() -{ - _comp_compgen_tilde && return - - local REPLY - _comp_quote_compgen "$cur" - local quoted=$REPLY - - local xspec=${_comp_xspecs[${1##*/}]-${_xspecs[${1##*/}]-}} - local -a toks - _comp_compgen -v toks -c "$quoted" -- -d - - # Munge xspec to contain uppercase version too - # https://lists.gnu.org/archive/html/bug-bash/2010-09/msg00036.html - # news://news.gmane.io/4C940E1C.1010304@case.edu - eval xspec="${xspec}" - local matchop=! - if [[ $xspec == !* ]]; then - xspec=${xspec#!} - matchop=@ - fi - xspec="$matchop($xspec|${xspec^^})" - - _comp_compgen -av toks -c "$quoted" -- -f -X "@(|!($xspec))" - - # Try without filter if it failed to produce anything and configured to - [[ ${BASH_COMPLETION_FILEDIR_FALLBACK-} && ${#toks[@]} -lt 1 ]] && - _comp_compgen -av toks -c "$quoted" -- -f - - ((${#toks[@]})) || return 1 - - # Remove . and .. (as well as */. and */..) from suggestions, unless .. or - # */.. was typed explicitly by the user (for users who use tab-completion - # to append a slash after '..') - if [[ $cur != ?(*/).. ]]; then - _comp_compgen -Rv toks -- -X '?(*/)@(.|..)' -W '"${toks[@]}"' || return 1 - fi - - compopt -o filenames - _comp_compgen -RU toks -- -W '"${toks[@]}"' -} - -_comp__init_install_xspec() -{ - local xspec=$1 cmd - shift - for cmd in "$@"; do - _comp_xspecs[$cmd]=$xspec - done -} -# bzcmp, bzdiff, bz*grep, bzless, bzmore intentionally not here, see Debian: #455510 -_comp__init_install_xspec '!*.?(t)bz?(2)' bunzip2 bzcat pbunzip2 pbzcat lbunzip2 lbzcat -_comp__init_install_xspec '!*.@(zip|[aegjkswx]ar|exe|pk3|wsz|zargo|xpi|s[tx][cdiw]|sx[gm]|o[dt][tspgfc]|od[bm]|oxt|?(o)xps|epub|cbz|apk|aab|ipa|do[ct][xm]|p[op]t[mx]|xl[st][xm]|pyz|vsix|whl|[Ff][Cc][Ss]td)' unzip zipinfo -_comp__init_install_xspec '*.Z' compress znew -# zcmp, zdiff, z*grep, zless, zmore intentionally not here, see Debian: #455510 -_comp__init_install_xspec '!*.@(Z|[gGd]z|t[ag]z)' gunzip zcat -_comp__init_install_xspec '!*.@(Z|[gGdz]z|t[ag]z)' unpigz -_comp__init_install_xspec '!*.Z' uncompress -# lzcmp, lzdiff intentionally not here, see Debian: #455510 -_comp__init_install_xspec '!*.@(tlz|lzma)' lzcat lzegrep lzfgrep lzgrep lzless lzmore unlzma -_comp__init_install_xspec '!*.@(?(t)xz|tlz|lzma)' unxz xzcat -_comp__init_install_xspec '!*.lrz' lrunzip -_comp__init_install_xspec '!*.@(gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx)' ee -_comp__init_install_xspec '!*.@(gif|jp?(e)g|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm|svg)' qiv -_comp__init_install_xspec '!*.@(gif|jp?(e)g?(2)|j2[ck]|jp[2f]|tif?(f)|png|p[bgpn]m|webp|bmp|x[bp]m|rle|rgb|pcx|fits|pm|?(e)ps)' xv -_comp__init_install_xspec '!*.@(@(?(e)ps|?(E)PS|pdf|PDF)?(.gz|.GZ|.bz2|.BZ2|.Z))' gv ggv kghostview -_comp__init_install_xspec '!*.@(dvi|DVI)?(.@(gz|Z|bz2))' xdvi kdvi -_comp__init_install_xspec '!*.dvi' dvips dviselect dvitype dvipdf advi dvipdfm dvipdfmx -_comp__init_install_xspec '!*.[pf]df' acroread gpdf xpdf -_comp__init_install_xspec '!*.@(?(e)ps|pdf)' kpdf -_comp__init_install_xspec '!*.@(okular|@(?(e|x)ps|?(E|X)PS|[pf]df|[PF]DF|dvi|DVI|cb[rz]|CB[RZ]|djv?(u)|DJV?(U)|dvi|DVI|gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|GIF|JP?(E)G|MIFF|TIF?(F)|PN[GM]|P[BGP]M|BMP|XPM|ICO|XWD|TGA|PCX|epub|EPUB|odt|ODT|fb?(2)|FB?(2)|mobi|MOBI|g3|G3|chm|CHM|md|markdown)?(.?(gz|GZ|bz2|BZ2|xz|XZ)))' okular -_comp__init_install_xspec '!*.pdf' epdfview pdfunite -_comp__init_install_xspec '!*.@(cb[rz7t]|djv?(u)|?(e)ps|pdf)' zathura -_comp__init_install_xspec '!*.@(?(e)ps|pdf)' ps2pdf ps2pdf12 ps2pdf13 ps2pdf14 ps2pdfwr -_comp__init_install_xspec '!*.texi*' makeinfo texi2html -_comp__init_install_xspec '!*.@(?(la)tex|texi|dtx|ins|ltx|dbj)' tex latex slitex jadetex pdfjadetex pdftex pdflatex texi2dvi xetex xelatex luatex lualatex -_comp__init_install_xspec '!*.mp3' mpg123 mpg321 madplay -_comp__init_install_xspec '!*@(.@(mp?(e)g|MP?(E)G|wm[av]|WM[AV]|avi|AVI|asf|vob|VOB|bin|dat|divx|DIVX|vcd|ps|pes|fli|flv|FLV|fxm|FXM|viv|rm|ram|yuv|mov|MOV|qt|QT|web[am]|WEB[AM]|mp[234]|MP[234]|m?(p)4[av]|M?(P)4[AV]|mkv|MKV|og[agmv]|OG[AGMV]|t[ps]|T[PS]|m2t?(s)|M2T?(S)|mts|MTS|wav|WAV|flac|FLAC|asx|ASX|mng|MNG|srt|m[eo]d|M[EO]D|s[3t]m|S[3T]M|it|IT|xm|XM)|+([0-9]).@(vdr|VDR))?(.@(crdownload|part))' xine aaxine cacaxine fbxine -_comp__init_install_xspec '!*@(.@(mp?(e)g|MP?(E)G|wm[av]|WM[AV]|avi|AVI|asf|vob|VOB|bin|dat|divx|DIVX|vcd|ps|pes|fli|flv|FLV|fxm|FXM|viv|rm|ram|yuv|mov|MOV|qt|QT|web[am]|WEB[AM]|mp[234]|MP[234]|m?(p)4[av]|M?(P)4[AV]|mkv|MKV|og[agmv]|OG[AGMV]|opus|OPUS|t[ps]|T[PS]|m2t?(s)|M2T?(S)|mts|MTS|wav|WAV|flac|FLAC|asx|ASX|mng|MNG|srt|m[eo]d|M[EO]D|s[3t]m|S[3T]M|it|IT|xm|XM|iso|ISO)|+([0-9]).@(vdr|VDR))?(.@(crdownload|part))' kaffeine dragon totem -_comp__init_install_xspec '!*.@(avi|asf|wmv)' aviplay -_comp__init_install_xspec '!*.@(rm?(j)|ra?(m)|smi?(l))' realplay -_comp__init_install_xspec '!*.@(mpg|mpeg|avi|mov|qt)' xanim -_comp__init_install_xspec '!*.@(og[ag]|m3u|flac|spx)' ogg123 -_comp__init_install_xspec '!*.@(mp3|ogg|pls|m3u)' gqmpeg freeamp -_comp__init_install_xspec '!*.fig' xfig -_comp__init_install_xspec '!*.@(mid?(i)|cmf)' playmidi -_comp__init_install_xspec '!*.@(mid?(i)|rmi|rcp|[gr]36|g18|mod|xm|it|x3m|s[3t]m|kar)' timidity -_comp__init_install_xspec '!*.@(669|abc|am[fs]|d[bs]m|dmf|far|it|mdl|m[eo]d|mid?(i)|mt[2m]|oct|okt?(a)|p[st]m|s[3t]m|ult|umx|wav|xm)' modplugplay modplug123 -_comp__init_install_xspec '*.@([ao]|so|so.!(conf|*/*)|[rs]pm|gif|jp?(e)g|mp3|mp?(e)g|avi|asf|ogg|class)' vi vim gvim rvim view rview rgvim rgview gview emacs xemacs sxemacs kate kwrite -_comp__init_install_xspec '!*.@(zip|z|gz|tgz)' bzme -# konqueror not here on purpose, it's more than a web/html browser -_comp__init_install_xspec '!*.@(?([xX]|[sS])[hH][tT][mM]?([lL]))' netscape mozilla lynx galeon dillo elinks amaya epiphany -_comp__init_install_xspec '!*.@(sxw|stw|sxg|sgl|doc?([mx])|dot?([mx])|rtf|txt|htm|html|?(f)odt|ott|odm|pdf)' oowriter lowriter -_comp__init_install_xspec '!*.@(sxi|sti|pps?(x)|ppt?([mx])|pot?([mx])|?(f)odp|otp)' ooimpress loimpress -_comp__init_install_xspec '!*.@(sxc|stc|xls?([bmx])|xlw|xlt?([mx])|[ct]sv|?(f)ods|ots)' oocalc localc -_comp__init_install_xspec '!*.@(sxd|std|sda|sdd|?(f)odg|otg)' oodraw lodraw -_comp__init_install_xspec '!*.@(sxm|smf|mml|odf)' oomath lomath -_comp__init_install_xspec '!*.odb' oobase lobase -_comp__init_install_xspec '!*.[rs]pm' rpm2cpio -_comp__init_install_xspec '!*.aux' bibtex -_comp__init_install_xspec '!*.po' poedit gtranslator kbabel lokalize -_comp__init_install_xspec '!*.@([Pp][Rr][Gg]|[Cc][Ll][Pp])' harbour gharbour hbpp -_comp__init_install_xspec '!*.[Hh][Rr][Bb]' hbrun -_comp__init_install_xspec '!*.ly' lilypond ly2dvi -_comp__init_install_xspec '!*.@(dif?(f)|?(d)patch)?(.@([gx]z|bz2|lzma))' cdiff -_comp__init_install_xspec '!@(*.@(ks|jks|jceks|p12|pfx|bks|ubr|gkr|cer|crt|cert|p7b|pkipath|pem|p10|csr|crl)|cacerts)' portecle -_comp__init_install_xspec '!*.@(mp[234c]|og[ag]|@(fl|a)ac|m4[abp]|spx|tta|w?(a)v|wma|aif?(f)|asf|ape)' kid3 kid3-qt -unset -f _comp__init_install_xspec - -# Minimal completion to use as fallback in _comp_complete_load. -# TODO:API: rename per conventions -_comp_complete_minimal() -{ - local cur prev words cword comp_args - _comp_initialize -- "$@" || return - compopt -o bashdefault -o default -} -# Complete the empty string to allow completion of '>', '>>', and '<' on < 4.3 -# https://lists.gnu.org/archive/html/bug-bash/2012-01/msg00045.html -complete -F _comp_complete_minimal '' - -# Initialize the variable "_comp__base_directory" -# @var[out] _comp__base_directory -_comp__init_base_directory() -{ - local REPLY - _comp_abspath "${BASH_SOURCE[0]-./bash_completion}" - _comp__base_directory=${REPLY%/*} - [[ $_comp__base_directory ]] || _comp__base_directory=/ - unset -f "$FUNCNAME" -} -_comp__init_base_directory - -# @since 2.12 -_comp_load() -{ - local flag_fallback_default="" IFS=$' \t\n' - local OPTIND=1 OPTARG="" OPTERR=0 opt - while getopts ':D' opt "$@"; do - case $opt in - D) flag_fallback_default=set ;; - *) - echo "bash_completion: $FUNCNAME: usage error" >&2 - return 2 - ;; - esac - done - shift "$((OPTIND - 1))" - - local cmd=$1 cmdname=${1##*/} dir compfile - local -a paths - [[ $cmdname ]] || return 1 - - local backslash= - if [[ $cmd == \\* ]]; then - cmd=${cmd:1} - # If we already have a completion for the "real" command, use it - $(complete -p -- "$cmd" 2>/dev/null || echo false) "\\$cmd" && return 0 - backslash=\\ - fi - - # Resolve absolute path to $cmd - local REPLY pathcmd origcmd=$cmd - if pathcmd=$(type -P -- "$cmd"); then - _comp_abspath "$pathcmd" - cmd=$REPLY - fi - - local -a dirs=() - - # Lookup order: - # 1) From BASH_COMPLETION_USER_DIR (e.g. ~/.local/share/bash-completion): - # User installed completions. - if [[ ${BASH_COMPLETION_USER_DIR-} ]]; then - _comp_split -F : paths "$BASH_COMPLETION_USER_DIR" && - dirs+=("${paths[@]/%//completions}") - else - dirs=("${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion/completions") - fi - - # 2) From the location of bash_completion: Completions relative to the main - # script. This is primarily for run-in-place-from-git-clone setups, where - # we want to prefer in-tree completions over ones possibly coming with a - # system installed bash-completion. (Due to usual install layouts, this - # often hits the correct completions in system installations, too.) - dirs+=("$_comp__base_directory/completions") - - # 3) From bin directories extracted from the specified path to the command, - # the real path to the command, and $PATH - paths=() - [[ $cmd == /* ]] && paths+=("${cmd%/*}") - _comp_realcommand "$cmd" && paths+=("${REPLY%/*}") - _comp_split -aF : paths "$PATH" - for dir in "${paths[@]%/}"; do - [[ $dir == ?*/@(bin|sbin) ]] && - dirs+=("${dir%/*}/share/bash-completion/completions") - done - - # 4) From XDG_DATA_DIRS or system dirs (e.g. /usr/share, /usr/local/share): - # Completions in the system data dirs. - _comp_split -F : paths "${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" && - dirs+=("${paths[@]/%//bash-completion/completions}") - - # Set up default $IFS in case loaded completions depend on it, - # as well as for $compspec invocation below. - local IFS=$' \t\n' - - # Look up and source - shift - local i prefix compspec - for prefix in "" _; do # Regular from all dirs first, then fallbacks - for i in ${!dirs[*]}; do - dir=${dirs[i]} - if [[ ! -d $dir ]]; then - unset -v 'dirs[i]' - continue - fi - for compfile in "$prefix$cmdname" "$prefix$cmdname.bash"; do - compfile="$dir/$compfile" - # Avoid trying to source dirs as long as we support bash < 4.3 - # to avoid an fd leak; https://bugzilla.redhat.com/903540 - if [[ -d $compfile ]]; then - # Do not warn with . or .. (especially the former is common) - [[ $compfile == */.?(.) ]] || - echo "bash_completion: $compfile: is a directory" >&2 - elif [[ -e $compfile ]] && . "$compfile" "$cmd" "$@"; then - # At least $cmd is expected to have a completion set when - # we return successfully; see if it already does - if compspec=$(complete -p -- "$cmd" 2>/dev/null); then - # $cmd is the case in which we do backslash processing - [[ $backslash ]] && eval "$compspec \"\$backslash\$cmd\"" - # If invoked without path, that one should be set, too - # ...but let's not overwrite an existing one, if any - [[ $origcmd != */* ]] && - ! complete -p -- "$origcmd" &>/dev/null && - eval "$compspec \"\$origcmd\"" - return 0 - fi - # If not, see if we got one for $cmdname - if [[ $cmdname != "$cmd" ]] && compspec=$(complete -p -- "$cmdname" 2>/dev/null); then - # Use that for $cmd too, if we have a full path to it - [[ $cmd == /* ]] && eval "$compspec \"\$cmd\"" - return 0 - fi - # Nothing expected was set, continue lookup - fi - done - done - done - - # Look up simple "xspec" completions - [[ -v _comp_xspecs[$cmdname] || -v _xspecs[$cmdname] ]] && - complete -F _comp_complete_filedir_xspec "$cmdname" "$backslash$cmdname" && return 0 - - if [[ $flag_fallback_default ]]; then - complete -F _comp_complete_minimal -- "$origcmd" && return 0 - fi - - return 1 -} - -# set up dynamic completion loading -# @since 2.12 -_comp_complete_load() -{ - # $1=_EmptycmD_ already for empty cmds in bash 4.3, set to it for earlier - local cmd=${1:-_EmptycmD_} - - # Pass -D to define *something*, or otherwise there will be no completion - # at all. - _comp_load -D -- "$cmd" && return 124 -} && - complete -D -F _comp_complete_load - -# Function for loading and calling functions from dynamically loaded -# completion files that may not have been sourced yet. -# @param $1 completion file to load function from in case it is missing -# @param $2 the xfunc name. When it does not start with `_', -# `_comp_xfunc_${1//[^a-zA-Z0-9_]/_}_$2' is used for the actual name of the -# shell function. -# @param $3... if any, specifies the arguments that are passed to the xfunc. -# @since 2.12 -_comp_xfunc() -{ - local xfunc_name=$2 - [[ $xfunc_name == _* ]] || - xfunc_name=_comp_xfunc_${1//[^a-zA-Z0-9_]/_}_$xfunc_name - declare -F -- "$xfunc_name" &>/dev/null || _comp_load -- "$1" - "$xfunc_name" "${@:3}" -} - -# Call a POSIX-compatible awk. Solaris awk is not POSIX-compliant, but Solaris -# provides a POSIX-compatible version through /usr/xpg4/bin/awk. We switch the -# implementation to /usr/xpg4/bin/awk in Solaris if any. -# @since 2.12 -if [[ $OSTYPE == *solaris* && -x /usr/xpg4/bin/awk ]]; then - _comp_awk() - { - /usr/xpg4/bin/awk "$@" - } -else - _comp_awk() - { - command awk "$@" - } -fi - -# List custom/extra completion files to source on the startup -## @param $1 path Path to "bash_completion" -## @var[out] _comp__init_startup_configs -_comp__init_collect_startup_configs() -{ - local base_path=${1:-${BASH_SOURCE[1]}} - _comp__init_startup_configs=() - - # source compat completion directory definitions - local -a compat_dirs=() - local compat_dir - if [[ ${BASH_COMPLETION_COMPAT_DIR-} ]]; then - compat_dirs+=("$BASH_COMPLETION_COMPAT_DIR") - else - compat_dirs+=(/etc/bash_completion.d) - # Similarly as for the "completions" dir, look up from relative to - # bash_completion, primarily for installed-with-prefix and - # run-in-place-from-git-clone setups. Notably we do it after the - # system location here, in order to prefer in-tree variables and - # functions. - if [[ $_comp__base_directory == */share/bash-completion ]]; then - compat_dir=${_comp__base_directory%/share/bash-completion}/etc/bash_completion.d - else - compat_dir=$_comp__base_directory/bash_completion.d - fi - [[ ${compat_dirs[0]} == "$compat_dir" ]] || - compat_dirs+=("$compat_dir") - fi - for compat_dir in "${compat_dirs[@]}"; do - [[ -d $compat_dir && -r $compat_dir && -x $compat_dir ]] || continue - local compat_files - _comp_expand_glob compat_files '"$compat_dir"/*' - local compat_file - for compat_file in "${compat_files[@]}"; do - [[ ${compat_file##*/} != @($_comp_backup_glob|Makefile*|${BASH_COMPLETION_COMPAT_IGNORE-}) && - -f $compat_file && -r $compat_file ]] && - _comp__init_startup_configs+=("$compat_file") - done - done - - # source user completion file - # - # Remark: We explicitly check that $user_completion is not '/dev/null' - # since /dev/null may be a regular file in broken systems and can contain - # arbitrary garbages of suppressed command outputs. - local user_file=${BASH_COMPLETION_USER_FILE:-~/.bash_completion} - [[ $user_file != "$base_path" && $user_file != /dev/null && -r $user_file && -f $user_file ]] && - _comp__init_startup_configs+=("$user_file") - - unset -f "$FUNCNAME" -} -_comp__init_collect_startup_configs "$BASH_SOURCE" -# shellcheck disable=SC2154 -for _comp_init_startup_config in "${_comp__init_startup_configs[@]}"; do - . "$_comp_init_startup_config" -done -unset -v _comp__init_startup_configs _comp_init_startup_config -unset -f have -unset -v have - -set $_comp__init_original_set_v -unset -v _comp__init_original_set_v - -# ex: filetype=sh - - _mise() { if ! command -v usage &> /dev/null; then echo >&2 @@ -3489,7 +13,7 @@ _mise() { local cur prev words cword was_split comp_args _comp_initialize -n : -- "$@" || return # shellcheck disable=SC2207 - _comp_compgen -- -W "$(usage complete-word --shell bash -s "${spec_variable}" --cword="$cword" -- "${words[@]}")" + _comp_compgen -- -W "$(usage complete-word --shell bash -s "${_usage_spec_mise_2024_12_9}" --cword="$cword" -- "${words[@]}")" _comp_ltrim_colon_completions "$cur" # shellcheck disable=SC2181 if [[ $? -ne 0 ]]; then diff --git a/docs/cli/activate.md b/docs/cli/activate.md index 4798e9de5f..94c2e50cde 100644 --- a/docs/cli/activate.md +++ b/docs/cli/activate.md @@ -11,12 +11,16 @@ Otherwise, it will only take effect in the current session. Typically, this can be added with something like the following: - echo 'eval "$(mise activate zsh)"' >> ~/.zshrc +``` +echo 'eval "$(mise activate zsh)"' >> ~/.zshrc +``` However, this requires that "mise" is in your PATH. If it is not, you need to specify the full path like this: - echo 'eval "$(/path/to/mise activate zsh)"' >> ~/.zshrc +``` +echo 'eval "$(/path/to/mise activate zsh)"' >> ~/.zshrc +``` Customize status output with `status` settings. @@ -42,7 +46,9 @@ Shell type to generate the script for Use shims instead of modifying PATH Effectively the same as: - PATH="$HOME/.local/share/mise/shims:$PATH" +``` +PATH="$HOME/.local/share/mise/shims:$PATH" +``` ### `-q --quiet` @@ -56,7 +62,9 @@ This can be helpful for debugging mise. If you run `eval "$(mise activate --no-h Examples: - eval "$(mise activate bash)" - eval "$(mise activate zsh)" - mise activate fish | source - execx($(mise activate xonsh)) +``` +eval "$(mise activate bash)" +eval "$(mise activate zsh)" +mise activate fish | source +execx($(mise activate xonsh)) +``` diff --git a/docs/cli/alias/get.md b/docs/cli/alias/get.md index 5028ae2e9a..5951e3622a 100644 --- a/docs/cli/alias/get.md +++ b/docs/cli/alias/get.md @@ -19,5 +19,7 @@ The alias to show Examples: - $ mise alias get node lts-hydrogen - 20.0.0 +``` +$ mise alias get node lts-hydrogen +20.0.0 +``` diff --git a/docs/cli/alias/ls.md b/docs/cli/alias/ls.md index 37cd2efa83..d64ee7b17e 100644 --- a/docs/cli/alias/ls.md +++ b/docs/cli/alias/ls.md @@ -10,8 +10,10 @@ These can come from user config or from plugins in `bin/list-aliases`. For user config, aliases are defined like the following in `~/.config/mise/config.toml`: - [alias.node.versions] - lts = "22.0.0" +``` +[alias.node.versions] +lts = "22.0.0" +``` ## Arguments @@ -27,5 +29,7 @@ Don't show table header Examples: - $ mise aliases - node lts-jod 22 +``` +$ mise aliases +node lts-jod 22 +``` diff --git a/docs/cli/alias/set.md b/docs/cli/alias/set.md index 9d3718a575..7f7e707fdc 100644 --- a/docs/cli/alias/set.md +++ b/docs/cli/alias/set.md @@ -24,4 +24,6 @@ The value to set the alias to Examples: - mise alias set node lts-jod 22.0.0 +``` +mise alias set node lts-jod 22.0.0 +``` diff --git a/docs/cli/alias/unset.md b/docs/cli/alias/unset.md index 62eaea1a4d..5571b3f0e5 100644 --- a/docs/cli/alias/unset.md +++ b/docs/cli/alias/unset.md @@ -20,4 +20,6 @@ The alias to remove Examples: - mise alias unset node lts-jod +``` +mise alias unset node lts-jod +``` diff --git a/docs/cli/backends/ls.md b/docs/cli/backends/ls.md index 4c9f03abbd..0988dde26f 100644 --- a/docs/cli/backends/ls.md +++ b/docs/cli/backends/ls.md @@ -8,10 +8,12 @@ List built-in backends Examples: - $ mise backends ls - cargo - go - npm - pipx - spm - ubi +``` +$ mise backends ls +cargo +go +npm +pipx +spm +ubi +``` diff --git a/docs/cli/completion.md b/docs/cli/completion.md index d7288ce459..e244d48832 100644 --- a/docs/cli/completion.md +++ b/docs/cli/completion.md @@ -28,6 +28,8 @@ you may source it separately or enable this flag to include it in the script. Examples: - mise completion bash > /etc/bash_completion.d/mise - mise completion zsh > /usr/local/share/zsh/site-functions/_mise - mise completion fish > ~/.config/fish/completions/mise.fish +``` +mise completion bash > /etc/bash_completion.d/mise +mise completion zsh > /usr/local/share/zsh/site-functions/_mise +mise completion fish > ~/.config/fish/completions/mise.fish +``` diff --git a/docs/cli/config/generate.md b/docs/cli/config/generate.md index 9d18fcaae9..c4f533e283 100644 --- a/docs/cli/config/generate.md +++ b/docs/cli/config/generate.md @@ -14,5 +14,7 @@ Output to file instead of stdout Examples: - mise cf generate > mise.toml - mise cf generate --output=mise.toml +``` +mise cf generate > mise.toml +mise cf generate --output=mise.toml +``` diff --git a/docs/cli/config/get.md b/docs/cli/config/get.md index b272c1a575..f28ab423ab 100644 --- a/docs/cli/config/get.md +++ b/docs/cli/config/get.md @@ -21,5 +21,7 @@ If not provided, the nearest mise.toml file will be used Examples: - $ mise toml get tools.python - 3.12 +``` +$ mise toml get tools.python +3.12 +``` diff --git a/docs/cli/config/ls.md b/docs/cli/config/ls.md index e22cc522b4..3e3975989b 100644 --- a/docs/cli/config/ls.md +++ b/docs/cli/config/ls.md @@ -18,7 +18,9 @@ Output in JSON format Examples: - $ mise config ls - Path Tools - ~/.config/mise/config.toml pitchfork - ~/src/mise/mise.toml actionlint, bun, cargo-binstall, cargo:cargo-edit, cargo:cargo-insta +``` +$ mise config ls +Path Tools +~/.config/mise/config.toml pitchfork +~/src/mise/mise.toml actionlint, bun, cargo-binstall, cargo:cargo-edit, cargo:cargo-insta +``` diff --git a/docs/cli/config/set.md b/docs/cli/config/set.md index 0465c52763..38fd6c32cc 100644 --- a/docs/cli/config/set.md +++ b/docs/cli/config/set.md @@ -25,8 +25,6 @@ If not provided, the nearest mise.toml file will be used ### `-t --type ` -Set the value of a setting in a mise.toml file - **Choices:** - `infer` @@ -38,10 +36,14 @@ Set the value of a setting in a mise.toml file Examples: - $ mise config set tools.python 3.12 - $ mise config set settings.always_keep_download true - $ mise config set env.TEST_ENV_VAR ABC - $ mise config set settings.disable_tools --type list node,rust - - # Type for `settings` is inferred - $ mise config set settings.jobs 4 +``` +mise config set tools.python 3.12 +mise config set settings.always_keep_download true +mise config set env.TEST_ENV_VAR ABC +mise config set settings.disable_tools --type list node,rust +``` + +``` +# Type for `settings` is inferred +$ mise config set settings.jobs 4 +``` diff --git a/docs/cli/deactivate.md b/docs/cli/deactivate.md index 6d3787b668..3fe3ec11e0 100644 --- a/docs/cli/deactivate.md +++ b/docs/cli/deactivate.md @@ -9,4 +9,6 @@ This can be used to temporarily disable mise in a shell session. Examples: - mise deactivate +``` +mise deactivate +``` diff --git a/docs/cli/doctor.md b/docs/cli/doctor.md index ca83897d7e..9a6df58799 100644 --- a/docs/cli/doctor.md +++ b/docs/cli/doctor.md @@ -12,5 +12,7 @@ Check mise installation for possible problems Examples: - $ mise doctor - [WARN] plugin node is not installed +``` +$ mise doctor +[WARN] plugin node is not installed +``` diff --git a/docs/cli/doctor/path.md b/docs/cli/doctor/path.md index 8d28526f56..d4a33c5b54 100644 --- a/docs/cli/doctor/path.md +++ b/docs/cli/doctor/path.md @@ -13,8 +13,10 @@ Print all entries including those not provided by mise Examples: - Get the current PATH entries mise is providing - $ mise path - /home/user/.local/share/mise/installs/node/24.0.0/bin - /home/user/.local/share/mise/installs/rust/1.90.0/bin - /home/user/.local/share/mise/installs/python/3.10.0/bin +``` +Get the current PATH entries mise is providing +$ mise path +/home/user/.local/share/mise/installs/node/24.0.0/bin +/home/user/.local/share/mise/installs/rust/1.90.0/bin +/home/user/.local/share/mise/installs/python/3.10.0/bin +``` diff --git a/docs/cli/en.md b/docs/cli/en.md index fb3cc78b3c..c8876fda07 100644 --- a/docs/cli/en.md +++ b/docs/cli/en.md @@ -27,12 +27,18 @@ Defaults to $SHELL Examples: - $ mise en . - $ node -v - v20.0.0 - - Skip loading bashrc: - $ mise en -s "bash --norc" - - Skip loading zshrc: - $ mise en -s "zsh -f" +``` +$ mise en . +$ node -v +v20.0.0 +``` + +``` +Skip loading bashrc: +$ mise en -s "bash --norc" +``` + +``` +Skip loading zshrc: +$ mise en -s "zsh -f" +``` diff --git a/docs/cli/env.md b/docs/cli/env.md index 2bd6875262..bb2b86a560 100644 --- a/docs/cli/env.md +++ b/docs/cli/env.md @@ -44,7 +44,9 @@ Shell type to generate environment variables for Examples: - eval "$(mise env -s bash)" - eval "$(mise env -s zsh)" - mise env -s fish | source - execx($(mise env -s xonsh)) +``` +eval "$(mise env -s bash)" +eval "$(mise env -s zsh)" +mise env -s fish | source +execx($(mise env -s xonsh)) +``` diff --git a/docs/cli/exec.md b/docs/cli/exec.md index c13384b319..c564f9ca35 100644 --- a/docs/cli/exec.md +++ b/docs/cli/exec.md @@ -41,11 +41,17 @@ Directly pipe stdin/stdout/stderr from plugin to user Sets --jobs=1 Examples: - $ mise exec node@20 -- node ./app.js # launch app.js using node-20.x - $ mise x node@20 -- node ./app.js # shorter alias - - # Specify command as a string: - $ mise exec node@20 python@3.11 --command "node -v && python -V" - - # Run a command in a different directory: - $ mise x -C /path/to/project node@20 -- node ./app.js +``` +mise exec node@20 -- node ./app.js # launch app.js using node-20.x +mise x node@20 -- node ./app.js # shorter alias +``` + +``` +# Specify command as a string: +$ mise exec node@20 python@3.11 --command "node -v && python -V" +``` + +``` +# Run a command in a different directory: +$ mise x -C /path/to/project node@20 -- node ./app.js +``` diff --git a/docs/cli/fmt.md b/docs/cli/fmt.md index 19cd6c4068..82ce5b314d 100644 --- a/docs/cli/fmt.md +++ b/docs/cli/fmt.md @@ -13,4 +13,6 @@ Format all files from the current directory Examples: - mise format +``` +mise format +``` diff --git a/docs/cli/generate/git-pre-commit.md b/docs/cli/generate/git-pre-commit.md index c002c736dd..1f3b3bed69 100644 --- a/docs/cli/generate/git-pre-commit.md +++ b/docs/cli/generate/git-pre-commit.md @@ -27,5 +27,7 @@ write to .git/hooks/pre-commit and make it executable Examples: - mise generate git-pre-commit --write --task=pre-commit - git commit -m "feat: add new feature" # runs `mise run pre-commit` +``` +mise generate git-pre-commit --write --task=pre-commit +git commit -m "feat: add new feature" # runs `mise run pre-commit` +``` diff --git a/docs/cli/generate/github-action.md b/docs/cli/generate/github-action.md index 03938b2a7c..7f4b3322f5 100644 --- a/docs/cli/generate/github-action.md +++ b/docs/cli/generate/github-action.md @@ -24,6 +24,8 @@ write to .github/workflows/$name.yml Examples: - mise generate github-action --write --task=ci - git commit -m "feat: add new feature" - git push # runs `mise run ci` on GitHub +``` +mise generate github-action --write --task=ci +git commit -m "feat: add new feature" +git push # runs `mise run ci` on GitHub +``` diff --git a/docs/cli/generate/task-docs.md b/docs/cli/generate/task-docs.md index 7ca2cd4ac5..ffda3dce8d 100644 --- a/docs/cli/generate/task-docs.md +++ b/docs/cli/generate/task-docs.md @@ -33,8 +33,6 @@ root directory to search for tasks ### `-s --style