Vim multiple autocmd on BufWritePre - vim

I am using both Chiel92/vim-autoformat and ntpeters/vim-better-whitespace. The first is for autoformat code and the second is for remove extra whitespace. Both of them I hope to use autocmd to call them on save files. It seems that I am not using autocmd correctly. I hope someone can help me out as I have little knowledge about vimL.
I used to have the following to enable autoformat on save:
Plugin 'Chiel92/vim-autoformat'
let auto_format_type_list = ['c', 'cpp', 'py']
autocmd BufWritePre * if index(auto_format_type_list, &ft) >= 0 | Autoformat | endif
and I also use 'ntpeters/vim-better-whitespace', which strip excessive whitespace on save as well.
Plugin 'ntpeters/vim-better-whitespace'
" turn on by default for all filetypes
autocmd BufWritePre * StripWhitespace
The problem is for each of them alone they works perfectly. But when put them together in .vimrc, at least one of them won't work depends one who shows up first in the script.
here's what I have after dumping the :au BufWritePre
:au bufwritepre
--- Auto-Commands ---
BufWrite
* if index(auto_format_type_list, &ft) >= 0 | Autoformat | endif
StripWhitespace
Update ...
After playing around for a while I found that by changing the way to autoformat on save:
autocmd BufWritePre * call Determine_if_auto_format()
function! Determine_if_auto_format()
let auto_format_type_list = ['c', 'cpp', 'py']
if index(auto_format_type_list, &ft) >= 0
Autoformat
endif
endfunction
Both of them can works with each other.
Can someone please help me out understanding what's going on here? Thanks!

Related

vimdiff: start in second split?

When using vimdiff, I'd like to start in the second pane (my changes), instead of the first.
I've tried adding this to my .vimrc, but it doesn't seem to work. Is there a different event I should be hooking?
if &diff
autocmd BufWinEnter * winc l
endif
The following worked for me
if &diff
autocmd VimEnter * normal ^W^L
endif
Note here that ^W and ^L are single characters. You can enter them using ctrlvctrlwctrlvctrll

How can I have Vim use absolute line numbers when I'm typing in the command line and relative otherwise?

I'd like a simple augroup that switches all buffers to absolute line numbers (for Ex commands) when I go into the command window
my current code is:
augroup cmdWin
autocmd!
autocmd CmdwinEnter * setglobal nornu
autocmd CmdwinLeave * setglobal rnu
augroup END
but this doesn't seem to work.
:setglobal won't work, because it just sets the future default, but doesn't update the values in existing windows. You need to apply this for all current windows, normally with :windo, but changing windows is a bad idea when the special command-line window is involved. Therefore, we toggle the option(s) "at a distance" via setwinvar() and a loop:
augroup cmdWin
autocmd!
autocmd CmdwinEnter * for i in range(1,winnr('$')) | call setwinvar(i, '&number', 1) | call setwinvar(i, '&relativenumber', 0) | endfor
autocmd CmdwinLeave * for i in range(1,winnr('$')) | call setwinvar(i, '&number', 0) | call setwinvar(i, '&relativenumber', 1) | endfor
augroup END
This toggles between nu + nornu and nonu + rnu; adapt the logic if you want to keep nu on and just toggle rnu.
I'd recommend to look at two vim plugins:
http://www.vim.org/scripts/script.php?script_id=4212
https://github.com/jeffkreeftmeijer/vim-numbertoggle

Vim remove whitespace for specific files

I've been using the following technique in my .vimrc to remove extra whitespace at the end of a line...
autocmd BufWritePre * :%s/\s\+$//e
But I realised I didn't want that to happen with Markdown files (e.g. either .md or .markdown) so I have the following VimScript...
fun! StripTrailingWhiteSpace()
" don't strip on these filetypes
if &ft =~ 'md\|markdown'
return
endif
%s/\s\+$//e
endfun
autocmd bufwritepre * :call StripTrailingWhiteSpace()
But that still removes the whitespace for all files.
So I then tried the following (which seemed better as it was shorter)...
let blacklist = ['md', 'markdown']
autocmd BufWritePre * if index(blacklist, &ft) < 0 | :%s/\s\+$//e
But, again, that still removes the whitespace for all files?
Neither of these techniques seem to work? They leave the whitespace still in the file?
Any ideas on how I can do this (at the moment I'm having to edit Markdown files in a separate writing app rather than Vim and that's quite annoying).
The first function should work except you should not be looking for md. ft is short for filetype which is markdown for Markdown files.
By changing it as follows it works fine. (Tested on Vim 7.4)
fun! StripTrailingWhiteSpace()
" don't strip on these filetypes
if &ft =~ 'markdown'
return
endif
%s/\s\+$//e
endfun
autocmd bufwritepre * :call StripTrailingWhiteSpace()
Thanks Kevin Sjoberg for the initial response, but it turns out I have a bigger issue.
Which is if I run :set filetype? from within my Markdown file then it reports back that Vim thinks the filetype is modula2
I'm not sure how I can fix this, so if any one knows then please do comment!
As a temp fix I've used the following work around...
fun! StripTrailingWhitespace()
" don't strip on these filetypes
if &ft =~ 'modula2\|markdown'
return
endif
%s/\s\+$//e
endfun
autocmd BufWritePre * call StripTrailingWhitespace()
...so it checks for both modula2 (whatever that is?) AND markdown files.
UPDATE: well it seems this is a known issue https://github.com/tpope/vim-markdown/issues/15 so I tried the suggested fix...
au BufRead,BufNewFile *.md set syntax=markdown
...but that didn't help, Vim still interpreted the file as modular2
Also tried adding the following into my vimrc file...
au! BufNewFile,BufRead *.md setf markdown
...but that didn't work to change the format.
UPDATE 2
Fixed it, the suggestion by both https://github.com/tpope/vim-markdown/issues/15 and Kevin Sjoberg were almost there.
I just added into my vimrc file a modified version of their suggestion au Bufread,BufNewFile *.md set filetype=markdown
Your implementation is simple, but has some shortcomings (e.g. it clobbers the last search pattern / search history). If you're not against installing a plugin, you can try my DeleteTrailingWhitespace plugin. With it, you can exclude certain buffers by setting a flag, e.g.:
autocmd FileType markdown let b:DeleteTrailingWhitespace = 0
I realize you solved the problem which was more than just the function you were trying to setup.
However, I liked your initial "blacklist" approach with a filetypes list. So for anyone else landing here that likes that, this is what I have.
It also saves your cursor position, and puts it back after running the removal of whitespace.
function! StripTrailingWhitespace()
" Preparation: save last search, and cursor position.
let _s=#/
let l = line(".")
let c = col(".")
" do the business:
%s/\s\+$//e
" clean up: restore previous search history, and cursor position
let #/=_s
call cursor(l, c)
endfunction
let noStripWhiteSpaceTypes = ['markdown']
autocmd BufWritePre * if index(noStripWhiteSpaceTypes, &ft) < 0 | call StripTrailingWhitespace() | endif

How to modify the last-position-jump vimscript to not do it for git commit messages

Here's the script for convenience:
" Uncomment the following to have Vim jump to the last position when
" reopening a file
if has("autocmd")
au BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$")
\| exe "normal! g'\"" | endif
endif
The feature is excellent but not when used with certain cases where Vim is invoked as editor: For instance often I write a two line git commit message so the next time I commit it's gonna drop me on the second line and I have to adjust for this.
Similarly many other systems allow you to specify Vim to be used as an editor as part of some process that involves editing a file.
How can we detect this and modify our last-position-jump script? Git's actually kind of special because it uses the .git/COMMIT_EDITMSG file which stays the same across commits which is why this is happening. With a temp file it wouldn't occur on files that Vim hasn't seen before.
This probably makes the task nearly trivial (augment the script with a check if current file == COMMIT_EDITMSG...)
But, a really perfect answer is if we can detect whether Vim is invoked from the command line or if it was opened by a script. Is there a way to tell? I know unix programs can determine if they are running in a term/pseudoterm or not, though either way they do end up receiving input from the terminal.
If you don't want to modify the global rule (like in FDinoff's answer) with all sorts of exceptions, you can also undo the jump by putting the following into ~/.vim/after/ftplugin/gitcommit.vim:
:autocmd BufWinEnter <buffer> normal! gg0
Though I haven't experienced any problems with the above command, even on buffer switches, a more robust version makes the autocmd fire once:
augroup DisableLastPositionJump
autocmd! BufWinEnter <buffer> execute 'normal! gg0' | autocmd! DisableLastPositionJump BufWinEnter <buffer>
augroup END
Git commit messages have the filetype gitcommit.
Just add a check to see if the file is not of the gitcommit filetype for deciding when to jump to the last position.
if has("autocmd")
au BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$") && &filetype != "gitcommit"
\| exe "normal! g'\"" | endif
endif
If you don't want VIM to remember where you were from the previous commit, set the following in ~/.vimrc:
autocmd FileType gitcommit call setpos('.', [0, 1, 1, 0])
Source: http://vim.wikia.com/wiki/Always_start_on_first_line_of_git_commit_message

How can you automatically remove trailing whitespace in vim

I am getting 'trailing whitespace' errors trying to commit some files in Git.
I want to remove these trailing whitespace characters automatically right before I save Python files.
Can you configure Vim to do this? If so, how?
I found the answer here.
Adding the following to my .vimrc file did the trick:
autocmd BufWritePre *.py :%s/\s\+$//e
The e flag at the end means that the command doesn't issue an error message if the search pattern fails. See :h :s_flags for more.
Compilation of above plus saving cursor position:
function! <SID>StripTrailingWhitespaces()
if !&binary && &filetype != 'diff'
let l:save = winsaveview()
keeppatterns %s/\s\+$//e
call winrestview(l:save)
endif
endfun
autocmd FileType c,cpp,java,php,ruby,python autocmd BufWritePre <buffer> :call <SID>StripTrailingWhitespaces()
If you want to apply this on save to any file, leave out the second autocmd and use a wildcard *:
autocmd BufWritePre,FileWritePre,FileAppendPre,FilterWritePre *
\ :call <SID>StripTrailingWhitespaces()
I also usually have a :
match Todo /\s\+$/
in my .vimrc file, so that end of line whitespace are hilighted.
Todo being a syntax hilighting group-name that is used for hilighting keywords like TODO, FIXME or XXX. It has an annoyingly ugly yellowish background color, and I find it's the best to hilight things you don't want in your code :-)
I both highlight existing trailing whitespace and also strip trailing whitespace.
I configure my editor (vim) to show white space at the end, e.g.
with this at the bottom of my .vimrc:
highlight ExtraWhitespace ctermbg=red guibg=red
match ExtraWhitespace /\s\+$/
autocmd BufWinEnter * match ExtraWhitespace /\s\+$/
autocmd InsertEnter * match ExtraWhitespace /\s\+\%#\#<!$/
autocmd InsertLeave * match ExtraWhitespace /\s\+$/
autocmd BufWinLeave * call clearmatches()
and I 'auto-strip' it from files when saving them, in my case *.rb for ruby files, again in my ~/.vimrc
function! TrimWhiteSpace()
%s/\s\+$//e
endfunction
autocmd BufWritePre *.rb :call TrimWhiteSpace()
Here's a way to filter by more than one FileType.
autocmd FileType c,cpp,python,ruby,java autocmd BufWritePre <buffer> :%s/\s\+$//e
I saw this solution in a comment at
VIM Wikia - Remove unwanted spaces
I really liked it. Adds a . on the unwanted white spaces.
Put this in your .vimrc
" Removes trailing spaces
function TrimWhiteSpace()
%s/\s*$//
''
endfunction
set list listchars=trail:.,extends:>
autocmd FileWritePre * call TrimWhiteSpace()
autocmd FileAppendPre * call TrimWhiteSpace()
autocmd FilterWritePre * call TrimWhiteSpace()
autocmd BufWritePre * call TrimWhiteSpace()
Copied and pasted from http://blog.kamil.dworakowski.name/2009/09/unobtrusive-highlighting-of-trailing.html (the link no longer works, but the bit you need is below)
"This has the advantage of not highlighting each space you type at the end of the line, only when you open a file or leave insert mode. Very neat."
highlight ExtraWhitespace ctermbg=red guibg=red
au ColorScheme * highlight ExtraWhitespace guibg=red
au BufEnter * match ExtraWhitespace /\s\+$/
au InsertEnter * match ExtraWhitespace /\s\+\%#\#<!$/
au InsertLeave * match ExtraWhiteSpace /\s\+$/
This is how I'm doing it. I can't remember where I stole it from tbh.
autocmd BufWritePre * :call <SID>StripWhite()
fun! <SID>StripWhite()
%s/[ \t]\+$//ge
%s!^\( \+\)\t!\=StrRepeat("\t", 1 + strlen(submatch(1)) / 8)!ge
endfun
A solution which simply strips trailing whitespace from the file is not acceptable in all circumstances. It will work in a project which has had this policy from the start, and so there are no such whitespace that you did not just add yourself in your upcoming commit.
Suppose you wish merely not to add new instances of trailing whitespace, without affecting existing whitespace in lines that you didn't edit, in order to keep your commit free of changes which are irrelevant to your work.
In that case, with git, you can can use a script like this:
#!/bin/sh
set -e # bail on errors
git stash save commit-cleanup
git stash show -p | sed '/^\+/s/ *$//' | git apply
git stash drop
That is to say, we stash the changes, and then filter all the + lines in the diff to remove their trailing whitespace as we re-apply the change to the working directory. If this command pipe is successful, we drop the stash.
The other approaches here somehow didn't work for me in MacVim when used in the .vimrc file. So here's one that does and highlights trailing spaces:
set encoding=utf-8
set listchars=trail:ยท
set list
For people who want to run it for specific file types (FileTypes are not always reliable):
autocmd BufWritePre *.c,*.cpp,*.cc,*.h,*.hpp,*.py,*.m,*.mm :%s/\s\+$//e
Or with vim7:
autocmd BufWritePre *.{c,cpp,cc,h,hpp,py,m,mm} :%s/\s\+$//e
If you trim whitespace, you should only do it on files that are already clean. "When in Rome...". This is good etiquette when working on codebases where spurious changes are unwelcome.
This function detects trailing whitespace and turns on trimming only if it was already clean.
The credit for this idea goes to a gem of a comment here: https://github.com/atom/whitespace/issues/10 (longest bug ticket comment stream ever)
autocmd BufNewFile,BufRead *.test call KarlDetectWhitespace()
fun! KarlDetectWhitespace()
python << endpython
import vim
nr_unclean = 0
for line in vim.current.buffer:
if line.rstrip() != line:
nr_unclean += 1
print "Unclean Lines: %d" % nr_unclean
print "Name: %s" % vim.current.buffer.name
cmd = "autocmd BufWritePre <buffer> call KarlStripTrailingWhitespace()"
if nr_unclean == 0:
print "Enabling Whitespace Trimming on Save"
vim.command(cmd)
else:
print "Whitespace Trimming Disabled"
endpython
endfun
fun! KarlStripTrailingWhitespace()
let l = line(".")
let c = col(".")
%s/\s\+$//e
call cursor(l, c)
endfun
autocmd BufWritePre *.py execute 'norm m`' | %s/\s\+$//e | norm g``
This will keep the cursor in the same position as it was just before saving
autocmd BufWritePre * :%s/\s\+$//<CR>:let #/=''<CR>

Resources