Odysseus v1.0
This commit is contained in:
92
scripts/_completion/odysseus.bash
Normal file
92
scripts/_completion/odysseus.bash
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env bash
|
||||
# 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
|
||||
Reference in New Issue
Block a user