How to automatically run a command after saving a file - vim

I want vim to run g++ after saving a .cpp file to compile it. How can I achieve this? I know how to map an external command to keys, but I want to know how to map a command to another command.

You use :autocmd for that. After a :write, the BufWritePost event is fired. See :h autocmd-events for what's available.
:autocmd BufWritePost <buffer> !g++ %
The % represents the current file (that is written).
A better alternative might be to invoke :make instead; this can also handle more than single file compiles.
To install that for all C++ files, you could just replace <buffer> with *.cpp, but then you're duplication the filetype detection built into Vim. Better put the above :autocmd into e.g. ~/.vim/ftplugin/cpp_autocompile.vim. (This requires that you have :filetype plugin on. Alternatively, you could define an :autocmd FileType cpp autocmd BufWritePost... directly in your ~/.vimrc, but this tends to become unwieldy once you have many customizations.

I wouldn't do that. Most of the time we save files that are not fully compilable (because we want to update tags database, make sure the file is saved before going home). Moreover most of the projects are not made of single files.
But anyway. You are looking for BufWritePost autocommands. For instance,
aug AutoCompileCppFiles
au!
au BufWritePost *.cpp,*.c make
aug END
BTW, :make shall do the work as it'll call gnumake on most systems, and gnumake already knows how to compile single isolated files. If you want to parametrize the compilation, just set $LDFLAGS and $CXXFLAGS ; e.g.:
:let $CXXFLAGS='-std=c++0x -Wall -pedantic'

Related

Is there a clean way to augment a `BufWrite` autocmd in Vim?

I've recently installed the VimWiki plug-in, and am learning about Vim's plugin architecture in general (and better using directories like after/ftplugin instead of cramming everything into my .vimrc file).
I would like to call a function prior to writing wiki files, like so:
autocmd BufWrite *.wiki call CleanMarkdown()
However, vimwiki sets its own BufWrite autocommand, which updates any tables-of-contents in the wiki file. I could clobber this autocommand with my own function that calls both the CleanMarkdown() plus whatever vimwiki is doing today, but that would be brittle in the face of possible future changes in the vimwiki plugin.
Is there a standard way to add to the list of things to do for a BufWrite autocommand?
Multiplicity of autocmds
There can be many :autocmds for any event; the command is cummulative. The corresponding :autocmd! removes certain sets of commands (depending on the arguments given to it).
If you don't specify a [group], the autocmd will be defined in the global space, and there's a high risk of getting this cleared by some :autocmd!. Therefore, it is recommended to specify a [group] (especially in plugins). With this, you avoid that another (mis-behaving) plugin or customization clobbers your autocmd.
Integrating with vimwiki plugin
As the plugin already defines its own filetype, you don't need to duplicate the filetype detection logic, i.e. the *.wiki pattern. Instead, if you put your :autocmd definition in ~/.vim/after/ftplugin/vimwiki.vim, you can use the <buffer> special pattern to make this autocmd apply only to the current (VimWiki) buffer.
augroup MyVimWikiCleanup
autocmd BufWrite <buffer> call CleanMarkdown()
augroup END
Ordering
The :autocmds are executed in the order in which they were defined. By using the after directory, yours will be executed after the plugin's.

autocmd event to execute a command on :wq - vimscript?

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

Run/Toggle command for certain filetypes only

I found this nice plugin for distraction free writing named Goyo, which is really well done.
I setup autocmds to enable Goyo based on the filetype, so if I work on a markdown or textfile Goyo gets initialized automatically. If I leave the buffer or change the filetype then Goyo gets closed. Below is how I implemented the behaviour:
autocmd FileType * :Goyo!
autocmd FileType markdown :Goyo
autocmd FileType text :Goyo
That seems to work fine. The question is, whether or not this is the way to go or if there is a better approach to solve the problem?
That's just fine and how I would implemented it, too. As you only hook into the FileType event, the toggling is only triggered when you :edit a new file, not when you recall an existing buffer with another filetype. You could do that with BufWinEnter, but it may cause too many inadvertent togglings. I guess the plugin comes with a quick toggle mapping to manually do this, anyway.
Alternative
An alternative to the autocmd FileType commands is filetype plugins (i.e. ~/.vim/ftplugin/markdown.vim etc.), which have the benefit of separating things neatly. But as you need a catch-all autocmd to turn off Goyo, and the list of filetypes is small, I would also prefer keeping things together, just like you did.
Improvements
Note that your set of commands would add a duplicate set of autocmds if you re-:source your ~/.vimrc (or whichever script you've put them in). To avoid that, you could wrap them in
augroup AutomaticGoyo
autocmd!
...
augroup END

Vim load buffer depending on file type

I am using vim for a lot of languages and I am hoping to improve the ctrl + p/n autocomplete. When I am going to work with a specific one I load a file in the buffer containing the substet of language specific functions I am using like so:
:badd perl.txt
This loads the functions inside that file to the auto-complete buffer
I have one .txt file for each language I am using. I wish to automate this process by having a particular buffer loaded depending on the file type. I tried searching but cloudn't find a good answer. The only lead I have is that I might need to use filetype plugins thought not sure how. Bonus points (though not important) if the solution is just in the rc file (since it will be easy to set up new work places that way)
One possible solution:
autocmd BufNewFile,BufRead *`<extention>` badd `<dir to file>`
Example:
autocmd BufNewFile,BufRead *pl badd /home/vim_autocomplete/perl.txt
To answer the question you asked, I think that
:au FileType * badd path/to/<amatch>.txt
(untested) will work. Instead of using :badd, I would modify the 'complete' option:
:au FileType * setl complete+=k/path/to/<amatch>.txt
Either way, you can wrap the command in a test:
:au FileType * if filereadable("path/to/<amatch>.txt") | ... | endif
(equally untested). Of course, if you want a single autocommand, then (whichever approach you use) you will have to name the files after the file types.
:help :au
:help FileType
:help <amatch>
:help 'complete'

How to perform File Extension based Actions in VIM?

I want to perform rubyf action in VIM when I press F5 if the file is of .rb extension.
Right now I just have
map <F5> :rubyf % <CR>.
But I also want to interpret scheme files if its .scm or compile tex etc using the same F5. How do I check the file extension and perform the correct binding? How do you guys compile different files in G/VIM?
You could create a different autocmd for each file extension. eg:
au BufEnter,BufNew *.rb map <F5> :rubyf % <CR>.
See :help autocmd for info about autocmds.
A better approach for your specific problem would be to map <F5> to always invoke :make % and then have a autocmd that set the makeprg option for each file type (use setlocal when you do this for best results). This wouldn't be for loading ruby into Vim (as you seem to be doing) but instead for invoking an external compiler/interpreter/linter. This is essentially what I do. The nice thing about doing it this way is that Vim can interpret the errors and warnings and automatically jump to the problems in your code. You can also bring up a list of the errors/warnings. See :help quickfix for info about this, as well as the help topics for 'makeprg', :make, :copen and 'errorformat'.
A slight variation on this would be to not use autocmds at all, but instead to have an external script that when given a source filename figures out what to run (ruby, your scheme compiler, pychecker, your C compiler, whatever). Then just set makeprg to always run that script.
Use filetype plugins.
Create a file ~/.vim/ftplugin/ruby/custom.vim
In that file, put any commands you want included only when the filetype of the current buffer is ruby. They'll be sourced appropriately.
If you want to do the same thing from scheme, create another file ~/.vim/ftplugin/scheme/custom.vim`` and do the same thing.
Each time you load a file in vim, it will detect the filetype, and load all the plugins corresponding to your filetype.
Autocommands is your friend.
it is defined as followed:
:au[tocmd] [group] {event} {pat} [nested] {cmd}
in your case the following line in .vimrc will do what you want.
autocmd BufRead,BufNewFile *.rb map <F5> :rubyf % <CR>.
for more information se:
http://www.ph.unimelb.edu.au/~ssk/vim/autocmd.html
This is answered fairly well in the answers for this question.

Resources