mirror of
https://github.com/ohmyzsh/ohmyzsh.git
synced 2026-07-17 05:51:18 +02:00
feat!: Add support for "iw" command
- CLI completion for iw (Linux wireless configuration utility). - Directly parses "iw help" output to discover commands and caches the result. - $service is used as the iw binary name. This allows this completion to work for differently-named iw binaries: compdef _iw my-iw-binary
This commit is contained in:
parent
70ad5e3df8
commit
8c079e8160
3 changed files with 277 additions and 0 deletions
40
plugins/iw/README.md
Normal file
40
plugins/iw/README.md
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# iw plugin
|
||||||
|
|
||||||
|
This plugin adds tab completion for [`iw`](https://wireless.wiki.kernel.org/en/users/documentation/iw),
|
||||||
|
the standard Linux command-line tool for configuring wireless network interfaces.
|
||||||
|
|
||||||
|
To use it, add `iw` to the plugins array in your zshrc file:
|
||||||
|
|
||||||
|
```zsh
|
||||||
|
plugins=(... iw)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Completion
|
||||||
|
|
||||||
|
Completion is generated dynamically by parsing the output of `iw help` and cached for
|
||||||
|
performance. The cache is stored in `$ZSH_CACHE_DIR/_iw_cache` and is automatically
|
||||||
|
regenerated when the installed version of `iw` changes.
|
||||||
|
|
||||||
|
The following command structure is completed:
|
||||||
|
|
||||||
|
| Level | Examples |
|
||||||
|
| ----- | -------- |
|
||||||
|
| Top-level commands | `dev`, `phy`, `wdev`, `reg`, `list`, `event`, … (discovered dynamically) |
|
||||||
|
| Interface / phy names | `wlan0`, `phy0` (discovered from `/sys/class/net` and `/sys/class/ieee80211`) |
|
||||||
|
| Subcommands | `dev <if> scan`, `dev <if> station`, `phy <phy> set`, … |
|
||||||
|
| Sub-subcommands | `dev <if> scan dump`, `dev <if> station get`, `phy <phy> set txpower`, … |
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
| Function | Description |
|
||||||
|
| -------- | ----------- |
|
||||||
|
| `iw-clear-cache` | Delete the cached completion data (useful after upgrading `iw`) |
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- `iw` must be installed and in `$PATH`
|
||||||
|
- Completion for a differently-named `iw` binary can be enabled with:
|
||||||
|
|
||||||
|
```zsh
|
||||||
|
compdef _iw my-iw-binary
|
||||||
|
```
|
||||||
220
plugins/iw/_iw
Normal file
220
plugins/iw/_iw
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
#compdef iw
|
||||||
|
#
|
||||||
|
|
||||||
|
# ZSH completion for iw (Linux wireless configuration utility).
|
||||||
|
# Parses 'iw help' output to discover commands and caches the result.
|
||||||
|
#
|
||||||
|
# $service is used as the iw binary name. This allows this completion to work
|
||||||
|
# for differently-named iw binaries: compdef _iw my-iw-binary
|
||||||
|
|
||||||
|
# Parse 'iw help' output and write a sourceable cache file.
|
||||||
|
_iw_build_cache() {
|
||||||
|
local iw_cmd="$1"
|
||||||
|
local version="$2"
|
||||||
|
local cache_file="$3"
|
||||||
|
local help_output
|
||||||
|
|
||||||
|
help_output=$($iw_cmd help 2>&1) || return 1
|
||||||
|
|
||||||
|
local -a top_cmds dev_subcmds phy_subcmds wdev_subcmds reg_subcmds
|
||||||
|
local -A dev_subs phy_subs wdev_subs
|
||||||
|
local line
|
||||||
|
local -a words lines
|
||||||
|
|
||||||
|
# Single pass: collect top-level commands, subcmds, and sub-subcommands.
|
||||||
|
# words[4] entries starting with '<', '[', or '-' are placeholders, not completions.
|
||||||
|
lines=(${(f)help_output})
|
||||||
|
for line in $lines; do
|
||||||
|
words=(${=line})
|
||||||
|
[[ $line == $'\t'[a-z]* && $line != $'\t\t'* ]] && top_cmds+=($words[1])
|
||||||
|
case $words[1] in
|
||||||
|
dev)
|
||||||
|
if [[ $words[2] == '<devname>' && $words[3] == [a-z]* ]]; then
|
||||||
|
dev_subcmds+=($words[3])
|
||||||
|
if (( ${#words} > 3 )); then
|
||||||
|
case $words[4] in
|
||||||
|
'<'*|'['*|'-'*) ;;
|
||||||
|
*) dev_subs[$words[3]]+=" $words[4]" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
phy)
|
||||||
|
if [[ $words[2] == '<phyname>' && $words[3] == [a-z]* ]]; then
|
||||||
|
phy_subcmds+=($words[3])
|
||||||
|
if (( ${#words} > 3 )); then
|
||||||
|
case $words[4] in
|
||||||
|
'<'*|'['*|'-'*) ;;
|
||||||
|
*) phy_subs[$words[3]]+=" $words[4]" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
wdev)
|
||||||
|
if [[ $words[2] == '<idx>' && $words[3] == [a-z]* ]]; then
|
||||||
|
wdev_subcmds+=($words[3])
|
||||||
|
if (( ${#words} > 3 )); then
|
||||||
|
case $words[4] in
|
||||||
|
'<'*|'['*|'-'*) ;;
|
||||||
|
*) wdev_subs[$words[3]]+=" $words[4]" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
reg)
|
||||||
|
[[ $words[2] == [a-z]* ]] && reg_subcmds+=($words[2])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# (ou): sorted + unique, replacing sort -u
|
||||||
|
top_cmds=(${(ou)top_cmds})
|
||||||
|
dev_subcmds=(${(ou)dev_subcmds})
|
||||||
|
phy_subcmds=(${(ou)phy_subcmds})
|
||||||
|
wdev_subcmds=(${(ou)wdev_subcmds})
|
||||||
|
reg_subcmds=(${(ou)reg_subcmds})
|
||||||
|
|
||||||
|
local subcmd subs_str
|
||||||
|
local -a subs_arr tmp_arr
|
||||||
|
|
||||||
|
{
|
||||||
|
print "# iw completion cache"
|
||||||
|
print "# version: ${version}"
|
||||||
|
|
||||||
|
print "_iw_top_cmds=(${top_cmds[*]})"
|
||||||
|
print "_iw_dev_subcmds=(${dev_subcmds[*]})"
|
||||||
|
for subcmd in $dev_subcmds; do
|
||||||
|
if [[ -n "${dev_subs[$subcmd]}" ]]; then
|
||||||
|
tmp_arr=(${=dev_subs[$subcmd]})
|
||||||
|
subs_arr=(${(ou)tmp_arr})
|
||||||
|
subs_str="${(j: :)subs_arr}"
|
||||||
|
print "_iw_dev_subsubcmds[${subcmd}]=${(qq)subs_str}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
print "_iw_phy_subcmds=(${phy_subcmds[*]})"
|
||||||
|
for subcmd in $phy_subcmds; do
|
||||||
|
if [[ -n "${phy_subs[$subcmd]}" ]]; then
|
||||||
|
tmp_arr=(${=phy_subs[$subcmd]})
|
||||||
|
subs_arr=(${(ou)tmp_arr})
|
||||||
|
subs_str="${(j: :)subs_arr}"
|
||||||
|
print "_iw_phy_subsubcmds[${subcmd}]=${(qq)subs_str}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
print "_iw_wdev_subcmds=(${wdev_subcmds[*]})"
|
||||||
|
for subcmd in $wdev_subcmds; do
|
||||||
|
if [[ -n "${wdev_subs[$subcmd]}" ]]; then
|
||||||
|
tmp_arr=(${=wdev_subs[$subcmd]})
|
||||||
|
subs_arr=(${(ou)tmp_arr})
|
||||||
|
subs_str="${(j: :)subs_arr}"
|
||||||
|
print "_iw_wdev_subsubcmds[${subcmd}]=${(qq)subs_str}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
print "_iw_reg_subcmds=(${reg_subcmds[*]})"
|
||||||
|
|
||||||
|
} >| "$cache_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
_iw() {
|
||||||
|
local context state line curcontext="$curcontext"
|
||||||
|
integer ret=1
|
||||||
|
|
||||||
|
# Declare cache variables; populated by sourcing the cache file below.
|
||||||
|
local -a _iw_top_cmds _iw_dev_subcmds _iw_phy_subcmds _iw_wdev_subcmds _iw_reg_subcmds
|
||||||
|
local -A _iw_dev_subsubcmds _iw_phy_subsubcmds _iw_wdev_subsubcmds
|
||||||
|
|
||||||
|
local cache_file="${ZSH_CACHE_DIR:-${HOME}/.cache}/_iw_cache"
|
||||||
|
local current_version ver_output
|
||||||
|
ver_output=$(${service} --version 2>&1)
|
||||||
|
[[ $ver_output =~ '([0-9]+\.[0-9]+)' ]] && current_version=$match[1] || current_version=""
|
||||||
|
|
||||||
|
local cache_ver="" _l1 _l2
|
||||||
|
if [[ -f "$cache_file" ]]; then
|
||||||
|
{ IFS= read -r _l1; IFS= read -r _l2; } < "$cache_file" 2>/dev/null
|
||||||
|
cache_ver=${_l2#\# version: }
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $cache_ver != $current_version ]]; then
|
||||||
|
_iw_build_cache "${service}" "$current_version" "$cache_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
source "$cache_file" 2>/dev/null
|
||||||
|
|
||||||
|
_arguments -C \
|
||||||
|
'--debug[enable netlink debugging]' \
|
||||||
|
'(- 1 2 3 4)--version[show version]' \
|
||||||
|
'1:: :->cmd' \
|
||||||
|
'2:: :->arg2' \
|
||||||
|
'3:: :->arg3' \
|
||||||
|
'4:: :->arg4' \
|
||||||
|
&& return 0
|
||||||
|
|
||||||
|
case "$state" in
|
||||||
|
cmd)
|
||||||
|
local -A _iw_cmd_descs
|
||||||
|
_iw_cmd_descs=(
|
||||||
|
dev 'network interface commands'
|
||||||
|
phy 'wireless hardware commands'
|
||||||
|
wdev 'wireless device commands'
|
||||||
|
reg 'regulatory domain commands'
|
||||||
|
list 'list all wireless devices and their capabilities'
|
||||||
|
event 'monitor kernel events'
|
||||||
|
features 'list supported features'
|
||||||
|
commands 'list all known commands'
|
||||||
|
help 'show command usage'
|
||||||
|
)
|
||||||
|
local -a top_cmds
|
||||||
|
local _cmd
|
||||||
|
for _cmd in $_iw_top_cmds; do
|
||||||
|
if [[ -n "${_iw_cmd_descs[$_cmd]}" ]]; then
|
||||||
|
top_cmds+=("${_cmd}:${_iw_cmd_descs[$_cmd]}")
|
||||||
|
else
|
||||||
|
top_cmds+=("$_cmd")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
_describe -t commands 'iw command' top_cmds && ret=0
|
||||||
|
;;
|
||||||
|
|
||||||
|
arg2)
|
||||||
|
case "$line[1]" in
|
||||||
|
dev)
|
||||||
|
local -a wlan_devs
|
||||||
|
wlan_devs=(/sys/class/net/*/phy80211(N:h:t))
|
||||||
|
compadd -a wlan_devs && ret=0
|
||||||
|
;;
|
||||||
|
phy)
|
||||||
|
local -a phy_devs
|
||||||
|
phy_devs=(/sys/class/ieee80211/*(N:t))
|
||||||
|
compadd -a phy_devs && ret=0
|
||||||
|
;;
|
||||||
|
reg)
|
||||||
|
compadd -a _iw_reg_subcmds && ret=0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
|
||||||
|
arg3)
|
||||||
|
case "$line[1]" in
|
||||||
|
dev) compadd -a _iw_dev_subcmds && ret=0 ;;
|
||||||
|
phy) compadd -a _iw_phy_subcmds && ret=0 ;;
|
||||||
|
wdev) compadd -a _iw_wdev_subcmds && ret=0 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
|
||||||
|
arg4)
|
||||||
|
local -a subs
|
||||||
|
case "$line[1]" in
|
||||||
|
dev) subs=(${=_iw_dev_subsubcmds[$line[3]]}) ;;
|
||||||
|
phy) subs=(${=_iw_phy_subsubcmds[$line[3]]}) ;;
|
||||||
|
wdev) subs=(${=_iw_wdev_subsubcmds[$line[3]]}) ;;
|
||||||
|
esac
|
||||||
|
(( ${#subs} > 0 )) && compadd -a subs && ret=0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
_iw "$@"
|
||||||
17
plugins/iw/iw.plugin.zsh
Normal file
17
plugins/iw/iw.plugin.zsh
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# iw Oh-My-ZSH plugin
|
||||||
|
# Provides tab completion for iw (Linux wireless configuration utility).
|
||||||
|
|
||||||
|
if (( ! $+commands[iw] )); then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove the cached iw completion data (useful after upgrading iw).
|
||||||
|
iw-clear-cache() {
|
||||||
|
local cache_file="${ZSH_CACHE_DIR:-${HOME}/.cache}/_iw_cache"
|
||||||
|
if [[ -f "$cache_file" ]]; then
|
||||||
|
rm -f "$cache_file"
|
||||||
|
print "iw completion cache cleared."
|
||||||
|
else
|
||||||
|
print "No iw completion cache found."
|
||||||
|
fi
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue