zsh/.zsh_completion

# zsh/.zsh_completion -- completion system tweaks. Sourced from .zshrc
# after 'autoload -Uz compinit && compinit'.
#
# fzf-tab is loaded separately in the .zshrc because it needs to be last.

# Menu selection UI: arrow keys navigate, tab cycles, enter accepts.
zstyle ':completion:*' menu select
zstyle ':completion:*' group-name ''
zstyle ':completion:*' list-dirs-first true
zstyle ':completion:*' verbose true
zstyle ':completion:*' squeeze-slashes true

# Group results by completion type so files/options/functions do not mix.
zstyle ':completion:*:matches' group yes
zstyle ':completion:*:descriptions' format '%F{244}-- %d --%f'
zstyle ':completion:*:warnings'     format '%F{red}no matches%f'
zstyle ':completion:*:messages'     format '%F{244}%d%f'
zstyle ':completion:*:corrections'  format '%F{244}%d (errors: %e)%f'

# Case-insensitive, then partial, then substring matching. I use this
# order deliberately: exact-case wins when it can so I notice typos.
zstyle ':completion:*' matcher-list \
  'm:{a-zA-Z}={A-Za-z}' \
  'r:|[._-]=* r:|=*' \
  'l:|=* r:|=*'

# Cache expensive completions (e.g. kubectl api-resources, apt-cache).
zstyle ':completion:*' use-cache on
zstyle ':completion:*' cache-path "${XDG_CACHE_HOME:-$HOME/.cache}/zsh/zcompcache"
mkdir -p -- "${XDG_CACHE_HOME:-$HOME/.cache}/zsh"

# Hide from 'kill <tab>' the processes I cannot send signals to anyway.
zstyle ':completion:*:*:kill:*:processes' command \
  'ps -u $USER -o pid,user,comm -w -w'
zstyle ':completion:*:*:kill:*' menu yes select
zstyle ':completion:*:kill:*' force-list always

# Do not offer already-listed args again (cd foo foo bar).
zstyle ':completion:*' ignore-line yes

# SSH completion: pull hosts from known_hosts and ~/.ssh/config without
# leaking hashed entries.
_ssh_hosts=()
if [[ -r ~/.ssh/known_hosts ]]; then
  _ssh_hosts=(${(f)"$(awk '!/^[|#]/ { split($1,a,","); for (h in a) print a[h] }' ~/.ssh/known_hosts 2>/dev/null)"})
fi
if [[ -r ~/.ssh/config ]]; then
  _ssh_hosts+=(${(f)"$(awk '$1 == "Host" { for (i=2;i<=NF;i++) if ($i !~ /[*?]/) print $i }' ~/.ssh/config)"})
fi
zstyle ':completion:*:(ssh|scp|sftp|rsync):*' hosts $_ssh_hosts
zstyle ':completion:*:(ssh|scp|sftp|rsync):*' users off

# Sort suffix-ignored entries so `.git` and friends end up after real dirs.
zstyle ':completion:*:files' ignored-patterns \
  '*.o' '*.class' '*.pyc' '*.swp' '__pycache__' '.git'

# Tab-completion for 'sudo' should look up commands on $PATH, not just files.
zstyle ':completion:*:sudo:*' command-path /usr/local/sbin /usr/local/bin \
  /usr/sbin /usr/bin /sbin /bin

# Ctrl-space: accept the current menu selection and stay in the menu so I
# can build 'cd foo/bar/baz' from tabs alone.
bindkey -M menuselect '^@' accept-and-infer-next-history

# Remove the annoying "waiting for xxxxx" delay on sparsely populated menus.
zstyle ':completion:*' timeout 2