Merge branch 'aw/complete-case-insensitive'

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
This commit is contained in:
Junio C Hamano 2022-12-19 11:46:18 +09:00
Родитель 4e09e0dae6 9de31f7bd2
Коммит 053650ddad
2 изменённых файлов: 53 добавлений и 3 удалений

Просмотреть файл

@ -58,6 +58,12 @@
# #
# When set to "1" suggest all options, including options which are # When set to "1" suggest all options, including options which are
# typically hidden (e.g. '--allow-empty' for 'git commit'). # typically hidden (e.g. '--allow-empty' for 'git commit').
#
# GIT_COMPLETION_IGNORE_CASE
#
# When set, uses for-each-ref '--ignore-case' to find refs that match
# case insensitively, even on systems with case sensitive file systems
# (e.g., completing tag name "FOO" on "git checkout f<TAB>").
case "$COMP_WORDBREAKS" in case "$COMP_WORDBREAKS" in
*:*) : great ;; *:*) : great ;;
@ -646,6 +652,7 @@ __git_heads ()
local pfx="${1-}" cur_="${2-}" sfx="${3-}" local pfx="${1-}" cur_="${2-}" sfx="${3-}"
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/heads/$cur_*" "refs/heads/$cur_*/**" "refs/heads/$cur_*" "refs/heads/$cur_*/**"
} }
@ -659,6 +666,7 @@ __git_remote_heads ()
local pfx="${1-}" cur_="${2-}" sfx="${3-}" local pfx="${1-}" cur_="${2-}" sfx="${3-}"
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/remotes/$cur_*" "refs/remotes/$cur_*/**" "refs/remotes/$cur_*" "refs/remotes/$cur_*/**"
} }
@ -669,6 +677,7 @@ __git_tags ()
local pfx="${1-}" cur_="${2-}" sfx="${3-}" local pfx="${1-}" cur_="${2-}" sfx="${3-}"
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/tags/$cur_*" "refs/tags/$cur_*/**" "refs/tags/$cur_*" "refs/tags/$cur_*/**"
} }
@ -688,6 +697,7 @@ __git_dwim_remote_heads ()
# but only output if the branch name is unique # but only output if the branch name is unique
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \ __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
--sort="refname:strip=3" \ --sort="refname:strip=3" \
${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \ "refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
uniq -u uniq -u
} }
@ -712,6 +722,7 @@ __git_refs ()
local format refs local format refs
local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}" local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
local match="${4-}" local match="${4-}"
local umatch="${4-}"
local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
__git_find_repo_path __git_find_repo_path
@ -735,12 +746,19 @@ __git_refs ()
fi fi
fi fi
if test "${GIT_COMPLETION_IGNORE_CASE:+1}" = "1"
then
# uppercase with tr instead of ${match,^^} for 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 [ "$list_refs_from" = path ]; then
if [[ "$cur_" == ^* ]]; then if [[ "$cur_" == ^* ]]; then
pfx="$pfx^" pfx="$pfx^"
fer_pfx="$fer_pfx^" fer_pfx="$fer_pfx^"
cur_=${cur_#^} cur_=${cur_#^}
match=${match#^} match=${match#^}
umatch=${umatch#^}
fi fi
case "$cur_" in case "$cur_" in
refs|refs/*) refs|refs/*)
@ -751,7 +769,7 @@ __git_refs ()
*) *)
for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do
case "$i" in case "$i" in
$match*) $match*|$umatch*)
if [ -e "$dir/$i" ]; then if [ -e "$dir/$i" ]; then
echo "$pfx$i$sfx" echo "$pfx$i$sfx"
fi fi
@ -765,6 +783,7 @@ __git_refs ()
;; ;;
esac esac
__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \ __git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"${refs[@]}" "${refs[@]}"
if [ -n "$track" ]; then if [ -n "$track" ]; then
__git_dwim_remote_heads "$pfx" "$match" "$sfx" __git_dwim_remote_heads "$pfx" "$match" "$sfx"
@ -784,15 +803,16 @@ __git_refs ()
*) *)
if [ "$list_refs_from" = remote ]; then if [ "$list_refs_from" = remote ]; then
case "HEAD" in case "HEAD" in
$match*) echo "${pfx}HEAD$sfx" ;; $match*|$umatch*) echo "${pfx}HEAD$sfx" ;;
esac esac
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \ __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/remotes/$remote/$match*" \ "refs/remotes/$remote/$match*" \
"refs/remotes/$remote/$match*/**" "refs/remotes/$remote/$match*/**"
else else
local query_symref local query_symref
case "HEAD" in case "HEAD" in
$match*) query_symref="HEAD" ;; $match*|$umatch*) query_symref="HEAD" ;;
esac esac
__git ls-remote "$remote" $query_symref \ __git ls-remote "$remote" $query_symref \
"refs/tags/$match*" "refs/heads/$match*" \ "refs/tags/$match*" "refs/heads/$match*" \

Просмотреть файл

@ -2255,6 +2255,36 @@ test_expect_success 'checkout completes ref names' '
EOF 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_COMPLETION_IGNORE_CASE=1 &&
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_COMPLETION_IGNORE_CASE=1 &&
test_completion "git checkout h" <<-\EOF
HEAD Z
EOF
)
'
test_expect_success 'git -C <path> checkout uses the right repo' ' test_expect_success 'git -C <path> checkout uses the right repo' '
test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
branch-in-other Z branch-in-other Z