summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaylor Blau <me@ttaylorr.com>2022-11-18 20:04:57 -0500
committerTaylor Blau <me@ttaylorr.com>2022-11-18 20:04:57 -0500
commit5bf1a142990bccd287935020edb9371a50de6fd7 (patch)
tree2494e2826402c83e11c4f3be935b8a497c6e97e9
parent2d8a6373445fc4351c4833ffb0de4ac4dbc90ba2 (diff)
parent3b9c8aaa07c4feed3c649ae419d39dc9f9043a59 (diff)
downloadgit-5bf1a142990bccd287935020edb9371a50de6fd7.tar.gz
Merge branch 'aw/complete-case-insensitive' into jch
Introduce a case insensitive mode to the Bash completion helpers. * aw/complete-case-insensitive: completion: add case-insensitive match of pseudorefs completion: add optional ignore-case when matching refs
-rw-r--r--contrib/completion/git-completion.bash51
-rwxr-xr-xt/t9902-completion.sh32
2 files changed, 80 insertions, 3 deletions
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index ba5c395d2d..161327057d 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -58,6 +58,11 @@
#
# When set to "1" suggest all options, including options which are
# typically hidden (e.g. '--allow-empty' for 'git commit').
+#
+# GIT_COMPLETION_IGNORE_CASE
+#
+# When set to "1", suggest refs that match case insensitively (e.g.,
+# completing "FOO" on "git checkout f<TAB>").
case "$COMP_WORDBREAKS" in
*:*) : great ;;
@@ -644,8 +649,15 @@ __git_complete_index_file ()
__git_heads ()
{
local pfx="${1-}" cur_="${2-}" sfx="${3-}"
+ local ignore_case=""
+
+ if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+ then
+ ignore_case="--ignore-case"
+ fi
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+ $ignore_case \
"refs/heads/$cur_*" "refs/heads/$cur_*/**"
}
@@ -657,8 +669,15 @@ __git_heads ()
__git_remote_heads ()
{
local pfx="${1-}" cur_="${2-}" sfx="${3-}"
+ local ignore_case=""
+
+ if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+ then
+ ignore_case="--ignore-case"
+ fi
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+ $ignore_case \
"refs/remotes/$cur_*" "refs/remotes/$cur_*/**"
}
@@ -667,8 +686,15 @@ __git_remote_heads ()
__git_tags ()
{
local pfx="${1-}" cur_="${2-}" sfx="${3-}"
+ local ignore_case=""
+
+ if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+ then
+ ignore_case="--ignore-case"
+ fi
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+ $ignore_case \
"refs/tags/$cur_*" "refs/tags/$cur_*/**"
}
@@ -682,12 +708,19 @@ __git_dwim_remote_heads ()
{
local pfx="${1-}" cur_="${2-}" sfx="${3-}"
local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
+ local ignore_case=""
+
+ if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+ then
+ ignore_case="--ignore-case"
+ fi
# employ the heuristic used by git checkout and git switch
# Try to find a remote branch that cur_es the completion word
# but only output if the branch name is unique
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
--sort="refname:strip=3" \
+ $ignore_case \
"refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
uniq -u
}
@@ -712,7 +745,9 @@ __git_refs ()
local format refs
local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
local match="${4-}"
+ local umatch="${4-}"
local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
+ local ignore_case=""
__git_find_repo_path
dir="$__git_repo_path"
@@ -735,12 +770,20 @@ __git_refs ()
fi
fi
+ if test "${GIT_COMPLETION_IGNORE_CASE-}" = "1"
+ then
+ ignore_case="--ignore-case"
+ # use tr instead of ${match,^^} to preserve bash 3.2 compatibility
+ umatch=$(echo "$match" | tr a-z A-Z 2> /dev/null || echo "$match")
+ fi
+
if [ "$list_refs_from" = path ]; then
if [[ "$cur_" == ^* ]]; then
pfx="$pfx^"
fer_pfx="$fer_pfx^"
cur_=${cur_#^}
match=${match#^}
+ umatch=${umatch#^}
fi
case "$cur_" in
refs|refs/*)
@@ -751,7 +794,7 @@ __git_refs ()
*)
for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do
case "$i" in
- $match*)
+ $match*|$umatch*)
if [ -e "$dir/$i" ]; then
echo "$pfx$i$sfx"
fi
@@ -765,6 +808,7 @@ __git_refs ()
;;
esac
__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
+ $ignore_case \
"${refs[@]}"
if [ -n "$track" ]; then
__git_dwim_remote_heads "$pfx" "$match" "$sfx"
@@ -784,15 +828,16 @@ __git_refs ()
*)
if [ "$list_refs_from" = remote ]; then
case "HEAD" in
- $match*) echo "${pfx}HEAD$sfx" ;;
+ $match*|$umatch*) echo "${pfx}HEAD$sfx" ;;
esac
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
+ $ignore_case \
"refs/remotes/$remote/$match*" \
"refs/remotes/$remote/$match*/**"
else
local query_symref
case "HEAD" in
- $match*) query_symref="HEAD" ;;
+ $match*|$umatch*) query_symref="HEAD" ;;
esac
__git ls-remote "$remote" $query_symref \
"refs/tags/$match*" "refs/heads/$match*" \
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 1bd4cae92f..27e3aa46c1 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2255,6 +2255,38 @@ test_expect_success 'checkout completes ref names' '
EOF
'
+test_expect_success 'checkout does not match ref names of a different case' '
+ test_completion "git checkout M" ""
+'
+
+test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+ (
+ . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+ GIT_COMPLETION_IGNORE_CASE=1 && export GIT_COMPLETION_IGNORE_CASE &&
+ test_completion "git checkout M" <<-\EOF
+ main Z
+ mybranch Z
+ mytag Z
+ EOF
+ )
+'
+
+test_expect_success 'checkout completes pseudo refs' '
+ test_completion "git checkout H" <<-\EOF
+ HEAD Z
+ EOF
+'
+
+test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+ (
+ . "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
+ GIT_COMPLETION_IGNORE_CASE=1 && export GIT_COMPLETION_IGNORE_CASE &&
+ test_completion "git checkout h" <<-\EOF
+ HEAD Z
+ EOF
+ )
+'
+
test_expect_success 'git -C <path> checkout uses the right repo' '
test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
branch-in-other Z