From vimdoc:
:checkt[ime] Check if any buffers were changed outside of Vim.
This checks and warns you if you would end up with two
versions of a file.
If this is called from an autocommand, a ":global"
command or is not typed the actual check is postponed
until a moment the side effects (reloading the file)
would be harmless.
How can I use it from an autocmd without delay?
EDIT
I somtimes use vim and an IDE to edit the same file, and I want to changes in one of them to be loaded into the other automatically.
Here is a possible solution:
autocmd CursorHold * checktime
function! Timer()
call feedkeys("f\e")
" K_IGNORE keycode does not work after version 7.2.025)
" there are numerous other keysequences that you can use
endfunction
But since checktime will be delayed, the effect may not be satisfactory.
As the quoted documentation explains, you can't, and for good reason (the reload might trigger other autocmds, the change might confuse following commands).
To work around this, you have to leave the current :autocmd, and re-trigger your code somehow. One idea is an :autocmd BufRead, which will fire if the buffer is actually reloaded. If you need to always retrigger, an :autocmd CursorHold (maybe with a temporarily reduced 'updatetime') can be used, or call feedkeys(":call Stage2()\<CR>") might be worth a try.
I ended up doing this:
autocmd CursorHold * call Timer()
function! Timer()
checktime
call feedkeys("f\e")
endfunction
It works quite well.
Related
I have some experience with vim but most of my time has been spent in neovim playing around with lua (although I'm still barely not a beginner). I missed out on the vimscript autocommand magic that I see alot of people pulling off and I'm wondering why not just write a lua function like...
function OpenTerm()
vim.cmd("bel split")
vim.cmd("terminal")
vim.cmd("setlocal nonumber norelativenumber")
end
instead of writing a an autocmd ?
You are conflating two totally unrelated things.
Your snippet (assuming it works, I don't use Neovim so I won't test it):
function OpenTerm()
vim.cmd("bel split")
vim.cmd("terminal")
vim.cmd("setlocal nonumber norelativenumber")
end
is a Lua function that is exactly equivalent to this Vimscript function:
function! OpenTerm()
bel split
terminal
setlocal nonumber norelativenumber
endfunction
and both functions have literally nothing to do with autocommands. They are completely passive and defining them only did some low-level memory-related things. For them to do anything, you have to call them.
Autocommands are a very different thing that allows you to tell Vim to perform some action when an event occurs, like this one:
autocmd VimEnter * call OpenTerm()
which, essentially, tells Vim this:
When you are done starting up, call the OpenTerm() function.
Unlike functions, which do nothing until they are called, autocommands have a real effect on your editor's state as soon as they are defined.
You can add an autocommand from a function, you can call a function from an autocommand, but you can't expect one to act as the other.
Basically, the question "Do I use an autocommand or a function?" makes no sense at all.
If you have any NERDTree instances open when you quit VIM then when you open your session again you get a number of errors:
Error detected while processing BufLeave Autocommands for "NERD_tree_*":
E121: Undefined variable: b:NERDTree
Error detected while processing WinLeave Autocommands for "NERD_tree_*":
Error detected while processing BufLeave Autocommands for "NERD_tree_*":
E121: Undefined variable: b:NERDTree
Error detected while processing WinLeave Autocommands for "NERD_tree_*":
I am trying to execute :tabdo NERDTreeClose automatically when vim exits (e.g. with qa or wqa or qa! etc)
I am adding:
autocmd VimLeave * tabdo NERDTreeClose<CR> or
autocmd VimLeave * :tabdo NERDTreeClose<CR>
with or without <CR> at the end but I can't make it work.
Any suggestions?
I have previously encountered the exact same issue with the combination of
creating (and reentering) [neo]Vim-sessions and multiple NERDTree-instances.
My solution, which might not be the precise answer that you are looking for
due to the reason that will be explained later, was to first close all NERDTree
instances before creating or updating the [neo]Vim-Session for later usage.
What you have been trying so far with the tabdo is thus a few "stages" too
late, as the triggering event for auto-command is VimLeave.
My primary suggestion (also my personal resort) is to create a quick
key-bind that performs the two procedures I stated above combined with a quick
save-all in serial:
cnoremap W tabdo NERDTreeClose <bar> wa <bar> mksession! ~/.vim/My_Session.vim
which can be comfortably remembered as the bigger brother of the default w in
commandline-mode for saving (a single buffer).
The one caveat of this method is that all instances of NERDTree will be closed
when reentering the session saved from above. This, however, can be somewhat
remedied by calling NERDTreeToggle with VimEnter as the triggering event for
autocmd.
If you insist on utilising autocmd for this, I would suggest putting the two
procedures enlisted above into a function and use autocmd to call that
function (with the [neo]Vim command: call) upon VimLeave just like you have
tried before, of course under the assumption that you feel compelled to save the session during every exit. I personally do not endorse this, as instances were abundant where
I would quickly fire up [neo]Vim for a quick note of something inconsequential
and swiftly exit, which certainly does not require that the session be saved.
As a sidenote: the syntax of autocmd:
:au[tocmd] [group] {event} {pat} [++once] [++nested] {cmd}
thus, substitute cmd with a command directly, i.e., the prefixing colon as you
have tried in your original post is a malpractice.
I want to execute system("cp /home/currently_opened_file.txt /somewhere/else") when I exit vim with :wq. Is there an autocmd event for that? Or any other way to do it?
Update:
The OP noted in comments that this combination did exactly what was wanted (execute the command only on :wq).
:autocmd BufWritePost * :autocmd VimLeave * :!cp % /somewhere/else
Original answer:
You can hook the BufWritePost event. This will run the command on every write, not only when you use :wq to leave the file.
:autocmd BufWritePost * :!cp % /somewhere/else
I suppose you could try hooking the BufDelete event (before deleting a buffer from the buffer list), but that seems like it would be problematic, as buffers are used for more than file editors. They are also used for things like quicklists, the help viewer, etc.
There are some events that take place when you are quitting, which could be an option.
QuitPre when using :quit, before deciding whether to quit
VimLeavePre before exiting Vim, before writing the viminfo file
VimLeave before exiting Vim, after writing the viminfo file
You can see the full list using :help autocmd-events.
Also note that you can restrict what matches the event. For instance, if you only want this to happen for HTML files and CSS files, you could use this:
:autocmd QuitPre *.html,*.css :!cp % /somewhere/else
I suspect you will need to experiment and see what works for you.
It looks like you need to automatically cascade the writing of a file to another location. My DuplicateWrite plugin provides comfortable commands to set up such. (The plugin page has links to alternative plugins.)
:DuplicateWrite /somewhere/else
In vim, I have autosave to file with:
augroup write_it
autocmd!
autocmd InsertLeave * write
autocmd TextChanged * write
augroup END
It works really good. But I need to place a wait in there for when I rapidly delete characters in command mode TextChanged. Any ideas how? It is a nightmare with livereload and gulp tasks watchers for front end development.
I tried exec 'sleep 2' but vim is async and it's useless.
Check the help for CursorHold and CursorHoldI events. They are triggered after some period of inactivity according to the 'updatetime' option. You can use them.
There is also an autowrite. Anyway, it can go really complicated, so in my opinion your best alternative is to reuse code from who already thought about all this :-)
• The AutoSave Plugin: https://github.com/907th/vim-auto-save.git
I'm working on a small vim plugin and needed to add an autocmd to call one of my functions MakeMatch whenever Insert mode is exited.
The actual setup to get the function to be called is pretty simple:
augroup Poi
autocmd!
autocmd InsertLeave * call s:MakeMatch()
augroup END
Originally I was under the impression that the function wasn't being called but then I added an echo into the definition and saw the string printed out.
The function is essentially the following:
function! s:MakeMatch()
"Iterate and create g:build_string up
"g:build_string=":match poi /\%5l\|\%6l/"
execute g:build_string
endfunction
If I was to :call s:MakeMatch() the build string will successfully execute as I had expected when leaving insert mode..
I've seen code in other plugins that uses au * exec.. without issue. I'm wondering if this is an issue with calling match during InsertLeave; I could definitely see something calling hi clear or maybe highlighting just isnt allowed during InsertLeave.
Been playing around with this with a co-worker and haven't been able to get it to run the match. We tried calling the match directly and other types of execute.. Would love to get some more info on why this may not be working.
Anyone have any ideas?
EDIT:
Here's the full code for the plugin I've wrote. It's working as expected now :D
I haven't got confirmation that this is the "correct" approach but it's the one that worked for me..
Removed the augroup and simply define an autocmd that will execute properly when vim loads my plugin's .vim file.
autocmd InsertLeave * call s:MakeMatch() was a little off the mark for a few reasons. The most obvious being that <SID> should have been used when attempting to call the function.
As an aside; #Peter Rinker: Mentioned trying to run autocmd InsertLeave * match Search /./. which works like a charm when running in :Ex mode but if you try to define the au! within the plugin/vimrc file it won't work..
I think this might have something to do with the fact that match is not an eval function but I am not sure if that is actually the case.
Ensure it ran as an Ex command. Since I had to run the command rather than have it be defined I had to change to {event} and call execute with the : like I had done to get #Peter's suggestion to work.
au! VimEnter * execute(":autocmd InsertLeave * call <SID>MakeMatch()")
The above did the trick for me but I'd definitely be interested in any other approach/more info.