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
|