Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [RFC] Case-insensitive path completion in _git

On 13.12.2020 05:40, dana wrote:
_git has issues completing files case-insensitively (if you have matcher-list
'm:{a-zA-Z}={A-Za-z}' or whatever). Looking into it, i found that __git_files
is trying to pass a glob pattern to `git ls-files`, and this fails if there's
not an exact case match, since ls-files is always case-sensitive.

There is a fall-back to `git ls-files` with no path, but this doesn't always
work either, because it defaults to the CWD, and the file you're trying to
complete may not be under the CWD. Even when the fall-back succeeds, it's not
ideal, because it'll pass every single file in the tree to _multi_parts, which
can be slow.

The following hack solves the problem for me, but it might be too silly to
commit. Can anyone think of a more proper fix? If not, would the hack be
viable (probably gated behind a style)?


+  pref=${pref//(#m)[[:alpha:]]/\[${(U)MATCH}${(L)MATCH}\]}

This solution only handles simple upper-lower-case conversion matcher-list styles,
but it will not work for more complicated styles like 'r:|[._-]=* r:|=*'.
That's probably fine for most use-cases.

I have been running with the following patch applied locally for quite some time:

diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index 81a060e4d..1a6619e31 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -7153,7 +7153,7 @@ __git_files () {
   # TODO: --directory should probably be added to $opts when --others is given.

   local pref=${(Q)${~PREFIX}}
-  [[ $pref[1] == '/' ]] || pref=$gittoplevel$gitprefix$pref
+  [[ $pref[1] == '/' ]] || pref=$gittoplevel$gitprefix

   # First allow ls-files to pattern-match in case of remote repository
   files=(${(0)"$(_call_program files git ls-files -z --exclude-standard ${(q)opts} -- ${(q)${pref:+$pref\*}:-.} 2>/dev/null)"})

It just lets _multi_parts do the matching.
Performance-wise, it's obviously worse than than your proposed solution, but
still better than the fallback, since it still passes $gitprefix to ls-files,
which should also avoid the CWD problem.

The trigger of the fallback is broken anyways, isn't it?

 # If ls-files succeeded but returned nothing, try again with no pattern
 if [[ -z "$files" && -n "$pref" ]]; then

It just considers the case where no match was found at all, but it does not
handle the case where *some* matches were found, but not all.

Messages sorted by: Reverse Date, Date, Thread, Author