48

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.
asked Jun 10, 2014 at 18:13
6
  • 1
    This unix.stackexchange.com/questions/128199/… could be useful. 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 ? 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. 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

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 "$@"
answered Nov 5, 2021 at 8:37
0

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

answered Jan 16, 2017 at 22:47
1
  • 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? Commented Jan 17, 2017 at 0:27

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.