diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:03:18 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:03:18 +0000 |
commit | f4acb49ea148cdd899f7f29f1591c7bc853c2135 (patch) | |
tree | b62d60873864065d6428a84a119dd8a3c90f1397 /completions/make | |
parent | Adding upstream version 1:2.11. (diff) | |
download | bash-completion-f4acb49ea148cdd899f7f29f1591c7bc853c2135.tar.xz bash-completion-f4acb49ea148cdd899f7f29f1591c7bc853c2135.zip |
Adding upstream version 1:2.12.0.upstream/1%2.12.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'completions/make')
-rw-r--r-- | completions/make | 214 |
1 files changed, 109 insertions, 105 deletions
diff --git a/completions/make b/completions/make index 96517c2..94e2b73 100644 --- a/completions/make +++ b/completions/make @@ -1,135 +1,128 @@ # bash completion for GNU make -*- shell-script -*- -_make_target_extract_script() +# Extract the valid target names starting with PREFIX from the output of +# `make -npq' +# @param mode If this is `-d', the directory names already specified in +# PREFIX are omitted in the output +# @param prefix Prefix of the target names +_comp_cmd_make__extract_targets() { - local mode="$1" - shift + local mode=$1 + local -x prefix=$2 - local prefix="$1" - local prefix_pat=$(command sed 's/[][\,.*^$(){}?+|/]/\\&/g' <<<"$prefix") - local basename=${prefix##*/} - local dirname_len=$((${#prefix} - ${#basename})) + # display mode, only output current path component to the next slash + local -x prefix_replace=$prefix + [[ $mode == -d && $prefix == */* ]] && + prefix_replace=${prefix##*/} - if [[ $mode == -d ]]; then - # display mode, only output current path component to the next slash - local output="\2" - else - # completion mode, output full path to the next slash - local output="\1\2" - fi - - cat <<EOF - 1,/^# * Make data base/ d; # skip any makefile output - /^# * Finished Make data base/,/^# * Make data base/{ - d; # skip any makefile output - } - /^# * Variables/,/^# * Files/ d; # skip until files section - /^# * Not a target/,/^$/ d; # skip not target blocks - /^${prefix_pat}/,/^$/! d; # skip anything user dont want - - # The stuff above here describes lines that are not - # explicit targets or not targets other than special ones - # The stuff below here decides whether an explicit target - # should be output. - - /^# * File is an intermediate prerequisite/ { - s/^.*$//;x; # unhold target - d; # delete line - } - - /^$/ { # end of target block - x; # unhold target - /^$/d; # dont print blanks - s|^\(.\{${dirname_len}\}\)\(.\{${#basename}\}[^:/]*/\{0,1\}\)[^:]*:.*$|${output}|p; - d; # hide any bugs - } - - # This pattern includes a literal tab character as \t is not a portable - # representation and fails with BSD sed - /^[^# :%]\{1,\}:/ { # found target block - /^\.PHONY:/ d; # special target - /^\.SUFFIXES:/ d; # special target - /^\.DEFAULT:/ d; # special target - /^\.PRECIOUS:/ d; # special target - /^\.INTERMEDIATE:/ d; # special target - /^\.SECONDARY:/ d; # special target - /^\.SECONDEXPANSION:/ d; # special target - /^\.DELETE_ON_ERROR:/ d; # special target - /^\.IGNORE:/ d; # special target - /^\.LOW_RESOLUTION_TIME:/ d; # special target - /^\.SILENT:/ d; # special target - /^\.EXPORT_ALL_VARIABLES:/ d; # special target - /^\.NOTPARALLEL:/ d; # special target - /^\.ONESHELL:/ d; # special target - /^\.POSIX:/ d; # special target - /^\.NOEXPORT:/ d; # special target - /^\.MAKE:/ d; # special target -EOF - - # don't complete with hidden targets unless we are doing a partial completion - if [[ -z ${prefix_pat} || ${prefix_pat} == */ ]]; then - cat <<EOF - /^${prefix_pat}[^a-zA-Z0-9]/d; # convention for hidden tgt -EOF - fi + _comp_awk -f "${BASH_SOURCE[0]%/*}/../helpers/make-extract-targets.awk" +} - cat <<EOF - h; # hold target - d; # delete line - } +# Truncate the non-unique filepaths in COMPREPLY to only generate unique +# directories or files. This function discards the files under subdirectories +# unless the path is unique under each subdirectory and instead generate the +# subdirectory path. For example, when there are two candidates, "abc/def" and +# "abc/xyz", we generate "abc/" instead of generating both candidates directly. +# When there is only one candidate "abc/def", we generate the full path +# "abc/def". +# +# @var[in] cur +# @var[in] mode +# @var[in,out] COMPREPLY +_comp_cmd_make__truncate_non_unique_paths() +{ + local prefix=$cur + [[ $mode == -d ]] && prefix= + if ((${#COMPREPLY[@]} > 0)); then + # collect the possible completions including the directory names in + # `paths' and count the number of children of each subdirectory in + # `nchild'. + local -A paths nchild + local target + for target in "${COMPREPLY[@]}"; do + local path=${target%/} + while [[ ! ${paths[$path]+set} ]] && + paths[$path]=set && + [[ $path == "$prefix"*/* ]]; do + path=${path%/*} + nchild[$path]=$((${nchild[$path]-0} + 1)) + done + done -EOF + COMPREPLY=() + local nreply=0 + for target in "${!paths[@]}"; do + # generate only the paths that do not have a unique child and whose + # all parent and ancestor directories have a unique child. + ((${nchild[$target]-0} == 1)) && continue + local path=$target + while [[ $path == "$prefix"*/* ]]; do + path=${path%/*} + ((${nchild[$path]-0} == 1)) || continue 2 + done + + # suffix `/' when the target path is a subdiretory, which has + # at least one child. + COMPREPLY[nreply++]=$target${nchild[$target]+/} + done + fi } -_make() +_comp_cmd_make() { - local cur prev words cword split - _init_completion -s || return + local cur prev words cword was_split comp_args + _comp_initialize -s -- "$@" || return local makef makef_dir=("-C" ".") i + local noargopts='!(-*|*[foWICmEDVxj]*)' + # shellcheck disable=SC2254 case $prev in --file | --makefile | --old-file | --assume-old | --what-if | --new-file | \ - --assume-new | -!(-*)[foW]) - _filedir + --assume-new | -${noargopts}[foW]) + _comp_compgen_filedir return ;; - --include-dir | --directory | -!(-*)[ICm]) - _filedir -d + --include-dir | --directory | -${noargopts}[ICm]) + _comp_compgen_filedir -d return ;; - -!(-*)E) - COMPREPLY=($(compgen -v -- "$cur")) + -${noargopts}E) + _comp_compgen -- -v return ;; - --eval | -!(-*)[DVx]) + --eval | -${noargopts}[DVx]) return ;; - --jobs | -!(-*)j) - COMPREPLY=($(compgen -W "{1..$(($(_ncpus) * 2))}" -- "$cur")) + --jobs | -${noargopts}j) + local REPLY + _comp_get_ncpus + _comp_compgen -- -W "{1..$((REPLY * 2))}" return ;; esac - $split && return + [[ $was_split ]] && return if [[ $cur == -* ]]; then - local opts="$(_parse_help "$1")" - COMPREPLY=($(compgen -W '${opts:-$(_parse_usage "$1")}' -- "$cur")) + _comp_compgen_help || _comp_compgen_usage [[ ${COMPREPLY-} == *= ]] && compopt -o nospace elif [[ $cur == *=* ]]; then prev=${cur%%=*} cur=${cur#*=} local diropt [[ ${prev,,} == *dir?(ectory) ]] && diropt=-d - _filedir $diropt + _comp_compgen_filedir $diropt else # before we check for makefiles, see if a path was specified # with -C/--directory for ((i = 1; i < ${#words[@]}; i++)); do - if [[ ${words[i]} == -@(C|-directory) ]]; then - # eval for tilde expansion - eval "makef_dir=( -C \"${words[i + 1]}\" )" + if [[ ${words[i]} == @(-${noargopts}C|--directory) ]]; then + # Expand tilde expansion + local REPLY + _comp_dequote "${words[i + 1]-}" && + [[ -d ${REPLY-} ]] && + makef_dir=(-C "$REPLY") break fi done @@ -137,25 +130,36 @@ _make() # before we scan for targets, see if a Makefile name was # specified with -f/--file/--makefile for ((i = 1; i < ${#words[@]}; i++)); do - if [[ ${words[i]} == -@(f|-?(make)file) ]]; then - # eval for tilde expansion - eval "makef=( -f \"${words[i + 1]}\" )" + if [[ ${words[i]} == @(-${noargopts}f|--?(make)file) ]]; then + # Expand tilde expansion + local REPLY + _comp_dequote "${words[i + 1]-}" && + [[ -f ${REPLY-} ]] && + makef=(-f "$REPLY") break fi done - # recognise that possible completions are only going to be displayed - # so only the base name is shown + # recognise that possible completions are only going to be displayed so + # only the base name is shown. + # + # Note: This is currently turned off because the test suite of + # bash-completion conflicts with it; it uses "set show-all-if-ambiguous + # on" (causing COMP_TYPE == 37) to retrieve the action completion + # results, and also the compact form with only the basenames is not + # essentially needed. To re-enable it, please uncomment the following + # if-statement. local mode=-- - if ((COMP_TYPE != 9)); then - mode=-d # display-only mode - fi + # if ((COMP_TYPE != 9 && COMP_TYPE != 37 && COMP_TYPE != 42)); then + # mode=-d # display-only mode + # fi - local IFS=$' \t\n' script=$(_make_target_extract_script $mode "$cur") - COMPREPLY=($(LC_ALL=C \ + _comp_split COMPREPLY "$(LC_ALL=C \ $1 -npq __BASH_MAKE_COMPLETION__=1 \ ${makef+"${makef[@]}"} "${makef_dir[@]}" .DEFAULT 2>/dev/null | - command sed -ne "$script")) + _comp_cmd_make__extract_targets "$mode" "$cur")" + + _comp_cmd_make__truncate_non_unique_paths if [[ $mode != -d ]]; then # Completion will occur if there is only one suggestion @@ -165,6 +169,6 @@ _make() fi } && - complete -F _make make gmake gnumake pmake colormake bmake + complete -F _comp_cmd_make make gmake gnumake pmake colormake bmake # ex: filetype=sh |