diff options
Diffstat (limited to 'completions/make')
-rw-r--r-- | completions/make | 101 |
1 files changed, 91 insertions, 10 deletions
diff --git a/completions/make b/completions/make index 1aec3489..b4ad9e73 100644 --- a/completions/make +++ b/completions/make @@ -1,11 +1,81 @@ # bash completion for GNU make -*- shell-script -*- +function _make_target_extract_script() +{ + local mode="$1" + shift + + local prefix="$1" + local prefix_pat=$( printf "%s\n" "$prefix" | \ + sed 's/[][\,.*^$(){}?+|/]/\\&/g' ) + local basename=${prefix##*/} + local dirname_len=$(( ${#prefix} - ${#basename} )) + + 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 + /^# Make data base/,/^# 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}}[^:/]*/?)[^:]*:.*$,${output},p + d # hide any bugs + } + + /^[^#\t:%]+:/ { # 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 + + /^[^a-zA-Z0-9]/ d # convention for hidden tgt + + h # hold target + d # delete line + } + +EOF +} + _make() { local cur prev words cword split _init_completion -s || return - local file makef makef_dir="." makef_inc i + local file makef makef_dir=( "-C" "." ) makef_inc i case $prev in -f|--file|--makefile|-o|--old-file|--assume-old|-W|--what-if|\ @@ -49,7 +119,7 @@ _make() for (( i=0; i < ${#words[@]}; i++ )); do if [[ ${words[i]} == -@(C|-directory) ]]; then # eval for tilde expansion - eval makef_dir=${words[i+1]} + eval makef_dir=( -C "${words[i+1]}" ) break fi done @@ -59,21 +129,32 @@ _make() for (( i=0; i < ${#words[@]}; i++ )); do if [[ ${words[i]} == -@(f|-?(make)file) ]]; then # eval for tilde expansion - eval makef=${words[i+1]} + eval makef=( -f "${words[i+1]}" ) break fi done - [[ -n $makef ]] && makef="-f ${makef}" - [[ -n $makef_dir ]] && makef_dir="-C ${makef_dir}" + # recognise that possible completions are only going to be displayed + # so only the base name is shown + local mode=-- + if (( COMP_TYPE != 9 )); then + mode=-d # display-only mode + fi + + local reset=$( set +o | grep -F posix ); set +o posix # for <(...) + COMPREPLY=( $( LC_ALL=C \ + make -npq "${makef[@]}" "${makef_dir[@]}" .DEFAULT 2>/dev/null | \ + sed -nrf <(_make_target_extract_script $mode "$cur") ) ) + $reset - COMPREPLY=( $( compgen -W "$( make -qp $makef $makef_dir 2>/dev/null | \ - awk -F':' '/^[a-zA-Z0-9][^$#\/\t=]*:([^=]|$)/ \ - {split($1,A,/ /);for(i in A)print A[i]}' )" \ - -- "$cur" ) ) + 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 _make make gmake gnumake pmake +complete -F _make make gmake gnumake pmake colormake # ex: ts=4 sw=4 et filetype=sh |