completion: handle unusual characters for sparse-checkout

Update the __gitcomp_directories method to de-quote and handle unusual characters in directory names. Although this initially involved an attempt to re-use the logic in __git_index_files, this method removed subdirectories (e.g. folder1/0/ became folder1/), so instead new custom logic was placed directly in the __gitcomp_directories method. Note there are two tests for this new functionality - one for spaces and accents and one for backslashes and tabs. The backslashes and tabs test uses FUNNYNAMES to avoid running on Windows. This is because: 1. Backslashes are explicitly not allowed in Windows file paths. 2. Although tabs appear to be allowed when creating a file in a Windows bash shell, they actually are not renderable (and appear as empty boxes in the shell). Co-authored-by: Johannes Schindelin <johannes.schindelin@gmx.de> Co-authored-by: Lessley Dennington <lessleydennington@gmail.com> Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Lessley Dennington <lessleydennington@gmail.com> Reviewed-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Lessley Dennington committed Feb 7, 2022 at 17:31 UTC 48803821b1712687d6e06e9d7a0e911eabecf4d1
2 files changed +60 -13
contrib/completion/git-completion.bash
+11 -13
@@ -2988,7 +2988,7 @@ _git_show_branch ()
2988
2989 __gitcomp_directories ()
2990 {
2991 - local _tmp_dir _tmp_completions
2991 + local _tmp_dir _tmp_completions _found=0
2992
2993 # Get the directory of the current token; this differs from dirname
2994 # in that it keeps up to the final trailing slash. If no slash found
@@ -2996,20 +2996,18 @@ __gitcomp_directories ()
2996 [[ "$cur" =~ .*/ ]]
2997 _tmp_dir=$BASH_REMATCH
2998
2999 - # Find possible directory completions, adding trailing '/' characters
3000 - _tmp_completions="$(git ls-tree -d --name-only HEAD $_tmp_dir |
3001 - sed -e s%$%/%)"
3002 -
3003 - if [[ -n "$_tmp_completions" ]]; then
3004 - # There were some directory completions, so find ones that
3005 - # start with "$cur", the current token, and put those in COMPREPLY
3006 - local i=0 c IFS=$' \t\n'
3007 - for c in $_tmp_completions; do
2999 + # Find possible directory completions, adding trailing '/' characters,
3000 + # de-quoting, and handling unusual characters.
3001 + while IFS= read -r -d $'\0' c ; do
3002 + # If there are directory completions, find ones that start
3003 + # with "$cur", the current token, and put those in COMPREPLY
3004 if [[ $c == "$cur"* ]]; then
3009 - COMPREPLY+=("$c")
3005 + COMPREPLY+=("$c/")
3006 + _found=1
3007 fi
3011 - done
3012 - elif [[ "$cur" =~ /$ ]]; then
3008 + done < <(git ls-tree -z -d --name-only HEAD $_tmp_dir)
3009 +
3010 + if [[ $_found == 0 ]] && [[ "$cur" =~ /$ ]]; then
3011 # No possible further completions any deeper, so assume we're at
3012 # a leaf directory and just consider it complete
3013 __gitcomp_direct_append "$cur "
t/t9902-completion.sh
+49
@@ -1505,6 +1505,55 @@ test_expect_success 'cone mode sparse-checkout completes directory names' '
1505 )
1506 '
1507
1508 +test_expect_success 'cone mode sparse-checkout completes directory names with spaces and accents' '
1509 + # reset sparse-checkout
1510 + git -C sparse-checkout sparse-checkout disable &&
1511 + (
1512 + cd sparse-checkout &&
1513 + mkdir "directory with spaces" &&
1514 + mkdir "directory-with-áccent" &&
1515 + >"directory with spaces/randomfile" &&
1516 + >"directory-with-áccent/randomfile" &&
1517 + git add . &&
1518 + git commit -m "Add directory with spaces and directory with accent" &&
1519 + git sparse-checkout set --cone "directory with spaces" \
1520 + "directory-with-áccent" &&
1521 + test_completion "git sparse-checkout add dir" <<-\EOF &&
1522 + directory with spaces/
1523 + directory-with-áccent/
1524 + EOF
1525 + rm -rf "directory with spaces" &&
1526 + rm -rf "directory-with-áccent" &&
1527 + git add . &&
1528 + git commit -m "Remove directory with spaces and directory with accent"
1529 + )
1530 +'
1531 +
1532 +# use FUNNYNAMES to avoid running on Windows, which doesn't permit backslashes or tabs in paths
1533 +test_expect_success FUNNYNAMES 'cone mode sparse-checkout completes directory names with backslashes and tabs' '
1534 + # reset sparse-checkout
1535 + git -C sparse-checkout sparse-checkout disable &&
1536 + (
1537 + cd sparse-checkout &&
1538 + mkdir "directory\with\backslashes" &&
1539 + mkdir "$(printf "directory\twith\ttabs")" &&
1540 + >"directory\with\backslashes/randomfile" &&
1541 + >"$(printf "directory\twith\ttabs")/randomfile" &&
1542 + git add . &&
1543 + git commit -m "Add directory with backslashes and directory with tabs" &&
1544 + git sparse-checkout set --cone "directory\with\backslashes" \
1545 + "$(printf "directory\twith\ttabs")" &&
1546 + test_completion "git sparse-checkout add dir" <<-\EOF &&
1547 + directory\with\backslashes/
1548 + directory with tabs/
1549 + EOF
1550 + rm -rf "directory\with\backslashes" &&
1551 + rm -rf "$(printf "directory\twith\ttabs")" &&
1552 + git add . &&
1553 + git commit -m "Remove directory with backslashes and directory with tabs"
1554 + )
1555 +'
1556 +
1557 test_expect_success 'non-cone mode sparse-checkout uses bash completion' '
1558 # reset sparse-checkout repo to non-cone mode
1559 git -C sparse-checkout sparse-checkout disable &&