Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[RFC] Case-insensitive path completion in _git
- X-seq: zsh-workers 47738
- From: dana <dana@xxxxxxx>
- To: Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: [RFC] Case-insensitive path completion in _git
- Date: Sat, 12 Dec 2020 22:40:43 -0600
- Archived-at: <https://zsh.org/workers/47738>
- Archived-at: <http://www.zsh.org/sympa/arcsearch_id/zsh-workers/2020-12/B25A8850-A141-4B81-A3E6-017F280B0CC6%40dana.is>
- Authentication-results: zsh.org; iprev=pass (mail-il1-f179.google.com) smtp.remote-ip=209.85.166.179; dkim=pass header.d=dana-is.20150623.gappssmtp.com header.s=20150623 header.a=rsa-sha256; dmarc=none header.from=dana.is; arc=none
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dana-is.20150623.gappssmtp.com; s=20150623; h=from:content-transfer-encoding:mime-version:subject:message-id:date :to; bh=fvy/LGK/tUq+887rBmfIOLgruhu9Ohm5ycxFNvkkWGU=; b=k4moGQoSSzkjD28/ovp9xt6OtfG87gpStp7B/dpR/JPNcCi7rs2Uq7GiyB8QllX+DW EsYBW/zSYOYnrbqiEXSzFE5FkgUK8F/VGkr3ucZsjpUCO4vow0bBbPs8pZQ7aX46Atz+ Cu2OwWZRRYnQYnBP2Wz7EW6yeGci6PuVKCdV4AtZ9OWOlJfgRixM7Udg4ynVPvno07jC 4Ix+NAqPms8pY7ix0Dwcsg4psDhTvftvhs/zWNJatySlWOe8l1HCpcInI/luEQwdtJJ4 0yHzpE4yhFRPQsWo1Hrf/NFKExgeUo5on8Hzi8dGTOedra9vyDl6uPUKsaJnRJaZAK2S Zszg==
- List-archive: <http://www.zsh.org/sympa/arc/zsh-workers>
- List-help: <mailto:sympa@zsh.org?subject=help>
- List-id: <zsh-workers.zsh.org>
- List-owner: <mailto:zsh-workers-request@zsh.org>
- List-post: <mailto:zsh-workers@zsh.org>
- List-subscribe: <mailto:sympa@zsh.org?subject=subscribe%20zsh-workers>
- List-unsubscribe: <mailto:sympa@zsh.org?subject=unsubscribe%20zsh-workers>
- Sender: zsh-workers-request@xxxxxxx
I've had this sitting for a while:
_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)?
dana
diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index 81a060e4d..7d0201efe 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -7138,6 +7138,7 @@ __git_files_relative () {
(( $+functions[__git_files] )) ||
__git_files () {
local compadd_opts opts tag description gittoplevel gitprefix files expl
+ local MATCH MBEGIN MEND
zparseopts -D -E -a compadd_opts V+: J+: 1 2 o+: n f x+: X+: M+: P: S: r: R: q F:
zparseopts -D -E -a opts -- -cached -deleted -modified -others -ignored -unmerged -killed x+: --exclude+:
@@ -7152,14 +7153,26 @@ __git_files () {
# TODO: --directory should probably be added to $opts when --others is given.
+ # ls-files allows the part of the path under the repository directory to be a
+ # glob pattern. However, these patterns are always case-sensitive (even if the
+ # file system is not). This means that if we have a matcher style set to make
+ # path completion case-insensitive, it won't (necessarily) work, because we
+ # won't get any results back from Git. To work around this, we can transform
+ # the pattern from abc to [Aa][Bb][Cc]. This is very dumb, but seemingly
+ # reliable enough
local pref=${(Q)${~PREFIX}}
+ pref=${pref//(#m)[[:alpha:]]/\[${(U)MATCH}${(L)MATCH}\]}
[[ $pref[1] == '/' ]] || pref=$gittoplevel$gitprefix$pref
# 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)"})
__git_command_successful $pipestatus || return
- # If ls-files succeeded but returned nothing, try again with no pattern
+ # If ls-files succeeded but returned nothing, try again with no pattern. Note
+ # that ls-files defaults to the CWD if not given a path, so if the file we
+ # were trying to add is in an *adjacent* directory, this won't return anything
+ # helpful. (If it did, the case-sensitivity issue mentioned above would only
+ # be a minor performance issue rather than a complete failure to return)
if [[ -z "$files" && -n "$pref" ]]; then
files=(${(0)"$(_call_program files git ls-files -z --exclude-standard ${(q)opts} -- 2>/dev/null)"})
__git_command_successful $pipestatus || return
Messages sorted by:
Reverse Date,
Date,
Thread,
Author