# 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_id() { echo "$(nmcli -t -f NAME con show c 2>/dev/null)" } _nmcli_con_id_active() { echo "$(nmcli -t -f NAME con show a 2>/dev/null)" } _nmcli_con_uuid() { echo "$(nmcli -t -f UUID con show c 2>/dev/null)" } _nmcli_con_path() { echo "$(nmcli -t -f DBUS-PATH con show c 2>/dev/null)" } _nmcli_con_apath() { echo "$(nmcli -t -f DBUS-PATH con show a 2>/dev/null)" } _nmcli_ap_ssid() { echo "$(nmcli -t -f SSID dev wifi list 2>/dev/null)" # without quotes #ssids="$(nmcli -t -f SSID dev wifi list 2>/dev/null)" #local IFS=$'\n' #for ssid in $ssids; do # temp="${ssid%\'}" # temp="${temp#\'}" # echo "$temp" #done } _nmcli_device_wifi_list_SSID() { echo "$(nmcli -t -f SSID device wifi list 2>/dev/null | sort | uniq)" } _nmcli_ap_bssid() { echo "$(nmcli -e no -t -f BSSID dev wifi list 2>/dev/null)" } _nmcli_NM_devices() { echo "$(nmcli -t -f DEVICE dev status 2>/dev/null)" } _nmcli_NM_dev_MAC() { echo "$(nmcli -t dev show | grep HWADDR | cut -d':' -f2- | sort | uniq)" } _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_complete_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" 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_complete_COMMAND_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 adsl bluetooth vpn olpc-mesh vlan bond bond-slave bridge bridge-slave team team-slave" fi return 0 fi OPTIONS_TYPE="${words[1]}" ;; master) if [[ "${#words[@]}" -eq 2 ]]; then if [[ "${words[1]}" = "" ]]; then _nmcli_list_nl "$(_nmcli_NM_devices)" else _nmcli_list_nl "$(printf "%s\n%s\n%s" "$(_nmcli_NM_devices)" "$(_nmcli_con_uuid)")" fi return 0 fi ;; dev) if [[ "${#words[@]}" -eq 2 ]]; then if [[ "${words[1]}" = "" ]]; then _nmcli_list_nl "$(_nmcli_NM_devices)" else _nmcli_list_nl "$(printf "%s\n%s\n%s" "$(_nmcli_NM_devices)" "$(_nmcli_ap_bssid)" "$(_nmcli_con_uuid)")" fi return 0 fi ;; primary| \ ifname) if [[ "${#words[@]}" -eq 2 ]]; then _nmcli_list_nl "$(_nmcli_NM_devices)" 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| \ password) if [[ "${#words[@]}" -eq 2 ]]; then return 0 fi ;; ssid) if [[ "${#words[@]}" -eq 2 ]]; then _nmcli_list_nl "$(_nmcli_device_wifi_list_SSID)" return 0 fi ;; ap| \ bssid) if [[ "${#words[@]}" -eq 2 ]]; then _nmcli_list_nl "$(_nmcli_ap_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_complete_COMMAND_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]}" case "${words[0]}" in id) if [[ ${#words[@]} -eq 2 ]]; then _nmcli_list_nl "$(_nmcli_con_id)" return 0 fi words=("${words[@]:2}") ;; uuid) if [[ ${#words[@]} -eq 2 ]]; then _nmcli_list_nl "$(_nmcli_con_uuid)" return 0 fi words=("${words[@]:2}") ;; path) if [[ ${#words[@]} -eq 2 ]]; then _nmcli_list_nl "$(_nmcli_con_path)" return 0 fi words=("${words[@]:2}") ;; apath) if [[ ${#words[@]} -eq 2 ]]; then _nmcli_list_nl "$(_nmcli_con_apath)" return 0 fi words=("${words[@]:2}") ;; ifname) if [[ ${#words[@]} -eq 2 ]]; then _nmcli_list_nl "$(_nmcli_NM_devices)" return 0 fi words=("${words[@]:2}") ;; *) COMMAND_CONNECTION_TYPE= COMMAND_CONNECTION_ID="${words[0]}" words=("${words[@]:1}") ;; esac return 1 } _nmcli_complete_commands() { local command="$1" shift if [[ "x${command:0:1}" == 'x-' ]]; then _nmcli_list "-h --help" else _nmcli_list "help $*" 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 lo` if [[ "$cur" =~ ^[[:space:]]+ ]]; then cur='' fi _nmcli_complete_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 case "${words[0]}" in h|he|hel|help) ;; g|ge|gen|gene|gener|genera|general) if [[ ${#words[@]} -eq 2 ]]; then _nmcli_complete_commands "$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_list_nl "$(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) words=("${words[@]:2}") OPTIONS=(level domains) _nmcli_complete_COMMAND_ARGS ;; esac fi ;; n|ne|net|netw|netwo|networ|network|networki|networkin|networking) if [[ ${#words[@]} -eq 2 ]]; then _nmcli_complete_commands "$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_list "check" ;; esac fi ;; r|ra|rad|radi|radio) if [[ ${#words[@]} -eq 2 ]]; then _nmcli_complete_commands "$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_list "on off" ;; esac fi ;; c|co|con|conn|conne|connec|connect|connecti|connectio|connection) if [[ ${#words[@]} -eq 2 ]]; then _nmcli_complete_commands "$command" show up down add modify edit delete reload elif [[ ${#words[@]} -gt 2 ]]; then case "$command" in s|sh|sho|show) if [[ ${#words[@]} -eq 3 ]]; then _nmcli_list "configured active" elif [[ ${#words[@]} -gt 3 ]]; then case "${words[2]}" in c|co|con|conf|confi|config|configu|configur|configure|configured) if [[ ${#words[@]} -eq 4 ]]; then _nmcli_list_nl "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_id)")" else words=("${words[@]:3}") OPTIONS=(id uuid path) _nmcli_complete_COMMAND_CONNECTION fi ;; a|ac|act|acti|activ|active) if [[ ${#words[@]} -eq 4 ]]; then _nmcli_list_nl "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_id_active)")" else words=("${words[@]:3}") OPTIONS=(id uuid path apath) _nmcli_complete_COMMAND_CONNECTION fi ;; esac fi ;; u|up) if [[ ${#words[@]} -eq 3 ]]; then _nmcli_list_nl "$(printf "ifname\nid\nuuid\npath\n%s" "$(_nmcli_con_id)")" elif [[ ${#words[@]} -gt 3 ]]; then local COMMAND_CONNECTION_TYPE='' words=("${words[@]:2}") OPTIONS=(ifname id uuid path) _nmcli_complete_COMMAND_CONNECTION && return 0 if [[ "$COMMAND_CONNECTION_TYPE" = "ifname" ]]; then OPTIONS=(ap nsp) else OPTIONS=(ifname ap nsp) fi _nmcli_complete_COMMAND_ARGS fi ;; d|do|dow|down) if [[ ${#words[@]} -eq 3 ]]; then _nmcli_list_nl "$(printf "id\nuuid\npath\napath\n%s" "$(_nmcli_con_id_active)")" elif [[ ${#words[@]} -gt 3 ]]; then words=("${words[@]:2}") OPTIONS=(id uuid path apath) _nmcli_complete_COMMAND_CONNECTION fi ;; a|ad|add) if [[ ${#words[@]} -eq 3 ]]; then _nmcli_complete_commands "${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_complete_COMMAND_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) ;; *) # 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_complete_COMMAND_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_complete_COMMAND_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_complete_COMMAND_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_complete_COMMAND_ARGS && return 0 fi ;; e|ed|edi|edit) if [[ ${#words[@]} -eq 3 ]]; then _nmcli_list_nl "$(printf "id\nuuid\npath\ntype\ncon-name\n%s" "$(_nmcli_con_id)")" elif [[ ${#words[@]} -gt 3 ]]; then words=("${words[@]:2}") if [[ "${words[0]}" = 'type' || "${words[0]}" = 'con-name' ]]; then OPTIONS=(type con-name) _nmcli_complete_COMMAND_ARGS else OPTIONS=(id uuid path apath) _nmcli_complete_COMMAND_CONNECTION fi fi ;; m|mo|mod|modi|modif|modify) if [[ ${#words[@]} -eq 3 ]]; then _nmcli_list_nl "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_id)")" elif [[ ${#words[@]} -gt 3 ]]; then words=("${words[@]:2}") OPTIONS=(id uuid path apath) _nmcli_complete_COMMAND_CONNECTION && return 0 if [[ ${#words[@]} -le 1 ]]; then _nmcli_list_nl "$(nmcli connection show configured "${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_list_nl "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_id)")" elif [[ ${#words[@]} -gt 3 ]]; then words=("${words[@]:2}") OPTIONS=(id uuid path apath) _nmcli_complete_COMMAND_CONNECTION fi ;; l|lo|loa|load) if [[ ${#words[@]} -gt 2 ]]; then compopt -o default COMPREPLY=() fi ;; esac fi ;; d|de|dev|devi|devic|device) if [[ ${#words[@]} -eq 2 ]]; then _nmcli_complete_commands "$command" status show connect disconnect wifi wimax elif [[ ${#words[@]} -gt 2 ]]; then case "$command" in s|st|sta|stat|statu|status) ;; 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_list_nl "$(_nmcli_NM_devices)" fi ;; w|wi|wif|wifi) if [[ ${#words[@]} -eq 3 ]]; then _nmcli_list "list connect rescan" else case "${words[2]}" in l|li|lis|list) words=("${words[@]:3}") OPTIONS=(ifname bssid) _nmcli_complete_COMMAND_ARGS ;; c|co|con|conn|conne|connec|connect) if [[ ${#words[@]} -eq 4 ]]; then if [[ "${words[3]}" = "" ]]; then _nmcli_list_nl "$(_nmcli_ap_ssid)" else _nmcli_list_nl "$(printf "%s\n%s" "$(_nmcli_ap_ssid)" "$(_nmcli_ap_bssid)")" fi else words=("${words[@]:4}") local OPTIONS=(password wep-key-type ifname bssid name private) _nmcli_complete_COMMAND_ARGS fi ;; r|re|res|resc|resca|rescan) words=("${words[@]:3}") OPTIONS=(ifname) _nmcli_complete_COMMAND_ARGS ;; esac fi ;; wim|wima|wimax) if [[ ${#words[@]} -eq 3 ]]; then _nmcli_list "list" else case "${words[2]}" in l|li|lis|list) words=("${words[@]:3}") OPTIONS=(ifname nsp) _nmcli_complete_COMMAND_ARGS ;; c|co|con|conn|conne|connec|connect) if [[ ${#words[@]} -eq 4 ]]; then if [[ "${words[3]}" = "" ]]; then _nmcli_list_nl "$(_nmcli_ap_ssid)" else _nmcli_list_nl "$(_nmcli_ap_ssid) $(_nmcli_ap_bssid)" fi else words=("${words[@]:4}") OPTIONS=(password wep-key-type ifname bssid name private) _nmcli_complete_COMMAND_ARGS fi ;; r|re|res|resc|resca|rescan) words=("${words[@]:3}") OPTIONS=(ifname) _nmcli_complete_COMMAND_ARGS ;; esac fi ;; esac fi ;; esac return 0 } && complete -F _nmcli nmcli # ex: ts=4 sw=4 et filetype=sh