Edit a remote file with
vim scp://remote/file
Saving the file with :w blocks the editor till the file changes are saved to the remote.
I was trying to use :Dispatch :write to avoid being blocked but that does not work (using tmux or iterm strategy). :Dispatch is provided by the plugin vim-dispatch.
Relevant internet search results suggest:
Ssh to remote and work there (if you have a slow connection, check this question or consider ssh-alternative mosh)
eshion/vim-sync offers the possibility to autosync changes of a local file to the remote
Git hook auto-push: after each commit push changes to the remote
satiani/async-scp-vim (see for details blog) launch SCP calls whenever the BufWritePost event is triggered
Ssh tunnel faster write due to open ssh connection (see also Speeding up Vim's Netrw plugin over ssh/scp and autossh).
sshfs/osxfuse-sshfs set directory=~/.vim/swaps//; set backupdir=~/.vim/backups
Neovim no release yet and nightly build does not do it out of the box. Any answer here appreciated. It has been reported as an issue #1464
Backchannel Vi
The solutions are helpful but require setup of vcs, config files, etc.
I'd prefer
to work locally
no configuration for each file (configuring the editor once and for all is ok)
Not every write should be a commit.
Keeping an ssh tunnel open didn't improve it either.
Update
I'd like to know whether there is a solution to run the save process asynchronously. The save process means here, as netrw is showing in the commandline, a scp call to copy the temp file to the remote which can take some time. I'd like to return to my editing in the meanwhile and don't be blocked. I hope this makes my question clearer.
Alternatives to tpope/dispatch are:
Shougo/vimproc, idbrii/AsyncCommand, which I haven't tried yet.
It was an old question, yet I encountered the same problem of how to work with remote files efficiently.
My solution is to use unison to sync files on the fly. A command is defined to call the sync function within vim.
function! s:Sync()
call system("unison -batch /home/user ssh://user#server//home/user")
endfunction
command! Sync :call <SID>Sync()
The speed of sync files using unison is so fast that I don't have much motivation to make it run asynchronously.
SSHFS: My Problem with sshfs was the vim plugin lightline.vim using fugitive.vim function.
The statusline is updated quite often when you scroll (line number changes) and therefore the fugitive function to show the current branch was evaluated all the time.
This slowed the scrolling significantly down. Removing fugitive status from statusline alleviated the slow down.
There is another plugin https://github.com/seletskiy/vim-refugi which reports that
git through sshfs is slow as hell.
I also installed this plugin for fugitive and applied their tip
Because this script uses ssh multiplexing, it is good to configure your
ssh to automatically open master connections.
E.g. you need this in your ~/.ssh/config:
host *
controlmaster auto
controlpath ~/.ssh/connections/%r_%h_%p
Plugin AsyncRun for vim8/neovim
describes on following wiki page how to get netrw using this plugin when saving to remote:
https://github.com/skywind3000/asyncrun.vim/wiki/Get-netrw-using-asyncrun-to-save-remote-files
Copy of the patch:
Following diff to $VIMRUNTIME/autoload/netrw.vim (version 156) saves asynchronously with AsyncRun when you put into your vimrc let g:netrw_write_AsyncRun = 1:
❯ git diff netrw-156.vim netrw.vim
diff --git a/netrw-156.vim b/netrw.vim
index 76485c2..183fc96 100644
--- a/netrw-156.vim
+++ b/netrw.vim
## -510,6 +510,7 ## call s:NetrwInit("g:NetrwTopLvlMenu","Netrw.")
call s:NetrwInit("g:netrw_win95ftp",1)
call s:NetrwInit("g:netrw_winsize",50)
call s:NetrwInit("g:netrw_wiw",1)
+call s:NetrwInit("g:netrw_write_AsyncRun",0)
if g:netrw_winsize > 100|let g:netrw_winsize= 100|endif
" ---------------------------------------------------------------------
" Default values for netrw's script variables: {{{2
## -2377,6 +2378,14 ## fun! netrw#NetWrite(...) range
" call Decho("(netrw) Processing your write request...",'~'.expand("<slnum>"))
endif
+ " NetWrite: Perform AsyncRun Write {{{3
+ " ============================
+ if exists("g:netrw_write_AsyncRun") && g:netrw_write_AsyncRun == 1
+ let bang_cmd = 'AsyncRun -post=call\ delete('.s:ShellEscape(tmpfile,1).')\ |\ echo\ "(netrw)\ Your\ write\ request\ has\ finished." '
+ else
+ let bang_cmd ="!"
+ endif
+
".........................................
" NetWrite: (rcp) NetWrite Method #1 {{{3
if b:netrw_method == 1
## -2515,7 +2524,7 ## fun! netrw#NetWrite(...) range
else
let useport= ""
endif
- call s:NetrwExe(s:netrw_silentxfer."!".g:netrw_scp_cmd.useport." ".s:ShellEscape(tmpfile,1)." ".s:ShellEscape(g:netrw_machine.":".b:netrw_fname,1))
+ call s:NetrwExe(s:netrw_silentxfer.bang_cmd.g:netrw_scp_cmd.useport." ".s:ShellEscape(tmpfile,1)." ".s:ShellEscape(g:netrw_machine.":".b:netrw_fname,1))
let b:netrw_lastfile = choice
".........................................
## -2612,9 +2621,11 ## fun! netrw#NetWrite(...) range
" NetWrite: Cleanup: {{{3
" call Decho("cleanup",'~'.expand("<slnum>"))
- if s:FileReadable(tmpfile)
-" call Decho("tmpfile<".tmpfile."> readable, will now delete it",'~'.expand("<slnum>"))
- call s:NetrwDelete(tmpfile)
+ if !exists("g:netrw_write_AsyncRun") || g:netrw_write_AsyncRun == 0
+ if s:FileReadable(tmpfile)
+" call Decho("tmpfile<".tmpfile."> readable, will now delete it",'~'.expand("<slnum>"))
+ call s:NetrwDelete(tmpfile)
+ endif
endif
call s:NetrwOptionRestore("w:")
Related
$ ls
Makefile html-page/ page-generator.m4
Run includes/
Alongside the Makefile, I have a script Run that is executed only when make completes without errors. This I've managed to implement with the following in my .vimrc file, which also looks for the Makefile in parent directories if needed.
" Before the 'make' quickfix command, run my quickfix pre-commands
autocmd QuickfixCmdPre make call MyQuickfixCmdPre()
" After the 'make' quickfix command, run my quickfix post-commands
autocmd QuickfixCmdPost make call MyQuickfixCmdPost()
and
function! MyQuickfixCmdPre()
" Save current buffer, but only if it's been modified
update
" (h)ead of (p)ath of % (current buffer), i.e. path of current file
let l:dir = expand('%:p:h')
" Remove final / and smack a /Makefile on the end, glob gives empty if file doesn't exist
while empty(glob(substitute(l:dir, '/$', '', '') . '/Makefile'))
" There's no Makefile here. Are we at the root dir?
if l:dir ==# "/"
" Just use dir of current file then
let l:dir = '.'
break
else
" Try the parent dir. Get (h)ead of dir, i.e. remove rightmost dir name from it
let l:dir = fnamemodify(l:dir, ':h')
endif
endwhile
" Makefile is in this dir, so local-cd (only this window) to the dir
execute "lcd " . l:dir
endfunction
function! MyQuickfixCmdPost()
" Get number of valid quickfix entries, i.e. number of errors reported,
" using filter to check the 'valid' flag
let l:err_count = len(filter(getqflist(), 'v:val.valid'))
if l:err_count ==# 0
" The make succeeded. Execute the Run script expected in the same dir as Makefile
call system('./Run')
redraw!
endif
endfunction
With this in place, after typing :mak in vim, the code is made and run... There are two possible results:
If there are errors during make, vim will present these errors with a Press ENTER or type command to continue afterwards, which is all good.
If make succeeds without errors, however, my Run script is executed, for testing my code (in this case an html file shown in a browser), but then when I switch back to vim, I have to press enter to get rid of a message from vim that I don't need to read because it doesn't tell me about errors. This message used to look like this:
"includes/m4includes/subs.m4" 34L, 759B written
:!make 2>&1| tee /var/folders/zk/0bsgbxne3pe5c86jsbgdt27f3333yd/T/vkbxFyd/255
m4 -I includes/m4includes page-generator.m4 >html-page/mypage.html
(1 of 1): m4 -I includes/m4includes page-generator.m4 >html-page/mypage.html
Press ENTER or type command to continue
but after introducing the redraw! in MyQuickfixCmdPost() is now reduced to:
(1 of 1): m4 -I includes/m4includes page-generator.m4 >html-page/mypage.html
Press ENTER or type command to continue
yet still with the need to press enter.
How do we avoid having to press enter every single time we return to vim after a successful compilation? Any ideas?
Note: vim has a -silent command-line option, but as far as I can see this would silence all the Press ENTERs, and the goal here is to only avoid them after a successful make.
Just add call feedkeys("\<CR>") afterwards. There are not many places you need feedkeys() (often normal! or similar commands will do), and there are subtle effects (look at the flags it takes carefully). Fortunately this is one place it is useful.
Since I have upgraded to Catalina, I cannot edit my dotfiles but get a message saying "Cannot write to backup file...".
I have checked the permissions on the file and my user account is the owner and has read and write permissions. If I edit the files with BBedit, I can save the files so the issue just seems to be editing within neovim.
I can also edit files using neovim in other directories but not within my dotfile directory.
Additional information added:
I have noticed that the files that I can't edit have the following permission structure:
.rwxrwxrwx# 1.4k pdd 30 Aug 2017 plugin_manager.vim
I have now removed the # attribute using xattr but that has not made any difference.
Additional Information Update
I have narrowed it down to something in my vimrc file. If I start neovim without my vimrc, I can save files in my vimrc directory.
I have the following code in my vimrc relating to backup files:
if exists('$SUDO_USER')
set nobackup " don't create root-owned files
set nowritebackup " don't create root-owned files
else
set backupdir=~/local/.config/nvim/tmp/backup
set backupdir+=~/.config/nvim/tmp/backup " keep backup files out of the way
set backupdir+=.
endif
If I comment these lines out, I can then save files in my vimrc directory. I am a little confused as I have had these in my vimrc for some time and have not had a problem.
I am probably missing something simple. Does anyone have any suggestions?
The original backup I used for vim was found here: https://vim.fandom.com/wiki/Incremental_backup_in_central_backup_directory created July 22, 2005 author Sylvain Lafleur
It doesn't work in neovim, but I was able to get it working:
I'm using KDE Neon. The original looks like it might work on windows, but I have not tested it.
A few things to note:
You will need to manually edit the g:backupdir and
g:this_root_backkup_dir (This may be reduced, but I didn't mess with it.)
I was unable to make $HOME work, so use /home/username on linux.
This is not my actual directory structure, but should suffice as an
example, in that /home/neon/vim existed before I used this code.
This is very redundant backup. Every time the file is saved it will
create a backup of the filename with date/time stamp.
In the .vimrc put your vim specific code in if !has('nvim')
and endif blocks. I put the following code in my init.vim file.
set backup
set backupcopy=yes
function Write_backup()
let g:backupdir='/home/neon/vim/vim_backups'
let &backupdir=g:backupdir
let g:backupext = strftime("_%Y-%m-%d_%H-%M-%S")
let &backupext=g:backupext
let g:this_root_backup_dir = '/home/neon/vim/vim_backups'
let g:this_dir = substitute(expand("%:p:h")," ","_","g")
let g:this_filename = substitute(expand("%")," ","_","g")
let g:this_drive = strpart(g:this_dir, 0, 1)
let g:this_backup_dir_drive = g:this_root_backup_dir . g:this_drive
let g:this_backup_dir = g:this_backup_dir_drive . strpart(g:this_dir, 1)
"--make DRIVE directory if it doesn't exist
if !filewritable(g:this_backup_dir_drive)
silent! execute expand('!mkdir -p ' . g:this_backup_dir_drive)
endif
"--make directory under DRIVE if it doesn't exist
if !filewritable(g:this_backup_dir)
silent! execute expand('!mkdir -p ' . g:this_backup_dir)
endif
"--set new backup dir
let g:backupdir = g:this_backup_dir
let &backupdir=g:backupdir
endfunction
call Write_backup()
inoremap <ESC> <ESC>:call Write_backup()<CR><C-l>
" note the <C-l> clears the output so remove if testing with echo
OS == FreeBSD-12.1p2
Vim == 8.1.2372
I am encountering a problem with vim having an excessively slow startup time on just one system. The content of vim --startuptime vim_startuptime.log follows:
times in msec
clock self+sourced self: sourced script
clock elapsed: other lines
000.030 000.030: --- VIM STARTING ---
000.166 000.136: Allocated generic buffers
000.293 000.127: locale set
000.307 000.014: GUI prepared
000.309 000.002: clipboard setup
000.334 000.025: window checked
001.000 000.666: inits 1
001.064 000.064: parsing arguments
001.066 000.002: expanding arguments
001.136 000.070: shell init
001.795 000.659: Termcap init
001.846 000.051: inits 2
002.060 000.214: init highlight
003.900 001.183 001.183: sourcing /usr/local/share/vim/vim81/syntax/syncolor.vim
. . .
018.890 001.561: loading plugins
018.997 000.107: loading packages
019.028 000.031: loading after plugins
019.077 000.049: inits 3
019.197 000.120: reading viminfo
75047.076 75027.879: setup clipboard
75047.146 000.070: setting raw mode
75047.161 000.015: start termcap
75047.191 000.030: clearing screen
75047.457 000.266: opening buffers
75047.551 000.094: BufEnter autocommands
75047.555 000.004: editing files in windows
75047.741 000.186: VimEnter autocommands
75047.744 000.003: before starting main loop
75048.149 000.405: first screen update
75048.151 000.002: --- VIM STARTED ---
However, if I disable X then this is the result (vim -X --startuptime vim_startuptime-X.log):
times in msec
clock self+sourced self: sourced script
clock elapsed: other lines
000.030 000.030: --- VIM STARTING ---
000.165 000.135: Allocated generic buffers
000.293 000.128: locale set
000.309 000.016: GUI prepared
000.310 000.001: clipboard setup
000.336 000.026: window checked
001.009 000.673: inits 1
001.074 000.065: parsing arguments
001.076 000.002: expanding arguments
001.146 000.070: shell init
001.801 000.655: Termcap init
001.853 000.052: inits 2
002.067 000.214: init highlight
003.936 001.214 001.214: sourcing /usr/local/share/vim/vim81/syntax/syncolor.vim
. . .
019.029 001.555: loading plugins
019.137 000.108: loading packages
019.168 000.031: loading after plugins
019.192 000.024: inits 3
019.307 000.115: reading viminfo
019.309 000.002: setup clipboard
019.363 000.054: setting raw mode
019.376 000.013: start termcap
019.402 000.026: clearing screen
019.811 000.409: opening buffers
019.856 000.045: BufEnter autocommands
019.859 000.003: editing files in windows
020.005 000.146: VimEnter autocommands
020.008 000.003: before starting main loop
020.390 000.382: first screen update
020.391 000.001: --- VIM STARTED ---
I connect to this system using ssh -X -t and generally use gvim to display the editing window on my desktop. When I do that on the problem host in addition to the long delay I get the message that the the child process could not open the GUI. I have previously run gvim on this host without issue.
Both hosts' /etc/ssh/sshd_config file are identical save for the Listen address. Yhe X11 entries in each are listed below:
grep -in x11 /etc/ssh/sshd_config
102:#X11Forwarding yes
103:#X11DisplayOffset 10
104:#X11UseLocalhost yes
147:# To allow ssh tunneling in jails set X11UseLocalhost to NO
148:X11UseLocalhost no
174:# X11Forwarding no
I have an identically configured host (hardware, OS, sshd_config) that I also connect to via ssh -X -t where this problem does not occur. I have tried removing and reinstalling vim on the problem host, which makes no difference.
Likewise I removed the .vim directory and .viminfo file from the user's home directory. This had no effect on startup time. This issue is not confined to a single userid in any case.
A debugging log (vim -V9vim_startup_debug.log) contains this:
. . .
Searching for "/usr/local/share/vim/vimfiles/after/plugin/**/*.vim"
Searching for "/root/.vim/after/plugin/**/*.vim"
not found in 'runtimepath': "plugin/**/*.vim"
Reading viminfo file "/root/.viminfo" info oldfiles
Opening the X display failed
Executing BufEnter Autocommands for "*"
autocommand sil call s:LocalBrowse(expand("<amatch>"))
. . .
I am open to suggestions as to how to resolve this problem. It is evident that X11 forwarding is somehow involved and that the clipboard setup is where the problem is happening, but I have no idea how to discover what the actual problem is.
Recently I tried to switch to having backup and swap files in a directory other than the working directory. With swp files, you can just put double-slashes at the end of the path:
set directory=~/.vim/swp//
However, this does not work with backupdir. I found an answer with a workaround however:
autocmd BufWritePost * :execute ':w! ' ."$HOME/.vim/backups/" . escape(substitute(expand('%:p'), "/", "%", "g"), "%")
I have a few questions regarding this workaround:
I know it saves files in $HOME/.vim/backups/[filename with path], but how does it do this?
How can I modify it so it saves the file as %full%file%path%filename~ (the difference is the ~ at the end)
Is it possible to reformat this command so it doesn't cross the preferred 80 char mark?
Thanks
My workaround was
" this is a default. to be updated per file type
autocmd BufNewFile,BufNew,BufRead * let b:buDir = "/work/BACKUP/vimBackups/all/"
then later, on a per-file-type basis I did
let b:buDir = "/work/BACKUP/vimBackups/text/"
or
let b:buDir = "/work/BACKUP/vimBackups/coding/"
Then, I call my backup on every exit
" the backup command
" currently, overwrite whatever is there: a new file will be made each second
" if necessary
autocmd VimLeavePre,BufWritePre * silent execute ":write! >> ".b:buDir."vim_bu_".strftime('%Y-%b-%d__%H:%M:%S')."_".b:buFilename.".bu.txt "
Then, in a daily clean-up script, run from cron (anacron), I delete out my old backups
# vim backups older than a month old
find $VIM_BU_DIR -not -newerat "1 month ago" -delete ;
I want to use GVim as a merge tool for TFS 2010.
I can't figure out the Arguments for GVim.
Specifically the argument %4, when I use it I get an empty buffer for it. if I don't use it I get an error message that I must use it.
This may not be exactly to your liking, but here's how I use GVim for a merge tool.
I set it up to do a two-way merge: it has the 'source' on the left (where I'm merging from), and the merge file on the right (starts off as what my destination branch has for information).
I set it up like this:
command: C:\Program Files (x86)\Vim\vim73\gvim.exe
argument: -c "vert diffsplit %1 " %4 -c "wincmd l|0read %2 |diff"
What this does is as follows:
Reads in the 'source' file on the left, and splits the window (-c "vert diffsplit %1")
Opens up on the right side the merge result (%4)
Runs a quick script which:
Moves over the right window (wincmd l)
Reads in my existing changes in the branch (0read %2)
Re-runs the diff algorithm (diff)
This lets me "diff" my work against the incoming merge, and saving the right hand side will resolve the merge.
Your screenshot suggests you are using Vim 7.3 . According to Vim site:
http://vim.wikia.com/wiki/Running_diff
At some point, the MyDiff function provided by the "Vim without Cream"
installer has been modified. As of Vim 7.3.138 it is still broken.
However, You can try the following verbose-mode parameters
command : gvim
argument: -V -od %1 %2