The zsh function cn

function cn() {
    nmcli device wifi connect "$1" --ask

will prompt for a password and connect to the network foo, if you type

cn foo

But it will not auto-complete foo, as when you write the nmcli command in full. How do I get auto-completion of the network name?

I'm using zsh 5.7.1.


The easy way in this specific case: make it an alias instead. This is possible because you can put --ask before the network name. Zsh expands aliases before doing completion by default.

alias cn='nmcli device wifi connect --ask'

If you use a function, you need to teach zsh about the arguments of the function: specify a completion function for cn, which may or may not be a custom function depending on what it has to do. (I assume that you're using the “new completion system”, i.e. you have compinit in your .zshrc.)

Here the function is a simple wrapper around another command. So see how this command's arguments are completed.

% echo $_comps[nmcli]

For most commands, the name of the completion function is the command name with an underscore before it, but for nmcli, in recent zsh versions, it's a different name. (It may be _nmcli on your system if you're running zsh &lt5.5.) Next, look at the source code to see how the function works. See How to look up zsh completion definitions for more information.

You don't need to understand everything (and good luck trying: the completion system is complex!) but for most commands it's reasonably easy to figure out how a specific subcommand or option is completed. In zsh ≥5.5 it's the function _nm_device_wifi_connect which in turn calls _nm_device_wifi_ssids. In zsh ≤5.4 I think _nmcli doesn't support this particular command line syntax (the syntax of nmcli keeps changing, so by the time zsh releases a version, its nmcli completion code tends to be already out of date).

With zsh ≥5.5, you can associate _nm_device_wifi_ssids with cn. However, there's a twist: if you first complete cn without having ever completed nmcli, zsh won't know where to find _nm_device_wifi_ssids, because completion functions are loaded on demand and this mechanism only knows how to find the main function _networkmanager, not auxiliary functions like _nm_XXX. See Can I use a helper function from a ZSH completion file in another and overwrite and reuse existing function in zsh for how to work around this.

Here the code of the zsh 5.5 function is simple, and zsh 5.4 doesn't have a corresponding function anyway. So the easiest solution is to copy the relevant part of the zsh 5.5 code into a new function.

function _cn {
    compadd -- ${(f)"$(_call_program nmcli nmcli -t -f ssid device wifi list)"}
compdef `_cn` cn
  • the first method doesn't work for me. there are completions, but not of network names.
    – Toothrot
    Nov 30 '19 at 22:27
  • in 5.7.1, i have a function called _nm, but no other function beginning with _nm_
    – Toothrot
    Nov 30 '19 at 22:53
  • @Toothrot As I mention in my answer, the _nm_XXX functions will appear once you've completed nmcli at least once. Nov 30 '19 at 23:02
  • would it perhaps also be possible to have something like an expandable alias (there would be a more correct term), such that typing nc<tab> would put nmcli device wifi connect | --ask on the readline, with the cursor at the tab?
    – Toothrot
    Dec 5 '19 at 14:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.