@@ -46,7 +46,7 @@ _make_target_extract_script()
4646 /^$/ { # end of target block
4747 x; # unhold target
4848 /^$/d; # dont print blanks
49- s|^${dirname_re-} \(.\{${# basename} \}[^:/]*/\{0,1\}\)[^:]* :.*$|${output} |p;
49+ s|^${dirname_re-} \(.\{${# basename} \}[^:]*\) :.*$|${output} |p;
5050 d; # hide any bugs
5151 }
5252
@@ -172,6 +172,53 @@ _make()
172172 ${makef+" ${makef[@]} " } " ${makef_dir[@]} " .DEFAULT 2> /dev/null |
173173 command sed -ne " $script " ) )
174174
175+ # discard the files under subdirectories unless the path is unique
176+ # under each subdirectory and instead generate the subdirectory path.
177+ # For example, when there are two candidates, "abc/def" and "abc/xyz",
178+ # we generate "abc/" instead of generating both candidates directly.
179+ # When there is only one candidate "abc/def", we generate the full path
180+ # "abc/def".
181+ local prefix=$cur
182+ [[ $mode == -d ]] && prefix=
183+ if (( ${# COMPREPLY[@]} > 0 )) ; then
184+ # collect the possible completions including the directory names in
185+ # `paths' and count the number of children of each subdirectory in
186+ # `nchild'.
187+ local -A paths nchild
188+ local target
189+ for target in " ${COMPREPLY[@]} " ; do
190+ local path=${target%/ }
191+ while [[ ! ${paths[$path]+set} ]] &&
192+ paths[$path ]=1 &&
193+ [[ $path == " $prefix " * /* ]]; do
194+ path=${path%/* }
195+ if [[ ! ${nchild[$path]+set} ]]; then
196+ (( nchild[\$path ] = 1 ))
197+ else
198+ (( nchild[\$path ]++ ))
199+ fi
200+ done
201+ done
202+
203+ COMPREPLY=()
204+ local nreply=0
205+ for target in " ${! paths[@]} " ; do
206+ # generate only the paths that do not have a unique child and
207+ # whose all parent and ancestor directories have a unique
208+ # child.
209+ (( ${nchild[$target]-0} == 1 )) && continue
210+ local path=$target
211+ while [[ $path == " $prefix " * /* ]]; do
212+ path=${path%/* }
213+ (( ${nchild[$path]-0} == 1 )) || continue 2
214+ done
215+
216+ # suffix `/' when the target path is a subdiretory, which has
217+ # at least one child.
218+ COMPREPLY[nreply++]=$target ${nchild[$target]+/ }
219+ done
220+ fi
221+
175222 if [[ $mode != -d ]]; then
176223 # Completion will occur if there is only one suggestion
177224 # so set options for completion based on the first one
0 commit comments