NetworkManager/clients/cli/nmcli-completion
Thomas Haller d742ea7817 cli: don't allow multiple <ifname> arguments to device-reapply
Just like `nmcli device connect` only allows one argument, don't allow
multiple device arguments for reapply.

Allowing multiple device names makes it more complicated to add
additional options to the command. For example, it would be useful
to have a

    nmcli device reapply eth0 connection id other-connection

but when allowing multiple device names, it gets more complicated in
documentation, command line parsing and bash completion.

Note that the user can achieve a very similar outcome by using the
shell:

    for DEV in eth0 eth1 eth2; do
        nmcli device reapply $DEV &
    done
    wait

argubaly, this doesn't report the exit status properly. To properly
handle that would require more effort. Also, it is somewhat less
efficient, but well.

This is an API change, however it is very new API that probably nobody
is using much. Also, the documentation (man nmcli) didn't mention the
possibility to pass multiple device names.
2016-05-03 11:52:57 +02:00

1518 lines
63 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
# Work-around bash_completion issue where bash interprets a colon
# as a separator.
# Colon is escaped here. Change "\\:" back to ":".
# See also:
# http://stackoverflow.com/questions/28479216/how-to-give-correct-suggestions-to-tab-complete-when-my-words-contains-colons
# http://stackoverflow.com/questions/2805412/bash-completion-for-maven-escapes-colon/12495727
i=0
for entry in ${COMPREPLY[*]}
do
entry="${entry//\\\\:/:}"
COMPREPLY[$i]=${entry}
(( 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
;;
ask)
_nmcli_array_delete_at words 0
;;
show-secrets)
_nmcli_array_delete_at words 0
;;
order)
if [[ "${#words[@]}" -eq 2 ]]; then
local ord="${words[1]}"
local ord_sta=""
local i
local c=()
# FIXME: currently the completion considers colon as separator
# for words. Hence the following doesn't work as $ord will
# not contain any colons at this point.
# See https://bugzilla.gnome.org/show_bug.cgi?id=745157
if [[ $ord = *":"* ]]; then
ord_sta="${ord%:*}:"
ord="${ord##*:}"
fi
if [[ $ord = [-+]* ]]; then
ord_sta="$ord_sta${ord:0:1}"
fi
for i in active name type path; do
c=("${c[@]}" "$ord_sta$i")
done
_nmcli_list "${c[*]}"
return 0
fi
_nmcli_array_delete_at words 0 1
;;
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
;;
colors)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "yes no auto"
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 tun ip-tunnel macvlan vxlan
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 aliases=${@}
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]}")
# change option name to alias
WORD0="${words[0]}"
for alias in "${aliases[@]}" ; do
if [[ "${WORD0}" == ${alias%%:*} ]]; then
WORD0=${alias#*:}
break
fi
done
case "${WORD0}" in
level)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "OFF ERR WARN INFO DEBUG TRACE"
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 bridge team pppoe adsl tun ip-tunnel macvlan vxlan"
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
case "$OPTIONS_TYPE" in
"wifi")
_nmcli_list "infrastructure ap adhoc"
;;
"tun")
_nmcli_list "tun tap"
;;
"ip-tunnel")
_nmcli_list "ipip gre sit isatap vti ip6ip6 ipip6 ip6gre vti6"
;;
"macvlan")
_nmcli_list "vepa bridge private passthru source"
;;
"bond"| \
*)
_nmcli_list "balance-rr active-backup balance-xor broadcast 802.3ad balance-tlb balance-alb"
esac
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
;;
slave-type)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "bond team bridge"
return 0
fi
;;
lacp-rate)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "slow fast"
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
;;
managed| \
autoconnect| \
stp| \
hairpin| \
save| \
hidden| \
private| \
pi| \
vnet-hdr| \
multi-queue|\
tap)
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| \
passwd-file| \
file)
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
;;
encapsulation)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "vcmux llc"
return 0
fi
;;
protocol)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "pppoa pppoe ipoatm"
return 0
fi
;;
band)
if [[ "${#words[@]}" -eq 2 ]]; then
_nmcli_list "a bg"
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
if ! _nmcli_array_has_value OPTIONS_REPEATABLE "${OPTIONS[$i]}" ; then
unset OPTIONS[$i]
fi
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.
# Actually, it can also ask for a device name, like `nmcli device set [ifname] <ifname>`
_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_compl_PROPERTIES()
{
while [[ "${#words[@]}" -gt 0 ]]; do
if [[ ${#words[@]} -le 1 ]]; then
local PREFIX=""
if [[ "${words[0]:0:1}" == [+-] ]]; then
PREFIX="${words[0]:0:1}"
fi
_nmcli_list_nl "$(echo -e 'print\nquit\nyes' |nmcli c edit "$@" 2>/dev/null |awk -F: '/\..*:/ {print "'$PREFIX'"$1}')"
return 0
elif [[ ${#words[@]} -le 2 ]]; then
return 0
fi
_nmcli_array_delete_at words 0 1
done
_nmcli_list_nl "$(echo -e 'print\nquit\nyes' |nmcli c edit "$@" 2>/dev/null |awk -F: '/\..*:/ {print $1}')"
}
_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 OPTIONS_SEP OPTIONS_REPEATABLE
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 colors escape ask show-secrets 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 agent monitor)
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
;;
s|st|sta|stat|statu|status| \
p|pe|per|perm|permi|permis|permiss|permissi|permissio|permission|permissions)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND "${words[2]}"
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
elif [[ ${#words[@]} -eq 3 ]]; then
case "$command" in
a|al|all | w|wi|wif|wifi | ww|wwa|wwan)
_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 clone edit delete monitor reload load import export
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 order
elif [[ ${#words[@]} -gt 3 ]]; then
_nmcli_array_delete_at words 0 1
LONG_OPTIONS=(help active order)
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 passwd-file)
else
OPTIONS=(ifname ap nsp passwd-file)
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 master slave-type
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 master slave-type
fi
return 0
;;
esac
OPTIONS_TYPE=
OPTIONS=(type ifname con-name autoconnect save master slave-type)
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_SEP=(--)
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_TYPE=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_TYPE=wifi
OPTIONS_TYPED=(ssid mac cloned-mac mtu mode)
OPTIONS_MANDATORY=(ssid)
;;
wim|wima|wimax)
OPTIONS_TYPE=wimax
OPTIONS_TYPED=(mac nsp)
;;
g|gs|gsm)
OPTIONS_TYPE=gsm
OPTIONS_TYPED=(apn user password)
OPTIONS_MANDATORY=(apn)
;;
c|cd|cdm|cdma)
OPTIONS_TYPE=cdma
OPTIONS_TYPED=(user password)
;;
i|in|inf|infi|infin|infini|infinib|infiniba|infiniban|infiniband)
OPTIONS_TYPE=infiniband
OPTIONS_TYPED=(mac mtu transport-mode parent p-key)
;;
bl|blu|blue|bluet|blueto|bluetoo|bluetoot|bluetooth)
OPTIONS_TYPE=bluetooth
OPTIONS_TYPED=(addr bt-type)
;;
vl|vla|vlan)
OPTIONS_TYPE=vlan
OPTIONS_TYPED=(dev id flags ingress egress mtu)
OPTIONS_MANDATORY=(dev)
;;
bond)
OPTIONS_TYPE=bond
OPTIONS_TYPED=(mode miimon downdelay updelay arp-interval arp-ip-target primary lacp-rate)
;;
team)
OPTIONS_TYPE=team
OPTIONS_TYPED=(config)
;;
bridge)
OPTIONS_TYPE=bridge
OPTIONS_TYPED=(stp priority forward-delay hello-time max-age ageing-time mac)
;;
vp|vpn)
OPTIONS_TYPE=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_TYPE=olpc-mesh
OPTIONS_TYPED=(ssid channel dhcp-anycast)
OPTIONS_MANDATORY=(ssid)
;;
p|pp|ppp|pppo|pppoe)
OPTIONS_TYPE=pppoe
OPTIONS_TYPED=(username password service mtu mac)
OPTIONS_MANDATORY=(username)
;;
a|ad|ads|adsl)
OPTIONS_TYPE=adsl
OPTIONS_TYPED=(username password protocol encapsulation)
OPTIONS_MANDATORY=(username protocol)
;;
tu|tun)
OPTIONS_TYPE=tun
OPTIONS_TYPED=(mode owner group pi vnet-hdr multi-queue)
OPTIONS_MANDATORY=(mode)
;;
ip|ip-|ip-t|ip-tu|ip-tun|ip-tunn|ip-tunne|ip-tunnel)
OPTIONS_TYPE=ip-tunnel
OPTIONS_TYPED=(mode remote local dev)
OPTIONS_MANDATORY=(mode remote)
;;
m|ma|mac|macv|macvl|macvla|macvlan)
OPTIONS_TYPE=macvlan
OPTIONS_TYPED=(dev mode tap)
OPTIONS_MANDATORY=(dev mode)
;;
vx|vxl|vxla|vxlan)
OPTIONS_TYPE=vxlan
OPTIONS_TYPED=(id remote local dev source-port-min source-port-max destination-port)
OPTIONS_MANDATORY=(id remote)
;;
*)
# 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[@]}") $(echo "${OPTIONS_SEP[@]}")"
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[@]}") $(echo "${OPTIONS_SEP[@]}")"
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}" ||
_nmcli_array_has_value OPTIONS_SEP "${OPTIONS_UNKNOWN_OPTION:1}"); then
# the unknown option is neither an IP option nor a separator.
return 0
fi
# The unknown option is an IP option or a separator, 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}" ||
_nmcli_array_has_value OPTIONS_SEP "${OPTIONS_UNKNOWN_OPTION:1}"); then
# the unknown option is neither an IP option nor a separator.
return 0
fi
fi
fi
# no mandatory options... do final completion including IP options
OPTIONS=("${OPTIONS[@]}" "${OPTIONS_IP[@]}" "${OPTIONS_SEP[@]}")
OPTIONS_NEXT_GROUP=("${OPTIONS_IP[@]}" "${OPTIONS_SEP[@]}")
_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_SEP[@]}")
OPTIONS_NEXT_GROUP=("${OPTIONS_SEP[@]}")
COMMAND_ARGS_WAIT_OPTIONS=0
_nmcli_compl_ARGS && return 0
_nmcli_array_delete_at words 0
_nmcli_compl_PROPERTIES type "$OPTIONS_TYPE"
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)
_nmcli_compl_ARGS_CONNECTION && return 0
_nmcli_compl_PROPERTIES ${COMMAND_CONNECTION_TYPE} "$COMMAND_CONNECTION_ID"
return 0
fi
;;
c|cl|clo|clon|clone)
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)
_nmcli_compl_ARGS_CONNECTION && return 0
return 0
fi
;;
de|del|dele|delet|delete| \
mon|moni|monit|monito|monitor)
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
;;
i|im|imp|impo|impor|import)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND "${words[2]}" type file --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 "${words[2]}" type file
fi
return 0
;;
esac
OPTIONS=(type file)
OPTIONS_MANDATORY=(type file)
ALIASES=("type:vpn-type")
_nmcli_compl_ARGS ${ALIASES[@]}
return 0
fi
;;
e|ex|exp|expo|expor|export)
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)
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)
_nmcli_compl_ARGS_CONNECTION && return 0
return 0
fi
;;
esac
fi
;;
d|de|dev|devi|devic|device)
if [[ ${#words[@]} -eq 2 ]]; then
_nmcli_compl_COMMAND "$command" status show connect reapply disconnect delete monitor wifi set lldp
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| \
r|re|rea|reap|reapp|reappl|reapply| \
c|co|con|conn|conne|connec|connect)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(_nmcli_dev_status DEVICE)"
fi
;;
d|di|dis|disc|disco|discon|disconn|disconne|disconnec|disconnect| \
de|del|dele|delet|delete| \
m|mo|mon|moni|monit|monito|monitor)
if [[ ${#words[@]} -ge 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(_nmcli_dev_status DEVICE)"
fi
;;
se|set)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "ifname\n%s" "$(_nmcli_dev_status DEVICE)")"
else
_nmcli_array_delete_at words 0 1
OPTIONS=(ifname)
_nmcli_compl_ARGS_CONNECTION && return 0
OPTIONS=(autoconnect managed)
_nmcli_compl_ARGS
fi
;;
w|wi|wif|wifi)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND "${words[2]}" list connect hotspot 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 hidden)
_nmcli_compl_ARGS
fi
;;
h|ho|hot|hots|hotsp|hotspo|hotspot)
_nmcli_array_delete_at words 0 2
OPTIONS=(ifname con-name ssid band channel password)
_nmcli_compl_ARGS
;;
r|re|res|resc|resca|rescan)
_nmcli_array_delete_at words 0 2
OPTIONS_REPEATABLE=(ssid)
OPTIONS=(ifname ssid)
_nmcli_compl_ARGS
;;
esac
fi
;;
l|ll|lld|lldp)
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)
_nmcli_compl_ARGS
;;
esac
fi
;;
esac
fi
;;
a|ag|age|agen|agent)
if [[ ${#words[@]} -eq 2 ]]; then
_nmcli_compl_COMMAND "$command" secret polkit all
fi
;;
m|mo|mon|moni|monit|monito|monitor)
;;
esac
return 0
} &&
complete -F _nmcli nmcli
# ex: ts=4 sw=4 et filetype=sh