Parent directory

_juju

7961 bytes
  1#compdef juju
  2(( $+functions[compdef] )) && compdef _juju juju
  3
  4# zsh completion for juju                                  -*- shell-script -*-
  5
  6__juju_debug()
  7{
  8    local file="$BASH_COMP_DEBUG_FILE"
  9    if [[ -n ${file} ]]; then
 10        echo "$*" >> "${file}"
 11    fi
 12}
 13
 14__juju_help_options()
 15{
 16    local out line token cleaned desc f
 17    local -a opts pending
 18    typeset -U opts
 19
 20    __juju_debug "[options] called with args: $*"
 21    out=$(command juju help "$@" 2>/dev/null)
 22    local rc=$?
 23    __juju_debug "[options] juju help exit code: $rc, output length: ${#out}"
 24    (( rc )) && return 1
 25
 26    while IFS= read -r line; do
 27        if [[ "$line" =~ '^[[:space:]]{0,3}-' ]]; then
 28            for f in "${pending[@]}"; do opts+=("$f"); done
 29            pending=()
 30            for token in ${(z)line}; do
 31                cleaned="${token%%,*}"
 32                cleaned="${cleaned%%;*}"
 33                cleaned="${cleaned%%]*}"
 34                cleaned="${cleaned%%)*}"
 35                cleaned="${cleaned%%=<*}"
 36                cleaned="${cleaned%%=*}"
 37                cleaned="${cleaned%%<*}"
 38                cleaned="${cleaned%%\[*}"
 39                cleaned="${cleaned%%\(*}"
 40                [[ "$cleaned" == --* || "$cleaned" == -[[:alnum:]] ]] || continue
 41                [[ "$cleaned" == "-" || "$cleaned" == "--" ]] && continue
 42                __juju_debug "[options] found flag: $cleaned"
 43                pending+=("$cleaned")
 44            done
 45        elif (( ${#pending} )) && [[ -n "$line" ]]; then
 46            desc="${line#"${line%%[![:space:]]*}"}"
 47            desc="${desc//:/\\:}"
 48            __juju_debug "[options] desc for ${pending[*]}: $desc"
 49            for f in "${pending[@]}"; do opts+=("${f}:${desc}"); done
 50            pending=()
 51        elif [[ -z "$line" ]]; then
 52            for f in "${pending[@]}"; do opts+=("$f"); done
 53            pending=()
 54        fi
 55    done < <(printf "%s\n" "$out")
 56
 57    for f in "${pending[@]}"; do opts+=("$f"); done
 58    __juju_debug "[options] total opts: ${#opts}, first few: ${opts[1]} ${opts[2]} ${opts[3]}"
 59
 60    printf "%s\n" "${opts[@]}"
 61}
 62
 63
 64__juju_help_commands()
 65{
 66    local line cmd desc out
 67    out=$(command juju help commands 2>/dev/null) || return 1
 68
 69    while IFS= read -r line; do
 70        # Strip leading whitespace
 71        line="${line#"${line%%[![:space:]]*}"}"
 72        # Only process lines starting with an alphanumeric (command names)
 73        [[ "$line" =~ '^[[:alnum:]]' ]] || continue
 74        # Split on the first run of 2+ spaces: left = cmd, right = description
 75        cmd="${line%%  *}"
 76        # Validate it's a clean command token (no spaces, only alnum and dash)
 77        [[ "$cmd" =~ '^[[:alnum:]][[:alnum:]-]*$' ]] || continue
 78        desc="${line#"$cmd"}"
 79        desc="${desc#"${desc%%[![:space:]]*}"}"
 80        if [[ -n "$desc" ]]; then
 81            printf "%s:%s\n" "$cmd" "$desc"
 82        else
 83            printf "%s\n" "$cmd"
 84        fi
 85    done <<< "$out"
 86}
 87
 88__juju_models()
 89{
 90    # Optional argument: controller name. If given, fetch models for that controller.
 91    if [[ -n "$1" ]]; then
 92        command juju models -c "$1" --format=json 2>/dev/null \
 93            | command jq -r '.models[]."short-name"' 2>/dev/null
 94    else
 95        command juju models --format=json 2>/dev/null \
 96            | command jq -r '.models[]."short-name"' 2>/dev/null
 97    fi
 98}
 99
100# Complete a model token that may be prefixed with "controller:" — if a colon is
101# present, fetch models for that controller and offer "ctrl:model" completions.
102__juju_complete_model()
103{
104    local current="$1"
105    local -a completions
106
107    __juju_debug "[complete_model] current='${current}'"
108
109    if [[ "$current" == *:* ]]; then
110        local ctrl="${current%%:*}"
111        local models
112        models=("${(@f)$(__juju_models "$ctrl")}")
113        completions=("${models[@]/#/${ctrl}:}")
114        __juju_debug "[complete_model] ctrl=${ctrl} completions=${#completions}: ${completions[*]}"
115        compadd -S '' -q -- "${completions[@]}"
116    else
117        local -a models ctrls
118        models=("${(@f)$(__juju_models)}")
119        ctrls=("${(@f)$(__juju_controllers)}")
120        __juju_debug "[complete_model] models=${#models}: ${models[*]}"
121        __juju_debug "[complete_model] ctrls=${#ctrls}: ${ctrls[*]}"
122        __juju_debug "[complete_model] calling _alternative"
123        _alternative \
124            'models:models:{__juju_debug "[complete_model] compadd models"; compadd "$expl[@]" -a models}' \
125            'controllers:controllers:{__juju_debug "[complete_model] compadd ctrls"; compadd "$expl[@]" -S : -q -a ctrls}'
126        __juju_debug "[complete_model] _alternative returned $?"
127    fi
128}
129
130# Commands whose first positional argument is a model name.
131_juju_model_commands=(
132    destroy-model
133    grant-model
134    revoke-model
135    switch
136)
137
138# Flags that take a model name as their value.
139_juju_model_flags=(
140    -m
141    --model
142)
143
144__juju_controllers()
145{
146    command juju controllers --format=json 2>/dev/null \
147        | command jq -r '.controllers | keys | .[]' 2>/dev/null
148}
149
150# Commands whose first positional argument is a controller name.
151_juju_controller_commands=(
152    destroy-controller
153    kill-controller
154    login
155    logout
156    unregister
157)
158
159# Flags that take a controller name as their value.
160_juju_controller_flags=(
161    -c
162    --controller
163)
164
165_juju()
166{
167    __juju_debug "[_juju] curcontext: ${curcontext}"
168    local -a completions
169
170    __juju_debug "[_juju] words: ${words[*]}, CURRENT: $CURRENT"
171
172    # Find the subcommand: first non-flag word typed after "juju", excluding the
173    # word currently being completed (words[CURRENT]).
174    local subcmd=""
175    local i
176    for (( i = 2; i < CURRENT; i++ )); do
177        if [[ "${words[i]}" != -* ]]; then
178            subcmd="${words[i]}"
179            break
180        fi
181    done
182
183    local current="${words[CURRENT]}"
184    local prev="${words[CURRENT-1]}"
185
186    __juju_debug "[_juju] subcmd: '${subcmd}', current: '${current}', prev: '${prev}'"
187
188    # Controller name completion: flag value (e.g. juju status -c <TAB>)
189    if (( ${_juju_controller_flags[(I)$prev]} )); then
190        completions=("${(@f)$(__juju_controllers)}")
191        __juju_debug "[_juju] controller flag completions: ${#completions}"
192        (( ${#completions} )) && _describe "controller" completions && return 0
193        return 1
194    fi
195
196    # Model name completion: flag value (e.g. juju status -m <TAB> or -m ctrl:<TAB>)
197    if (( ${_juju_model_flags[(I)$prev]} )); then
198        __juju_debug "[_juju] model flag completion, current: '${current}'"
199        __juju_complete_model "$current" && return 0
200        return 1
201    fi
202
203    if [[ -z "$subcmd" ]]; then
204        # No subcommand yet — complete subcommand names.
205        completions=("${(@f)$(__juju_help_commands)}")
206        __juju_debug "[_juju] command completions count: ${#completions}"
207        (( ${#completions} )) && _describe "command" completions && return 0
208        return 1
209    fi
210
211    # Controller name completion: positional arg (e.g. juju destroy-controller <TAB>)
212    if (( ${_juju_controller_commands[(I)$subcmd]} )) && [[ "$current" != -* ]]; then
213        completions=("${(@f)$(__juju_controllers)}")
214        __juju_debug "[_juju] controller command completions: ${#completions}"
215        (( ${#completions} )) && _describe "controller" completions && return 0
216        return 1
217    fi
218
219    # Model name completion: positional arg (e.g. juju destroy-model <TAB> or ctrl:<TAB>)
220    if (( ${_juju_model_commands[(I)$subcmd]} )) && [[ "$current" != -* ]]; then
221        __juju_debug "[_juju] model command completion, current: '${current}'"
222        __juju_complete_model "$current" && return 0
223        return 1
224    fi
225
226    # Flag completion for all other subcommands (also shown without leading dash)
227    completions=("${(@f)$(__juju_help_options "$subcmd")}")
228    __juju_debug "[_juju] option completions count: ${#completions}"
229    (( ${#completions} )) && _describe "option" completions && return 0
230    return 1
231}