Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
_path_files deleting typed words on ambiguous path
- X-seq: zsh-workers 53789
- From: Ryan Rotter <rrotter@xxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: _path_files deleting typed words on ambiguous path
- Date: Sun, 15 Jun 2025 17:15:02 -0400
- Archived-at: <https://zsh.org/workers/53789>
- List-id: <zsh-workers.zsh.org>
I added the following zstyle to my .zshrc:
zstyle ':completion:*:complete:*' matcher-list '' 'l:|=* r:|=*'
The goal was to add left hand matching so `cd Lib/Sup<tab>` would complete to `cd Lib/Application Support`, and to that end this works great, but I found what looks to me to be a bug in _path_files.
It seems that even though the matcher-list style is only used for expanding the final path segment it is erroneously used to determine ambiguity for every path segment, resulting in the typed words on the line getting deleted in certain cases.
Consider the following:
% ls /opt/omebrew/include<tab>
# note the intentionally missing 'h'; "/opt/homebrew/include" is a real file
# as expected, this does nothing, path will never complete to "/opt/homebrew/include"
% ls /o/h/i<tab>
# as expected, this expands to /opt/homebrew/include
% ls /o/h/u<tab>
# here's where the bug starts:
# deletes entire path back to space char, I'm expecting the path to expand to "/opt/homebrew/include", offer alternatives, or at worst do nothing at all.
This is apparently because _path_files treats anything matching the glob /*o*/*h*/*u* as a match, even though only /o*/h*/*u* are eligible matches.
Excerpt of completion trace:
…
# I think this is where we start going wrong, since left expansion never applies to the parent path, it makes no sense to use the matcher-list here
+_path_files:463> compfiles -P tmp1 accex '' 'l:|=* r:|=* l:|=* r:|=*' '' fake
+_path_files:472> tmp1=( /Applications /bin /cores /dev /etc /home /Library /opt /private /sbin /System /tmp /Users /usr /var /Volumes )
…
# tmp1 keeps growing… much of this removed because it's 100+ items long
+_path_files:468> compfiles -p tmp1 accex / 'l:|=* r:|=* l:|=* r:|=*' '' fake '*'
+_path_files:472> tmp1=( … /Applications/Ghostty.app/Contents … /opt/homebrew/include … '/Volumes/Macintosh HD/usr' '/Volumes/Macintosh HD/var' '/Volumes/Macintosh HD/Volumes' )
…
# tmp4 should be zero here, but we have excess items in tmp1
+_path_files:623> tmp1=( opt/homebrew/include 'Volumes/Macintosh HD/usr' 'Volumes/Macintosh HD/Volumes' )
+_path_files:627> true
+_path_files:634> compfiles -r tmp1 o/h/u
+_path_files:635> tmp4=1
…
For comparison, here's another case where a similar completion works as expected, because there is no ambiguous left hand expansion in a parent path:
% ls /o/h/g<tab>
# expands path to /opt/homebrew/age, as expected
% ls -d1 /*o*/*h*/*g*
/opt/homebrew/manpages
/opt/homebrew/package
I'm not including a suggested patch here because I'm not quite sure how to fix this. I'm happy to try if I figure more of this out, but I'm hoping that the solution will be clearer to folks here. Also worth noting that the section of code in question is littered with comments about "pws non-canonical hack", so even if I could find a solution, I'm far from confident I wouldn't break something else.
Messages sorted by:
Reverse Date,
Date,
Thread,
Author