I work mostly in gvim and many terminals. Originally, I preferred to open all my files in a single vim instance. To that end I used an alias to open files from my terminals in the current 'vim server'.

alias rv="gvim --remote-silent"

But having many files from multiple projects open in a single vim instance impacts my productivity, so I'm upgrading my alias to a function.

# main function
rv() {
    local args options server

    options=$(getopt -o hils:t: -l "help,info,list,set:,target:" -- "$@")

    if [[ $? -ne 0 ]]; then
        echo "Failed to parse options."
        return 1

    # a little magic, necessary when using getopt
    eval set -- "$options"

    # go through the options with a case and use shift to analyze one option at a time.
    while true; do
        case "$1" in
                echo "Usage: $0 [-hil] [--help] [--info] [--list]";
                echo "       $0 {-s | --set} <name> [<file1 file2...>]";
                echo "       $0 {-t | --target} <name>] <file1 file2...>";
                return 0;;
                return 0;;
                return 0;;
                gvim_set_server_name ${2:u};
                shift 2;;
                shift 2;;

    if [[ "$#" -eq 0 ]]; then
        # if no files specified...
        if [[ -n "$server" ]]; then
            # throw error if --target option was specified.
            echo "Error!  --target requires one or more filenames."
            return 1;
        # if files were specified...
        if [[ -n "$server" ]]; then
            # if --target was specified
            gvim_run_remote $server "$@"
            gvim_run_remote $(gvim_get_default_server) "$@"

    return 0;

Now this new rv has it's own options. I can use it to:

  • list available vim servers (-l --list)
  • set the default vim server for the current shell (-s --set)
  • show the default vim server (-i --info)
  • open files in a specific vim server (-t --target)
  • open files in default vim server: rv files...

However, since I'm using a function for rv instead of an alias, I lose the zsh completion I previously enjoyed. I've read up on creating a completion function, _rv, that will show rv's options, but I want to combine my completion options with the existing vim completion options. I know there may be some conflicts with rv's -s and vim's -s, but I figure I can handle that elegantly with the -- separator.

TLDR; So, how do I create a completion script that combines the _arguments options for both _rv and _vim? I prefer to reuse _vim if possible instead of copy-pasting it's arguments list into _rv.

Here's my _rv. Updated 2014/6/10 16:10

#compdef rv

_rv() {
    typeset -A opt_args
    local alternatives

        'args:rv options:_rv_options'

    _alternative $alternatives && return 0

    return 1

_rv_options() {
    local arguments

        '(-i -l -s -t --info --list --set --target)'{-h,--help}'[Print usage info.]'
        '(-h -l -s -t --help --list --set --target)'{-i,--info}'[Print default vim server. As stored in $GVIM_SERVER.]'
        '(-i -h -s -t --info --help --set --target)'{-l,--list}'[Print list of existing vim servers.]'
        '(-i -h -l -t --info --help --list --target)'{-s,--set}'[Set default vim server for the current shell.]:vim servers:_rv_vim_servers'
        '(-i -h -l -s --info --help --list --set)'{-t,--target}'[Open files in a particular vim server.]:vim servers:_rv_vim_servers'

    _arguments -s -C $arguments && return 0

    return 1

_rv_vim_servers() {
    local -a servers
    servers=( ${(f)"$(_call_program servers vim --serverlist 2>/dev/null)"} )
    _wanted servers expl server compadd -M 'm:{a-z}={A-Z}' -a servers && return

# invoke the completion command during autoload
_rv "$@"

Current Behavior

Currently _rv completion will is usable, but not ideal.

  • When I type rv <TAB>, I do not see the vim options. Only rv options and file paths are displayed. _vim is completing file paths for me, so hooray to that!
  • When I type rv -s <TAB>, I see the list of vim servers, but also the file paths are displayed. A file is not permitted at this point in the command, and should not appear in the autocomplete.

Expected Behavior

  • When I type rv <TAB>, I expect to see: 1) rv options, 2) vim options, 3) file path list
  • When I type rv -s <TAB>, I expect to see: 1) vim server names (as provided by _rv_vim_servers.
  • When I type rv /valid/file/path/<TAB>, I expect to only see a file path list. Since _vim already has this capability, I would prefer to rely on it.
  • 1
    This unix.stackexchange.com/questions/128199/… could be useful.
    – clobrano
    Nov 20, 2015 at 8:50
  • 1
    compdef has a -n option which says it "prevents any completions already defined for the command or context from being overwritten". So, have you tried compdef _vim rv followed by compdev -n _rv rv ?
    – Lqueryvg
    Apr 9, 2016 at 19:07
  • 3
    28 upvotes and no answer... and it's a question about zsh... I'll try to invoke @StéphaneChazelas for you ^^ (I try not to abuse this, but it's fun. Please Stephane, tell me if I should not do this... and I'll delete this and never do it again) ... If someone here may know the answer, it should be him Sep 14, 2016 at 16:25
  • 1
    @OlivierDulac I think you only get notifications if you have already posted in the thread. (Duplicate names are allowed, so this makes sense.) You could possibly find him in chat though.
    – Sparhawk
    Oct 10, 2016 at 10:39
  • Could it be possible to source the original _vim file, but before doing so overwrite the _arguments function with a custom local function? By doing so you would get the arguments from _vim. Maybe with a separate zsh process. Jan 17, 2017 at 9:59

2 Answers 2


You can monkey-patch the _arguments function to extend the _vim completer:

#compdef rv

_rv_vim_servers() {
    local expl
    _wanted servers expl server \
        compadd -- ${(f)"$( _call_program servers vim --serverlist 2>/dev/null )"}

_rv() {
  autoload +X -Uz _arguments             # Load the function body.
  functions -c _arguments _rv_arguments  # Make a copy.

  # Replace the original function.
  _arguments() {
    # Call the original function with additional completions.
    _rv_arguments "$@" \
        '(-i -l -s -t --info --list --set --target)'{-h,--help}'[print usage info]' \
        '(-h -l -s -t --help --list --set --target)'{-i,--info}'[print default vim server as stored in $GVIM_SERVER]' \
        '(-i -h -s -t --info --help --set --target)'{-l,--list}'[print list of existing vim servers]' \
        '(-i -h -l -t --info --help --list --target)'{-s,--set}'[set default vim server for the current shell]:vim servers:_rv_vim_servers' \
        '(-i -h -l -s --info --help --list --set)'{-t,--target}'[open files in a particular vim server]:vim servers:_rv_vim_servers'

    _vim "$@"
  } always {
    functions -c _rv_arguments _arguments  # Restore the original.
    unfunction _rv_arguments               # Discard our copy.

_rv "$@"

I found /usr/share/zsh/functions/Completion/Unix/_git which had some tips for aliases like this and ended up defining these functions for the aliases:

_git-ls () {
  # Just return the _git-ls-files autocomplete function

Then, do a straight compdef g=git. The autocomplete system will see that you are running, for example, g ls and use the _git-ls autocomplete function.

As found Here

  • 1
    thanks, but not quite. your solution assumes I only want the auto-complete from _git-ls-files. This question has a git-ls (to stick with your convention) with its own options, and some of those options overlap with git-ls-files. Instead of writing autocomplete for all options of git-ls, how do I write an autocomplete that takes the autocomplete from _git-ls-files (which covers say 90%), and combines them with the autocomplete of the remaining (say 10%) options?
    – Justin C
    Jan 17, 2017 at 0:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .