From 7655fa7fa9f58503f21e2354f4a12fd949efa712 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 10 Apr 2013 04:08:18 -0500 Subject: [PATCH 1/8] completion: add more cherry-pick options Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 2ba1461422..8ad842e462 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1124,9 +1124,14 @@ _git_cherry () _git_cherry_pick () { + local dir="$(__gitdir)" + if [ -f "$dir"/CHERRY_PICK_HEAD ]; then + __gitcomp "--continue --quit --abort" + return + fi case "$cur" in --*) - __gitcomp "--edit --no-commit" + __gitcomp "--edit --no-commit --signoff --strategy= --mainline" ;; *) __gitcomp_nl "$(__git_refs)" From cdbff7d6ad3c1c3e8c9dbd1cbd5c43fa240982be Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 10 Apr 2013 01:57:51 -0500 Subject: [PATCH 2/8] completion: trivial test improvement Instead of passing a dummy "", let's check if the last character is a space, and then move the _cword accordingly. Apparently we were passing "" all the way to compgen, which fortunately expanded it to nothing. Lets do the right thing though. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- t/t9902-completion.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index adc1372b3c..99d5c0142f 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -69,6 +69,7 @@ run_completion () local -a COMPREPLY _words local _cword _words=( $1 ) + test "${1: -1}" == ' ' && _words+=('') (( _cword = ${#_words[@]} - 1 )) __git_wrap__git_main && print_comp } @@ -148,7 +149,7 @@ test_expect_success '__gitcomp - suffix' ' ' test_expect_success 'basic' ' - run_completion "git \"\"" && + run_completion "git " && # built-in grep -q "^add \$" out && # script From 0285118e593833be90b3f025d70dde432c1859e7 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 10 Apr 2013 01:57:52 -0500 Subject: [PATCH 3/8] completion: get rid of empty COMPREPLY assignments There's no functional reason for those, the only purpose they are supposed to serve is to say "we don't provide any words here", but even for that it's not used consistently. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 8ad842e462..d1b731cf65 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -208,7 +208,6 @@ __gitcomp () case "$cur_" in --*=) - COMPREPLY=() ;; *) local IFS=$'\n' @@ -614,7 +613,6 @@ __git_complete_remote_or_refspec () case "$cmd" in push) no_complete_refspec=1 ;; fetch) - COMPREPLY=() return ;; *) ;; @@ -630,7 +628,6 @@ __git_complete_remote_or_refspec () return fi if [ $no_complete_refspec = 1 ]; then - COMPREPLY=() return fi [ "$remote" = "." ] && remote= @@ -951,7 +948,6 @@ _git_am () " return esac - COMPREPLY=() } _git_apply () @@ -971,7 +967,6 @@ _git_apply () " return esac - COMPREPLY=() } _git_add () @@ -1031,7 +1026,6 @@ _git_bisect () __gitcomp_nl "$(__git_refs)" ;; *) - COMPREPLY=() ;; esac } @@ -1175,7 +1169,6 @@ _git_clone () return ;; esac - COMPREPLY=() } _git_commit () @@ -1359,7 +1352,6 @@ _git_fsck () return ;; esac - COMPREPLY=() } _git_gc () @@ -1370,7 +1362,6 @@ _git_gc () return ;; esac - COMPREPLY=() } _git_gitk () @@ -1447,7 +1438,6 @@ _git_init () return ;; esac - COMPREPLY=() } _git_ls_files () @@ -1583,7 +1573,6 @@ _git_mergetool () return ;; esac - COMPREPLY=() } _git_merge_base () @@ -1896,7 +1885,6 @@ _git_config () return ;; *.*) - COMPREPLY=() return ;; esac @@ -2277,7 +2265,6 @@ _git_remote () __gitcomp "$c" ;; *) - COMPREPLY=() ;; esac } @@ -2393,8 +2380,6 @@ _git_stash () *) if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then __gitcomp "$subcommands" - else - COMPREPLY=() fi ;; esac @@ -2407,14 +2392,12 @@ _git_stash () __gitcomp "--index --quiet" ;; show,--*|drop,--*|branch,--*) - COMPREPLY=() ;; show,*|apply,*|drop,*|pop,*|branch,*) __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \ | sed -n -e 's/:.*//p')" ;; *) - COMPREPLY=() ;; esac fi @@ -2531,7 +2514,6 @@ _git_svn () __gitcomp "--revision= --parent" ;; *) - COMPREPLY=() ;; esac fi @@ -2556,13 +2538,10 @@ _git_tag () case "$prev" in -m|-F) - COMPREPLY=() ;; -*|tag) if [ $f = 1 ]; then __gitcomp_nl "$(__git_tags)" - else - COMPREPLY=() fi ;; *) From 1ce23aad3446c8a423cd4ec4de1b91361cdf4a85 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 10 Apr 2013 01:57:53 -0500 Subject: [PATCH 4/8] completion: add new __gitcompadd helper The idea is to never touch the COMPREPLY variable directly. This allows other completion systems (i.e. zsh) to override __gitcompadd, and do something different instead. Also, this allows further optimizations down the line. There should be no functional changes. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d1b731cf65..f7e9a56528 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -195,6 +195,11 @@ _get_comp_words_by_ref () } fi +__gitcompadd () +{ + COMPREPLY=($(compgen -W "$1" -P "$2" -S "$4" -- "$3")) +} + # Generates completion reply with compgen, appending a space to possible # completion words, if necessary. # It accepts 1 to 4 arguments: @@ -211,9 +216,7 @@ __gitcomp () ;; *) local IFS=$'\n' - COMPREPLY=($(compgen -P "${2-}" \ - -W "$(__gitcomp_1 "${1-}" "${4-}")" \ - -- "$cur_")) + __gitcompadd "$(__gitcomp_1 "${1-}" "${4-}")" "${2-}" "$cur_" "" ;; esac } @@ -230,7 +233,7 @@ __gitcomp () __gitcomp_nl () { local IFS=$'\n' - COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}")) + __gitcompadd "$1" "${2-}" "${3-$cur}" "${4- }" } # Generates completion reply with compgen from newline-separated possible @@ -1825,7 +1828,7 @@ _git_config () local remote="${prev#remote.}" remote="${remote%.fetch}" if [ -z "$cur" ]; then - COMPREPLY=("refs/heads/") + __gitcompadd "refs/heads/" "" "" "" return fi __gitcomp_nl "$(__git_refs_remotes "$remote")" From 43369a22588373b987d427a937b761bb04817e4d Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 10 Apr 2013 01:57:54 -0500 Subject: [PATCH 5/8] completion: add __gitcomp_nl tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original patch by SZEDER Gábor. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- t/t9902-completion.sh | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 99d5c0142f..b752f4d33c 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -105,6 +105,23 @@ test_gitcomp () test_cmp expected out } +# Test __gitcomp_nl +# Arguments are: +# 1: current word (cur) +# -: the rest are passed to __gitcomp_nl +test_gitcomp_nl () +{ + local -a COMPREPLY && + sed -e 's/Z$//' >expected && + cur="$1" && + shift && + __gitcomp_nl "$@" && + print_comp && + test_cmp expected out +} + +invalid_variable_name='${foo.bar}' + test_expect_success '__gitcomp - trailing space - options' ' test_gitcomp "--re" "--dry-run --reuse-message= --reedit-message= --reset-author" <<-EOF @@ -148,6 +165,49 @@ test_expect_success '__gitcomp - suffix' ' EOF ' +test_expect_failure '__gitcomp - doesnt fail because of invalid variable name' ' + __gitcomp "$invalid_variable_name" +' + +read -r -d "" refs <<-\EOF +maint +master +next +pu +EOF + +test_expect_success '__gitcomp_nl - trailing space' ' + test_gitcomp_nl "m" "$refs" <<-EOF + maint Z + master Z + EOF +' + +test_expect_success '__gitcomp_nl - prefix' ' + test_gitcomp_nl "--fixup=m" "$refs" "--fixup=" "m" <<-EOF + --fixup=maint Z + --fixup=master Z + EOF +' + +test_expect_success '__gitcomp_nl - suffix' ' + test_gitcomp_nl "branch.ma" "$refs" "branch." "ma" "." <<-\EOF + branch.maint.Z + branch.master.Z + EOF +' + +test_expect_success '__gitcomp_nl - no suffix' ' + test_gitcomp_nl "ma" "$refs" "" "ma" "" <<-\EOF + maintZ + masterZ + EOF +' + +test_expect_failure '__gitcomp_nl - doesnt fail because of invalid variable name' ' + __gitcomp_nl "$invalid_variable_name" +' + test_expect_success 'basic' ' run_completion "git " && # built-in From 7d13e0a3afbc9d2f58a32ec27391a947e58e382c Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 10 Apr 2013 01:57:55 -0500 Subject: [PATCH 6/8] completion: get rid of compgen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functionality we use from compgen is not much, we can do the same manually, with drastic improvements in speed, especially when dealing with only a few words. This patch also has the sideffect that brekage reported by Jeroen Meijer and SZEDER Gábor gets fixed because we no longer expand the resulting words. Here are some numbers filtering N amount of words: == 1 == original: 0.002s new: 0.000s == 10 == original: 0.002s new: 0.000s == 100 == original: 0.003s new: 0.002s == 1000 == original: 0.012s new: 0.011s == 10000 == original: 0.056s new: 0.066s == 100000 == original: 2.669s new: 0.622s If the results are not narrowed: == 1 == original: 0.002s new: 0.000s == 10 == original: 0.002s new: 0.001s == 100 == original: 0.004s new: 0.004s == 1000 == original: 0.020s new: 0.015s == 10000 == original: 0.101s new: 0.355s == 100000 == original: 2.850s new: 31.941s So, unless 'git checkout ' usually gives you more than 10000 results, you'll get an improvement :) Other possible solutions perform better after 1000 words, but worst if less than that: COMPREPLY=($(awk -v cur="$3" -v pre="$2" -v suf="$4" '$0 ~ cur { print pre$0suf }' <<< "$1" )) COMPREPLY=($(printf -- "$2%s$4\n" $1 | grep "^$2$3")) Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 15 ++++++++++----- t/t9902-completion.sh | 6 +++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index f7e9a56528..d45d082846 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -197,11 +197,16 @@ fi __gitcompadd () { - COMPREPLY=($(compgen -W "$1" -P "$2" -S "$4" -- "$3")) + local i=0 + for x in $1; do + if [[ "$x" == "$3"* ]]; then + COMPREPLY[i++]="$2$x$4" + fi + done } -# Generates completion reply with compgen, appending a space to possible -# completion words, if necessary. +# Generates completion reply, appending a space to possible completion words, +# if necessary. # It accepts 1 to 4 arguments: # 1: List of possible completion words. # 2: A prefix to be added to each possible completion word (optional). @@ -221,8 +226,8 @@ __gitcomp () esac } -# Generates completion reply with compgen from newline-separated possible -# completion words by appending a space to all of them. +# Generates completion reply from newline-separated possible completion words +# by appending a space to all of them. # It accepts 1 to 4 arguments: # 1: List of possible completion words, separated by a single newline. # 2: A prefix to be added to each possible completion word (optional). diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index b752f4d33c..6d9d1418a0 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -165,7 +165,7 @@ test_expect_success '__gitcomp - suffix' ' EOF ' -test_expect_failure '__gitcomp - doesnt fail because of invalid variable name' ' +test_expect_success '__gitcomp - doesnt fail because of invalid variable name' ' __gitcomp "$invalid_variable_name" ' @@ -204,7 +204,7 @@ test_expect_success '__gitcomp_nl - no suffix' ' EOF ' -test_expect_failure '__gitcomp_nl - doesnt fail because of invalid variable name' ' +test_expect_success '__gitcomp_nl - doesnt fail because of invalid variable name' ' __gitcomp_nl "$invalid_variable_name" ' @@ -332,7 +332,7 @@ test_expect_success 'complete tree filename with spaces' ' EOF ' -test_expect_failure 'complete tree filename with metacharacters' ' +test_expect_success 'complete tree filename with metacharacters' ' echo content >"name with \${meta}" && git add . && git commit -m meta && From b4cfbc969cd910992a08b12dc612d19323668e09 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 10 Apr 2013 01:57:56 -0500 Subject: [PATCH 7/8] completion: inline __gitcomp_1 to its sole callsite There is no point in calling a separate function that is only used in one place. Especially considering that there's no need to call compgen, and we traverse the words ourselves both in __gitcompadd, and __gitcomp_1. Let's squash the functions together, and traverse only once. This improves performance. For N number of words: == 1 == original: 0.002s new: 0.000s == 10 == original: 0.005s new: 0.001s == 100 == original: 0.009s new: 0.006s == 1000 == original: 0.027s new: 0.019s == 10000 == original: 0.163s new: 0.151s == 100000 == original: 1.555s new: 1.497s No functional changes. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index d45d082846..f38579214f 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -53,19 +53,6 @@ __gitdir () fi } -__gitcomp_1 () -{ - local c IFS=$' \t\n' - for c in $1; do - c="$c$2" - case $c in - --*=*|*.) ;; - *) c="$c " ;; - esac - printf '%s\n' "$c" - done -} - # The following function is based on code from: # # bash_completion - programmable completion functions for bash 3.2+ @@ -220,8 +207,17 @@ __gitcomp () --*=) ;; *) - local IFS=$'\n' - __gitcompadd "$(__gitcomp_1 "${1-}" "${4-}")" "${2-}" "$cur_" "" + local c i=0 IFS=$' \t\n' + for c in $1; do + c="$c${4-}" + case $c in + --*=*|*.) ;; + *) c="$c " ;; + esac + if [[ $c == "$cur_"* ]]; then + COMPREPLY[i++]="${2-}$c" + fi + done ;; esac } From ddc996d767025a4ffcb52a813d32a5095f357e44 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Wed, 10 Apr 2013 01:57:57 -0500 Subject: [PATCH 8/8] completion: small optimization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to calculate a new $c with a space if we are not going to do anything it with it. There should be no functional changes, except that a word "foo " with no suffixes can't be matched. But $cur cannot have a space at the end anyway. So it's safe. Based on the code from SZEDER Gábor. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- contrib/completion/git-completion.bash | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index f38579214f..6df62c2173 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -210,11 +210,11 @@ __gitcomp () local c i=0 IFS=$' \t\n' for c in $1; do c="$c${4-}" - case $c in - --*=*|*.) ;; - *) c="$c " ;; - esac if [[ $c == "$cur_"* ]]; then + case $c in + --*=*|*.) ;; + *) c="$c " ;; + esac COMPREPLY[i++]="${2-}$c" fi done