Skip to content

Commit f241c08

Browse files
committed
Merge branch 'fc/completion'
* fc/completion: completion: remove __git_index_file_list_filter() completion: add space after completed filename completion: add hack to enable file mode in bash < 4 completion: refactor __git_complete_index_file() completion: refactor diff_index wrappers completion: use __gitcompadd for __gitcomp_file completion; remove unuseful comments completion: document tilde expansion failure in tests completion: add file completion tests
2 parents 6bf931a + c29e317 commit f241c08

File tree

2 files changed

+107
-115
lines changed

2 files changed

+107
-115
lines changed

contrib/completion/git-completion.bash

Lines changed: 30 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -252,106 +252,50 @@ __gitcomp_file ()
252252
# since tilde expansion is not applied.
253253
# This means that COMPREPLY will be empty and Bash default
254254
# completion will be used.
255-
COMPREPLY=($(compgen -P "${2-}" -W "$1" -- "${3-$cur}"))
255+
__gitcompadd "$1" "${2-}" "${3-$cur}" ""
256256

257-
# Tell Bash that compspec generates filenames.
258-
compopt -o filenames 2>/dev/null
257+
# use a hack to enable file mode in bash < 4
258+
compopt -o filenames +o nospace 2>/dev/null ||
259+
compgen -f /non-existing-dir/ > /dev/null
259260
}
260261

261-
__git_index_file_list_filter_compat ()
262-
{
263-
local path
264-
265-
while read -r path; do
266-
case "$path" in
267-
?*/*) echo "${path%%/*}/" ;;
268-
*) echo "$path" ;;
269-
esac
270-
done
271-
}
272-
273-
__git_index_file_list_filter_bash ()
274-
{
275-
local path
276-
277-
while read -r path; do
278-
case "$path" in
279-
?*/*)
280-
# XXX if we append a slash to directory names when using
281-
# `compopt -o filenames`, Bash will append another slash.
282-
# This is pretty stupid, and this the reason why we have to
283-
# define a compatible version for this function.
284-
echo "${path%%/*}" ;;
285-
*)
286-
echo "$path" ;;
287-
esac
288-
done
289-
}
290-
291-
# Process path list returned by "ls-files" and "diff-index --name-only"
292-
# commands, in order to list only file names relative to a specified
293-
# directory, and append a slash to directory names.
294-
__git_index_file_list_filter ()
295-
{
296-
# Default to Bash >= 4.x
297-
__git_index_file_list_filter_bash
298-
}
299-
300-
# Execute git ls-files, returning paths relative to the directory
301-
# specified in the first argument, and using the options specified in
302-
# the second argument.
262+
# Execute 'git ls-files', unless the --committable option is specified, in
263+
# which case it runs 'git diff-index' to find out the files that can be
264+
# committed. It return paths relative to the directory specified in the first
265+
# argument, and using the options specified in the second argument.
303266
__git_ls_files_helper ()
304267
{
305268
(
306269
test -n "${CDPATH+set}" && unset CDPATH
307-
# NOTE: $2 is not quoted in order to support multiple options
308-
cd "$1" && git ls-files --exclude-standard $2
270+
cd "$1"
271+
if [ "$2" == "--committable" ]; then
272+
git diff-index --name-only --relative HEAD
273+
else
274+
# NOTE: $2 is not quoted in order to support multiple options
275+
git ls-files --exclude-standard $2
276+
fi
309277
) 2>/dev/null
310278
}
311279

312280

313-
# Execute git diff-index, returning paths relative to the directory
314-
# specified in the first argument, and using the tree object id
315-
# specified in the second argument.
316-
__git_diff_index_helper ()
317-
{
318-
(
319-
test -n "${CDPATH+set}" && unset CDPATH
320-
cd "$1" && git diff-index --name-only --relative "$2"
321-
) 2>/dev/null
322-
}
323-
324281
# __git_index_files accepts 1 or 2 arguments:
325282
# 1: Options to pass to ls-files (required).
326-
# Supported options are --cached, --modified, --deleted, --others,
327-
# and --directory.
328283
# 2: A directory path (optional).
329284
# If provided, only files within the specified directory are listed.
330285
# Sub directories are never recursed. Path must have a trailing
331286
# slash.
332287
__git_index_files ()
333288
{
334-
local dir="$(__gitdir)" root="${2-.}"
289+
local dir="$(__gitdir)" root="${2-.}" file
335290

336291
if [ -d "$dir" ]; then
337-
__git_ls_files_helper "$root" "$1" | __git_index_file_list_filter |
338-
sort | uniq
339-
fi
340-
}
341-
342-
# __git_diff_index_files accepts 1 or 2 arguments:
343-
# 1) The id of a tree object.
344-
# 2) A directory path (optional).
345-
# If provided, only files within the specified directory are listed.
346-
# Sub directories are never recursed. Path must have a trailing
347-
# slash.
348-
__git_diff_index_files ()
349-
{
350-
local dir="$(__gitdir)" root="${2-.}"
351-
352-
if [ -d "$dir" ]; then
353-
__git_diff_index_helper "$root" "$1" | __git_index_file_list_filter |
354-
sort | uniq
292+
__git_ls_files_helper "$root" "$1" |
293+
while read -r file; do
294+
case "$file" in
295+
?*/*) echo "${file%%/*}" ;;
296+
*) echo "$file" ;;
297+
esac
298+
done | sort | uniq
355299
fi
356300
}
357301

@@ -552,44 +496,23 @@ __git_complete_revlist_file ()
552496
}
553497

554498

555-
# __git_complete_index_file requires 1 argument: the options to pass to
556-
# ls-file
499+
# __git_complete_index_file requires 1 argument:
500+
# 1: the options to pass to ls-file
501+
#
502+
# The exception is --committable, which finds the files appropriate commit.
557503
__git_complete_index_file ()
558504
{
559-
local pfx cur_="$cur"
505+
local pfx="" cur_="$cur"
560506

561507
case "$cur_" in
562508
?*/*)
563509
pfx="${cur_%/*}"
564510
cur_="${cur_##*/}"
565511
pfx="${pfx}/"
566-
567-
__gitcomp_file "$(__git_index_files "$1" "$pfx")" "$pfx" "$cur_"
568-
;;
569-
*)
570-
__gitcomp_file "$(__git_index_files "$1")" "" "$cur_"
571512
;;
572513
esac
573-
}
574514

575-
# __git_complete_diff_index_file requires 1 argument: the id of a tree
576-
# object
577-
__git_complete_diff_index_file ()
578-
{
579-
local pfx cur_="$cur"
580-
581-
case "$cur_" in
582-
?*/*)
583-
pfx="${cur_%/*}"
584-
cur_="${cur_##*/}"
585-
pfx="${pfx}/"
586-
587-
__gitcomp_file "$(__git_diff_index_files "$1" "$pfx")" "$pfx" "$cur_"
588-
;;
589-
*)
590-
__gitcomp_file "$(__git_diff_index_files "$1")" "" "$cur_"
591-
;;
592-
esac
515+
__gitcomp_file "$(__git_index_files "$1" "$pfx")" "$pfx" "$cur_"
593516
}
594517

595518
__git_complete_file ()
@@ -1213,7 +1136,7 @@ _git_commit ()
12131136
esac
12141137

12151138
if git rev-parse --verify --quiet HEAD >/dev/null; then
1216-
__git_complete_diff_index_file "HEAD"
1139+
__git_complete_index_file "--committable"
12171140
else
12181141
# This is the first commit
12191142
__git_complete_index_file "--cached"
@@ -2702,14 +2625,6 @@ if [[ -n ${ZSH_VERSION-} ]]; then
27022625

27032626
compdef _git git gitk
27042627
return
2705-
elif [[ -n ${BASH_VERSION-} ]]; then
2706-
if ((${BASH_VERSINFO[0]} < 4)); then
2707-
# compopt is not supported
2708-
__git_index_file_list_filter ()
2709-
{
2710-
__git_index_file_list_filter_compat
2711-
}
2712-
fi
27132628
fi
27142629

27152630
__git_func_wrap ()

t/t9902-completion.sh

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,4 +347,81 @@ test_expect_success 'send-email' '
347347
test_completion "git send-email ma" "master "
348348
'
349349

350+
test_expect_success 'complete files' '
351+
git init tmp && cd tmp &&
352+
test_when_finished "cd .. && rm -rf tmp" &&
353+
354+
echo "expected" > .gitignore &&
355+
echo "out" >> .gitignore &&
356+
357+
git add .gitignore &&
358+
test_completion "git commit " ".gitignore" &&
359+
360+
git commit -m ignore &&
361+
362+
touch new &&
363+
test_completion "git add " "new" &&
364+
365+
git add new &&
366+
git commit -a -m new &&
367+
test_completion "git add " "" &&
368+
369+
git mv new modified &&
370+
echo modify > modified &&
371+
test_completion "git add " "modified" &&
372+
373+
touch untracked &&
374+
375+
: TODO .gitignore should not be here &&
376+
test_completion "git rm " <<-\EOF &&
377+
.gitignore
378+
modified
379+
EOF
380+
381+
test_completion "git clean " "untracked" &&
382+
383+
: TODO .gitignore should not be here &&
384+
test_completion "git mv " <<-\EOF &&
385+
.gitignore
386+
modified
387+
EOF
388+
389+
mkdir dir &&
390+
touch dir/file-in-dir &&
391+
git add dir/file-in-dir &&
392+
git commit -m dir &&
393+
394+
mkdir untracked-dir &&
395+
396+
: TODO .gitignore should not be here &&
397+
test_completion "git mv modified " <<-\EOF &&
398+
.gitignore
399+
dir
400+
modified
401+
untracked
402+
untracked-dir
403+
EOF
404+
405+
test_completion "git commit " "modified" &&
406+
407+
: TODO .gitignore should not be here &&
408+
test_completion "git ls-files " <<-\EOF
409+
.gitignore
410+
dir
411+
modified
412+
EOF
413+
414+
touch momified &&
415+
test_completion "git add mom" "momified"
416+
'
417+
418+
test_expect_failure 'complete with tilde expansion' '
419+
git init tmp && cd tmp &&
420+
test_when_finished "cd .. && rm -rf tmp" &&
421+
422+
touch ~/tmp/file &&
423+
424+
test_completion "git add ~/tmp/" "~/tmp/file"
425+
'
426+
350427
test_done

0 commit comments

Comments
 (0)