Closed
Description
Describe the bug
Make target completion doesn't work when target files are in subdirectories.
To reproduce
There are two behaviours that happen here. Sample makefile:
.PHONY: abc/xyz
abc/xyz:
mkdir -p abc
date > $@
For clarity, i've marked spaces with ·
- When typing
make·TAB
the result ismake·abc/·
- When typing
make·abc/TAB
the result ismake·xyz·
Expected behavior
Both described cases should auto complete to make·abc/xyz·
because it is unambiguous.
Versions (please complete the following information)
- Operating system name/distribution and version: Artix Linux on WSL
- bash version:
5.1.8(1)-release
- bash-completion version:
2.11
(md5sum completions/make =84866af8ff59c9e1698f90a8f3a67f22
)
Additional context
Debug trace
+++ _on_command_start
�[?2004h�[38;5;214mᛋ �[97;1mmake abc/+ local cur prev words cword split
+ _init_completion -s
+ local exclude= flag outx errx inx OPTIND=1
+ getopts n:e:o:i:s flag -s
+ case $flag in
+ split=false
+ exclude+==
+ getopts n:e:o:i:s flag -s
+ COMPREPLY=()
+ local 'redir=@(?([0-9])<|?([0-9&])>?(>)|>&)'
+ _get_comp_words_by_ref -n '=<>&' cur prev words cword
+ local exclude flag i OPTIND=1
+ words=()
+ local cur cword words
+ upargs=()
+ upvars=()
+ local upargs upvars vcur vcword vprev vwords
+ getopts c:i:n:p:w: flag -n '=<>&' cur prev words cword
+ case $flag in
+ exclude='=<>&'
+ getopts c:i:n:p:w: flag -n '=<>&' cur prev words cword
+ [[ 6 -ge 3 ]]
+ case ${!OPTIND} in
+ vcur=cur
+ (( OPTIND += 1 ))
+ [[ 6 -ge 4 ]]
+ case ${!OPTIND} in
+ vprev=prev
+ (( OPTIND += 1 ))
+ [[ 6 -ge 5 ]]
+ case ${!OPTIND} in
+ vwords=words
+ (( OPTIND += 1 ))
+ [[ 6 -ge 6 ]]
+ case ${!OPTIND} in
+ vcword=cword
+ (( OPTIND += 1 ))
+ [[ 6 -ge 7 ]]
+ __get_cword_at_cursor_by_ref '=<>&' words cword cur
+ words=()
+ local cword words
+ __reassemble_comp_words_by_ref '=<>&' words cword
+ local exclude i j line ref
+ [[ -n =<>& ]]
+ exclude='[=<>&]'
+ printf -v cword %s 1
+ [[ -v exclude ]]
+ line='make abc/'
+ (( i = 0, j = 0 ))
+ (( i < 2 ))
+ [[ 0 -gt 0 ]]
+ ref='words[0]'
+ printf -v 'words[0]' %s make
+ line=' abc/'
+ (( i == COMP_CWORD ))
+ (( i++, j++ ))
+ (( i < 2 ))
+ [[ 1 -gt 0 ]]
+ [[ abc/ == +([=<>&]) ]]
+ ref='words[1]'
+ printf -v 'words[1]' %s abc/
+ line=
+ (( i == COMP_CWORD ))
+ printf -v cword %s 1
+ (( i++, j++ ))
+ (( i < 2 ))
+ (( i == COMP_CWORD ))
+ local i cur= index=9 'lead=make abc/'
+ [[ 9 -gt 0 ]]
+ [[ -n make abc/ ]]
+ [[ -n makeabc/ ]]
+ cur='make abc/'
+ (( i = 0 ))
+ (( i <= cword ))
+ [[ 9 -ge 4 ]]
+ [[ make != \m\a\k\e ]]
+ (( i < cword ))
+ local old_size=9
+ cur=' abc/'
+ local new_size=5
+ (( index -= old_size - new_size ))
+ (( ++i ))
+ (( i <= cword ))
+ [[ 5 -ge 4 ]]
+ [[ abc != \a\b\c\/ ]]
+ cur=abc/
+ (( index > 0 ))
+ (( index-- ))
+ [[ 4 -ge 4 ]]
+ [[ abc/ != \a\b\c\/ ]]
+ (( i < cword ))
+ (( ++i ))
+ (( i <= cword ))
+ [[ -n abc/ ]]
+ [[ ! -n abc/ ]]
+ (( index < 0 ))
+ local words cword cur
+ _upvars -a2 words make abc/ -v cword 1 -v cur abc/
+ (( 10 ))
+ (( 10 ))
+ case $1 in
+ [[ -n 2 ]]
+ printf %d 2
+ [[ -n words ]]
+ unset -v words
+ eval 'words=("${@:3:2}")'
++ words=("${@:3:2}")
+ shift 4
+ (( 6 ))
+ case $1 in
+ [[ -n cword ]]
+ unset -v cword
+ eval 'cword="$3"'
++ cword=1
+ shift 3
+ (( 3 ))
+ case $1 in
+ [[ -n cur ]]
+ unset -v cur
+ eval 'cur="$3"'
++ cur=abc/
+ shift 3
+ (( 0 ))
+ [[ -v vcur ]]
+ upvars+=("$vcur")
+ upargs+=(-v $vcur "$cur")
+ [[ -v vcword ]]
+ upvars+=("$vcword")
+ upargs+=(-v $vcword "$cword")
+ [[ -v vprev ]]
+ [[ 1 -ge 1 ]]
+ upvars+=("$vprev")
+ upargs+=(-v $vprev "${words[cword - 1]}")
+ [[ -v vwords ]]
+ upvars+=("$vwords")
+ upargs+=(-a${#words[@]} $vwords ${words+"${words[@]}"})
+ (( 4 ))
+ local cur cword prev words
+ _upvars -v cur abc/ -v cword 1 -v prev make -a2 words make abc/
+ (( 13 ))
+ (( 13 ))
+ case $1 in
+ [[ -n cur ]]
+ unset -v cur
+ eval 'cur="$3"'
++ cur=abc/
+ shift 3
+ (( 10 ))
+ case $1 in
+ [[ -n cword ]]
+ unset -v cword
+ eval 'cword="$3"'
++ cword=1
+ shift 3
+ (( 7 ))
+ case $1 in
+ [[ -n prev ]]
+ unset -v prev
+ eval 'prev="$3"'
++ prev=make
+ shift 3
+ (( 4 ))
+ case $1 in
+ [[ -n 2 ]]
+ printf %d 2
+ [[ -n words ]]
+ unset -v words
+ eval 'words=("${@:3:2}")'
++ words=("${@:3:2}")
+ shift 4
+ (( 0 ))
+ _variables
+ [[ abc/ =~ ^(\$(\{[!#]?)?)([A-Za-z0-9_]*)$ ]]
+ [[ abc/ =~ ^(\$\{[#!]?)([A-Za-z0-9_]*)\[([^]]*)$ ]]
+ [[ abc/ =~ ^\$\{[#!]?[A-Za-z0-9_]*\[.*]$ ]]
+ case ${prev-} in
+ return 1
+ [[ abc/ == @(?([0-9])<|?([0-9&])>?(>)|>&)* ]]
+ [[ make == @(?([0-9])<|?([0-9&])>?(>)|>&) ]]
+ local i skip
+ (( i = 1 ))
+ (( i < 2 ))
+ [[ abc/ == @(?([0-9])<|?([0-9&])>?(>)|>&)* ]]
+ (( i++ ))
+ (( 1 ))
+ (( i < 2 ))
+ (( cword <= 0 ))
+ prev=make
+ [[ -n false ]]
+ _split_longopt
+ [[ abc/ == --?*=* ]]
+ return 1
+ return 0
+ makef_dir=('-C' '.')
+ local makef makef_dir i
+ case $prev in
+ false
+ [[ abc/ == -* ]]
+ [[ abc/ == *=* ]]
+ (( i = 1 ))
+ (( i < 2 ))
+ [[ abc/ == -@(C|-directory) ]]
+ (( i++ ))
+ (( i < 2 ))
+ (( i = 1 ))
+ (( i < 2 ))
+ [[ abc/ == -@(f|-?(make)file) ]]
+ (( i++ ))
+ (( i < 2 ))
+ local mode=--
+ (( COMP_TYPE != 9 ))
+ mode=-d
++ _make_target_extract_script -d abc/
++ local mode=-d
++ shift
++ local prefix=abc/
+++ command sed 's/[][\,.*^$(){}?+|/]/\\&/g'
++ local 'prefix_pat=abc\/'
++ local basename=
++ local dirname_len=4
++ [[ -d == -d ]]
++ local 'output=\2'
++ cat
++ [[ -z abc\/ ]]
++ [[ abc\/ == */ ]]
++ cat
++ cat
+ local 'IFS=
' 'script= 1,/^# * Make data base/ d; # skip any makefile output
/^# * Finished Make data base/,/^# * Make data base/{
d; # skip any makefile output
}
/^# * Variables/,/^# * Files/ d; # skip until files section
/^# * Not a target/,/^$/ d; # skip not target blocks
/^abc\//,/^$/! 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|^\(.\{4\}\)\(.\{0\}[^:/]*/\{0,1\}\)[^:]*:.*$|\2|p;
d; # hide any bugs
}
# This pattern includes a literal tab character as \t is not a portable
# representation and fails with BSD sed
/^[^# :%]\{1,\}:/ { # 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
/^abc\/[^a-zA-Z0-9]/d; # convention for hidden tgt
h; # hold target
d; # delete line
}'
+ COMPREPLY=($(LC_ALL=C $1 -npq __BASH_MAKE_COMPLETION__=1 ${makef+"${makef[@]}"} "${makef_dir[@]}" .DEFAULT 2>/dev/null |
command sed -ne "$script"))
++ LC_ALL=C
++ make -npq __BASH_MAKE_COMPLETION__=1 -C . .DEFAULT
++ command sed -ne ' 1,/^# * Make data base/ d; # skip any makefile output
/^# * Finished Make data base/,/^# * Make data base/{
d; # skip any makefile output
}
/^# * Variables/,/^# * Files/ d; # skip until files section
/^# * Not a target/,/^$/ d; # skip not target blocks
/^abc\//,/^$/! 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|^\(.\{4\}\)\(.\{0\}[^:/]*/\{0,1\}\)[^:]*:.*$|\2|p;
d; # hide any bugs
}
# This pattern includes a literal tab character as \t is not a portable
# representation and fails with BSD sed
/^[^# :%]\{1,\}:/ { # 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
/^abc\/[^a-zA-Z0-9]/d; # convention for hidden tgt
h; # hold target
d; # delete line
}'
+ [[ -d != -d ]]
����xyz
�[C�[C�[Kset +x && exec 2>/dev/tty
�[?2004l
++ _on_command_start
+ set +x
Metadata
Metadata
Assignees
Labels
No labels