wfxr / forgit

:zzz: A utility tool powered by fzf for using git interactively.
MIT License
4.32k stars 136 forks source link

zsh completion doesn't seem to work with zinit #330

Closed Gerrit-K closed 5 months ago

Gerrit-K commented 6 months ago

Check list

Environment info

Problem / Steps to reproduce

I'm by far not an expert when it comes to zsh completions, but I noticed there are no _git-* completion functions, but also no git-* commands on my system. Everything is handled by git [command] and the _git completion function. Maybe the forgit completions don't account for that?

carlfriedrich commented 6 months ago

git-forgit should be in your PATH, isn't that the case?

Gerrit-K commented 6 months ago

git-forgit should be in your PATH, isn't that the case?

Apparently not. I never had and it was never causing issues, because I only use forgit's aliases, which are referencing the forgit:: functions from the shell plugin. But I apparently never used git-forgit or git forgit directly.

However, adding the bin folder to PATH (so that git-forgit is available) doesn't fix the issue with completions.

sandr01d commented 5 months ago

Hi @Gerrit-K,

I don't know a lot about zinit or macOS, but I wrote the zsh completion functions for forgit so hopefully we can figure this out together :slightly_smiling_face:

Additionally to git-forgit having to be in your PATH, the completion file (_git-forgit) needs to be in your $fpath is that the case? Do completions work when you use forgit as a git subcommand or not at all? E.g. git forgit <TAB> should print a list of all available commands.

I noticed there are no _git- completion functions, but also no git- commands on my system.

That's a bit odd and forgit needs the completion functions for the individual git commands for the completions to function properly. Could you please run the following in your zsh and let me know the results?

for line in $fpath; do grep _git-add "$line/"**/*(-.); done

Also can you post the content of the _git completion function on your system? The easiest way to obtain it is by running which _git.

Just to be sure could you let me know how you initialize completions in your .zshrc? For example, mine looks like this

autoload -Uz compinit
compinit

It would also be good to know which version of git you're using and where you installed it from.

Gerrit-K commented 5 months ago

Hey @sandr01d, first of all, thank you so much for the detailed answer and all the effort to help me ❤️ It might very well be just a niche edge case, but I really appreciate it!

To get back to your replies:

the completion file (_git-forgit) needs to be in your $fpath is that the case?

Yes ✔️

Do completions work when you use forgit as a git subcommand or not at all? E.g. git forgit <TAB> should print a list of all available commands.

Not at all, unfortunately. git forgit <TAB> just lists files from the current directory. git forgit works, though. When I hit enter, I get the forgit: missing command ... reply.

I noticed there are no _git- completion functions, but also no git- commands on my system.

That's a bit odd and forgit needs the completion functions for the individual git commands for the completions to function properly. Could you please run the following in your zsh and let me know the results?

for line in $fpath; do grep _git-add "$line/"**/*(-.); done

Sure, here's the (slighly anonymized 😉) result:

/Users/user/.zinit/completions/_git-forgit:                     add) _git-add ;;
zsh: no matches found: /usr/local/share/zsh/site-functions/**/*(-.)
/opt/homebrew/Cellar/zsh/5.9/share/zsh/functions/_git:(( $+functions[_git-add] )) ||
/opt/homebrew/Cellar/zsh/5.9/share/zsh/functions/_git:_git-add () {

Also can you post the content of the _git completion function on your system? The easiest way to obtain it is by running which _git.

_git function ``` ❯ which _git _git () { local _ret=1 local cur cword prev cur=${words[CURRENT]} prev=${words[CURRENT-1]} let cword=CURRENT-1 if (( $+functions[__${service}_zsh_main] )) then __${service}_zsh_main elif (( $+functions[__${service}_main] )) then emulate ksh -c __${service}_main elif (( $+functions[_${service}] )) then emulate ksh -c _${service} elif (( $+functions[_${service//-/_}] )) then emulate ksh -c _${service//-/_} fi let _ret && _default && _ret=0 return _ret } ```

Just to be sure could you let me know how you initialize completions in your .zshrc? For example, mine looks like this

autoload -Uz compinit
compinit

This is unfortunately a bit more convoluted in my setup, due to how zinit works. It's kind of similar to this config (which I've adapted, but diverged from, several years ago) with the matching call here. I can try to simplify my setup to see if it fixes the issue 👍

It would also be good to know which version of git you're using and where you installed it from.

Sure! It's 2.43.0 from Homebrew.

sandr01d commented 5 months ago

/opt/homebrew/Cellar/zsh/5.9/share/zsh/functions/_git:(( $+functions[_git-add] )) || /opt/homebrew/Cellar/zsh/5.9/share/zsh/functions/_git:_git-add () {

_git-add appears to be present on your system and also in your $fpath. Not sure why it isn't being picked up by compinit though.

Do completions work when you use forgit as a git subcommand or not at all? E.g. git forgit should print a list of all available commands.

Not at all, unfortunately. git forgit just lists files from the current directory.

So what this essentially boils down to is _git-forgit is not properly picked up from compsys, the question is just why. Let's focus on this one first because, as far as forgit is involved, this does all the heavy lifting. git-forgit.zsh only makes sure the completions are also passed along to the functions and aliases. Given that _git-forgit appears to reside in a zinit specific directory (/Users/user/.zinit/completions/_git-forgit), which is not in the $fpath by default, could it be that zinit is adding this directory to the $fpath after compinit already ran? I've noticed you're using lucid, which is asynchronous. Maybe there is some sort of race condition (wild guess here)? Try placing _git-forgit inside one of the directories that are included in $fpath by default (/usr/local/share/zsh/site-functions is probably a good start) and check if the completions get picked up for forgit as a git subcommand. If it does, I think we'd need to take a closer look of your zinit/.zshrc setup, if it does not my guess would be something to how compinit is called.

Gerrit-K commented 5 months ago

Hey, sorry for the delayed reply!

I think I've figured out what's happening. First of all, the reason why _git-add wasn't picked up, despite being in my $fpath was that .../zsh/functions/_git was shadowed by .../zsh/site-functions/_git. The former links to the completion installed by the zsh package whereas the latter links to a completion installed by git package. I found this out by luckily stumbling over this reddit post, where they suggest to simply remove the symlink from the git package. After that, the completions for git forgit <tab> worked correctly ✅

Next problem was to get the aliases working. When I source git-forgit.zsh from a fully loaded shell, everything seemed to be working. However, when I added that to my config, I got zsh: command not found: _git. Here, the issue was my zinit order. I roughly had this:

zi lucid for \
 completions \
 sbin'bin/*' \
 src'completions/git-forgit.zsh' \
    wfxr/forgit \
 atinit'zicompinit; zicdreplay' \
    zdharma-continuum/fast-syntax-highlighting

The idea (based on this example) was that:

However, git-forgit.zsh never actually got to the point of issuing compdef commands, because compinit was not yet called at this point, so _git was not available (triggering the cnf error from above).

I reordered the plugins so that forgit gets loaded immediately after syntax-highlighting, which fixed the cnf error, but the completions were still broken. This was due to zinit still suppressing and recording the compdef calls. So all that was missing was an additional zicdreplay command:

zi lucid for \
 atinit'zicompinit; zicdreplay' \
    zdharma-continuum/fast-syntax-highlighting
 completions \
 sbin'bin/*' \
 src'completions/git-forgit.zsh' \
 atload'zicdreplay' \
    wfxr/forgit \

With that, everything finally worked. It's not the most ideal solution and I'll probably continue working on it, but for now I'm happy that this case is solved.

I'm sorry to have bothered you with this, but I'm really grateful for your help, as I probably wouldn't have invested the time to fix this if you hadn't provided troubleshooting suggestions. Thank you!

Gerrit-K commented 4 months ago

Fwiw, the changes from #340 fixed all issues described above and zinit is now handling the single completion file perfectly well 👏

sandr01d commented 4 months ago

Nice, thanks for the info! Also thanks for the write-up, what an interesting edge case.