1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
# bash completion for GNU make -*- shell-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
local -x prefix=$2
# display mode, only output current path component to the next slash
local -x prefix_replace=$prefix
[[ $mode == -d && $prefix == */* ]] &&
prefix_replace=${prefix##*/}
_comp_awk -f "${BASH_SOURCE[0]%/*}/../helpers/make-extract-targets.awk"
}
# 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
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
}
_comp_cmd_make()
{
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 | -${noargopts}[foW])
_comp_compgen_filedir
return
;;
--include-dir | --directory | -${noargopts}[ICm])
_comp_compgen_filedir -d
return
;;
-${noargopts}E)
_comp_compgen -- -v
return
;;
--eval | -${noargopts}[DVx])
return
;;
--jobs | -${noargopts}j)
local REPLY
_comp_get_ncpus
_comp_compgen -- -W "{1..$((REPLY * 2))}"
return
;;
esac
[[ $was_split ]] && return
if [[ $cur == -* ]]; then
_comp_compgen_help || _comp_compgen_usage
[[ ${COMPREPLY-} == *= ]] && compopt -o nospace
elif [[ $cur == *=* ]]; then
prev=${cur%%=*}
cur=${cur#*=}
local diropt
[[ ${prev,,} == *dir?(ectory) ]] && diropt=-d
_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]} == @(-${noargopts}C|--directory) ]]; then
# Expand tilde expansion
local REPLY
_comp_dequote "${words[i + 1]-}" &&
[[ -d ${REPLY-} ]] &&
makef_dir=(-C "$REPLY")
break
fi
done
# 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]} == @(-${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.
#
# 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 && COMP_TYPE != 37 && COMP_TYPE != 42)); then
# mode=-d # display-only mode
# fi
_comp_split COMPREPLY "$(LC_ALL=C \
$1 -npq __BASH_MAKE_COMPLETION__=1 \
${makef+"${makef[@]}"} "${makef_dir[@]}" .DEFAULT 2>/dev/null |
_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
# so set options for completion based on the first one
[[ ${COMPREPLY-} == */ ]] && compopt -o nospace
fi
fi
} &&
complete -F _comp_cmd_make make gmake gnumake pmake colormake bmake
# ex: filetype=sh
|