From ddf07bddef9aac37cf54ef744452f2a9ad4e312e Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 27 Apr 2013 15:09:59 -0500 Subject: [PATCH 1/9] completion: add file completion tests The commit fea16b4 (git-completion.bash: add support for path completion) introduced quite a few changes, without the usual tests. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- t/t9902-completion.sh | 68 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 6d9d1418a0..385e1e455c 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -347,4 +347,72 @@ test_expect_success 'send-email' ' test_completion "git send-email ma" "master " ' +test_expect_success 'complete files' ' + git init tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + echo "expected" > .gitignore && + echo "out" >> .gitignore && + + git add .gitignore && + test_completion "git commit " ".gitignore" && + + git commit -m ignore && + + touch new && + test_completion "git add " "new" && + + git add new && + git commit -a -m new && + test_completion "git add " "" && + + git mv new modified && + echo modify > modified && + test_completion "git add " "modified" && + + touch untracked && + + : TODO .gitignore should not be here && + test_completion "git rm " <<-\EOF && + .gitignore + modified + EOF + + test_completion "git clean " "untracked" && + + : TODO .gitignore should not be here && + test_completion "git mv " <<-\EOF && + .gitignore + modified + EOF + + mkdir dir && + touch dir/file-in-dir && + git add dir/file-in-dir && + git commit -m dir && + + mkdir untracked-dir && + + : TODO .gitignore should not be here && + test_completion "git mv modified " <<-\EOF && + .gitignore + dir + modified + untracked + untracked-dir + EOF + + test_completion "git commit " "modified" && + + : TODO .gitignore should not be here && + test_completion "git ls-files " <<-\EOF + .gitignore + dir + modified + EOF + + touch momified && + test_completion "git add mom" "momified" +' + test_done From f03efba4c0a7046ceb51ec4b57f7413fe6e931eb Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 27 Apr 2013 15:10:00 -0500 Subject: [PATCH 2/9] completion: document tilde expansion failure in tests Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- t/t9902-completion.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 385e1e455c..81a1657efb 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -415,4 +415,13 @@ test_expect_success 'complete files' ' test_completion "git add mom" "momified" ' +test_expect_failure 'complete with tilde expansion' ' + git init tmp && cd tmp && + test_when_finished "cd .. && rm -rf tmp" && + + touch ~/tmp/file && + + test_completion "git add ~/tmp/" "~/tmp/file" +' + test_done From 9ab8d18322657db8bbe0cdf3b0dc19b479a3d4e5 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 27 Apr 2013 15:10:01 -0500 Subject: [PATCH 3/9] completion; remove unuseful comments The only caller, __git_complete_index_file() doesn't specify any limits to the options for 'git ls-files', neither should this function. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 2 -- 1 file changed, 2 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index bc3fc9e323..f7b0f3c8f0 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -323,8 +323,6 @@ __git_diff_index_helper () # __git_index_files accepts 1 or 2 arguments: # 1: Options to pass to ls-files (required). -# Supported options are --cached, --modified, --deleted, --others, -# and --directory. # 2: A directory path (optional). # If provided, only files within the specified directory are listed. # Sub directories are never recursed. Path must have a trailing From 0afe8e9e98b0b066105e03476f7c8f4c14bc1c15 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 27 Apr 2013 15:10:02 -0500 Subject: [PATCH 4/9] completion: use __gitcompadd for __gitcomp_file Like the rest of the script does; let's not access COMPREPLY directly. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index f7b0f3c8f0..7f1ebe4895 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -252,7 +252,7 @@ __gitcomp_file () # since tilde expansion is not applied. # This means that COMPREPLY will be empty and Bash default # completion will be used. - COMPREPLY=($(compgen -P "${2-}" -W "$1" -- "${3-$cur}")) + __gitcompadd "$1" "${2-}" "${3-$cur}" "" # Tell Bash that compspec generates filenames. compopt -o filenames 2>/dev/null From f825972c38ba5a8e0309a552b401ad55aeaaaf36 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 27 Apr 2013 15:10:03 -0500 Subject: [PATCH 5/9] completion: refactor diff_index wrappers At the end of the day what we really need is to find out the files that have been staged, or modified, because those files are the ones that make sense to pass as arguments to 'git commit'. We need diff-index to find those out, since 'git ls-files' doesn't do that. But we don't need wrappers and wrappers basically identical to the ones used for 'git ls-files', when we can pretend it receives a --committable option that would return what we need. That way, we can remove a bunch of code without any functional changes. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 71 ++++++-------------------- 1 file changed, 16 insertions(+), 55 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 7f1ebe4895..25612655ab 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -297,30 +297,25 @@ __git_index_file_list_filter () __git_index_file_list_filter_bash } -# Execute git ls-files, returning paths relative to the directory -# specified in the first argument, and using the options specified in -# the second argument. +# Execute 'git ls-files', unless the --committable option is specified, in +# which case it runs 'git diff-index' to find out the files that can be +# committed. It return paths relative to the directory specified in the first +# argument, and using the options specified in the second argument. __git_ls_files_helper () { ( test -n "${CDPATH+set}" && unset CDPATH - # NOTE: $2 is not quoted in order to support multiple options - cd "$1" && git ls-files --exclude-standard $2 + cd "$1" + if [ "$2" == "--committable" ]; then + git diff-index --name-only --relative HEAD + else + # NOTE: $2 is not quoted in order to support multiple options + git ls-files --exclude-standard $2 + fi ) 2>/dev/null } -# Execute git diff-index, returning paths relative to the directory -# specified in the first argument, and using the tree object id -# specified in the second argument. -__git_diff_index_helper () -{ - ( - test -n "${CDPATH+set}" && unset CDPATH - cd "$1" && git diff-index --name-only --relative "$2" - ) 2>/dev/null -} - # __git_index_files accepts 1 or 2 arguments: # 1: Options to pass to ls-files (required). # 2: A directory path (optional). @@ -337,22 +332,6 @@ __git_index_files () fi } -# __git_diff_index_files accepts 1 or 2 arguments: -# 1) The id of a tree object. -# 2) A directory path (optional). -# If provided, only files within the specified directory are listed. -# Sub directories are never recursed. Path must have a trailing -# slash. -__git_diff_index_files () -{ - local dir="$(__gitdir)" root="${2-.}" - - if [ -d "$dir" ]; then - __git_diff_index_helper "$root" "$1" | __git_index_file_list_filter | - sort | uniq - fi -} - __git_heads () { local dir="$(__gitdir)" @@ -550,8 +529,10 @@ __git_complete_revlist_file () } -# __git_complete_index_file requires 1 argument: the options to pass to -# ls-file +# __git_complete_index_file requires 1 argument: +# 1: the options to pass to ls-file +# +# The exception is --committable, which finds the files appropriate commit. __git_complete_index_file () { local pfx cur_="$cur" @@ -570,26 +551,6 @@ __git_complete_index_file () esac } -# __git_complete_diff_index_file requires 1 argument: the id of a tree -# object -__git_complete_diff_index_file () -{ - local pfx cur_="$cur" - - case "$cur_" in - ?*/*) - pfx="${cur_%/*}" - cur_="${cur_##*/}" - pfx="${pfx}/" - - __gitcomp_file "$(__git_diff_index_files "$1" "$pfx")" "$pfx" "$cur_" - ;; - *) - __gitcomp_file "$(__git_diff_index_files "$1")" "" "$cur_" - ;; - esac -} - __git_complete_file () { __git_complete_revlist_file @@ -1211,7 +1172,7 @@ _git_commit () esac if git rev-parse --verify --quiet HEAD >/dev/null; then - __git_complete_diff_index_file "HEAD" + __git_complete_index_file "--committable" else # This is the first commit __git_complete_index_file "--cached" From fda54ef1aa66b54031a37c72a463ef15d6411912 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 27 Apr 2013 15:10:04 -0500 Subject: [PATCH 6/9] completion: refactor __git_complete_index_file() The calls to __gitcomp_file() are essentially the same, but with different prefix. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 25612655ab..9cea17036e 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -535,20 +535,17 @@ __git_complete_revlist_file () # The exception is --committable, which finds the files appropriate commit. __git_complete_index_file () { - local pfx cur_="$cur" + local pfx="" cur_="$cur" case "$cur_" in ?*/*) pfx="${cur_%/*}" cur_="${cur_##*/}" pfx="${pfx}/" - - __gitcomp_file "$(__git_index_files "$1" "$pfx")" "$pfx" "$cur_" - ;; - *) - __gitcomp_file "$(__git_index_files "$1")" "" "$cur_" ;; esac + + __gitcomp_file "$(__git_index_files "$1" "$pfx")" "$pfx" "$cur_" } __git_complete_file () From 3ffa4df4b2a26768938fc6bf1ed0640885b2bdf1 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 27 Apr 2013 15:10:05 -0500 Subject: [PATCH 7/9] completion: add hack to enable file mode in bash < 4 This way we don't need all the compat stuff, different filters, and so on. Also, now we complete exactly the same in bash 3 and bash 4. This is the way bash-completion did it for quite some time, when bash 3 was supported. For more information about the hack: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=272660#64 Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 55 ++++++-------------------- 1 file changed, 13 insertions(+), 42 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 9cea17036e..f9e8e7dae5 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -254,38 +254,9 @@ __gitcomp_file () # completion will be used. __gitcompadd "$1" "${2-}" "${3-$cur}" "" - # Tell Bash that compspec generates filenames. - compopt -o filenames 2>/dev/null -} - -__git_index_file_list_filter_compat () -{ - local path - - while read -r path; do - case "$path" in - ?*/*) echo "${path%%/*}/" ;; - *) echo "$path" ;; - esac - done -} - -__git_index_file_list_filter_bash () -{ - local path - - while read -r path; do - case "$path" in - ?*/*) - # XXX if we append a slash to directory names when using - # `compopt -o filenames`, Bash will append another slash. - # This is pretty stupid, and this the reason why we have to - # define a compatible version for this function. - echo "${path%%/*}" ;; - *) - echo "$path" ;; - esac - done + # use a hack to enable file mode in bash < 4 + compopt -o filenames 2>/dev/null || + compgen -f /non-existing-dir/ > /dev/null } # Process path list returned by "ls-files" and "diff-index --name-only" @@ -293,8 +264,16 @@ __git_index_file_list_filter_bash () # directory, and append a slash to directory names. __git_index_file_list_filter () { - # Default to Bash >= 4.x - __git_index_file_list_filter_bash + local path + + while read -r path; do + case "$path" in + ?*/*) + echo "${path%%/*}" ;; + *) + echo "$path" ;; + esac + done } # Execute 'git ls-files', unless the --committable option is specified, in @@ -2651,14 +2630,6 @@ if [[ -n ${ZSH_VERSION-} ]]; then compdef _git git gitk return -elif [[ -n ${BASH_VERSION-} ]]; then - if ((${BASH_VERSINFO[0]} < 4)); then - # compopt is not supported - __git_index_file_list_filter () - { - __git_index_file_list_filter_compat - } - fi fi __git_func_wrap () From fbe451182ed1a6830b9c46b12899fd9f20381ad4 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 27 Apr 2013 15:10:06 -0500 Subject: [PATCH 8/9] completion: add space after completed filename Just like before fea16b4 (git-completion.bash: add support for path completion). Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index f9e8e7dae5..20c971875d 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -255,7 +255,7 @@ __gitcomp_file () __gitcompadd "$1" "${2-}" "${3-$cur}" "" # use a hack to enable file mode in bash < 4 - compopt -o filenames 2>/dev/null || + compopt -o filenames +o nospace 2>/dev/null || compgen -f /non-existing-dir/ > /dev/null } From c29e317994d1077fe3ac9cdeae5a5b35ffaa3440 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sat, 27 Apr 2013 15:10:07 -0500 Subject: [PATCH 9/9] completion: remove __git_index_file_list_filter() Refactor the code into the only caller; __git_index_files(). Also, Somehow messing up with the 'path' variable messes up the 'PATH' variable. So let's not do that. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 28 ++++++++------------------ 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 20c971875d..edb7428266 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -259,23 +259,6 @@ __gitcomp_file () compgen -f /non-existing-dir/ > /dev/null } -# Process path list returned by "ls-files" and "diff-index --name-only" -# commands, in order to list only file names relative to a specified -# directory, and append a slash to directory names. -__git_index_file_list_filter () -{ - local path - - while read -r path; do - case "$path" in - ?*/*) - echo "${path%%/*}" ;; - *) - echo "$path" ;; - esac - done -} - # Execute 'git ls-files', unless the --committable option is specified, in # which case it runs 'git diff-index' to find out the files that can be # committed. It return paths relative to the directory specified in the first @@ -303,11 +286,16 @@ __git_ls_files_helper () # slash. __git_index_files () { - local dir="$(__gitdir)" root="${2-.}" + local dir="$(__gitdir)" root="${2-.}" file if [ -d "$dir" ]; then - __git_ls_files_helper "$root" "$1" | __git_index_file_list_filter | - sort | uniq + __git_ls_files_helper "$root" "$1" | + while read -r file; do + case "$file" in + ?*/*) echo "${file%%/*}" ;; + *) echo "$file" ;; + esac + done | sort | uniq fi }