summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2013-08-21 18:55:11 +0200
committerThomas Haller <thaller@redhat.com>2013-08-28 14:36:49 +0200
commitab231cb0d910456015b523617c2dffeb0a79ed82 (patch)
treed628e386d4183e3d53ab5336b6cb526184b9e137
parent2a0ec59dba57b066dcff739c3a1be3958785ff57 (diff)
downloadNetworkManager-ab231cb0d910456015b523617c2dffeb0a79ed82.tar.gz
cli: improve bash completion by parsing options separately.
To support optimal completion, more context must be considered. Especially the OPTIONS, which must appear before the OBJECT. Modify bash completion to try parsing first the options. Before, whenever you had options, completion did not work anymore (because the object was expected as first argument). Moreover, options were also suggested after specifying the object. This is now mitigated by parsing the command line in two steps. Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r--cli/completion/nmcli429
1 files changed, 254 insertions, 175 deletions
diff --git a/cli/completion/nmcli b/cli/completion/nmcli
index 5743c68769..ac66359ddc 100644
--- a/cli/completion/nmcli
+++ b/cli/completion/nmcli
@@ -62,24 +62,115 @@ _nmcli_NM_dev_MAC()
echo "$(nmcli -t dev show | grep HWADDR | cut -d':' -f2- | sort | uniq)"
}
+# 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 )
+
+ 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
+}
+
_nmcli()
{
local cur prev words cword
_init_completion || return
+ # we don't care about any arguments after the current curser position
+ # because we only parse from left to right. So, if there are some arguments
+ # right of the curser, just ignore them. Also don't care about ${words[0]}.
+ words=("${words[@]:1:$cword}")
+
+ _nmcli_complete_OPTIONS && return 0
+
+ # FIXME: the following block completes certain parameters without
+ # considering enough context, while they only make sense depending on
+ # the OBJECT and COMMAND.
case $prev in
- -m|--mode)
- _nmcli_list "tabular multiline"
- return 0
- ;;
- -f|--fields)
- _nmcli_list "all common"
- return 0
- ;;
- -e|--escape)
- _nmcli_list "yes no"
- return 0
- ;;
id)
_nmcli_list_nl "$(_nmcli_con_id)"
return 0
@@ -154,190 +245,178 @@ _nmcli()
;;
esac
- if [[ $cword -eq 1 ]] ; then
- if [[ "$cur" == -* ]]; then
- if [[ "$cur" == -[tpmfenavh] ]]; then
- _nmcli_list "-t -p -m -f -e -n -a -v -h"
- else
- _nmcli_list "--terse --pretty --mode --fields --escape --nocheck --ask --version --help"
- fi
- else
- _nmcli_list "general networking radio connection device"
- fi
- else
- local object=${words[1]}
- local command=${words[2]}
-
- [[ $command == help ]] && return 0
-
- case $object in
- g|ge|gen|gene|gener|genera|general)
- if [[ ${#words[@]} -gt 3 ]]; then
- case $command in
- s|st|sta|stat|statu|status | p|pe|per|perm|permi|permis|permiss|permissi|permissio|permission|permissions)
- return 0
- ;;
- l|lo|log|logg|loggi|loggin|logging)
- _nmcli_list "level domains"
- return 0
- ;;
- esac
- fi
-
- _nmcli_list "status permissions logging help"
- ;;
+ local object=${words[0]}
+ local command=${words[1]}
- n|ne|net|netw|netwo|networ|network|networki|networkin|networking)
- if [[ ${#words[@]} -gt 3 ]]; then
- case $command in
- on | off)
+ case $object in
+ h|he|hel|help)
+ return 0
+ ;;
+ g|ge|gen|gene|gener|genera|general)
+ if [[ ${#words[@]} -gt 2 ]]; then
+ case $command in
+ s|st|sta|stat|statu|status | p|pe|per|perm|permi|permis|permiss|permissi|permissio|permission|permissions)
return 0
;;
- esac
- fi
- _nmcli_list "on off help"
- ;;
+ l|lo|log|logg|loggi|loggin|logging)
+ _nmcli_list "level domains"
+ return 0
+ ;;
+ esac
+ fi
- r|ra|rad|radi|radio)
- if [[ ${#words[@]} -gt 3 ]]; then
- case $command in
- a|al|all | w|wi|wif|wifi | ww|wwa|wwan | wim|wima|wimax)
- _nmcli_list "on off"
- return 0
- ;;
- esac
- fi
+ _nmcli_list "status permissions logging help"
+ ;;
- _nmcli_list "all wifi wwan wimax help"
- ;;
+ n|ne|net|netw|netwo|networ|network|networki|networkin|networking)
+ if [[ ${#words[@]} -gt 2 ]]; then
+ case $command in
+ on | off)
+ return 0
+ ;;
+ esac
+ fi
+ _nmcli_list "on off help"
+ ;;
- c|co|con|conn|conne|connec|connect|connecti|connectio|connection)
- if [[ ${#words[@]} -gt 3 ]]; then
- case $command in
- s|sh|sho|show)
- local subcommand=${words[3]}
-
- if [[ ${#words[@]} -gt 4 ]]; then
- case $subcommand in
- c|co|con|conf|confi|config|configu|configur|configure|configured)
- _nmcli_list "id uuid path"
- return 0
- ;;
- a|ac|act|acti|activ|active)
- _nmcli_list "id uuid path apath"
- return 0
- ;;
- esac
- fi
-
- _nmcli_list "configured active"
- return 0
- ;;
- u|up)
- if [[ "$cur" == -* ]]; then
- _nmcli_list "--nowait --timeout"
- else
- _nmcli_list "id uuid path iface ap nsp"
- fi
- return 0
- ;;
- d|do|dow|down)
- _nmcli_list "id uuid path apath"
- return 0
- ;;
- a|ad|add)
- _nmcli_list "type con-name autoconnect ifname help"
- return 0
- ;;
- e|ed|edi|edit)
- _nmcli_list "id uuid path type con-name"
- return 0
- ;;
- m|mo|mod|modi|modif|modify)
- _nmcli_list_nl "$(_nmcli_con_id)"
- return 0
- ;;
- de|del|dele|delet|delete)
- _nmcli_list "id uuid path"
- return 0
- ;;
- esac
- fi
- _nmcli_list "show up down add modify edit delete reload help"
- ;;
+ r|ra|rad|radi|radio)
+ if [[ ${#words[@]} -gt 2 ]]; then
+ case $command in
+ a|al|all | w|wi|wif|wifi | ww|wwa|wwan | wim|wima|wimax)
+ _nmcli_list "on off"
+ return 0
+ ;;
+ esac
+ fi
- d|de|dev|devi|devic|device)
- if [[ ${#words[@]} -gt 3 ]]; then
- case $command in
- sh|sho|show)
- _nmcli_list_nl "$(_nmcli_NM_devices)"
- return 0
- ;;
- d|di|dis|disc|disco|discon|disconn|disconne|disconnec|disconnect)
- if [[ "$cur" == -* ]]; then
- _nmcli_list "--nowait --timeout"
- else
- _nmcli_list_nl "$(_nmcli_NM_devices)"
- fi
- return 0
- ;;
- w|wi|wif|wifi)
- local subcommand=${words[3]}
+ _nmcli_list "all wifi wwan wimax help"
+ ;;
+ c|co|con|conn|conne|connec|connect|connecti|connectio|connection)
+ if [[ ${#words[@]} -gt 2 ]]; then
+ case $command in
+ s|sh|sho|show)
+ local subcommand=${words[2]}
+
+ if [[ ${#words[@]} -gt 3 ]]; then
case $subcommand in
- l|li|lis|list)
- _nmcli_list "iface bssid"
+ c|co|con|conf|confi|config|configu|configur|configure|configured)
+ _nmcli_list "id uuid path"
return 0
;;
- c|co|con|conn|conne|connec|connect)
- if [[ "$cur" == -* ]]; then
- _nmcli_list "--private --nowait --timeout"
- else
- if [[ "$prev" == "connect" ]]; then
- _nmcli_list_nl "$(_nmcli_ap_ssid)"
- else
- _nmcli_list "password wep-key-type iface bssid name"
- fi
- fi
+ a|ac|act|acti|activ|active)
+ _nmcli_list "id uuid path apath"
return 0
;;
- r|re|res|resc|resca|rescan)
- if [[ "$cur" == i* ]]; then
- _nmcli_list "iface"
+ esac
+ fi
+
+ _nmcli_list "configured active"
+ return 0
+ ;;
+ u|up)
+ if [[ "$cur" == -* ]]; then
+ _nmcli_list "--nowait --timeout"
+ else
+ _nmcli_list "id uuid path iface ap nsp"
+ fi
+ return 0
+ ;;
+ d|do|dow|down)
+ _nmcli_list "id uuid path apath"
+ return 0
+ ;;
+ a|ad|add)
+ _nmcli_list "type con-name autoconnect ifname help"
+ return 0
+ ;;
+ e|ed|edi|edit)
+ _nmcli_list "id uuid path type con-name"
+ return 0
+ ;;
+ m|mo|mod|modi|modif|modify)
+ _nmcli_list_nl "$(_nmcli_con_id)"
+ return 0
+ ;;
+ de|del|dele|delet|delete)
+ _nmcli_list "id uuid path"
+ return 0
+ ;;
+ esac
+ fi
+ _nmcli_list "show up down add modify edit delete reload help"
+ ;;
+
+ d|de|dev|devi|devic|device)
+ if [[ ${#words[@]} -gt 2 ]]; then
+ case $command in
+ sh|sho|show)
+ _nmcli_list_nl "$(_nmcli_NM_devices)"
+ return 0
+ ;;
+ d|di|dis|disc|disco|discon|disconn|disconne|disconnec|disconnect)
+ if [[ "$cur" == -* ]]; then
+ _nmcli_list "--nowait --timeout"
+ else
+ _nmcli_list_nl "$(_nmcli_NM_devices)"
+ fi
+ return 0
+ ;;
+ w|wi|wif|wifi)
+ local subcommand=${words[2]}
+
+ case $subcommand in
+ l|li|lis|list)
+ _nmcli_list "iface bssid"
+ return 0
+ ;;
+ c|co|con|conn|conne|connec|connect)
+ if [[ "$cur" == -* ]]; then
+ _nmcli_list "--private --nowait --timeout"
+ else
+ if [[ "$prev" == "connect" ]]; then
+ _nmcli_list_nl "$(_nmcli_ap_ssid)"
else
- _nmcli_list_nl "$(_nmcli_NM_devices)"
+ _nmcli_list "password wep-key-type iface bssid name"
fi
+ fi
+ return 0
+ ;;
+ r|re|res|resc|resca|rescan)
+ if [[ "$cur" == i* ]]; then
+ _nmcli_list "iface"
+ else
+ _nmcli_list_nl "$(_nmcli_NM_devices)"
+ fi
+ return 0
+ ;;
+ esac
+
+ _nmcli_list "list connect scan"
+ return 0
+ ;;
+ wim|wima|wimax)
+ local subcommand=${words[2]}
+
+ if [[ ${#words[@]} -gt 3 ]]; then
+ case $subcommand in
+ l|li|lis|list)
+ _nmcli_list "iface nsp"
return 0
;;
esac
+ fi
- _nmcli_list "list connect scan"
- return 0
- ;;
- wim|wima|wimax)
- local subcommand=${words[3]}
-
- if [[ ${#words[@]} -gt 4 ]]; then
- case $subcommand in
- l|li|lis|list)
- _nmcli_list "iface nsp"
- return 0
- ;;
- esac
- fi
-
- _nmcli_list "list"
- return 0
- ;;
-
- esac
- fi
+ _nmcli_list "list"
+ return 0
+ ;;
- _nmcli_list "status show disconnect wifi wimax help"
- ;;
- esac
+ esac
+ fi
- fi
+ _nmcli_list "status show disconnect wifi wimax help"
+ ;;
+ esac
return 0
} &&