aboutsummaryrefslogtreecommitdiffhomepage
path: root/share/completions
diff options
context:
space:
mode:
authorGravatar Fabian Homborg <FHomborg@gmail.com>2016-05-19 13:23:00 +0200
committerGravatar Fabian Homborg <FHomborg@gmail.com>2016-05-19 13:23:00 +0200
commit8dc74de92e12ed6c49e4c34273a7081481ceb85d (patch)
tree16d8df5e3e84975d6ba7a36568191f368732e7ca /share/completions
parent21fc2decd741d3a18c88445e11de8860148060d0 (diff)
Add completion for `ip`
This is quite ugly because the syntax is ugly, the documentation both under- and overspecified at the same time (a BNF that isn't...) and it has a lot of functionality. But the completion works half-decent for `ip address`, so let's ship it.
Diffstat (limited to 'share/completions')
-rw-r--r--share/completions/ip.fish344
1 files changed, 344 insertions, 0 deletions
diff --git a/share/completions/ip.fish b/share/completions/ip.fish
new file mode 100644
index 00000000..b7ded602
--- /dev/null
+++ b/share/completions/ip.fish
@@ -0,0 +1,344 @@
+# ip(8) completion for fish
+
+# The difficulty here is that ip allows abbreviating options, so we need to complete "ip a" like "ip address", but not "ip m" like "ip mroute"
+# Also the manpage and even the grammar it accepts is utter shite (options can only be before commands, some things are only in the BNF, others only in the text)
+# It also quite likes the word "dev", even though it needs it less than the BNF specifies
+
+set -l ip_commands link address addrlabel route rule neigh ntable tunnel tuntap maddr mroute mrule monitor xfrm netns l2tp tcp_metrics
+set -l ip_addr a ad add addr addre addres address
+set -l ip_link l li lin link
+set -l ip_all_commands $ip_commands $ip_addr $ip_link
+
+function __fish_ip_commandwords
+ set -l skip 0
+ set -l cmd (commandline -opc)
+ # HACK: Handle and/or/not specially because they have hardcoded completion behavior
+ # that doesn't remove them from the commandline
+ if contains -- $cmd[1] and or not
+ set -e cmd[1]
+ end
+ # Remove the first word because it's "ip" or an alias for it
+ set -e cmd[1]
+ set -l have_command 0
+ for word in $cmd
+ switch $word
+ # Normalize the commands to their full form - `ip a` is `ip address`
+ # This can't be just an unambiguity check because there's also `ip addrlabel`
+ case a ad add addr addre addres address
+ # "addr add" is a thing, so we can only echo "address" if it's actually the command
+ if test $have_command = 0
+ set have_command 1
+ echo address
+ else
+ echo $word
+ end
+ case l li lin link
+ if test $have_command = 0
+ set have_command 1
+ echo link
+ else
+ echo $word
+ end
+ case "addrl*"
+ if test $have_command = 0
+ set have_command 1
+ echo addrlabel
+ else
+ echo $word
+ end
+ case r ro rou rout route
+ if test $have_command = 0
+ set have_command 1
+ echo route
+ else
+ echo $word
+ end
+ case "ru*"
+ if test $have_command = 0
+ set have_command 1
+ echo rule
+ else
+ echo $word
+ end
+ case n ne nei neig neigh
+ if test $have_command = 0
+ set have_command 1
+ echo neigh
+ else
+ echo $word
+ end
+ case nt
+ if test $have_command = 0
+ set have_command 1
+ echo ntable
+ else
+ echo $word
+ end
+ case t tu tun tunn tunne tunnel
+ if test $have_command = 0
+ set have_command 1
+ echo tunnel
+ else
+ echo $word
+ end
+ case "tunt*"
+ if test $have_command = 0
+ set have_command 1
+ echo tuntap
+ else
+ echo $word
+ end
+ case m ma mad madd maddr maddre maddres maddress
+ if test $have_command = 0
+ set have_command 1
+ echo maddress
+ else
+ echo $word
+ end
+ case mr "mro*"
+ if test $have_command = 0
+ set have_command 1
+ echo mroute
+ else
+ echo $word
+ end
+ case "mru*"
+ if test $have_command = 0
+ set have_command 1
+ echo mrule
+ else
+ echo $word
+ end
+ case "mo*"
+ if test $have_command = 0
+ set have_command 1
+ echo monitor
+ else
+ echo $word
+ end
+ case "x*"
+ if test $have_command = 0
+ set have_command 1
+ echo xfrm
+ else
+ echo $word
+ end
+ case "net*"
+ if test $have_command = 0
+ set have_command 1
+ echo netns
+ else
+ echo $word
+ end
+ case "l*"
+ if test $have_command = 0
+ set have_command 1
+ echo l2tp
+ else
+ echo $word
+ end
+ case "tc*"
+ if test $have_command = 0
+ set have_command 1
+ echo tcp_metrics
+ else
+ echo $word
+ end
+ case "to*"
+ if test $have_command = 0
+ set have_command 1
+ echo token
+ else
+ echo $word
+ end
+ case '-n' '-netns' '--netns'
+ if test $have_command = 0
+ set skip 1
+ else
+ echo $word
+ end
+ case '-*'
+ test $have_command = 0; and continue
+ echo $word
+ case '*'
+ if test $skip = 1
+ set skip 0
+ continue
+ end
+ echo $word
+ end
+ end
+ # Print an empty line if the current token is empty, so we know that the one before it is finished
+ # TODO: For some reason it is necessary to always print the current token - why doesn't the above loop catch it?
+ set -l token (commandline -ct)
+ echo $token
+end
+
+function __fish_ip_device
+ ip -o link show | while read a b c
+ printf '%s\t%s\n' (string replace ':' '' -- $b) "Device"
+ end
+end
+
+function __fish_ip_scope
+ if test -r /etc/iproute2/rt_scopes
+ string replace -r '#.*' '' < /etc/iproute2/rt_scopes \
+ | string match -v '^\s*$' \
+ | string replace -r '(\S+)\s*(\S+)' '$1\t$2\n$2\t$1' \
+ | string match -rv '^(global|link|host).*' # Ignore scopes with better descriptions
+ end
+ # Predefined scopes
+ printf '%s\t%s\n' global "Address is globally valid" \
+ link "Address is link-local, only valid on this device" \
+ host "Address is only valid on this host"
+end
+
+function __fish_complete_ip
+ set -l cmd (__fish_ip_commandwords)
+ set -l count (count $cmd)
+ switch "$cmd[1]"
+ case address
+ # We're still _on_ the second word, which is the subcommand
+ if not set -q cmd[3]
+ printf '%s\t%s\n' add "Add new protocol address" \
+ delete "Delete protocol address" \
+ show "Look at protocol addresses" \
+ flush "Flush protocol addresses"
+ else
+ switch $cmd[2]
+ # Change and replace are undocumented (apart from mentions in the BNF)
+ case add change replace
+ switch $count
+ case 3
+ # __fish_ip_complete_ip
+ case '*'
+ switch $cmd[-2]
+ case dev
+ __fish_ip_device
+ case scope
+ __fish_ip_scope
+ # TODO: Figure out how to complete these
+ case label
+ # Prefix
+ case local peer broadcast
+ # Address
+ case valid_lft preferred_lft
+ # Lifetime
+ case '*'
+ printf '%s\t%s\n' forever "Keep address valid forever" \
+ home "(Ipv6 only) Designate address as home adress" \
+ nodad "(Ipv6 only) Don't perform duplicate address detection" \
+ dev "Add address to specified device" \
+ scope "Set scope of address" \
+ label "Tag address with label"
+ end
+ end
+ case delete
+ switch $count
+ case 3
+ ip -o addr show | while read a b c d e
+ echo $d
+ end
+ case 4
+ # A dev argument is mandatory, but contrary to the BNF, other things (like "scope") are also valid here
+ # And yes, unlike e.g. show, this _needs_ the "dev" before the device
+ # Otherwise it barfs and says "??? prefix is expected"
+ # Anyway, try to steer the user towards supplying a device
+ echo dev
+ case 5
+ switch $cmd[-2]
+ case dev
+ ip -o addr show | string match "*$cmd[3]*" | while read a b c
+ echo $b
+ end
+ # TODO: Moar
+ end
+ case show save flush # These take the same args
+ switch $cmd[-2]
+ case dev
+ __fish_ip_device
+ case scope
+ __fish_ip_scope
+ case to
+ # Prefix
+ case label
+ # Label-pattern
+ case '*'
+ printf '%s\t%s\n' up "Only active devices" \
+ dev "Limit to a certain device" \
+ scope "Limit scope" \
+ to "Limit prefix" \
+ label "Limit by label" \
+ dynamic "(Ipv6 only) Limit to dynamic addresses" \
+ permanent "(Ipv6 only) Limit to permanent addresses"
+ __fish_ip_device
+ # TODO: Moar
+ end
+ end
+ end
+ end
+ case link
+ if not set -q cmd[3]
+ printf '%s\t%s\n' add "Add virtual link" \
+ delete "Delete virtual link" \
+ set "Change device attributes" \
+ show "Display device attributes" \
+ help "Display help"
+ else
+ # TODO: Add moar
+ switch $cmd[2]
+ case add
+ switch $cmd[-2]
+ case link
+ __fish_ip_device
+ case name
+ case type
+ printf '%s\t%s\n' \
+ macvtap "Virtual interface based on link layer address (MAC) and TAP." \
+ vcan "Virtual Controller Area Network interface" \
+ veth "Virtual ethernet interface" \
+ vlan "802.1q tagged virtual LAN interface" \
+ vxlan "Virtual eXtended LAN" \
+ ip6tnl "Virtual tunnel interface IPv4|IPv6 over IPv6" \
+ ipip "Virtual tunnel interface IPv4 over IPv4" \
+ sit "Virtual tunnel interface IPv6 over IPv4" \
+ gre "Virtual tunnel interface GRE over IPv4" \
+ gretap "Virtual L2 tunnel interface GRE over IPv4" \
+ ip6gre "Virtual tunnel interface GRE over IPv6" \
+ ip6gretap "Virtual L2 tunnel interface GRE over IPv6" \
+ vti "Virtual tunnel interface" \
+ nlmon "Netlink monitoring device" \
+ ipvlan "Interface for L3 (IPv6/IPv4) based VLANs" \
+ lowpan "Interface for 6LoWPAN (IPv6) over IEEE 802.15.4 / Bluetooth" \
+ geneve "GEneric NEtwork Virtualization Encapsulation"
+ end
+ case delete
+ case set
+ case show
+ case help
+ end
+ end
+ end
+end
+
+complete -f -c ip
+complete -f -c ip -a '(__fish_complete_ip)'
+complete -f -c ip -n "not __fish_seen_subcommand_from $ip_all_commands" -a "$ip_commands"
+# Yes, ip only takes options before "objects"
+complete -c ip -s b -l batch -d "Read commands from file or stdin" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -l force -d "Don't terminate on errors in batch mode" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -s V -l Version -d "Print the version" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s s -l stats -d "Output more information" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s d -l details -d "Output more detailed information" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s l -l loops -d "Specify maximum number of loops for 'ip addr flush'" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s f -l family -d "The protocol family to use" -a "inet inet6 bridge ipx dnet link any" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s 4 -d "Short for --family inet" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s 6 -d "Short for --family inet6" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s B -d "Short for --family bridge" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s D -d "Short for --family decnet" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s I -d "Short for --family ipx" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s O -d "Short for --family link" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s o -l oneline -d "Output on one line" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s r -l resolve -d "Resolve names and print them instead of addresses" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s n -l net -l netns -d "Use specified network namespace" -n "not __fish_seen_subcommand_from $ip_commands"
+complete -c ip -f -s a -l all -d "Execute command for all objects" -n "not __fish_seen_subcommand_from $ip_commands"