Files
NetworkManager/clients/cli/nmcli-completion
Dan Winship 3d25d70461 clients: reorganize source tree, put all the installed clients together
Create a new clients/ subdirectory at the top level, and move cli/ and
tui/ into it, as well as nm-online.c (which was previously in test/,
which made no sense).

cli/ was split into two subdirectories, src/ and completion/. While
this does simplify things (given that the completion file and the
binary both need to be named "nmcli"), it bloats the source tree, and
we can work around it by just renaming the completion file at install
time. Then we can combine the two directories into one and just have
it all under clients/cli/.
2014-07-30 15:56:19 -04:00

1238 lines
51 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 ) )
# Now escape special characters (spaces, single and double quotes),
# so that the argument is really regarded a single argument by bash.
# See http://stackoverflow.com/questions/1146098/properly-handling-spaces-and-quotes-in-bash-completion
local escaped_single_quote="'\''"
local i=0
local entry
for entry in ${COMPREPLY[*]}
do
if [[ "${cur:0:1}" == "'" ]]; then
# started with single quote, escaping only other single quotes
# [']bla'bla"bla\bla bla --> [']bla'\''bla"bla\bla bla
COMPREPLY[$i]="${entry//\'/${escaped_single_quote}}"
elif [[ "${cur:0:1}" == '"' ]]; then
# started with double quote, escaping all double quotes and all backslashes
# ["]bla'bla"bla\bla bla --> ["]bla'bla\"bla\\bla bla
entry="${entry//\\/\\\\}"
entry="${entry//\"/\\\"}"
COMPREPLY[$i]="$entry"
else
# no quotes in front, escaping _everything_
# [ ]bla'bla"bla\bla bla --> [ ]bla\'bla\"bla\\bla\ bla
entry="${entry//\\/\\\\}"
entry="${entry//\'/\'}"
entry="${entry//\"/\\\"}"
entry="${entry// /\\ }"
COMPREPLY[$i]="$entry"
fi
(( i++ ))
done
}
_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 the name of an array as first parameter and
# returns true if if one of the remaining arguments is
# contained in the array ${$1[@]}
eval "local ARRAY=(\"\${$1[@]}\")"
local arg a
shift
for arg; do
for a in "${ARRAY[@]}"; do
if [[ "$a" = "$arg" ]]; then
return 0
fi
done
done
return 1
}
_nmcli_array_delete_at()
{
eval "local ARRAY=(\"\${$1[@]}\")"
local i
local tmp=()
local lower=$2
local upper=${3:-$lower}
# for some reason the following fails. So this clumsy workaround...
# A=(a "")
# echo " >> ${#A[@]}"
# >> 2
# A=("${A[@]:1}")
# echo " >> ${#A[@]}"
# >> 0
# ... seriously???
for i in "${!ARRAY[@]}"; do
if [[ "$i" -lt "$2" || "$i" -gt "${3-$2}" ]]; then
tmp=("${tmp[@]}" "${ARRAY[$i]}")
fi
done
eval "$1=(\"\${tmp[@]}\")"
}
_nmcli_compl_match_option()
{
local S="$1"
local V
shift
if [[ "${S:0:2}" == "--" ]]; then
S="${S:2}"
elif [[ "${S:0:1}" == "-" ]]; then
S="${S:1}"
fi
for V; do
case "$V" in
"$S"*)
printf "%s" "$V"
return 0
;;
esac
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 i W
for (( ; ; )); do
if [[ "${#words[@]}" -le 1 ]]; then
return 1
fi
W="$(_nmcli_compl_match_option "${words[0]}" "${LONG_OPTIONS[@]}")"
if [[ $? != 0 ]]; then
return 2
fi
# remove the options already seen.
for i in ${!LONG_OPTIONS[@]}; do
if [[ "${LONG_OPTIONS[$i]}" == "$W" ]]; then
_nmcli_array_delete_at LONG_OPTIONS $i
break
fi
done
if [[ "$HELP_ONLY_AS_FIRST" == '1' ]]; then
for i in ${!LONG_OPTIONS[@]}; do
if [[ "${LONG_OPTIONS[$i]}" == "help" ]]; then
_nmcli_array_delete_at LONG_OPTIONS $i
break
fi
done
fi
case "$W" in
terse)
_nmcli_array_delete_at words 0
;;
pretty)
_nmcli_array_delete_at words 0
;;
nocheck)
_nmcli_array_delete_at words 0
;;
ask)
_nmcli_array_delete_at words 0
;;
active)
_nmcli_array_delete_at words 0
;;
version)
_nmcli_array_delete_at words 0
;;
help)
_nmcli_array_delete_at words 0
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
HELP_ONLY_AS_FIRST=0
return 0
fi
HELP_ONLY_AS_FIRST=0
;;
temporary)
_nmcli_array_delete_at words 0
;;
mode)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "tabular multiline"
return 0
fi
_nmcli_array_delete_at words 0 1
;;
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
_nmcli_array_delete_at words 0 1
;;
escape)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "no yes"
return 0
fi
_nmcli_array_delete_at words 0 1
;;
wait)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list ""
return 0
fi
_nmcli_array_delete_at words 0 1
;;
*)
# something unexpected. We are finished with parsing the OPTIONS.
return 2
;;
esac
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
if ! _nmcli_array_has_value OPTIONS_ALL "${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 "ERR 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 WIMAX INFINIBAND FIREWALL ADSL BOND VLAN BRIDGE DBUS_PROPS TEAM CONCHECK DCB DISPATCH)
if [[ "${words[1]}" != "" ]]; then
# split the comma separaeted domain string into its parts LOGD
local oIFS="$IFS"
IFS=","
local LOGD=($(printf '%s' "${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]}"
if [[ "x$OPTIONS_MANDATORY_IFNAME" != x ]]; then
# the ifname is not a mandatory option for a few connection types...
# Check, if we have such a 'type' and remove the 'ifname' from the list
# of mandatory options.
case "$OPTIONS_TYPE" in
vl|vla|vlan| \
bond| \
team| \
bridge)
for i in ${!OPTIONS_MANDATORY[*]}; do
if [[ "${OPTIONS_MANDATORY[$i]}" = "ifname" ]]; then
unset OPTIONS_MANDATORY[$i]
fi
done
;;
*)
;;
esac
OPTIONS_MANDATORY_IFNAME=
fi
;;
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 libreswan ssh l2tp iodine"
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| \
save| \
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
;;
*)
return 1
;;
esac
if [[ "${#OPTIONS_NEXT_GROUP[@]}" -gt 0 ]]; then
if _nmcli_array_has_value OPTIONS_NEXT_GROUP "${words[0]}"; then
# the current value is from the next group...
# We back off, because the current group is complete.
return 1
fi
fi
_nmcli_array_delete_at words 0 $((N_REMOVE_WORDS-1))
# 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()
{
if ! _nmcli_array_has_value OPTIONS "${words[0]}"; then
COMMAND_CONNECTION_TYPE=
COMMAND_CONNECTION_ID="${words[0]}"
_nmcli_array_delete_at words 0
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
_nmcli_array_delete_at words 0 1
;;
uuid)
if [[ ${#words[@]} -le 2 ]]; then
_nmcli_list_nl "$(_nmcli_con_show UUID $CON_TYPE)"
return 0
fi
_nmcli_array_delete_at words 0 1
;;
path)
if [[ ${#words[@]} -le 2 ]]; then
_nmcli_list_nl "$(_nmcli_con_show DBUS-PATH $CON_TYPE)"
return 0
fi
_nmcli_array_delete_at words 0 1
;;
apath)
if [[ ${#words[@]} -le 2 ]]; then
_nmcli_list_nl "$(_nmcli_con_show ACTIVE-PATH --active)"
return 0
fi
_nmcli_array_delete_at words 0 1
;;
ifname)
if [[ ${#words[@]} -le 2 ]]; then
_nmcli_list_nl "$(_nmcli_dev_status DEVICE)"
return 0
fi
_nmcli_array_delete_at words 0 1
;;
*)
COMMAND_CONNECTION_TYPE=
COMMAND_CONNECTION_ID="${words[0]}"
_nmcli_array_delete_at words 0
;;
esac
return 1
}
_nmcli_compl_COMMAND() {
local command="$1"
shift
local V=("$@")
local H=
if [[ "${command[0]:0:1}" != '-' ]]; then
H=help
elif [[ "${command[0]:1:1}" == '-' || "${command[0]}" == "-" ]]; then
H=--help
else
H=-help
fi
if [[ "x$COMPL_COMMAND_NO_HELP" == x ]]; then
V=("${V[@]}" "$H")
fi
_nmcli_list "${V[*]}"
}
_nmcli_compl_COMMAND_nl() {
local command="$1"
local a="$2"
shift
shift
local V=("$@")
local H=
if [[ "${command[0]:0:1}" != '-' ]]; then
V=("${V[@]/#/--}")
H=help
elif [[ "${command[0]:1:1}" == '-' || "${command[0]}" == "-" ]]; then
V=("${V[@]/#/--}")
H=--help
else
V=("${V[@]/#/-}")
H=-help
fi
if [[ "x$COMPL_COMMAND_NO_HELP" == x ]]; then
V=("${V[@]}" "$H")
fi
local IFS=$'\n'
V="${V[*]}"
_nmcli_list_nl "$(printf "%s%s\n%s" "" "$V" "$a")"
}
_nmcli()
{
local cur prev words cword i
_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]}.
_nmcli_array_delete_at words $((cword+1)) ${#words[@]}
_nmcli_array_delete_at words 0
# _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]="$(printf '%s' "${words[i]}" | xargs printf '%s\n' 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
local OPTIONS_UNKNOWN_OPTION OPTIONS_TYPE OPTIONS_TYPED OPTIONS OPTIONS_MANDATORY COMMAND_ARGS_WAIT_OPTIONS OPTIONS_IP OPTIONS_MANDATORY OPTIONS_NEXT_GROUP
local COMMAND_CONNECTION_TYPE COMMAND_CONNECTION_ID OPTIONS_MANDATORY_IFNAME HELP_ONLY_AS_FIRST
local COMMAND_CONNECTION_ACTIVE=""
HELP_ONLY_AS_FIRST=
local LONG_OPTIONS=(terse pretty mode fields escape nocheck ask wait version help)
_nmcli_compl_OPTIONS
i=$?
if [[ "$HELP_ONLY_AS_FIRST" == '0' ]]; then
# got a --help. No more completion.
return 0
fi
case $i in
0)
return 0
;;
1)
# 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)
elif [[ "${words[0]:1:1}" == '-' || "${words[0]}" == "-" ]]; then
OPTIONS=("${LONG_OPTIONS[@]/#/--}")
else
OPTIONS=("${LONG_OPTIONS[@]/#/-}")
fi
_nmcli_list "${OPTIONS[*]}"
return 0
;;
esac
local command="${words[1]}"
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
_nmcli_array_delete_at words 0 1
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%s" "$(_nmcli_con_show NAME)")" active
elif [[ ${#words[@]} -gt 3 ]]; then
_nmcli_array_delete_at words 0 1
LONG_OPTIONS=(help active)
HELP_ONLY_AS_FIRST=1
_nmcli_compl_OPTIONS
i=$?
if ! _nmcli_array_has_value LONG_OPTIONS active; then
COMMAND_CONNECTION_ACTIVE=1
fi
case $i in
0)
return 0
;;
1)
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
if [[ "x$COMMAND_CONNECTION_ACTIVE" = x ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME)")" "${LONG_OPTIONS[@]}"
else
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME --active)")" "${LONG_OPTIONS[@]}"
fi
fi
return 0
;;
esac
OPTIONS=(id uuid path apath)
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
_nmcli_array_delete_at words 0 1
LONG_OPTIONS=(help)
HELP_ONLY_AS_FIRST=1
_nmcli_compl_OPTIONS
case $? in
0)
return 0
;;
1)
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "ifname\nid\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")" "${LONG_OPTIONS[@]}"
fi
return 0
;;
esac
local COMMAND_CONNECTION_TYPE=''
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
_nmcli_array_delete_at words 0 1
LONG_OPTIONS=(help)
HELP_ONLY_AS_FIRST=1
_nmcli_compl_OPTIONS
case $? in
0)
return 0
;;
1)
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_show NAME --active)")" "${LONG_OPTIONS[@]}"
fi
return 0
;;
esac
OPTIONS=(id uuid path apath)
COMMAND_CONNECTION_ACTIVE=1
_nmcli_compl_ARGS_CONNECTION && return 0
fi
;;
a|ad|add)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND "${words[2]}" type ifname con-name autoconnect
elif [[ ${#words[@]} -gt 3 ]]; then
_nmcli_array_delete_at words 0 1
LONG_OPTIONS=(help)
HELP_ONLY_AS_FIRST=1
_nmcli_compl_OPTIONS
case $? in
0)
return 0
;;
1)
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
_nmcli_compl_COMMAND "${words[2]}" type ifname con-name autoconnect
fi
return 0
;;
esac
OPTIONS_TYPE=
OPTIONS=(type ifname con-name autoconnect save)
OPTIONS_MANDATORY=(type ifname)
COMMAND_ARGS_WAIT_OPTIONS=1
OPTIONS_MANDATORY_IFNAME=1
_nmcli_compl_ARGS && return 0
OPTIONS_MANDATORY_IFNAME=
if _nmcli_array_has_value OPTIONS "${OPTIONS_MANDATORY[@]}"; then
# we still have some missing mandatory options...
if [[ "$OPTIONS_UNKNOWN_OPTION" != '' ]]; then
if ! _nmcli_array_has_value OPTIONS "${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 mac)
;;
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
if ! _nmcli_array_has_value OPTIONS_IP "${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
if _nmcli_array_has_value OPTIONS "${OPTIONS_MANDATORY[@]}"; then
_nmcli_list "$(echo "${OPTIONS[@]}")"
return 0
fi
if [[ "$OPTIONS_UNKNOWN_OPTION" != "" ]]; then
if ! _nmcli_array_has_value OPTIONS_IP "${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
_nmcli_array_delete_at words 0 1
LONG_OPTIONS=(help)
HELP_ONLY_AS_FIRST=1
_nmcli_compl_OPTIONS
case $? in
0)
return 0
;;
1)
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\ntype\ncon-name\n%s" "$(_nmcli_con_show NAME)")" "${LONG_OPTIONS[@]}"
fi
return 0
;;
esac
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)")" temporary
elif [[ ${#words[@]} -gt 3 ]]; then
_nmcli_array_delete_at words 0 1
LONG_OPTIONS=(help temporary)
HELP_ONLY_AS_FIRST=1
_nmcli_compl_OPTIONS
case $? in
0)
return 0
;;
1)
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")" "${LONG_OPTIONS[@]}"
fi
return 0
;;
esac
OPTIONS=(id uuid path apath)
_nmcli_compl_ARGS_CONNECTION && return 0
while [[ "${#words[@]}" -gt 0 ]]; do
if [[ ${#words[@]} -le 1 ]]; then
_nmcli_list_nl "$(nmcli --fields profile connection show "${COMMAND_CONNECTION_TYPE:-id}" "$COMMAND_CONNECTION_ID" 2>/dev/null | sed -n 's/^\([^:]\+\):.*/\1/p')"
return 0
elif [[ ${#words[@]} -le 2 ]]; then
return 0
fi
_nmcli_array_delete_at words 0 1
done
_nmcli_list_nl "$(nmcli --fields profile connection show "${COMMAND_CONNECTION_TYPE:-id}" "$COMMAND_CONNECTION_ID" 2>/dev/null | sed -n 's/^\([^:]\+\):.*/\1/p')"
return 0
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
_nmcli_array_delete_at words 0 1
LONG_OPTIONS=(help)
_nmcli_compl_OPTIONS
case $? in
0)
return 0
;;
1)
if ! _nmcli_array_has_value LONG_OPTIONS "help"; then
return 0
fi
;;
esac
OPTIONS=(id uuid path apath)
while [[ ${#words[@]} -gt 0 ]]; do
_nmcli_compl_ARGS_CONNECTION && return 0
done
_nmcli_list_nl "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")"
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 delete 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| \
de|del|dele|delet|delete)
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)
_nmcli_array_delete_at words 0 2
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
_nmcli_array_delete_at words 0 3
local OPTIONS=(password wep-key-type ifname bssid name private)
_nmcli_compl_ARGS
fi
;;
r|re|res|resc|resca|rescan)
_nmcli_array_delete_at words 0 2
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)
_nmcli_array_delete_at words 0 2
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