diff --git a/completions/make b/completions/make index 13de378fd3f..6f66b17eb35 100644 --- a/completions/make +++ b/completions/make @@ -46,7 +46,7 @@ _make_target_extract_script() /^$/ { # end of target block x; # unhold target /^$/d; # dont print blanks - s|^${dirname_re-}\(.\{${#basename}\}[^:/]*/\{0,1\}\)[^:]*:.*$|${output}|p; + s|^${dirname_re-}\(.\{${#basename}\}[^:]*\):.*$|${output}|p; d; # hide any bugs } @@ -170,6 +170,53 @@ _make() ${makef+"${makef[@]}"} "${makef_dir[@]}" .DEFAULT 2>/dev/null | command sed -ne "$script")) + # discard 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". + 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]=1 && + [[ $path == "$prefix"*/* ]]; do + path=${path%/*} + if [[ ! ${nchild[$path]+set} ]]; then + ((nchild[\$path] = 1)) + else + ((nchild[\$path]++)) + fi + 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 + if [[ $mode != -d ]]; then # Completion will occur if there is only one suggestion # so set options for completion based on the first one