zimfw/completion

Autocomplete issue

Closed this issue · 8 comments

sQVe commented
  • I've checked the existing issues and I'm not duplicating a report.
  • I'm using the latest version of zimfw.
  • I've checked the Changelog and I'm not being affected by documented changes.
  • I've checked the 📢 Announcements and I'm not being affected by announced changes.
  • I was able to reproduce the issue with a clean installation of Zim.
  • I've pasted the output of zimfw info below.

Describe the bug
When trying to cd into similar named directories it fails to autocomplete, sometimes.

Steps to reproduce
The fist 4 steps restart the shell with a clean installation of Zim in a temporary directory.
Use exec zsh when restarting the terminal or restarting the shell is needed.

  1. cd ${$(mktemp -d):A}
  2. ZDOTDIR=${PWD} HOME=${PWD} ZIM_HOME=${PWD}/.zim exec zsh
  3. curl -fsSL https://raw.githubusercontent.com/zimfw/install/master/install.zsh | zsh
  4. exec zsh
  5. mkdir -p tmp/{users,utils}
  6. cd tmp
  7. type cd u and then Tab to autocomplete.

Current behavior
When pressing Tab it incorrectly autocompletes to uT and then utils/ if you press Tab again.

Expected behavior
It should give correct autocomplete, proving users/ and utils/ as options.

Screenshots

simplescreenrecorder-2022-06-20_16.40.16.mp4

zimfw info

zimfw version: 1.9.1 (built at 2022-05-24 21:25:10 UTC, previous commit is 5bcfb8c)
ZIM_HOME:      /home/sqve/.local/share/zim
Zsh version:   5.9
System info:   Linux calcifer 5.18.5-arch1-1 #1 SMP PREEMPT_DYNAMIC Thu, 16 Jun 2022 20:40:45 +0000 x86_64 GNU/Linux

Hey @sQVe! Thanks for the detailed report! I was able to reproduce it in macOS too (which has a case insensitive file system), and even with setopt caseglob.

Our matcher-list configuration is known to be buggy. See a longer discussion in zimfw/zimfw#212. Your example adds to the long list of expected behavior discussed in that issue.

@marlonrichert has figured out a great configuration for the completion system in https://github.com/marlonrichert/zsh-autocomplete/blob/main/scripts/.autocomplete.config. I haven't had time to explore the details of his implementation, but I believe we might be able to figure out the solution for a fuzzy completion like we expect based on his work.

sQVe commented

I tried playing around with this module and if I unset NO_CASE_GLOB and comment out zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' '+r:|?=**' I get the correct completion for this case. I'm well aware that it isn't that simple but thought it might be worth noting.

sQVe commented

I tried changing the matcher-list to https://github.com/marlonrichert/zsh-autocomplete/blob/4decd760641377e818d11146ef1249f5474c224a/scripts/.autocomplete.config#L64-L72 and that seems to work well, as far as I can tell.

Cool. I believe you'll also need an extra configuration to enable the loose and fuzzy matchers. This is done here: https://github.com/marlonrichert/zsh-autocomplete/blob/4decd760641377e818d11146ef1249f5474c224a/scripts/.autocomplete.config#L26-L33

sQVe commented

I'm a bit unsure what the differences between the three are. Just setting:

zstyle ':completion:*' matcher-list \
  'm:{[:lower:]-}={[:upper:]_} r:|[.]=**' \
  '+l:|=*'

Seems to work fine for my use-cases.

The documentation for Zsh completion matchers has been a mess for years. However, I recently wrote completely new documentation for it, which has been released with Zsh 5.9: https://zsh.sourceforge.io/Doc/Release/Completion-Widgets.html#Completion-Matching-Control

Hopefully, this makes things more clear.

(Note, however, that there are long-standing bugs in the :||= matchers. The docs that I wrote describe how they are intended to work, but they don’t actually work like that at present. I would avoid them for now.)

sQVe commented

@marlonrichert Cheers for great information! Could you possibly provide insight into what the matcher-list I'm using above actually does?

m:{[:lower:]-}={[:upper:]_}

Each lowercase letter in the input can also match its uppercase counterpart and each - in the input can also match a _.

r:|[.]=**

r:|.=**

Each empty substring in the input that has a . to the right of it can match any substring, including those containing other instances of .. (If you had just a single * there, then it couldn’t match substrings containing .) In other words, this inserts a wildcard to the left of each ..

+

If the previous matcher fails, then append this matcher to it and try again. (Note that this is unique to zstyle […] matcher-list and thus not handled in the chapter I linked to above. See here instead.)

l:|=*

If there is an empty substring at the left edge of the input (which is by definition always the case), then it can match any substring. In other words, this adds a wildcard to the left edge of the input.