Skip to content

Commit

Permalink
fix(make): show unique targets in subdirs
Browse files Browse the repository at this point in the history
When many targets in subdirectories are defined in Makefile, we
typically want to list the files or subdirectories in the current
directory.  However, when the file in the subdirectory is unique, we
may generate the full path.  See also the discussion on GitHub:

scop#544
scop#546 (comment)
  • Loading branch information
akinomyoga committed Jan 10, 2023
1 parent a1a94f6 commit 1ea3326
Showing 1 changed file with 53 additions and 1 deletion.
54 changes: 53 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,56 @@ 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 +222,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 1ea3326

Please sign in to comment.