Is there a clean way to augment a `BufWrite` autocmd in Vim? - 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.

Related

How to correctly reload .vimrc file so it will be equal to restart of vim?

I use MacVim and in my .vimrc file I have map ,V :source $MYVIMRC<CR> binding that allows me to apply the newest version of .vimrc in a case it was recently modified.
However I noticed that strange things can happen, relaunch can slow down vim and some plugins can start to conflict after pressing ,V, when everything works fine if I just close and relaunch MacVim from the scratch.
I'd be very thankful if you could give me a hint on the reason of this behavior as I'd like to have a possibility to update .vimrc file that will completely clear internal vim state and grab new configuration file
The only viable way to re-apply your config to a pristine Vim is actually to restart it.
But the most likely cause of slow downs is the overuse/misuse of autocommands.
Autocommands are added without checking for existing ones. One consequence is that they tend to pile-up if you don't manage them properly and every individual autocommand corresponding to a specific event is executed when that event is triggered, leading to dreadful slow downs.
Here are the two ways you are supposed to use autocommands in your vimrc:
Method #1
" anywhere
augroup nameofthegroup
autocmd!
autocmd EventName pattern commandtoexecute
autocmd AnotherEventName anotherpattern anothercommandtoexecute
augroup END
Method #2
" near the top of your vimrc
augroup nameofthegroup
autocmd!
augroup END
" anywhere
autocmd nameofthegroup EventName pattern commandtoexecute
autocmd nameofthegroup AnotherEventName anotherpattern anothercommandtoexecute
The idea is to create a group of autocommands that clears itself whenever it is invoked and thus prevents them from piling-up.

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

How to automatically run a command after saving a file

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'

Get vim to provide tab completion for CSS class and ID names

The one IDE feature that I always missed and invariably plug into vim is tab completion.
I'm a big fan of SuperTab, but one thing I can't stand is the fact that it treats the parts of CSS class names and IDs with dashes as individual words.
I've found a couple of possible solutions for camelCase and underscore_completion but I can't seem to find anything that supports plain-old-dashes.
This is not a CSS-specific problem: Vim uses the value of iskeyword to perform completion.
Type :set iskeyword? to see what characters are considered to be part of keywords. The default on a Mac is supposed to be #,48-57,_,192-255.
You can add the dash to the list with this command:
:set iskeyword+=-
Add this line to your ~/.vimrc to make this setting stick:
set iskeyword+=-
This seems to work for me:
autocmd FileType css,scss set iskeyword=#,48-57,_,-,?,!,192-255
Taken from here: VIM: How to autocomplete in a CSS file with tag ids and class names declared in HTML file
For future readers: if you want the benefits of dashes for edit/movement commands, but want full property autocompletion, try adding this to your .vimrc:
augroup css_dash_autocompletion
autocmd FileType scss,css autocmd! css_dash_autocompletion InsertEnter <buffer> set isk+=-
autocmd FileType scss,css autocmd css_dash_autocompletion InsertLeave <buffer> set isk-=-
augroup END
The first ! prevents duplicate event firing. Thanks to ZyX for the structure. If you re-source your .vimrc, you will need to :e any (S)CSS files you have open to pick up the change.

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