summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/completion/git-completion.bash66
-rwxr-xr-xt/t9902-completion.sh17
2 files changed, 79 insertions, 4 deletions
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 1cd019d2e9..63903f22f1 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -461,8 +461,70 @@ __git_index_files ()
paths[$1] = 1
}
END {
- for (p in paths)
- print p
+ for (p in paths) {
+ if (substr(p, 1, 1) != "\"") {
+ # No special characters, easy!
+ print p
+ continue
+ }
+
+ # The path is quoted.
+ p = dequote(p)
+ if (p == "")
+ continue
+
+ # Even when a directory name itself does not contain
+ # any special characters, it will still be quoted if
+ # any of its (stripped) trailing path components do.
+ # Because of this we may have seen the same direcory
+ # both quoted and unquoted.
+ if (p in paths)
+ # We have seen the same directory unquoted,
+ # skip it.
+ continue
+ else
+ print p
+ }
+ }
+ function dequote(p, bs_idx, out, esc, esc_idx, dec) {
+ # Skip opening double quote.
+ p = substr(p, 2)
+
+ # Interpret backslash escape sequences.
+ while ((bs_idx = index(p, "\\")) != 0) {
+ out = out substr(p, 1, bs_idx - 1)
+ esc = substr(p, bs_idx + 1, 1)
+ p = substr(p, bs_idx + 2)
+
+ if ((esc_idx = index("abtvfr\"\\", esc)) != 0) {
+ # C-style one-character escape sequence.
+ out = out substr("\a\b\t\v\f\r\"\\",
+ esc_idx, 1)
+ } else if (esc == "n") {
+ # Uh-oh, a newline character.
+ # We cant reliably put a pathname
+ # containing a newline into COMPREPLY,
+ # and the newline would create a mess.
+ # Skip this path.
+ return ""
+ } else {
+ # Must be a \nnn octal value, then.
+ dec = esc * 64 + \
+ substr(p, 1, 1) * 8 + \
+ substr(p, 2, 1)
+ out = out sprintf("%c", dec)
+ p = substr(p, 3)
+ }
+ }
+ # Drop closing double quote, if there is one.
+ # (There isnt any if this is a directory, as it was
+ # already stripped with the trailing path components.)
+ if (substr(p, length(p), 1) == "\"")
+ out = out substr(p, 1, length(p) - 1)
+ else
+ out = out p
+
+ return out
}'
}
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 9d460768ef..955932174c 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -1527,7 +1527,7 @@ else
say "Your filesystem does not allow \\ and \" in filenames."
rm -rf 'New\Dir'
fi
-test_expect_failure FUNNYNAMES_BS_DQ \
+test_expect_success FUNNYNAMES_BS_DQ \
'complete files - C-style escapes in ls-files output' '
test_when_finished "rm -r \"New\\\\Dir\"" &&
@@ -1548,7 +1548,7 @@ else
say 'Your filesystem does not allow special separator characters (FS, GS, RS, US) in filenames.'
rm -rf $'New\034Special\035Dir'
fi
-test_expect_failure FUNNYNAMES_SEPARATORS \
+test_expect_success FUNNYNAMES_SEPARATORS \
'complete files - \nnn-escaped control characters in ls-files output' '
test_when_finished "rm -r '$'New\034Special\035Dir''" &&
@@ -1562,6 +1562,19 @@ test_expect_failure FUNNYNAMES_SEPARATORS \
"'$'New\034Special\035Dir/New\036Special\037File''"
'
+test_expect_success FUNNYNAMES_BS_DQ \
+ 'complete files - removing repeated quoted path components' '
+ test_when_finished rm -rf NewDir &&
+ mkdir NewDir && # A dirname which in itself would not be quoted ...
+ >NewDir/0-file &&
+ >NewDir/1\"file && # ... but here the file makes the dirname quoted ...
+ >NewDir/2-file &&
+ >NewDir/3\"file && # ... and here, too.
+
+ # Still, we should only list it once.
+ test_completion "git test-path-comp New" "NewDir"
+'
+
test_expect_success "completion uses <cmd> completion for alias: !sh -c 'git <cmd> ...'" '
test_config alias.co "!sh -c '"'"'git checkout ...'"'"'" &&