Files
NetworkManager/cli/completion/nmcli
Thomas Haller b5e2a45266 cli/bash-completion: update completion for new nmcli connection show syntax
As nmcli changes the syntax for the 'connection show' command,
this patch for bash completion also breaks several cases when
completing for an old nmcli command.

Signed-off-by: Thomas Haller <thaller@redhat.com>
2014-01-23 13:46:46 +01:00

956 lines
41 KiB
Bash

# nmcli(1) completion -*- shell-script -*-
# Originally based on
# https://github.com/GArik/bash-completion/blob/master/completions/nmcli
_nmcli_list()
{
COMPREPLY=( $( compgen -W '$1' -- $cur ) )
}
_nmcli_list_nl()
{
local IFS=$'\n'
COMPREPLY=( $( compgen -W '$1' -- $cur ) )
}
_nmcli_con_show()
{
nmcli -t -f "$1" connection show $2 2> /dev/null
}
_nmcli_wifi_list()
{
nmcli -t -f "$1" device wifi list 2>/dev/null
}
_nmcli_dev_status()
{
nmcli -t -f "$1" device status 2>/dev/null
}
_nmcli_array_has_value() {
# expects an array variable ARRAY defined and returns true
# if one of the arguments $@ is contained in ${ARRAY[@]}
local arg a
for arg; do
for a in "${ARRAY[@]}"; do
if [[ "$a" = "$arg" ]]; then
return 0
fi
done
done
return 1
}
# OPTIONS appear first at the command line (before the OBJECT).
# This iterates over the argument list and tries to complete
# the options. If there are options that are to be completed,
# zero is returned and completion will be performed.
# Otherwise it will remove all the option parameters from the ${words[@]}
# array and return with zero (so that completion of OBJECT can continue).
_nmcli_compl_OPTIONS()
{
local OPTIONS=( -t --terse -p --pretty -m --mode -f --fields -e --escape -n --nocheck -a --ask -w --wait -v --version -h --help )
local i REMOVE_OPTIONS
for (( ; ; )); do
if [[ "${#words[@]}" -le 1 ]]; then
# we show for completion either the (remaining) OPTIONS
# (if the current word starts with a dash) or the OBJECT list
# otherwise.
if [[ "${words[0]:0:1}" != '-' ]]; then
OPTIONS=(help general networking radio connection device)
fi
_nmcli_list "$(echo "${OPTIONS[@]}")"
return 0
fi
case "${words[0]}" in
-t|--terse)
REMOVE_OPTIONS=(-t --terse)
words=("${words[@]:1}")
;;
-p|--pretty)
REMOVE_OPTIONS=(-p --pretty)
words=("${words[@]:1}")
;;
-n|--nocheck)
REMOVE_OPTIONS=(-n --nocheck)
words=("${words[@]:1}")
;;
-a|--ask)
REMOVE_OPTIONS=(-a --ask)
words=("${words[@]:1}")
;;
-v|--version)
REMOVE_OPTIONS=(-v --version)
words=("${words[@]:1}")
;;
-h|--help)
REMOVE_OPTIONS=(-h --help)
words=("${words[@]:1}")
;;
-m|--mode)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "tabular multiline"
return 0
fi
REMOVE_OPTIONS=(-m --mode)
words=("${words[@]:2}")
;;
-f|--fields)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "all common
NAME UUID TYPE TIMESTAMP TIMESTAMP-REAL AUTOCONNECT READONLY DBUS-PATH ACTIVE DEVICE STATE ACTIVE-PATH
connection 802-3-ethernet 802-1x 802-11-wireless 802-11-wireless-security ipv4 ipv6 serial ppp pppoe gsm cdma bluetooth 802-11-olpc-mesh vpn wimax infiniband bond vlan adsl bridge bridge-port team team-port dcb
GENERAL IP4 DHCP4 IP6 DHCP6 VPN
profile active"
return 0
fi
REMOVE_OPTIONS=(-f --fields)
words=("${words[@]:2}")
;;
-e|--escape)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "no yes"
return 0
fi
REMOVE_OPTIONS=(-e --escape)
words=("${words[@]:2}")
;;
-w|--wait)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list ""
return 0
fi
REMOVE_OPTIONS=(-w --wait)
words=("${words[@]:2}")
;;
*)
# something unexpected. We are finished with parsing the OPTIONS.
return 1
;;
esac
# remove the options already seen.
for i in ${!OPTIONS[*]}; do
if [[ "${OPTIONS[$i]}" = "${REMOVE_OPTIONS[0]}" || "${OPTIONS[$i]}" = "${REMOVE_OPTIONS[1]}" ]]; then
unset OPTIONS[$i]
fi
done
done
}
# after the OPTIONS, the OBJECT, the COMMAND and possible the COMMAND_CONNECTION, the syntax for nmcli
# expects several options with parameters. This function can parse them and remove them from the words array.
_nmcli_compl_ARGS()
{
local OPTIONS_ALL N_REMOVE_WORDS REMOVE_OPTIONS OPTIONS_HAS_MANDATORY i
OPTIONS_ALL=("${OPTIONS[@]}")
OPTIONS_UNKNOWN_OPTION=
OPTIONS_HAS_MANDATORY=0
if [[ "${#OPTIONS_MANDATORY[@]}" -ge 1 ]]; then
OPTIONS_HAS_MANDATORY=1
fi
for (( ; ; )); do
if [[ "${#words[@]}" -le 1 ]]; then
# we have no more words left...
if [[ ${#OPTIONS[@]} -eq 0 ]]; then
return 1;
fi
if [[ "$COMMAND_ARGS_WAIT_OPTIONS" -ne 1 ]]; then
_nmcli_list "$(echo "${OPTIONS[@]}")"
return 0
fi
COMMAND_ARGS_WAIT_OPTIONS=0
return 1
fi
ARRAY=("${OPTIONS_ALL[@]}")
if ! _nmcli_array_has_value "${words[0]}"; then
# This is an entirely unknown option.
OPTIONS_UNKNOWN_OPTION="?${words[0]}"
return 1
fi
if [[ "$OPTIONS_HAS_MANDATORY" -eq 1 && "${#OPTIONS_MANDATORY[@]}" -eq 0 ]]; then
# we had some mandatory options, but they are all satisfied... stop here...
# This means, that we can continue with more additional options from the NEXT_GROUP.
return 1
fi
N_REMOVE_WORDS=2
REMOVE_OPTIONS=("${words[0]}")
case "${words[0]}" in
level)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "ERROR WARN INFO DEBUG"
return 0
fi
;;
domains)
if [[ "${#words[@]}" -eq 2 ]]; then
local OPTIONS_DOM=(ALL DEFAULT PLATFORM RFKILL ETHER WIFI BT MB DHCP4 DHCP6 PPP WIFI_SCAN IP4 IP6 AUTOIP4 DNS VPN SHARING SUPPLICANT AGENTS SETTINGS SUSPEND CORE DEVICE OLPC_MESH WIMAX INFINIBAND FIREWALL ADSL BOND VLAN BRIDGE DBUS_PROPS TEAM CONCHECK)
if [[ "${words[1]}" != "" ]]; then
# split the comma separaeted domain string into its parts LOGD
local oIFS="$IFS"
IFS=","
local LOGD=($(echo "${words[1]}" | sed 's/\(^\|,\)/,#/g'))
IFS="$oIFS"
unset oIFS
local LOGDLAST LOGDLAST_IS_OPTION LOGDI i
# first we iterate over all present domains and remove them from OPTIONS_DOM
for LOGDI in ${LOGD[@]}; do
LOGDI="${LOGDI:1}"
LOGDLAST="$LOGDI"
LOGDLAST_IS_OPTION=0
for i in ${!OPTIONS_DOM[*]}; do
if [[ "${OPTIONS_DOM[$i]}" = "$LOGDI" ]]; then
LOGDLAST_IS_OPTION=1
unset OPTIONS_DOM[$i]
fi
done
done
local OPTIONS_DOM2=()
if [[ "$LOGDLAST" = "" ]]; then
# we have a word that ends with ','. Just append all remaining options.
for i in ${!OPTIONS_DOM[*]}; do
OPTIONS_DOM2[${#OPTIONS_DOM2[@]}]="${words[1]}${OPTIONS_DOM[$i]}"
done
else
# if the last option is not "" we keep only those option with the same prefix
# as the last domain (LOGDLAST)
for i in ${!OPTIONS_DOM[*]}; do
if [[ "${OPTIONS_DOM[$i]:0:${#LOGDLAST}}" == "$LOGDLAST" ]]; then
# modify the option with the present prefix
OPTIONS_DOM2[${#OPTIONS_DOM2[@]}]="${words[1]}${OPTIONS_DOM[$i]:${#LOGDLAST}}"
fi
done
if [[ $LOGDLAST_IS_OPTION -eq 1 ]]; then
# if the last logd itself was a valid iption, ${words[1]} is itself a valid match
OPTIONS_DOM2[${#OPTIONS_DOM2[@]}]="${words[1]}"
# also, add all remaining options by comma separated to the word.
for i in ${!OPTIONS_DOM[*]}; do
OPTIONS_DOM2[${#OPTIONS_DOM2[@]}]="${words[1]},${OPTIONS_DOM[$i]}"
done
fi
if [[ ${#OPTIONS_DOM2[@]} -eq 1 ]]; then
for i in ${!OPTIONS_DOM[*]}; do
if [[ "$LOGDLAST" != "${OPTIONS_DOM[$i]:0:${#LOGDLAST}}" ]]; then
OPTIONS_DOM2[${#OPTIONS_DOM2[@]}]="${OPTIONS_DOM2[0]},${OPTIONS_DOM[$i]}"
fi
done
fi
fi
OPTIONS_DOM=(${OPTIONS_DOM2[@]})
fi
_nmcli_list "$(echo "${OPTIONS_DOM[@]}")"
return 0
fi
;;
type)
if [[ "$OPTIONS_TYPE" != "" ]]; then
return 1
fi
if [[ "${#words[@]}" -eq 2 ]]; then
if [[ "${words[1]:0:1}" = "8" ]]; then
# usually we don't want to show the 802-x types (because the shorter aliases are more
# user friendly. Only complete them, if the current word already starts with an "8".
_nmcli_list "802-3-ethernet 802-11-wireless 802-11-olpc-mesh"
else
_nmcli_list "ethernet wifi wimax gsm cdma infiniband bluetooth vpn olpc-mesh vlan bond bond-slave bridge bridge-slave team team-slave pppoe"
fi
return 0
fi
OPTIONS_TYPE="${words[1]}"
;;
master)
if [[ "${#words[@]}" -eq 2 ]]; then
if [[ "${words[1]}" = "" ]]; then
_nmcli_list_nl "$(_nmcli_dev_status DEVICE)"
else
_nmcli_list_nl "$(printf "%s\n%s\n%s" "$(_nmcli_dev_status DEVICE)" "$(_nmcli_con_show UUID)")"
fi
return 0
fi
;;
dev)
if [[ "${#words[@]}" -eq 2 ]]; then
if [[ "${words[1]}" = "" ]]; then
_nmcli_list_nl "$(_nmcli_dev_status DEVICE)"
else
_nmcli_list_nl "$(printf "%s\n%s\n%s" "$(_nmcli_dev_status DEVICE)" "$(_nmcli_wifi_list BSSID)" "$(_nmcli_con_show UUID)")"
fi
return 0
fi
;;
primary| \
ifname)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list_nl "$(_nmcli_dev_status DEVICE)"
return 0
fi
;;
mode)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "balance-rr active-backup balance-xor broadcast 802.3ad balance-tlb balance-alb"
return 0
fi
;;
transport-mode)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "datagram connected"
return 0
fi
;;
vpn-type)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "vpnc openvpn pptp openconnect openswan"
return 0
fi
;;
bt-type)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "panu dun-gsm dun-cdma"
return 0
fi
;;
wep-key-type)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "key phrase"
return 0
fi
;;
autoconnect| \
stp| \
hairpin| \
private)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "yes no"
return 0
fi
;;
config)
if [[ "${#words[@]}" -eq 2 ]]; then
compopt -o default
COMPREPLY=()
return 0
fi
;;
ip4| \
ip6| \
gw4| \
gw6| \
priority| \
forward-delay| \
hello-time| \
max-age| \
ageing-time| \
nsp| \
path-cost| \
name| \
mtu| \
cloned-mac| \
addr| \
parent| \
miimon| \
arp-interval| \
arp-ip-target| \
downdelay| \
updelay| \
p-key| \
mac| \
id| \
flags| \
ingress| \
dhcp-anycast| \
channel| \
egress| \
apn| \
con-name| \
user| \
username| \
service| \
password)
if [[ "${#words[@]}" -eq 2 ]]; then
return 0
fi
;;
ssid)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list_nl "$(_nmcli_wifi_list SSID)"
return 0
fi
;;
ap| \
bssid)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list_nl "$(_nmcli_wifi_list BSSID)"
return 0
fi
;;
*)
echo
echo "unexpected option. This is a bug in the completion. Check for \"${words[0]}\""
echo
return 1
;;
esac
if [[ "${#OPTIONS_NEXT_GROUP[@]}" -gt 0 ]]; then
ARRAY=("${OPTIONS_NEXT_GROUP[@]}")
if _nmcli_array_has_value "${words[0]}"; then
# the current value is from the next group...
# We back off, because the current group is complete.
return 1
fi
fi
words=("${words[@]:$N_REMOVE_WORDS}")
# remove the options already seen.
for i in ${!OPTIONS[*]}; do
if [[ "${OPTIONS[$i]}" = "${REMOVE_OPTIONS[0]}" || "${OPTIONS[$i]}" = "${REMOVE_OPTIONS[1]}" ]]; then
unset OPTIONS[$i]
fi
done
for i in ${!OPTIONS_MANDATORY[*]}; do
if [[ "${OPTIONS_MANDATORY[$i]}" = "${REMOVE_OPTIONS[0]}" || "${OPTIONS_MANDATORY[$i]}" = "${REMOVE_OPTIONS[1]}" ]]; then
unset OPTIONS_MANDATORY[$i]
fi
done
done
}
# some commands expect a connection as parameter. This connection can either be given
# as id|uuid|path|apath. Parse that connection parameter.
_nmcli_compl_ARGS_CONNECTION()
{
ARRAY=("${OPTIONS[@]}")
if ! _nmcli_array_has_value "${words[0]}"; then
COMMAND_CONNECTION_TYPE=
COMMAND_CONNECTION_ID="${words[0]}"
words=("${words[@]:1}")
return 1
fi
COMMAND_CONNECTION_TYPE="${words[0]}"
COMMAND_CONNECTION_ID="${words[1]}"
local CON_TYPE=
if [[ "x$COMMAND_CONNECTION_ACTIVE" != x ]]; then
CON_TYPE=--active
fi
case "${words[0]}" in
id)
if [[ ${#words[@]} -le 2 ]]; then
_nmcli_list_nl "$(_nmcli_con_show NAME $CON_TYPE)"
return 0
fi
words=("${words[@]:2}")
;;
uuid)
if [[ ${#words[@]} -le 2 ]]; then
_nmcli_list_nl "$(_nmcli_con_show UUID $CON_TYPE)"
return 0
fi
words=("${words[@]:2}")
;;
path)
if [[ ${#words[@]} -le 2 ]]; then
_nmcli_list_nl "$(_nmcli_con_show DBUS-PATH $CON_TYPE)"
return 0
fi
words=("${words[@]:2}")
;;
apath)
if [[ ${#words[@]} -le 2 ]]; then
_nmcli_list_nl "$(_nmcli_con_show ACTIVE-PATH --active)"
return 0
fi
words=("${words[@]:2}")
;;
ifname)
if [[ ${#words[@]} -le 2 ]]; then
_nmcli_list_nl "$(_nmcli_dev_status DEVICE)"
return 0
fi
words=("${words[@]:2}")
;;
*)
COMMAND_CONNECTION_TYPE=
COMMAND_CONNECTION_ID="${words[0]}"
words=("${words[@]:1}")
;;
esac
return 1
}
_nmcli_compl_COMMAND() {
local command="$1"
shift
if [[ "x${command:0:1}" == 'x-' ]]; then
_nmcli_list "-h --help"
else
_nmcli_list "help $*"
fi
}
_nmcli_compl_COMMAND_nl() {
local command="$1"
shift
if [[ "x${command:0:1}" == 'x-' ]]; then
_nmcli_list_nl "$(printf "%s-h\n--help\n%s" "" "$*")"
else
_nmcli_list_nl "$(printf "help\n%s" "$*")"
fi
}
_nmcli()
{
local cur prev words cword
_init_completion || return
# we don't care about any arguments after the current cursor position
# because we only parse from left to right. So, if there are some arguments
# right of the cursor, just ignore them. Also don't care about ${words[0]}.
words=("${words[@]:1:$cword}")
# _init_completion returns the words with all the quotes and escaping
# characters. We don't care about them, drop them at first.
for i in ${!words[*]}; do
words[i]="$(echo "${words[i]}" | xargs 2>/dev/null || true)"
done
# In case the cursor is not at the end of the line,
# $cur consists of spaces that we want do remove.
# For example: `nmcli connection modify id <TAB> lo`
if [[ "$cur" =~ ^[[:space:]]+ ]]; then
cur=''
fi
_nmcli_compl_OPTIONS && return 0
local command="${words[1]}"
local OPTIONS_UNKNOWN_OPTION OPTIONS_TYPE OPTIONS_TYPED OPTIONS OPTIONS_MANDATORY COMMAND_ARGS_WAIT_OPTIONS ARRAY OPTIONS_IP OPTIONS_MANDATORY OPTIONS_NEXT_GROUP
local COMMAND_CONNECTION_TYPE COMMAND_CONNECTION_ID
local COMMAND_CONNECTION_ACTIVE=""
case "${words[0]}" in
h|he|hel|help)
;;
g|ge|gen|gene|gener|genera|general)
if [[ ${#words[@]} -eq 2 ]]; then
_nmcli_compl_COMMAND "$command" status permissions logging hostname
elif [[ ${#words[@]} -gt 2 ]]; then
case "$command" in
ho|hos|host|hostn|hostna|hostnam|hostname)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" \
"$(printf '%s\n%s\n%s\n' \
"$(nmcli general hostname 2>/dev/null)" \
"$(cat /etc/hostname 2>/dev/null)" \
"$(hostnamectl status 2>/dev/null | sed -n '1s/^.\+hostname: \(.\+\)$/\1/p')" \
"$HOSTNAME")"
fi
;;
l|lo|log|logg|loggi|loggin|logging)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND "${words[2]}" level domains
else
words=("${words[@]:2}")
OPTIONS=(level domains)
_nmcli_compl_ARGS
fi
;;
esac
fi
;;
n|ne|net|netw|netwo|networ|network|networki|networkin|networking)
if [[ ${#words[@]} -eq 2 ]]; then
_nmcli_compl_COMMAND "$command" on off connectivity
elif [[ ${#words[@]} -eq 3 ]]; then
case "$command" in
c|co|con|conn|conne|connec|connect|connecti|connectiv|connectivi|connectivit|connectivity)
_nmcli_compl_COMMAND "${words[2]}" "check"
;;
esac
fi
;;
r|ra|rad|radi|radio)
if [[ ${#words[@]} -eq 2 ]]; then
_nmcli_compl_COMMAND "$command" all wifi wwan wimax
elif [[ ${#words[@]} -eq 3 ]]; then
case "$command" in
a|al|all | w|wi|wif|wifi | ww|wwa|wwan | wim|wima|wimax)
_nmcli_compl_COMMAND "${words[2]}" "on off"
;;
esac
fi
;;
c|co|con|conn|conne|connec|connect|connecti|connectio|connection)
if [[ ${#words[@]} -eq 2 ]]; then
_nmcli_compl_COMMAND "$command" show up down add modify edit delete reload load
elif [[ ${#words[@]} -gt 2 ]]; then
case "$command" in
s|sh|sho|show)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\napath\n--active\n%s" "$(_nmcli_con_show NAME)")"
elif [[ ${#words[@]} -gt 3 ]]; then
OPTIONS=(id uuid path apath)
words=("${words[@]:2}")
case "${words[0]}" in
--a|--ac|--act|--acti|--activ|--active)
COMMAND_CONNECTION_ACTIVE=1
words=("${words[@]:1}")
;;
esac
while [[ ${#words[@]} -gt 0 ]]; do
_nmcli_compl_ARGS_CONNECTION && return 0
done
if [[ "x$COMMAND_CONNECTION_ACTIVE" = x ]]; then
_nmcli_list_nl "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME)")"
else
_nmcli_list_nl "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME --active)")"
fi
fi
;;
u|up)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "ifname\nid\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")"
elif [[ ${#words[@]} -gt 3 ]]; then
local COMMAND_CONNECTION_TYPE=''
words=("${words[@]:2}")
OPTIONS=(ifname id uuid path)
_nmcli_compl_ARGS_CONNECTION && return 0
if [[ "$COMMAND_CONNECTION_TYPE" = "ifname" ]]; then
OPTIONS=(ap nsp)
else
OPTIONS=(ifname ap nsp)
fi
_nmcli_compl_ARGS
fi
;;
d|do|dow|down)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME --active)")"
elif [[ ${#words[@]} -gt 3 ]]; then
words=("${words[@]:2}")
OPTIONS=(id uuid path apath)
COMMAND_CONNECTION_ACTIVE=1
_nmcli_compl_ARGS_CONNECTION
fi
;;
a|ad|add)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND "${words[2]}" type ifname con-name autoconnect
elif [[ ${#words[@]} -gt 3 ]]; then
words=("${words[@]:2}")
OPTIONS_TYPE=
OPTIONS=(type ifname con-name autoconnect)
OPTIONS_MANDATORY=(type)
COMMAND_ARGS_WAIT_OPTIONS=1
_nmcli_compl_ARGS && return 0
ARRAY=("${OPTIONS[@]}")
if _nmcli_array_has_value "${OPTIONS_MANDATORY[@]}"; then
# we still have some missing mandatory options...
if [[ "$OPTIONS_UNKNOWN_OPTION" != '' ]]; then
ARRAY="${OPTIONS[@]}"
if ! _nmcli_array_has_value "${OPTIONS_UNKNOWN_OPTION:1}"; then
# if we encountered an unknown option while having mandatory
# options, just return.
return 0
fi
fi
_nmcli_list "$(echo "${OPTIONS[@]}")"
return 0
fi
OPTIONS_IP=(ip4 ip6 gw4 gw6)
OPTIONS_MANDATORY=()
case "$OPTIONS_TYPE" in
802-3|802-3-|802-3-e|802-3-et|802-3-eth|802-3-ethe|802-3-ether|802-3-ethern|802-3-etherne|802-3-ethernet| \
e|et|eth|ethe|ether|ethern|etherne|ethernet)
OPTIONS_TYPED=(mac cloned-mac mtu)
;;
802-11-w|802-11-wi|802-11-wir|802-11-wire|802-11-wirel|802-11-wirele|802-11-wireles|802-11-wireless| \
wif|wifi)
OPTIONS_TYPED=(ssid mac cloned-mac mtu)
OPTIONS_MANDATORY=(ssid)
;;
wim|wima|wimax)
OPTIONS_TYPED=(mac nsp)
;;
g|gs|gsm)
OPTIONS_TYPED=(apn user password)
OPTIONS_MANDATORY=(apn)
;;
c|cd|cdm|cdma)
OPTIONS_TYPED=(user password)
;;
i|in|inf|infi|infin|infini|infinib|infiniba|infiniban|infiniband)
OPTIONS_TYPED=(mac mtu transport-mode parent p-key)
;;
bl|blu|blue|bluet|blueto|bluetoo|bluetoot|bluetooth)
OPTIONS_TYPED=(addr bt-type)
;;
vl|vla|vlan)
OPTIONS_TYPED=(dev id flags ingress egress mtu)
OPTIONS_MANDATORY=(dev)
;;
bond)
OPTIONS_TYPED=(mode miimon downdelay updelay arp-interval arp-ip-target primary)
;;
bond-|bond-s|bond-sl|bond-sla|bond-slav|bond-slave)
OPTIONS_TYPED=(master)
OPTIONS_MANDATORY=(master)
OPTIONS_IP=()
;;
team)
OPTIONS_TYPED=(config)
;;
team-|team-s|team-sl|team-sla|team-slav|team-slave)
OPTIONS_TYPED=(master config)
OPTIONS_MANDATORY=(master)
OPTIONS_IP=()
;;
bridge)
OPTIONS_TYPED=(stp priority forward-delay hello-time max-age ageing-time)
;;
bridge-|bridge-s|bridge-sl|bridge-sla|bridge-slav|bridge-slave)
OPTIONS_TYPED=(master priority path-cost hairpin)
OPTIONS_MANDATORY=(master)
OPTIONS_IP=()
;;
vp|vpn)
OPTIONS_TYPED=(vpn-type user)
OPTIONS_MANDATORY=(vpn-type)
;;
802-11-o|802-11-ol|802-11-olp|802-11-olpc|802-11-olpc-|802-11-olpc-m|802-11-olpc-me|802-11-olpc-mes|802-11-olpc-mesh| \
o|ol|olp|olpc|olpc-|olpc-m|olpc-me|olpc-mes|olpc-mesh)
OPTIONS_TYPED=(ssid channel dhcp-anycast)
OPTIONS_MANDATORY=(ssid)
;;
p|pp|ppp|pppo|pppoe)
OPTIONS_TYPED=(username password service mtu mac)
OPTIONS_MANDATORY=(username)
;;
*)
# for an unknown connection type, we stop completion here
return 0
;;
esac
if [[ "$COMMAND_ARGS_WAIT_OPTIONS" -ne 1 ]]; then
# means, we are at the end of options. Nothing more to parse, just show
# what are the options now.
if [[ "${#OPTIONS_MANDATORY[@]}" -gt 0 ]]; then
_nmcli_list "$(echo "${OPTIONS[@]}") $(echo "${OPTIONS_TYPED[@]}")"
else
_nmcli_list "$(echo "${OPTIONS[@]}") $(echo "${OPTIONS_TYPED[@]}") $(echo "${OPTIONS_IP[@]}")"
fi
return 0
fi
if [[ "${#OPTIONS[@]}" -gt 0 ]]; then
# we still have some options from before, but no mandatory ones. Mix them with OPTIONS_TYPED
# and continue parsing the options...
OPTIONS=("${OPTIONS[@]}" "${OPTIONS_TYPED[@]}")
OPTIONS_NEXT_GROUP=("${OPTIONS_TYPED[@]}")
_nmcli_compl_ARGS && return 0
if [[ "$COMMAND_ARGS_WAIT_OPTIONS" -ne 1 ]]; then
# means, we are at the end of options. Nothing more to parse, just show
# what are the options now.
if [[ "${#OPTIONS_MANDATORY[@]}" -gt 0 ]]; then
_nmcli_list "$(echo "${OPTIONS[@]}")"
else
_nmcli_list "$(echo "${OPTIONS[@]}") $(echo "${OPTIONS_IP[@]}")"
fi
return 0
fi
if [[ "$OPTIONS_UNKNOWN_OPTION" != "" ]]; then
# there was an unknown option specified. Maybe we have to stop with the completion.
if [[ "${#OPTIONS_MANDATORY[@]}" -gt 0 ]]; then
# we have an unknown option, but still mandatory ones that must be fullfiled first.
return 0
fi
ARRAY=("${OPTIONS_IP[@]}")
if ! _nmcli_array_has_value "${OPTIONS_UNKNOWN_OPTION:1}"; then
# the unknown option is NOT an IP option.
return 0
fi
# The unknown option is an IP option, which is fine... continue...
fi
fi
OPTIONS=("${OPTIONS_TYPED[@]}")
OPTIONS_NEXT_GROUP=()
if [[ "${#OPTIONS_MANDATORY[@]}" -ge 1 ]]; then
# we have some mandatory options... don't check for IP options yet...
_nmcli_compl_ARGS && return 0
ARRAY=("${OPTIONS[@]}")
if _nmcli_array_has_value "${OPTIONS_MANDATORY[@]}"; then
_nmcli_list "$(echo "${OPTIONS[@]}")"
return 0
fi
if [[ "$OPTIONS_UNKNOWN_OPTION" != "" ]]; then
ARRAY=("${OPTIONS_IP[@]}")
if ! _nmcli_array_has_value "${OPTIONS_UNKNOWN_OPTION:1}"; then
# the unknown option is NOT an IP option.
return 0
fi
fi
fi
# no mandatory options... do final completion including IP options
OPTIONS=("${OPTIONS[@]}" "${OPTIONS_IP[@]}")
OPTIONS_NEXT_GROUP=("${OPTIONS_IP[@]}")
_nmcli_compl_ARGS && return 0
if [[ "$OPTIONS_UNKNOWN_OPTION" != "" ]]; then
return 0
fi
if [[ "$COMMAND_ARGS_WAIT_OPTIONS" -ne 1 ]]; then
# means, we are at the end of options. Nothing more to parse, just show
# what are the options now.
_nmcli_list "$(echo "${OPTIONS[@]}")"
return 0
fi
# process the last group of options, as the OPTIONS_TYPED are already handled...
OPTIONS=("${OPTIONS_IP[@]}")
OPTIONS_NEXT_GROUP=()
COMMAND_ARGS_WAIT_OPTIONS=0
_nmcli_compl_ARGS && return 0
fi
;;
e|ed|edi|edit)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\ntype\ncon-name\n%s" "$(_nmcli_con_show NAME)")"
elif [[ ${#words[@]} -gt 3 ]]; then
words=("${words[@]:2}")
if [[ "${words[0]}" = 'type' || "${words[0]}" = 'con-name' ]]; then
OPTIONS=(type con-name)
_nmcli_compl_ARGS
else
OPTIONS=(id uuid path apath)
_nmcli_compl_ARGS_CONNECTION
fi
fi
;;
m|mo|mod|modi|modif|modify)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")"
elif [[ ${#words[@]} -gt 3 ]]; then
words=("${words[@]:2}")
OPTIONS=(id uuid path apath)
_nmcli_compl_ARGS_CONNECTION && return 0
if [[ ${#words[@]} -le 1 ]]; then
_nmcli_list_nl "$(nmcli connection show "${COMMAND_CONNECTION_TYPE:-id}" "$COMMAND_CONNECTION_ID" 2>/dev/null | sed -n 's/^\([^:]\+\):.*/\1/p')"
fi
fi
;;
de|del|dele|delet|delete)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")"
elif [[ ${#words[@]} -gt 3 ]]; then
words=("${words[@]:2}")
OPTIONS=(id uuid path apath)
_nmcli_compl_ARGS_CONNECTION
fi
;;
l|lo|loa|load)
if [[ ${#words[@]} -gt 2 ]]; then
# we should also complete for help/--help, but who to mix that
# with file name completion?
compopt -o default
COMPREPLY=()
fi
;;
esac
fi
;;
d|de|dev|devi|devic|device)
if [[ ${#words[@]} -eq 2 ]]; then
_nmcli_compl_COMMAND "$command" status show connect disconnect wifi wimax
elif [[ ${#words[@]} -gt 2 ]]; then
case "$command" in
s|st|sta|stat|statu|status)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND "${words[2]}"
fi
;;
sh|sho|show| \
c|co|con|conn|conne|connec|connect| \
d|di|dis|disc|disco|discon|disconn|disconne|disconnec|disconnect)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(_nmcli_dev_status DEVICE)"
fi
;;
w|wi|wif|wifi)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND "${words[2]}" list connect rescan
else
case "${words[2]}" in
l|li|lis|list)
words=("${words[@]:3}")
OPTIONS=(ifname bssid)
_nmcli_compl_ARGS
;;
c|co|con|conn|conne|connec|connect)
if [[ ${#words[@]} -eq 4 ]]; then
if [[ "${words[3]}" = "" ]]; then
_nmcli_list_nl "$(_nmcli_wifi_list SSID)"
else
_nmcli_list_nl "$(printf "%s\n%s" "$(_nmcli_wifi_list SSID)" "$(_nmcli_wifi_list BSSID)")"
fi
else
words=("${words[@]:4}")
local OPTIONS=(password wep-key-type ifname bssid name private)
_nmcli_compl_ARGS
fi
;;
r|re|res|resc|resca|rescan)
words=("${words[@]:3}")
OPTIONS=(ifname)
_nmcli_compl_ARGS
;;
esac
fi
;;
wim|wima|wimax)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND "${words[2]}" list
else
case "${words[2]}" in
l|li|lis|list)
words=("${words[@]:3}")
OPTIONS=(ifname nsp)
_nmcli_compl_ARGS
;;
esac
fi
;;
esac
fi
;;
esac
return 0
} &&
complete -F _nmcli nmcli
# ex: ts=4 sw=4 et filetype=sh