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
    Commented 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
    Commented 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 Commented 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
    Commented 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. Commented 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

  • 2
    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
    Commented 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 .