For easily specifying remote files for editing with vim or emacs from the shell, I would like to have tab-completion like available for scp.

Completions for scp work well and fast, if your .ssh/config is correctly configured.

So why not for vim, and other ssh-capable editors? I feel, the standard bash-completion package could benefit from a completion function set for ssh-capable editors, which AFAIK does not yet exist publicly.

(In environments, where afuse and sshfs are available to me, I use "as work-around" a user-level afuse sshfs auto-mounter daemon spawned from shell init to on-demand background mount remote file-systems into a tree under ~/scp/.)


I played around with your solution. Here is a slightly tweaked version which works better for me on a Mac OSX 10.11 system using homebrew.

First, in a file rvim_fun.sh, I define

vi () {
  local params=();
  while [[ ! -z $1 ]]; do
    # test if arg begins a sequence S of characters
    #    - . A-Z a-z 0-9 @ _
    # followed by a colon,
    # if so, we replace S: by scp://S/ to match vim syntax

    if [[ "$1" =~ ^[-.A-Za-z0-9@_]*:.*$ ]]; then
      params=("scp://${1/://}" "${params[@]}");
  echo vi ${params[@]};
  $HOME/bin/vi ${params[@]};

I found that this somehow works better for me (also, I have a program vi installed in ~/bin that invokes MaxVim).

Now, on my Mac, I installed bash-completion via homebrew. All I had to do was place the following in my .bashrc file:

case "$-" in
*i*)    source rvim_func.sh 
        complete -F _scp -o nospace vi
*)  ;;

So I didn't directly source anything else, except for what one has to do with homebrew:

if [ -f $(brew --prefix)/etc/bash_completion ]; then
  . $(brew --prefix)/etc/bash_completion

That is from the homebrew discussion board...

Anyway, this works pretty well for me now...thanks!

| improve this answer | |

I hacked up something that "misuses" the available standard _scp bash completion function to enable completion of remote hosts/paths/files.

A vim-wrapping function then mangles the returned paths in the form ho.st:/fol/der/fi.le into the vim-expected form scp://ho.st///fol/der/fi.le.

vim () {
  local params=();
  while [[ ! -z $1 ]]; do
    if [[ "$1" =~ ^[a-z0-9-]*:/.*$ ]]; then
      params=("scp://${1/:\//\/\//}" "${params[@]}");
  echo vim ${params[@]};
  /usr/bin/vim ${params[@]};
. /usr/share/bash-completion/completions/scp
complete -F _scp -o nospace vim

For emacs use: params=("/scp:$1" "${params[@]}");

But, this setup could work better. Currently, this approach has the following minor shortcomings:

  • I can't tab-complete vim -o ptions. But I rarely use them anyway.
  • The scp options are still in there (but I never see them)
  • Only works for scp:// paths. But I only rarely use others like rsync or http.
  • The last 2 lines feel sub-optimal, and leave my env cluttered with lots of helper functions.

    I tried using this as second-last line instead, but this does not seem reliable:

    _completion_loader scp

    Sometimes, but not in tmux, spawning a new shell resulted in '_completion_loader not found'-Error. Yet running _completion_loader _scp results in functioning completion without error for this shell.

This works well enough for me, since I can just type the rare -o ption or http:// path.

But I do not consider this a good solution/answer, and won't accept it, because I am hoping for a better one to come up.

Note: I previously tried just using a modified standard supplied _known_hosts_real() function, found a way to run-time patch it to support more options, but then couldn't quickly wrap that into _vim(), so I just ignored the minor inconveniences of using _scp(), and started using that.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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