Fabric
Fabric copied to clipboard
[Feature request]: zsh autocompletion plugin
What do you need?
Can we have zsh_autocompletion for fabric commands?
Here is a quick pass. Feel free to enhance. https://gist.github.com/stuartsaunders/ac486fc23b1c97693435cff3d2a819e8
@stuartsaunders This Bash implementation in #659 may not run as fast as your statically defined zsh functions, but I think auto-completion should utilize fabric's builtin functionality to --listpatterns, --listmodels, --listcontexts, and --listsessions so that the lists don't get "stale" when new items are dynamically added.
Here's a working completion for ZSH.
I put this in ~/.zsh/completions/_fabric and have fpath=(~/.zsh/completions $fpath) in my ~/.zshrc
#compdef fabric
_fabric() {
local curcontext="$curcontext" state line
typeset -A opt_args
_arguments -C \
'(-p --pattern)'{-p,--pattern}'[Pattern]: :->patterns' \
'(-m --model)'{-m,--model}'[Model]: :->models' \
'(-C --context)'{-C,--context}'[Context]: :->contexts' \
'(--session)--session[Session]: :->sessions' \
'(-o --output)'{-o,--output}'[Output]: :->output' \
'*: :->args'
case $state in
patterns)
local -a patterns
patterns=( ${(f)"$(fabric --listpatterns)"} )
_describe 'patterns' patterns
;;
models)
local -a models
models=( ${(f)"$(fabric --listmodels | sed -En 's/^[[:blank:]]+\[[0-9]+\][[:blank:]]+(.+)$/\1/p')"} )
_describe 'models' models
;;
contexts)
local -a contexts
contexts=( ${(f)"$(fabric --listcontexts)"} )
[[ "$contexts" != *"No Contexts"* ]] && _describe 'contexts' contexts
;;
sessions)
local -a sessions
sessions=( ${(f)"$(fabric --listsessions)"} )
[[ "$sessions" != *"No Sessions"* ]] && _describe 'sessions' sessions
;;
output)
_files -/
;;
args)
local -a opts
opts=( ${(f)"$(fabric --help | sed -En 's/^[[:blank:]]+((-[a-zA-Z],)?[[:blank:]]--[a-z][-_a-zA-Z]+=?[[:blank:]]).*$/\1/p' | \
sed -E 's/[,=]//g;s/[[:blank:]]/\n/g;/^$/d;s/^(-[^-])/-\1/' | sort -f | sed -E 's/^-(-.)$/\1/')"} )
_describe 'options' opts
;;
esac
}
compdef _fabric fabric
Thanks, @natemccurdy! Extended this a bit to show descriptions of the arguments and improve formatting in the completions menu.
#compdef fabric
_fabric() {
###################################################################
# Enable extendedglob for advanced pattern matching (no PCRE)
###################################################################
setopt extendedglob
local curcontext="$curcontext" state line
typeset -A opt_args
###################################################################
# Gather lines from "fabric -h"
###################################################################
local -a options_with_desc
while IFS= read -r line; do
options_with_desc+=("$line")
done < <(
fabric -h |
sed -n '/Application Options:/,/Help Options:/p' |
grep -E '^( -| --)' |
sed 's/^ *//'
)
###################################################################
# Parse each line to extract short_opt, long_opt, and desc:
#
# short+long format: "-p, --pattern= Some description"
# long-only format: "--session= Some description"
###################################################################
local -a formatted_options=()
local -A seen_options
local short_opt long_opt desc
for line in "${options_with_desc[@]}"; do
# short+long
if [[ "$line" =~ '^-([^[:space:],]+),[[:space:]]*--([^[:space:]]+)[[:space:]]+(.*)$' ]]; then
short_opt=$match[1]
long_opt=$match[2]
desc=$match[3]
short_opt="-$short_opt"
long_opt="--$long_opt"
# long-only
elif [[ "$line" =~ '^(--[^[:space:]]+)[[:space:]]+(.*)$' ]]; then
short_opt=""
long_opt=$match[1]
desc=$match[2]
else
continue
fi
# Trim whitespace from description
desc="${desc## }"
desc="${desc%% }"
# Remove trailing '=' from long options if present
if [[ "$long_opt" == *= ]]; then
long_opt="${long_opt%=}"
fi
local key="$short_opt|$long_opt"
# Skip duplicate options to avoid redundancy in completions
[[ -n ${seen_options[$key]} ]] && continue
seen_options[$key]=1
################################################################
# Map options to sub-completions
################################################################
local argSpec=""
local base_opt="${long_opt#--}"
# Short options
case $short_opt in
-p) argSpec=":arg:->patterns" ;;
-m) argSpec=":arg:->models" ;;
-C) argSpec=":arg:->contexts" ;;
esac
# Long options
case $base_opt in
pattern) argSpec=":arg:->patterns" ;;
model) argSpec=":arg:->models" ;;
context) argSpec=":arg:->contexts" ;;
session) argSpec=":arg:->sessions" ;;
esac
# Add formatted options to the completion list
if [[ -n $short_opt ]]; then
if [[ -n $argSpec ]]; then
formatted_options+=( "${short_opt}[${desc}]${argSpec}" )
else
formatted_options+=( "${short_opt}[${desc}]" )
fi
fi
if [[ -n $argSpec ]]; then
formatted_options+=( "${long_opt}[${desc}]${argSpec}" )
else
formatted_options+=( "${long_opt}[${desc}]" )
fi
done
###################################################################
# _arguments sets up main completions, then sub-completions
# based on $state in the case statement below
###################################################################
_arguments -S -s \
"*::arg:->args" \
${formatted_options[@]}
###################################################################
# Sub-completion states
###################################################################
case $state in
patterns)
local -a patterns
patterns=( ${(f)"$(fabric --listpatterns 2>/dev/null)"} )
_describe 'patterns' patterns
;;
models)
local -a models
models=( ${(f)"$(fabric --listmodels 2>/dev/null | sed -En 's/^[[:blank:]]+\[[0-9]+\][[:blank:]]+(.+)$/\1/p')"} )
_describe 'models' models
;;
contexts)
local -a contexts
contexts=( ${(f)"$(fabric --listcontexts 2>/dev/null)"} )
[[ "$contexts" != *"No Contexts"* ]] && _describe 'contexts' contexts
;;
sessions)
local -a sessions
sessions=( ${(f)"$(fabric --listsessions 2>/dev/null)"} )
[[ "$sessions" != *"No Sessions"* ]] && _describe 'sessions' sessions
;;
esac
}
compdef _fabric fabric
I extended @KenMacD's recent fish completion script and added new updated scripts for zsh, fish and bash in the referenced PR. Comments welcome. Cheers!
Does the zsh auto-complete I just added in the PR close this issue, @samuk10 ?
https://github.com/user-attachments/assets/c322344a-b482-46cb-9089-6a2afc64cbca