mattmc3 / antidote

https://getantidote.github.io - the cure to slow zsh plugin management
MIT License
855 stars 21 forks source link

`command not found: compdef` when using oh-my-zsh #186

Closed segevfiner closed 2 months ago

segevfiner commented 2 months ago

oh-my-zsh had a custom use oh-my-zsh command to handle the ZSH and ZSH_CACHE_DIR variables (Although they forgot to add $ZSH_CACHE_DIR/completions to the $fpath). It would be nice to document the correct code to properly use oh-my-zsh.

mattmc3 commented 2 months ago

oh-my-zsh had a custom use oh-my-zsh command

Are you referring to antigen?

mattmc3 commented 2 months ago

OMZ usage is covered in this discussion here: https://github.com/mattmc3/antidote/discussions/70

segevfiner commented 2 months ago

Thanks! 😃 Maybe you want to link this information somewhere more prominent? Like adding this info to the documentation site: https://getantidote.github.io/ ?

BTW, I'm hitting have command not found: compdef not defined when loading oh-my-zsh with those instructions...

I wonder what's the right way to handle this... antigen used to have a buggy feature (Which I had to fix and was never merged, as antigen is abandoned) to defer compdef calls like this, since you often load plugins before compinit and some try to call compdef directly instead of adding completion files to the fpath. Doesn't look like belak/zsh-utils path:completion handles this, and loading oh-my-zsh after compinit is likely to not work right either as it does add stuff to fpath as well...

/root/.cache/antidote/https-COLON--SLASH--SLASH-github.com-SLASH-ohmyzsh-SLASH-ohmyzsh/lib/directories.zsh:34: command not found: compdef
/root/.cache/antidote/https-COLON--SLASH--SLASH-github.com-SLASH-ohmyzsh-SLASH-ohmyzsh/plugins/git/git.plugin.zsh:101: command not found: compdef
/root/.cache/antidote/https-COLON--SLASH--SLASH-github.com-SLASH-ohmyzsh-SLASH-ohmyzsh/plugins/git/git.plugin.zsh:182: command not found: compdef
/root/.cache/antidote/https-COLON--SLASH--SLASH-github.com-SLASH-ohmyzsh-SLASH-ohmyzsh/plugins/git/git.plugin.zsh:209: command not found: compdef
/root/.cache/antidote/https-COLON--SLASH--SLASH-github.com-SLASH-ohmyzsh-SLASH-ohmyzsh/plugins/git/git.plugin.zsh:216: command not found: compdef
/root/.cache/antidote/https-COLON--SLASH--SLASH-github.com-SLASH-ohmyzsh-SLASH-ohmyzsh/plugins/git/git.plugin.zsh:246: command not found: compdef
/root/.cache/antidote/https-COLON--SLASH--SLASH-github.com-SLASH-ohmyzsh-SLASH-ohmyzsh/plugins/git/git.plugin.zsh:272: command not found: compdef
/root/.cache/antidote/https-COLON--SLASH--SLASH-github.com-SLASH-ohmyzsh-SLASH-ohmyzsh/plugins/git/git.plugin.zsh:286: command not found: compdef
/root/.cache/antidote/https-COLON--SLASH--SLASH-github.com-SLASH-ohmyzsh-SLASH-ohmyzsh/plugins/git/git.plugin.zsh:297: command not found: compdef
/root/.cache/antidote/https-COLON--SLASH--SLASH-github.com-SLASH-ohmyzsh-SLASH-ohmyzsh/plugins/git/git.plugin.zsh:308: command not found: compdef
/root/.cache/antidote/https-COLON--SLASH--SLASH-github.com-SLASH-ohmyzsh-SLASH-ohmyzsh/plugins/git/git.plugin.zsh:327: command not found: compdef

Actually I'll open this as a discussion so it gets more visibility...

mattmc3 commented 2 months ago

I have definitely implemented something similar in my Zephyr project to defer compdef calls until compinit is called. I should just publish that snippet as a plugin, but I lack testers to give me feedback as to whether this is sufficient. If we rename this issue as command not found: compdef when using OMZ, I can re-open and we can track.

If you wouldn't mind, try this snippet out before you load antidote. If it's working for you, we can simply make this a plugin and recommend that path since many people seem to have this same struggle:

# Define compinit placeholder functions (compdef) so we can queue up calls to compdef.
# That way when the real compinit is called, we can execute the queue.
typeset -gHa __my_compdef_queue=()
function compdef {
  (( $# )) || return
  local compdef_args=("${@[@]}")
  __my_compdef_queue+=("$(typeset -p compdef_args)")
}

# Wrap compinit temporarily so that when the real compinit call happens and compdef is defined,
# the queue of compdef calls is processed.
function compinit {
  unfunction compinit compdef &>/dev/null
  autoload -Uz compinit && compinit "$@"
  local typedef_compdef_args
  for typedef_compdef_args in $__my_compdef_queue; do
    eval $typedef_compdef_args
    compdef "$compdef_args[@]"
  done
  unset __my_compdef_queue
}
segevfiner commented 2 months ago

It seems to work using belak/zsh-utils path:completion. Would have been nice to have a plugin that handles all that for you so you can just include it at the start and will also call compinit at the end (Somehow... it needs to know when to call it, I think antigen used some hook to detect the first shown prompt or something)

mattmc3 commented 2 months ago

Yes, a hook something like: add-zsh-hook precmd my-compinit-runner where my-compinit-runner ensures compinit was run.

I'm going to publish a simple plugin called antidote-use-omz to bridge this gap. I hope to have it out later today. There's really no reason not to - there's enough OMZ users with antidote and people migrating from antigen that it's worth it. I can set $ZSH, $ZSH_CACHE_DIR, lazy-load libs as needed, queue up compdef calls, and defer run compinit - all the things you get by running oh-my-zsh.sh without the slowness. That's way better than adding complexity to antidote, making users of antidote read all the docs and do all that themselves piecemeal. Including mattmc3/antidote-use-omz at the top of .zsh_plugins.txt will become the recommended way to use OMZ with antidote.

segevfiner commented 2 months ago

Cool, but do note the deferred compinit/compdef can be useful without oh-my-zsh as well, for example nvm has this code:

# complete is a bash builtin, but recent versions of ZSH come with a function
# called bashcompinit that will create a complete in ZSH. If the user is in
# ZSH, load and run bashcompinit before calling the complete function.
if [[ -n ${ZSH_VERSION-} ]]; then
  # First calling compinit (only if not called yet!)
  # and then bashcompinit as mentioned by zsh man page.
  if ! command -v compinit > /dev/null; then
    autoload -U +X compinit && if [[ ${ZSH_DISABLE_COMPFIX-} = true ]]; then
      compinit -u
    else
      compinit
    fi
  fi
  autoload -U +X bashcompinit && bashcompinit
fi

complete -o default -F __nvm nvm

Which a deferred compinit will handle, so you might want a plugin that handles the deferred compinit which can be used standalone and is used by mattmc3/antidote-use-omz. Or some other variation of a recommended plugin to handle completions like you would have gotten from antigen.

EDIT: Plugins don't have dependencies though, so it might need to be published as part of the oh-my-zsh plugin and also separately to be usable that way...

segevfiner commented 2 months ago

Hmm actually, for stuff like nvm which isn't a zsh plugin and just calls compdef or complete (from bashcompinit), I can just move them after antidote, so I guess just having this inside mattmc3/antidote-use-omz will be enough.

segevfiner commented 2 months ago

I see you also have mattmc3/zephyr path:plugins/completion, but it does include some stuff that isn't strictly belak/zsh-utils path:completion + deferred compdef/compinit, like zsh-users/zsh-completions or extra completion files for starship...

mattmc3 commented 2 months ago

Zephyr has some of the features you need to use OMZ piecemeal (like deferred completions), but it's made more as a replacement for OMZ/Prezto rather than as a true compliment to it. It doesn't set $ZSH or $ZSH_CACHE_DIR which many plugins assume exist. It also doesn't have any way to tell you that you blew it and forgot to load a lib file required. I published use-omz yesterday. Give it a whirl. Feedback welcome.

An example project to demonstrate usage is here: https://github.com/getantidote/zdotdir/tree/ohmyzsh.