Skip to content

Commit

Permalink
fix(make): show unique targets in subdirs
Browse files Browse the repository at this point in the history
  • Loading branch information
akinomyoga committed Jan 10, 2023
1 parent a1a94f6 commit 33114f9
Showing 1 changed file with 54 additions and 1 deletion.
55 changes: 54 additions & 1 deletion completions/make
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -87,6 +87,57 @@ EOF
EOF
}

# Truncate the non-unique filepaths in COMPRELY 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_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]=1 &&
[[ $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
}

_make()
{
local cur prev words cword split comp_args
Expand Down Expand Up @@ -172,6 +223,8 @@ _make()
${makef+"${makef[@]}"} "${makef_dir[@]}" .DEFAULT 2>/dev/null |
command sed -ne "$script"))

_comp_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
Expand Down

0 comments on commit 33114f9

Please sign in to comment.