Can I use a helper function from a ZSH completion file in another

I’m writing a ZSH completion file for a command which is a wrapper around another command that already has ZSH completion support. I’d like to use “private” helper functions defined in the other command’s completion, but the naive approach isn’t working. Here’s what I am trying so far:

#compdef wrapper

_arguments ':action:(foo bar baz)' ':target:_other_command_helper_func'

when I try to do completion at the command line, I get

_arguments:450: command not found: _other_command_helper_func

Is it possible to do what I want to do here?

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

There are no private functions, so it’ll work if _other_command_helper_func is already loaded. Since completion functions are normally autoloaded, that means that, with this approach, the completion for wrapper will only work if completion of the original command has already been attempted.

One solution is to force the loading of the original command’s completion function file, but this is not straightforward. You can use autoload -X +U to load the completer for the original command, but what this in fact does is to create a function _other_command (assuming that’s the name of the original command) whose definition is the content of the _other_command file, consisting of the definition of auxiliary functions and other initialization followed by a call to the main function.

_other_command () {
        _other_command_helper_func () {
                …
        }

        _other_command () {
                …
        }

        _other_command "[email protected]"
}

You could try to parse that. If the definition is under your control, you can make some assumptions regarding the initialization code. If it comes from a third party, that’s more risky. Most complex completion function definition files follow the model of having initialization followed by a last line of the form _main_function "[email protected]", so this will usually work:

if ((!$+functions[_other_command_helper_func])); then
  autoload +X +U _other_command
  functions[_other_command]=${functions[_other_command]%$'\n'*}
  _other_command
fi

If you get weird errors, this may be due to options that affect the parser (I had this problem loading _git in this way). This worked for me:

load_helper_functions () {
  emulate -LR zsh
  if ((!$+functions[$1])) || [[ $functions[$1] = 'builtin autoload'* ]]; then
    autoload +X +U $1
    functions[$1]=${functions[$1]%$'\n'*}
    $1
  fi
}
load_helper_functions _git

Alternatively, you can just run the completion function in your .zshrc and let it choke silently because it wasn’t run in a completion context. For example, I had this precise problem with CVS; I put _cvs 2>/dev/null in my .zshrc.

If the definition of the original is under your control, then there are better solutions. You could use the same completion function for the original command and for the wrapper (check $service to see what command’s arguments are being completed). Or you could define the auxiliary function in a separate file.

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply