How can I make Vim autosave files when it loses focus? - vim

I'm used to my editors autosaving files when they lose focus. I recently switched to MacVim, and I can't recreate that behavior. I tried this:
autocmd BufLeave,FocusLost * wall
but if a buffer is unnamed when the window or MacVim loses focus, I get an error like the following:
Error detected while processing BufLeave Auto commands for "*":
E141: No file name for buffer 1
I'm confused, because :wall's documentation says:
Write all changed buffers. Buffers without a file
name or which are readonly are not written.
so I'd expect it to skip unnamed buffers. Is there a better way to do this?
Edit:
I'm pretty sure that the better way to do what I intended by using BufLeave -- saving buffers when I switch between them, so I don't get "No write since last change" -- is to set 'autowriteall'. The question still stands for when MacVim loses focus to other applications (FocusLost).

You don’t care about errors in those circumstances since there is nothing you can reasonably do about them anyway – especially when losing focus. So just swallow them:
autocmd BufLeave,FocusLost * silent! wall
Much simpler than an elaborate dance to figure out where there would be an error in order to avoid it.

I suspect when docs for wall say "without a file name" they may be referring to buffers with buftype=nofile . One way to get what you want would be to have the autocmd have bufdo call a simple function. E.g., some untested code to give the idea:
autocmd BufLeave,FocusLost * bufdo! call WriteFile()
function WriteFile()
if (&buftype=="") && (expand("%:r") > "") && (&readonly==0)
write
endif
endfunction
I think the standard way of getting something like this automatic saving of buffers would be to set the autosave option in Vim.

autocmd BufLeave,FocusLost * bufdo! call WriteFile()
function WriteFile()
if (&buftype=="") && (expand("%:r") > "") && (&readonly==0)
write
endif
endfunction
This method has a side-effect that, you can only open one unamed buffer. If you open the second one, it would automatically be synced to the content of the first unamed buffer.

just put this in .vimrc
set updatetime=1000
autocmd CursorHoldI * silent w

Related

Automatically save a buffer when using bdelete command in Vim

I would like to automatically write a buffer on removing it from the list of open buffers with the bd the same way I use x when I only have one open buffer.
I have set the set hidden option of course.
I have tried to put autocmd BufDelete * w (or ... update or ...w!) but alas it does not work.
I have also tried to set autowrite in my .vimrc although it does more than what I would like but it did not work either :
No matter what vim complains that the changes have not been written.
I did read the manual :h autowrite/hidden/autocmd-events and did not find my answer.
How do I do it or what am I missing ? Is there something wrong with my buffer workflow ?
Thanks in advance.
I think this is the only way:
function! CarefullyDelCurrentBuf()
update
bdelete!
endfunction
command! BD call CarefullyDelCurrentBuf()
Now use :BD instead of :bd.

is it possible to set BufLeave autocmd in vim on the fly?

What I want to do:
Inside a file/buffer in vim, especially an unnamed one (for example, created with :enew), sometimes I feel the content I'm writing is worth saving (say, I suddenly want to send it via an email), but don't feel the particular need to save it to a temp file, nor do I trust myself enough to "remember" to save it upon exit.
So I thought, what if I run
autocmd BufLeave * ggvG"+y
in the vim command line once and be free from the fear of losing this content.
But it doesn't work. When I exit vim, the system clipboard reminds intact.
My questions:
does it do anything if we run autocmd on the fly, as opposed to in vimrc?
is there a way to tell vim to "hey, when you exit, run these"?
Thanks a ton!
Two problems:
1) You didn't leave the buffer to go to another buffer (BufLeave); you left Vim (VimLeave).
2) autocmd expects a command, not normal mode keystrokes.
With that in mind,
autocmd VimLeave * normal gg"+yG

Vim: Delete Buffer When Quitting Split Window

I have this very useful function in my .vimrc:
function! MyGitDiff()
!git cat-file blob HEAD:% > temp/compare.tmp
diffthis
belowright vertical new
edit temp/compare.tmp
diffthis
endfunction
What it does is basically opening the file I am currently working on from repository in a vertical split window, then compare with it. This is very handy, as I can easily compare changes to the original file.
However, there is a problem. After finishing the compare, I remove the split window by typing :q. This however doesn't remove the buffer from the buffer list and I can still see the compare.tmp file in the buffer list. This is annoying because whenever I make new compare, I get this message:
Warning: File "temp/compare.tmp" has changed since editing started.
Is there anyway to delete the file from buffers as well as closing the vertical split window?
Perhaps you need the bwipe command?
:bw[ipeout][!] N1 N2 ...
Like |:bdelete|, but really delete the buffer. Everything
related to the buffer is lost. All marks in this buffer
become invalid, option settings are lost, etc. Don't use this
unless you know what you are doing.
One option would be to define the following:
function! DelBuf(filename)
let bname = bufname(filename)
if l:bname != ""
let bidx = buffer_number(l:bname)
exec = "bw " . l:bidx
endif
endfunction
and add a call to DelBuf("comapre.tmp") at the beginning of your function.
In theory it should be possible to bind DelBuf to the `bufhidden event like this:
autocmd! bufhidden "compare.tmp" call DelTmp("compare.tmp")
... but for some reason it didn't work for me.
You need to use autocmd winleave bd (buffer delete). Be warned that if you have the buffer open in more than one window they will all be removed.
I usually define the following things for diff-buffers:
setlocal bt=nofile bh=wipe nobl noswf ro
nnoremap <buffer> q :bw<cr>
The first line is what will make the difference in your case (:h 'bh' -> no need for a single execution autcocommand), the second line is just a shortcut.
BTW: use r! git instead of producing a temporary file. This way, you won't have to clear that file either.

Completely exit location list (lcl) created by Syntastic as well the main buffer when using :q, :q! or :wq! in VIM

I'm using Syntastic plugin. I have some files with some errors (Warnings) that I can't change. When I have a file opened with error messages, and I quit the file(buffer) pressing :q, the error messages are still visible(another buffer), so I have to press :q twice to completely exit when editing a file.
So, how do I press :q just once with a file with a buffer containing my file and another buffer (location list) containing Syntastic errors? I've searched a little bit and the command to close the location list is :lcl.
When I exit a buffer with :q, if the location list for that buffer is active, I want to close it with the location list within, calling :lcl. I'm reading some autocmd BufLeave and BufWinLeave and trying to create a mapping for this, but I cant know the difference between the two. Can someone help me?
Remembering, :w, :q, :q!, :wq should all work as intended.
As lcl work even if there is no error window you can map q to lcl and q
cnoremap q<cr> \|lcl\|q<cr>
As suggested an abbreviation seems better
cabbrev q lcl\|q
(note the \ before |, without it does the abbreviation then quit )
I realize this question is old and that the answer was accepted sometime ago. I tried using the accepted answer but it does not seem to work any more.
I did however find a workaround from this question, should others run in to this.
Basically, use a script to check if there are any other remaining windows open and if the last remaining window is a location-list, quit.
:autocmd WinEnter * if &buftype ==# 'quickfix' && winnr('$') == 1 | quit | endif
I think this may not be ideal but works well enough in the meantime.

How can I execute a command when a buffer is closed in vim?

Is there something like a close-window-hook in vim/vimscript, so that I can call a function every time a window is closed?
I want to use it for the following scenario:
I use an extra scratch window to display information about the file, and when I close the file I want the scratch window to be closed automatically so that vim exits.
If you have any ideas how to achieve that without a hook that will be just as fine.
edit:
I know about :qa[ll], but I am lazy and only want to type :q or ZZ.
edit2.71828183:
I accepted the autocommand answer as it was closest to the original question, but found another solution in using a preview window instead of a split window. A preview window is automatically closed when the last "normal" window is closed..
autocommands are amazing! I'm pretty sure that in this case, BufLeave will do the job, but you might want BufWinLeave? Have a look at :help autocmd-events for a full list of events.
The other bit you'll care about is: you can have buffer-local autocommands! (:help autocmd-buflocal)
You can define one for the current buffer using au BufLeave <buffer> .... My best guess is that you could run this in whatever command creates the scratch window. You should be able to cache the scratch window's buffer number in a global variable when you open the scratch window, then your autocommand could just delete that buffer (:help :bdelete).
au BufLeave <buffer> bdelete g:scratch_buffer
call CreateScratchWindow()
function CreateScratchWindow() {
...
let g:scratch_buffer = bufnr("")
}
There's also a function winbufnr, for getting buffer numbers by window. You can use either one - just make sure that the scratch window/buffer is current when you use it! (The "" means current window/buffer).
Add a mapping.
:nnoremap :q :qa
then, if you only want to use :q one day, you can just
:qa<backspace>
and normally, you can just
:q<enter>
and get
:qa<enter>
for free.
Ok, not really a new question, but I found it looking for, what I now know, BufWinLeave. However, the scenario the author is describing is something I have in my vimrc with NerdTree, e.g. when the last buffer is closed, I want vim to close the NerdTree "buffer" and then quit.
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif
Replace the NERDTree specific stuff with how the scratch buffer is identified.
You can use
:quitall
or
:qall
to close all windows at once.
add a ! if you want to ignore unsaved changes.
:qall!

Resources