zsh completion difference - zsh

I have seen many do this
autoload -Uz compinit
compinit
and others do this
autoload -U compinit
compinit -i
I would like to know the difference. which one should I use?

autoload, from man zshbuiltins:
The flags -z and -k mark the function to be autoloaded in native or ksh emulation, as if the option KSH_AUTOLOAD were unset or were set, respectively.
The -U flag can be traced back: autoload is equivalent to function -u, which is equivalent to typeset -f. typeset, in a nutshell, is used to:
Set or display attributes and values for shell parameters.
When -f is used in combination with -U:
[The -f flag causes] The names refer to functions rather than parameters. ... The -u and -U flags cause the function to be marked for autoloading; -U also causes alias expansion to be suppressed when the function is loaded.
compinit is the completion initialization function used by compsys, the 'newer' Z-Shell completion system. See man zshcompsys for details.
The -i flag is used to:
to make compinit silently ignore all insecure files and directories use the option -i
In general, you should be using autoload -Uz, according to this interesting read.

Related

Where should I put miscellaneous shell commands in zsh?

I use zsh with Oh My Zsh for easy theme configuration.
Where should I put miscellaneous commands, like brew and auto-completion?
if [[ -x "/opt/homebrew/bin/brew" ]]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
fi
if type brew &>/dev/null; then
FPATH=$(brew --prefix)/share/zsh-completions:$FPATH
autoload -Uz compinit
compinit
fi
source <(kubectl completion zsh)
I thought of using ~/.zprofile, but it's sourced before ~/.zshrc, and so source <(kubectl completion zsh) doesn't work (why?).

Zsh inherit xtrace option

Similar to this question: bash recursive xtrace, but for Zsh.
How can I make all the Zsh subshells inherit the xtrace option?
For example, if script1.sh is calling ./script2.sh and I run zsh -x script1.sh, I want script2.sh to also have the xtrace mode enabled.
For Bash, the answer is to export the SHELLOPTS variable.
Is there a solution for Zsh?
You can take advantage of startup/shutdown files in Zsh (see man zshall): Zsh will always read (and execute) the file $ZDOTDIR/.zshenv at startup (if ZDOTDIR is unset, HOME is used instead). So you can put set -x in $ZDOTDIR/.zshenv and every Zsh script will run with xtrace mode enabled.
This is how I used it in a script:
env_dir="$(mktemp -d)"
echo "set -x" > "${env_dir}/.zshenv"
export ZDOTDIR="${env_dir}"
zsh "$#"
unset ZDOTDIR
rm -rf "${env_dir}"
In fact, this solution can be used for Bash as well, using the BASH_ENV variable, which points to a file that will, similarly, be executed when Bash starts.

What's the difference between -a and -e in a zsh conditional expression?

I was looking up the meaning of flags like -a in zsh if statements, eg.
if [[ -a file.txt ]]; do
# do something
fi
and I found this
-a file
true if file exists.
-e file
true if file exists.
What is the difference between -a and -e? And if there is none, why do they both exist?
POSIX sheds some light on this.
tl;dr: Ksh traditionally used -a and several other shells followed suit. POSIX instead borrowed -e from Csh to avoid confusion. Now many shells support both.
The -e primary, possessing similar functionality to that provided by the C shell, was added because it provides the only way for a shell script to find out if a file exists without trying to open the file. Since implementations are allowed to add additional file types, a portable script cannot use:
test -b foo -o -c foo -o -d foo -o -f foo -o -p foo
to find out if foo is an existing file. On historical BSD systems, the existence of a file could be determined by:
test -f foo -o -d foo
but there was no easy way to determine that an existing file was a regular file. An early proposal used the KornShell -a primary (with the same meaning), but this was changed to -e because there were concerns about the high probability of humans confusing the -a primary with the -a binary operator.

compadd failure during optparse-applicative zsh completion script

So I'm not exactly sure whether this is something wrong with optparse-applicative's script or if I'm using it wrong.
In the optparse-applicative readme, it states that programs are made available with automatic completion scripts, with options for zsh. For my program setup:
$> setup --zsh-completion-script `which setup`
Outputs:
#compdef setup
local request
local completions
local word
local index=$((CURRENT - 1))
request=(--bash-completion-enriched --bash-completion-index $index)
for arg in ${words[#]}; do
request=(${request[#]} --bash-completion-word $arg)
done
IFS=$'\n' completions=($( /Users/anrothan/.local/bin/setup "${request[#]}" ))
for word in $completions; do
local -a parts
# Split the line at a tab if there is one.
IFS=$'\t' parts=($( echo $word ))
if [[ -n $parts[2] ]]; then
if [[ $word[1] == "-" ]]; then
local desc=("$parts[1] ($parts[2])")
compadd -d desc -- $parts[1]
else
local desc=($(print -f "%-019s -- %s" $parts[1] $parts[2]))
compadd -l -d desc -- $parts[1]
fi
else
compadd -f -- $word
fi
done
I'm running the following in my zshrc (I use oh-my-zsh, but I removed it and this still happens in a bare-minimum config with only a small PATH addition to get the setup script).
autoload -U +X compinit && compinit
autoload -U +X bashcompinit && bashcompinit
source <(setup --zsh-completion-script `which setup`)
I get the following error several times:
/dev/fd/11:compadd:24: can only be called from completion function
I've run compinit, and the completion script seems to look right to me, and I've looked around but I can't seem to figure out why this error is happening...
You don't need to source zsh-completion scripts, they just need to be added to your fpath parameter.
So just place the output of setup --zsh-completion-script $(which setup) in a file call _setup in $HOME/.config/zsh/completions.
fpath=($HOME/.config/zsh/completions $fpath)
autoload -U compinit && compinit

Using zsh's compdef or compctl to complete a certain directory with _hosts for all commands

I use afuse to automount other hosts to my local file system with sshfs. Like so:
afuse -o timeout=30 -o mount_template=sshfs -C %r:/ %m -o unmount_template=fusermount -u -z %m ~/remote/
This works great, but I would like to be able to autocomplete/TAB commands using my ~/remote directory. Zsh understandably thinks ~/remote is empty, since afuse is a magical virtual FUSE file system. Once I have typed the host manually the subdirectories work fine. E.g ~/remote/host/[TAB] works fine.
Most zsh compdef tutorials focus on building a custom completer for your custom command. That is not quite what I want.
I have been trying to use compdef to override the completion of that particular directory to my hosts file (using the built-in _hosts completion function), but as far as I understand, compdef works on a per-command-basis. I want my completer to work on all commands trying to do a normal file/directory-complete on that directory.
It feels like it is so basic, that it is a one-liner, if only I knew how. How can I do this?
Add the following to your ~.zshrc file (or paste it into the command line, to try it out):
autoload -Uz compinit && compinit
bindkey '^I' complete-word
zstyle -e ':completion:*' fake-files _fake_files
_fake_files() {
[[ $PWD/$PREFIX$SUFFIX == ~/remote/ ]] &&
ISUFFIX=/
reply=(
~/remote:${(j: :v)${(s: :)${(ps:\t:)${${(f)~~"$(
< /etc/hosts
)"}%%\#*}##[:blank:]#[^[:blank:]]#}}}
)
}
I tried this and it works. I took the long parameter expansion from _host's source code.

Resources