Search code examples
zshzsh-completion

zsh: Complete `command1` the same as `command2 ARG`


Given two commands:

  • command1 - which has completions already set up for it
  • commmand2- which is a wrapper function, that in the end calls command1 ARG

How do I make command2 complete in the same manner as command1 ARG1 would without writing a custom completion for command1?

Here's an example:

alias command1="git ls-files"

command2() {
  echo "I'm a wrapper for git ls-files" >&2
  git ls-files $@
}

One can do compdef command2=command1 - but that will make command2 complete the same way as git would and not like git ls-files.

Edit: I'm looking for a broad and general solution that'd also work with commands that do not define separate completion functions such as git has. For these you can do what Marlon Richert suggested below.

Here's a better example:

alias command1="kubectl get pod"

command2() {
  echo "I'm a wrapper for kubectl get pod" >&2
  kubectl get pod $@
}

Solution

  • Do this to find out the name of the function that needs to be called:

    % git ls-files ^Xh  # That is, press Ctrl-X, then H.
    tags in context :completion::complete:git-ls-files::
        argument-rest options  (_arguments _git-ls-files _git)
    tags in context :completion::complete:git-ls-files:argument-rest:
        globbed-files  (_files _arguments _git-ls-files _git)
    tags in context :completion::complete:git::
        argument-rest  (_arguments _git)
    

    As you can see, it's _git-ls-files.

    Then, discard the leading _ and use the remainder as the $service argument to compdef:

    compdef _git command2=git-ls-files
    

    Now it works correctly:

    % command2 ^Xh
    tags in context :completion::complete:command2::
        argument-rest options  (_arguments _git-ls-files _git)
    tags in context :completion::complete:command2:argument-rest:
        globbed-files  (_files _arguments _git-ls-files _git)
    

    Update

    For your kubectl example, things are slightly less easy, because its completion is not Zsh-native. Instead, it's just a thin Zsh wrapper around a Bash completion function. In this case, you will have to write your own completion function, but thankfully, it's going to be just a mercifully short one:

    _command2 () {
      # Fake having `kubectl get pod` on the line instead of `command2`.
      local -a words=( kubectl get pod $words[2,-1] )
      local -i CURRENT=$(( CURRENT + 2 ))
    
      # Restart completion with our new, simulated command line.
      _normal
    }
    compdef _command2 command2
    

    Done!