Spaces:
Runtime error
Runtime error
| # Tab-completion for the `odysseus` umbrella + every `odysseus-*` CLI. | |
| # | |
| # Source from your shell rc: | |
| # source /path/to/odysseus-ui/scripts/_completion/odysseus.bash | |
| # | |
| # Or wire it once per machine: | |
| # sudo install -m 644 odysseus.bash /etc/bash_completion.d/odysseus | |
| # | |
| # What it does: | |
| # - On the first word after `odysseus`, complete with the list of | |
| # subcommands (`mail`, `calendar`, ...). | |
| # - On subsequent words, complete with the subcommand's first-token | |
| # subcommands (`list`, `show`, ...) which we cache by parsing the | |
| # tool's own --help output. Updates lazily; refresh by running | |
| # `_odysseus_refresh_cache`. | |
| # - Same completion works for the individual `odysseus-foo` scripts. | |
| _odysseus_scripts_dir() { | |
| # Resolve the scripts/ dir from the script that sources us. We assume | |
| # the user sourced the file directly out of scripts/_completion/. | |
| local self="${BASH_SOURCE[0]}" | |
| while [ -L "$self" ]; do self=$(readlink "$self"); done | |
| cd "$(dirname "$self")/.." && pwd | |
| } | |
| declare -A _ODYSSEUS_SUBS_CACHE=() | |
| _odysseus_refresh_cache() { | |
| local dir="$(_odysseus_scripts_dir)" | |
| _ODYSSEUS_SUBS_CACHE=() | |
| # Prefer the project venv's Python so deps (bcrypt, sqlalchemy, ...) | |
| # resolve. Falls back to system `python3` for container installs. | |
| local py="$dir/../venv/bin/python" | |
| [ -x "$py" ] || py="$(command -v python3)" | |
| local f | |
| for f in "$dir"/odysseus-*; do | |
| [ -x "$f" ] || continue | |
| case "$f" in *.bak|*.pyc|*.pre-*) continue ;; esac | |
| local name="$(basename "$f")" | |
| local sub="${name#odysseus-}" | |
| local help_out | |
| help_out=$("$py" "$f" --help 2>/dev/null) || continue | |
| local commands | |
| commands=$(echo "$help_out" | grep -oE '\{[a-z0-9_,-]+\}' | head -1 \ | |
| | tr -d '{}' | tr ',' ' ') | |
| _ODYSSEUS_SUBS_CACHE[$sub]="$commands" | |
| done | |
| } | |
| _odysseus_complete() { | |
| [ ${#_ODYSSEUS_SUBS_CACHE[@]} -eq 0 ] && _odysseus_refresh_cache | |
| local cur="${COMP_WORDS[COMP_CWORD]}" | |
| local cmd="${COMP_WORDS[0]}" | |
| # `odysseus <tab>` → list every subcommand | |
| if [ "$cmd" = "odysseus" ]; then | |
| if [ "$COMP_CWORD" -eq 1 ]; then | |
| local subs="${!_ODYSSEUS_SUBS_CACHE[@]} help" | |
| COMPREPLY=($(compgen -W "$subs" -- "$cur")) | |
| return 0 | |
| fi | |
| # `odysseus foo <tab>` — complete with foo's own subcommands | |
| local sub="${COMP_WORDS[1]}" | |
| # `odysseus help <tab>` lists every subcommand | |
| if [ "$sub" = "help" ] && [ "$COMP_CWORD" -eq 2 ]; then | |
| COMPREPLY=($(compgen -W "${!_ODYSSEUS_SUBS_CACHE[*]}" -- "$cur")) | |
| return 0 | |
| fi | |
| if [ "$COMP_CWORD" -eq 2 ]; then | |
| COMPREPLY=($(compgen -W "${_ODYSSEUS_SUBS_CACHE[$sub]}" -- "$cur")) | |
| return 0 | |
| fi | |
| return 0 | |
| fi | |
| # Direct `odysseus-foo <tab>` (no umbrella) | |
| local sub="${cmd#odysseus-}" | |
| if [ "$COMP_CWORD" -eq 1 ]; then | |
| COMPREPLY=($(compgen -W "${_ODYSSEUS_SUBS_CACHE[$sub]}" -- "$cur")) | |
| return 0 | |
| fi | |
| } | |
| # Register the completion for every odysseus-* script + the umbrella. | |
| complete -F _odysseus_complete odysseus | |
| for f in "$(_odysseus_scripts_dir)"/odysseus-*; do | |
| [ -x "$f" ] || continue | |
| case "$f" in *.bak|*.pyc|*.pre-*) continue ;; esac | |
| complete -F _odysseus_complete "$(basename "$f")" | |
| done | |