|
1 | 1 | # bash completion for GNU make -*- shell-script -*- |
2 | 2 |
|
3 | | -# TODO: rename per API conventions, rework to use vars rather than outputting(?) |
4 | | -_make_target_extract_script() |
| 3 | +# Extract the valid target names starting with PREFIX from the output of |
| 4 | +# `make -npq' |
| 5 | +# @param mode If this is `-d', the directory names already specified in |
| 6 | +# PREFIX are omitted in the output |
| 7 | +# @param prefix Prefix of the target names |
| 8 | +_comp_cmd_make__extract_targets() |
5 | 9 | { |
6 | | - local mode="$1" |
7 | | - shift |
8 | | - |
9 | | - local prefix="$1" |
10 | | - local prefix_pat=$(command sed 's/[][\,.*^$(){}?+|/]/\\&/g' <<<"$prefix") |
11 | | - local basename=${prefix##*/} |
12 | | - local dirname_len=$((${#prefix} - ${#basename})) |
13 | | - # Avoid expressions like '\(.\{0\}\)', FreeBSD sed doesn't like them: |
14 | | - # > sed: 1: ...: RE error: empty (sub)expression |
15 | | - local dirname_re= |
16 | | - ((dirname_len > 0)) && dirname_re="\(.\{${dirname_len}\}\)" |
17 | | - |
18 | | - if [[ ! $dirname_re ]]; then |
19 | | - local output="\1" |
20 | | - elif [[ $mode == -d ]]; then |
21 | | - # display mode, only output current path component to the next slash |
22 | | - local output="\2" |
23 | | - else |
24 | | - # completion mode, output full path to the next slash |
25 | | - local output="\1\2" |
26 | | - fi |
27 | | - |
28 | | - cat <<EOF |
29 | | - 1,/^# * Make data base/ d; # skip any makefile output |
30 | | - /^# * Finished Make data base/,/^# * Make data base/{ |
31 | | - d; # skip any makefile output |
32 | | - } |
33 | | - /^# * Variables/,/^# * Files/ d; # skip until files section |
34 | | - /^# * Not a target/,/^$/ d; # skip not target blocks |
35 | | - /^${prefix_pat}/,/^$/! d; # skip anything user dont want |
36 | | -
|
37 | | - # The stuff above here describes lines that are not |
38 | | - # explicit targets or not targets other than special ones |
39 | | - # The stuff below here decides whether an explicit target |
40 | | - # should be output. |
41 | | -
|
42 | | - /^# * File is an intermediate prerequisite/ { |
43 | | - s/^.*$//;x; # unhold target |
44 | | - d; # delete line |
45 | | - } |
46 | | -
|
47 | | - /^$/ { # end of target block |
48 | | - x; # unhold target |
49 | | - /^$/d; # dont print blanks |
50 | | - s|^${dirname_re-}\(.\{${#basename}\}[^:]*\):.*$|${output}|p; |
51 | | - d; # hide any bugs |
52 | | - } |
53 | | -
|
54 | | - # This pattern includes a literal tab character as \t is not a portable |
55 | | - # representation and fails with BSD sed |
56 | | - /^[^# :%]\{1,\}:/ { # found target block |
57 | | - /^\.PHONY:/ d; # special target |
58 | | - /^\.SUFFIXES:/ d; # special target |
59 | | - /^\.DEFAULT:/ d; # special target |
60 | | - /^\.PRECIOUS:/ d; # special target |
61 | | - /^\.INTERMEDIATE:/ d; # special target |
62 | | - /^\.SECONDARY:/ d; # special target |
63 | | - /^\.SECONDEXPANSION:/ d; # special target |
64 | | - /^\.DELETE_ON_ERROR:/ d; # special target |
65 | | - /^\.IGNORE:/ d; # special target |
66 | | - /^\.LOW_RESOLUTION_TIME:/ d; # special target |
67 | | - /^\.SILENT:/ d; # special target |
68 | | - /^\.EXPORT_ALL_VARIABLES:/ d; # special target |
69 | | - /^\.NOTPARALLEL:/ d; # special target |
70 | | - /^\.ONESHELL:/ d; # special target |
71 | | - /^\.POSIX:/ d; # special target |
72 | | - /^\.NOEXPORT:/ d; # special target |
73 | | - /^\.MAKE:/ d; # special target |
74 | | -EOF |
75 | | - |
76 | | - # don't complete with hidden targets unless we are doing a partial completion |
77 | | - if [[ ! ${prefix_pat} || ${prefix_pat} == */ ]]; then |
78 | | - cat <<EOF |
79 | | - /^${prefix_pat}[^a-zA-Z0-9]/d; # convention for hidden tgt |
80 | | -EOF |
81 | | - fi |
| 10 | + local mode=$1 |
| 11 | + local -x prefix=$2 |
82 | 12 |
|
83 | | - cat <<EOF |
84 | | - h; # hold target |
85 | | - d; # delete line |
86 | | - } |
| 13 | + # display mode, only output current path component to the next slash |
| 14 | + local -x prefix_replace=$prefix |
| 15 | + [[ $mode == -d && $prefix == */* ]] && |
| 16 | + prefix_replace=${prefix##*/} |
87 | 17 |
|
88 | | -EOF |
| 18 | + _comp_awk -f "${BASH_SOURCE[0]%/*}/../helpers/make-extract-targets.awk" |
89 | 19 | } |
90 | 20 |
|
91 | 21 | # Truncate the non-unique filepaths in COMPREPLY to only generate unique |
@@ -224,11 +154,11 @@ _comp_cmd_make() |
224 | 154 | # mode=-d # display-only mode |
225 | 155 | # fi |
226 | 156 |
|
227 | | - local IFS=$' \t\n' script=$(_make_target_extract_script $mode "$cur") |
| 157 | + local IFS=$' \t\n' |
228 | 158 | COMPREPLY=($(LC_ALL=C \ |
229 | 159 | $1 -npq __BASH_MAKE_COMPLETION__=1 \ |
230 | 160 | ${makef+"${makef[@]}"} "${makef_dir[@]}" .DEFAULT 2>/dev/null | |
231 | | - command sed -ne "$script")) |
| 161 | + _comp_cmd_make__extract_targets "$mode" "$cur")) |
232 | 162 |
|
233 | 163 | _comp_cmd_make__truncate_non_unique_paths |
234 | 164 |
|
|
0 commit comments