Complete a command (with arguments) like another command (with other arguments)
Asked Answered
R

1

3

compdef cmd1=service can be used to define a completion alias, however, that works only when the arguments are going to be the same.

For example, consider a helper script which rewrites some arguments before executing another command:

| What is typed | What is executed           |
|---------------+----------------------------|
| s             | systemctl                  |
| s q           | systemctl status           |
| s q foo       | systemctl status foo       |
| s j foo       | journalctl --unit foo      |
| s r foo       | sudo systemctl restart foo |

We can ask the script to print the arguments it would execute, so e.g. PRINT_ONLY=1 s would print just systemctl.

Assuming completion is already set up for systemctl / journalctl / sudo, how would one define a zsh completion for such a script? Rather than redundantly reimplementing completion for those commands, how to implement completion for s such that the completion system is invoked with a transformed command -- i.e. something like function _s() { get_completions $(PRINT_ONLY=1 s "$@") ; }?

Rosemare answered 3/7, 2022 at 6:51 Comment(0)
S
2

This should go in a file named _s somewhere on your $fpath:

#compdef s

local -a orig_command new_words
orig_command=("${words[@]}")
if [[ $words[-1] == '' ]]; then
  # remove an empty word at the end, which the completion system cares about
  orig_command[-1]=()
fi
# split the rewritten command into words using the shell parser
new_words=("${(z)$(PRINT_ONLY=1 "${orig_command[@]}")}")
if [[ $words[-1] == '' ]]; then
  # restore the empty word if we removed it
  new_words+=('')
fi
# update the cursor position
CURRENT=$(( CURRENT - $#words + $#new_words ))
words=("${new_words[@]}")
# restart completion with the rewritten command
_normal

Note: this doesn't do any error handling and just assumes that any unknown arguments will be passed to the default command (e.g. s start foo -> systemctl start foo). If that's not the case, let me know how s behaves in those cases and I can update the completion script.

Sweptback answered 8/7, 2022 at 0:24 Comment(1)
Perfect, thank you so much. Since I could edit the helper script, I modified it to output transformed parameters as NUL-terminated, which allowed simplifying the completion further: gist.github.com/CyberShadow/d453fd5ab13d859207b7c03f768b4b94Rosemare

© 2022 - 2024 — McMap. All rights reserved.