40

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
    fi

    # 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
            -h|--help)
                echo "Usage: $0 [-hil] [--help] [--info] [--list]";
                echo "       $0 {-s | --set} <name> [<file1 file2...>]";
                echo "       $0 {-t | --target} <name>] <file1 file2...>";
                return 0;;
            -i|--info)
                gvim_show_info;
                return 0;;
            -l|--list)
                gvim_list_servers;
                return 0;;
            -s|--set)
                gvim_set_server_name ${2:u};
                shift 2;;
            -t|--target)
                server="$2";
                shift 2;;
            --)
                shift;
                break;;
        esac
    done

    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;
        fi
    else
        # if files were specified...
        if [[ -n "$server" ]]; then
            # if --target was specified
            gvim_run_remote $server "$@"
        else
            gvim_run_remote $(gvim_get_default_server) "$@"
        fi
    fi

    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

    alternatives=(
        'args:rv options:_rv_options'
        'files:file:_vim_files'
    )

    _alternative $alternatives && return 0

    return 1
}

_rv_options() {
    local arguments

    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 '15 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 '16 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 – Olivier Dulac Sep 14 '16 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 '16 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. – Raphael Ahrens Jan 17 '17 at 9:59
1

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
  _git-ls-files
}

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

  • 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 '17 at 0:27

protected by Community Mar 15 '17 at 13:33

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.