How can I have vim execute a shell command upon every :w? - vim

Basically, I have a pre-processor for my code which reads all my .foo files and converts them to corresponding compiled .bar versions, though without ever modifying any of the originals. Each time I write changes to my source files, I would like vim to !./run-my-preprocessor-script.js after it has finished saving my file. How can this be done? I only want this to happen when I'm editing files with names ending in .foo.
Thanks

You can use Vim’s autocmd feature (see :help :autocmd). It has lots of hooks for “events”; the one you want should be BufWritePost. E.g., in your ~/.vimrc:
autocmd BufWritePost *.foo !./run-my-preprocessor-script.js

You can use autocmd to hook into the BufWritePost event like so:
autocmd BufWritePost * execute '!ls'
This means that every time the BufWritePost (after the buffer has been written) event is triggered on any file, you'll execute the command !ls. It's easy to specialize this to work only on *.foo files that are saved:
autocmd BufWritePost *.foo execute '!ls'
Now, the command !ls will only be triggered when a file with a filename matching the expression *.foo is written.
Obviously, you'll need to change ls to whatever you do to execute your preprocessor script, but the process is the same. Put that modified autocmd into your .vimrc file and it should work!

Related

Prevent Vim warning after autocommand changes file being edited

I run a command every time a save a file which, among other things, lints the current file. Vim does two annoying things which I wanted to avoid:
It asks me to press enter after the command was executed.
It notifies me that the current file has been modified outside of Vim.
How to get rid of this? I just want this to behave unobtrusively as ALE linters. This is my code:
autocmd BufWritePost *.prisma :execute '!npx prisma format'
#romainl's comment gave me an idea on how to do it:
autocmd BufWritePre *.prisma silent write | silent :execute '!npx prisma format' | edit! %
It's not the cleanest way to do it but it works. silent hides the command output and edit! forces Vim to open the modified file.

Prevent Vim's autocmd from running on write just once

I have the following line in my .vimrc to automatically beautify js files after I save them:
autocmd BufWritePost *.js :call JsBeautify()
I want this 99% of the time, but sometimes I just want to write without having this function called. Is there an easy way to do that?
I guess you're looking for :noa.
Usage:
:noa w
Excerpt from help:
:noautocmd :noa
To disable autocommands for just one command use the ":noautocmd" command
modifier. This will set 'eventignore' to "all" for the duration of the
following command. Example:
:noautocmd w fname.gz
This will write the file without triggering the autocommands defined by
the
gzip plugin.

Automatic first line in vim

Is it possible to make vim write something on the first line (or on few first lines) automatically everytime when I create file with a specific extension?
For example (and this is only an example) if I create .txt file I would like vim to write "Hello" on the first line.
Is it possible? If it is, how?
Yes, you can achieve this with autocommands. The general structure of an autocommand is
au event filetype command
In your specific case, you want
au BufNewFile *.txt normal iHello
Explanation:
au "Define a new autocommand
BufNewFile "When you create a new file
*.txt "With the extension '.txt'
normal iHello "Execute the command 'normal iHello', which is like typing 'iHello' manually
The docs give an idea of how to do this in :h skeleton. Essentially, you just need a BufNewFile autocommand in your .vimrc.
The docs assume you'll be reading your initial content from a file. So, for your example, assuming skeleton.txt contains the text "Hello":
autocmd BufNewFile *.txt 0r ~/vim/skeleton.txt
Alternatively, if your first line is relatively simple, you can always hardcode it by just entering insert mode and adding the text you need.
au BufNewFile *.txt normal iHello
This answer from vi.stackexchange provides a couple examples that call functions and are a bit more complex.
In my case, to bash files, I have this on my ~/.vimrc
augroup sh
au BufNewFile *.sh 0r ~/.vim/skel/template.sh
"au BufWritePost *.sh,*.pl,*.py,*.cgi :silent !chmod a+x <afile>
augroup end
If I create a new file "BufNewFile" vim opens at the line zero "0" by reading "r" the content of the file template.sh, on that file I can put wherever I want.
If I uncoment the seccond line removing the " at beginning I have also a change on file permission automatically

Golang: running `go build` on save using vim (macvim) and vim-go

I am recently moving from sublime 3 go to mvim (vim on the mac os) and am trying to get my Golang development environment to be as similar on vim to my sublime implementation as possible.
Within my sublime setup, it runs go build anytime I save the a Go file. This provides me instant feedback on if I have unused vars or other info go build provides.
I'm attempting to move to vim, and am wondering if I can have this functionality implemented there as well. I am using vim-go but have not found a setting to implement this.
In short I want to run :GoBuild upon the saving of a Go file while using vim / vim-go. Is this Possible and how do I do so?
yes, use vim autocommand to run :GoBuild:
You can specify commands to be executed automatically when reading or
writing a file, when entering or leaving a buffer or window, and when
exiting Vim. The usual place to put autocommands is in your .vimrc or
.exrc file.
Run the following command:
:autocmd BufWritePre *.go :GoBuild
Now each time you save your Go file with :w it will run :GoBuild too.
The event type is BufWritePre, which means the event will be checked just before you write *.go file.
BufWritePre starting to write the whole buffer to a file
BufWritePost after writing the whole buffer to a file
and:
When your .vimrc file is sourced twice, the autocommands will appear
twice. To avoid this, put this command in your .vimrc file, before
defining autocommands:
:autocmd! " Remove ALL autocommands for the current group.
If you don't want to remove all autocommands, you can instead use a
variable to ensure that Vim includes the autocommands only once:
:if !exists("autocommands_loaded")
: let autocommands_loaded = 1
: au ...
:endif
like this (put this at the end of your vim startup file):
:if !exists("autocommands_loaded")
: let autocommands_loaded = 1
: autocmd BufWritePost *.go :GoBuild
:endif
ref:
http://vimdoc.sourceforge.net/htmldoc/autocmd.html
http://learnvimscriptthehardway.stevelosh.com/chapters/12.html
Create ~/.vim/after/ftplugin/go.vim with:
autocmd BufWritePre *.go :GoBuild

how to use pythontidy in vim

what I am using now is ,
autocmd BufWritePost *.py !python PythonTidy.py % %
It really call the tidy programe and change the file, but the vim does not reload the new file.
And I do not want to install another plugin for it.
=======================
note: I found it's dangerous about this feature, PythonTidy will will output a empty file if the command faild, it means if you have syntax error, you will lose your file unless press "u" to get it,but you can't save before you fix syntax error.
I call :!PythonTidy % % manually after pylint complete now.
Use BufWritePre instead of BufWritePost and combine Vim range filtering with PythonTidy’s stdin/stdout mode.
autocmd FileType python autocmd BufWritePre <buffer> let s:saveview = winsaveview() | exe '%!python PythonTidy.py' | call winrestview(s:saveview) | unlet s:saveview
(The use of autocmd FileType python autocmd BufWritePre <buffer> makes this a bit more accurate than matching on a glob pattern: it means “any time a Python file is detected, install this autocmd for that buffer” – so it works independently of file name.)
Unfortunately this cannot preserve your cursor position if you undo the filtering. (You are filtering a whole-file range; when undoing a filter operation, the cursor jumps to the first line in the range; so you end up at the top of the file.) I was hoping to find a way to create a no-op undo state, before, so you could hit u twice and get back to the right place, but I can’t make that work as yet. Maybe someone else knows how.
hi the following fixed the cursor postion problem
function! PythonTidySaver()
let oldpos=getpos('.')
%!PythonTidy
call setpos('.',oldpos)
endfunction
autocmd! bufwritepost *.py call PythonTidySaver()
Based on :help :e:
*:e* *:edit*
:e[dit] [++opt] [+cmd] Edit the current file. This is useful to re-edit the
current file, when it has been changed outside of Vim.
This fails when changes have been made to the current
buffer and 'autowriteall' isn't set or the file can't
be written.
Also see |++opt| and |+cmd|.
{Vi: no ++opt}
So you'd need to use :e after updating the file externally. However, :! doesn't let you use | normally (see :help :!), so you need to wrap it:
autocmd BufWritePost *.py execute "!python PythonTidy.py % %" | e
(:autocmd doesn't interpret | normally either, which is why you don't need to escape it yet again.)

Resources