From 1ffce9ed20a17c59fdff8cc5443f60fe163984e0 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Mon, 3 Aug 2026 09:36:33 +0200 Subject: [PATCH] Add utility to generate shell completions --- .bash_completion | 3 + .local/bin/dotfiles-install | 4 + .local/bin/generate-shell-completions | 124 ++++++++++++++++++++++++++ .zshrc | 6 ++ 4 files changed, 137 insertions(+) create mode 100755 .local/bin/generate-shell-completions diff --git a/.bash_completion b/.bash_completion index f8628ad..daa5a4d 100644 --- a/.bash_completion +++ b/.bash_completion @@ -8,6 +8,9 @@ complete -W '--force' dotfiles-install dotfiles-update +complete -W '--quieter' generate-shell-completions + + # Automagical completion for all ~/.config/shell/aliases # # See: https://github.com/cykerway/complete-alias diff --git a/.local/bin/dotfiles-install b/.local/bin/dotfiles-install index 4eb1b13..6f4d997 100755 --- a/.local/bin/dotfiles-install +++ b/.local/bin/dotfiles-install @@ -134,6 +134,10 @@ if command -v batcat >/dev/null 2>&1 && ! command -v bat >/dev/null 2>&1; then fi +sh "$XDG_BIN_HOME/generate-shell-completions" --quieter \ + || echo "WARN: generating shell completions failed" >&2 + + # Keep only the most recent backups _keep=10 if [ -d "$BACKUPS_DIR" ]; then diff --git a/.local/bin/generate-shell-completions b/.local/bin/generate-shell-completions new file mode 100755 index 0000000..176ff21 --- /dev/null +++ b/.local/bin/generate-shell-completions @@ -0,0 +1,124 @@ +#!/bin/sh + +# Generate shell completions for various tools into the XDG data directories, +# so that they are loaded lazily instead of `eval`ed on every shell start +# +# Run this after installing or updating any of the tools below + +set -eu + + + +XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}" +XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}" + +BASH_DIR="$XDG_DATA_HOME/bash-completion/completions" +ZSH_DIR="$XDG_DATA_HOME/zsh/completions" + + + +case "${1:-}" in + "") _quieter=0 ;; + --quieter) _quieter=1 ;; + *) + echo "Usage: $(basename "$0") [--quieter]" >&2 + exit 1 + ;; +esac + + + +# We consider these folders owned by this script and +# regenerate them deterministically on each run +# => Never place completion files here manually +rm -rf "$BASH_DIR" "$ZSH_DIR" + +mkdir -p "$BASH_DIR" "$ZSH_DIR" + + + +_command_exists() { + command -v "$1" 1>/dev/null 2>&1 +} + + + +# Write to a temporary file first, +# so that a failing tool does not leave a truncated completion file +_generate() { + _name="$1" + _target="$2" + shift 2 + + if "$@" > "$_target.tmp" 2>/dev/null && [ -s "$_target.tmp" ]; then + mv "$_target.tmp" "$_target" + echo " $_name" + else + rm -f "$_target.tmp" + echo " $_name => FAILED" >&2 + fi +} + + + +echo "Generating bash completions in: $BASH_DIR" + + +_command_exists pip \ + && _generate pip "$BASH_DIR/pip" pip completion --bash + + +_command_exists register-python-argcomplete \ + && _command_exists pipx \ + && _generate pipx "$BASH_DIR/pipx" register-python-argcomplete pipx + + +_command_exists poetry \ + && _generate poetry "$BASH_DIR/poetry" poetry completions bash + + + +echo "Generating zsh completions in: $ZSH_DIR" + + +_strip_leading_blanks() { "$@" | sed '/./,$!d'; } + + +_pip_zsh() { + pip completion --zsh | sed -n '/^#compdef/,$p' +} + + +_pipx_zsh() { + _strip_leading_blanks register-python-argcomplete --shell zsh pipx +} + + +_poetry_zsh() { + _strip_leading_blanks poetry completions zsh +} + + +_command_exists pip \ + && _generate pip "$ZSH_DIR/_pip" _pip_zsh + + +_command_exists register-python-argcomplete \ + && _command_exists pipx \ + && _generate pipx "$ZSH_DIR/_pipx" _pipx_zsh + + +_command_exists poetry \ + && _generate poetry "$ZSH_DIR/_poetry" _poetry_zsh + + +rm -f "$XDG_STATE_HOME/zsh/zcompdump"* + + + +if [ "$_quieter" -ne 1 ]; then + echo "" + echo "Reload your shell to use them:" + echo " exec \$SHELL -l" + echo "" +fi diff --git a/.zshrc b/.zshrc index 249a1c1..5814642 100644 --- a/.zshrc +++ b/.zshrc @@ -63,12 +63,18 @@ stty -ixon # Prevent s from freezing `zsh` # Enable (tab) completions +# Look for completion files generated by ~/.local/bin/generate-shell-completions +fpath=("${XDG_DATA_HOME:-$HOME/.local/share}/zsh/completions" $fpath) + # "-u" disables the ownership check on completion dirs, which is safe since only we write to them autoload -Uz compinit && compinit -u -d "${XDG_STATE_HOME:-$HOME/.local/state}/zsh/zcompdump" # Complete the `--force` flag of the `dotfiles` utilities in ~/.local/bin compdef '_arguments "--force[skip safety checks / reinstall]"' dotfiles-install dotfiles-update +# Complete the `--quieter` flag of the `generate-shell-completions` utility in ~/.local/bin +compdef '_arguments "--quieter[suppress the reload hint]"' generate-shell-completions + # Enable match highlighting and scrolling through long lists, # and provide a different style of menu completion zmodload zsh/complist