Last active
November 30, 2017 01:07
-
-
Save adscriven/9c3fdb98f9bdd9924b236f4878ce435d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
" badfmt.vim | |
" Tasks | |
" [ ] BadFmtOn and BadFmtOff commands. Let user turn it on. | |
" [ ] globals -> script local and other plugin infrastructure | |
" This plugin highlights: | |
" incorrect use of tabs or spaces; | |
" incorrect indentation size when using spaces; | |
" excessively long lines; | |
" trailing whitespace. | |
" Config | |
hi def BadFmtIndent ctermfg=cyan guibg=darkred guifg=red gui=none | |
hi def link BadFmtLongLine visual | |
hi def link BadFmtIndentSize visual | |
hi def link BadFmtTrailingWS visual | |
" g:badFmtMaxLen -- in case you want a fixed warning line length everywhere | |
" b:badFmtMaxLen -- warning line length per buffer; set via autocmd or ftplugin | |
" g:badFmtMaxLenOffset -- where you want the warning to occur | |
" defaults to after the max line length | |
" g:badFmtShowLongLine | |
" b:badFmtShowLongLine | |
" b:badFmtTabsWithSpacesForAlignment | |
if has('autocmd') | |
fun! s:highlight() | |
let maxlenoff = get(g:,'badFmtMaxLenOffset', +1) | |
let gmaxlen = get(g:,'badFmtMaxLen',&l:tw) | |
let maxlen = get(b:,'badFmtMaxLen',gmaxlen) + maxlenoff | |
let gshowlongline = get(g:,'badFmtShowLongLine',1) | |
let showlongline = get(b:,'badFmtShowLongLine',gshowlongline) | |
if exists('w:badfmt_hlids') | |
for id in w:badfmt_hlids | |
silent! call matchdelete(id) | |
endfor | |
endif | |
let w:badfmt_hlids = [] | |
" Highlight bad indentation. | |
" 1) Match indenting spaces with a tab later (not alignment); | |
" 2) match an indenting space preceded with a tab-space mix. | |
let bad_tabindents_spacealigns_relaxed = | |
\ '\%(^\s*\)\@<= \%(\s*\t\)\@=\|' . | |
\ '\%(^\t\+ \s*\t\s*\)\@<= ' | |
" 3) Also match an indenting space not preceded by | |
" a starting tab. This disallows spaces for alignment | |
" without preceding indentation, but, on the other hand, | |
" will catch spaces used for indentation. For help files, | |
" for example, the preceding regexp is better, since they | |
" use 'top-level' spaces for alignment. | |
let bad_tabindents_spacealigns_strict = | |
\ '\%(^\t\@!\s*\)\@<= \|' . | |
\ bad_tabindents_spacealigns_relaxed | |
" * Allow tabs at start and then any spaces for alignment. This | |
" is complicated and makes it impossible, in general, to | |
" differentiate incorrect indentation from valid alignment. | |
" The following is, I think, the best we can do in this scenario. | |
if exists('b:badFmtTabsWithSpacesForAlignment') | |
if b:badFmtTabsWithSpacesForAlignment == 'strict' | |
let badindent = bad_tabindents_spacealigns_strict | |
elseif b:badFmtTabsWithSpacesForAlignment == 'relaxed' | |
let badindent = bad_tabindents_spacealigns_relaxed | |
else | |
echoerr 'b:badFmtTabsWithSpacesForAlignment: bad value: ' . | |
\ b:badFmtTabsWithSpacesForAlignment | |
endif | |
" No differentiation between indentation and alignment. How the | |
" matching is done depends on settings for 'sw', 'ts' and 'et'. | |
else | |
" tabs then spaces | |
if shiftwidth() != &ts && !&et | |
" Highlight spaces not preceded by all tabs, or if there | |
" are too many spaces. Just highlight all the | |
" indentation in this case. E.g. set noet ts=8 sw=4 | |
let badindent = '^\(\t* \{0,'.(&ts-1).'}\S\)\@!\s\+\ze\S' | |
" all tabs or all spaces | |
else | |
" Highlight tabs for &et or spaces otherwise. Allow | |
" a single space before * in C comments, even if using | |
" tabs. | |
let badindent = '\%(^\s*\)\@<='.(&et ? '\t' : ' \%( *\*\)\@!') | |
endif | |
endif | |
call add(w:badfmt_hlids, matchadd('BadFmtIndent', badindent, -1)) | |
let w:badws = badindent | |
" Also highlight wrong multiple of &sw. | |
if !exists('b:badFmtNoSwCheck') | |
" Discounts ' *' to allow C-style banner comments. | |
let wrongmultiple = '\%(^\t*\%( \{' . &sw . | |
\ '}\)*\)\@>\%( \*\)\@! \+\ze\S' | |
call add(w:badfmt_hlids, | |
\ matchadd('BadFmtIndentSize', wrongmultiple, -1)) | |
let w:badws .= '\|' . wrongmultiple | |
endif | |
" Highlight trailing whitespace. | |
" But not if the cursor is at the EOL while editing: it's | |
" distracting. (Corner case with 'virtualedit', but not enough | |
" of an issue to worry about.) | |
let trailingws = '\s\+\%#\@!$' | |
call add(w:badfmt_hlids, matchadd('BadFmtTrailingWS', trailingws, -1)) | |
let w:badws .= '\|' . trailingws | |
let longline = '\%' . maxlen . 'v.' | |
if showlongline | |
call add(w:badfmt_hlids, matchadd('BadFmtLongLine', longline, -1)) | |
let w:badws .= '\|' . longline | |
endif | |
let w:badwsinbuf = search(w:badws, 'wn', '', 100) ? 1 : 0 | |
endfun | |
com! HL call s:highlight() | |
fun! BadFmtNext(srchflags) | |
if exists('w:badws') | |
let v = winsaveview() | |
" sil! + | |
if !search(w:badws, 'w' . a:srchflags, '', 400) | |
call winrestview(v) | |
endif | |
endif | |
endfun | |
fun! BadFmtInBuffer() | |
return exists('w:badwsinbuf') ? w:badwsinbuf : 0 | |
endfun | |
map ]w :call BadFmtNext('z')<cr> | |
map [w :call BadFmtNext('b')<cr> | |
augroup badfmt_highlight | |
au! | |
au stdinreadpost,filereadpost,filterreadpost,insertleave,bufenter, | |
\winenter,filetype,bufwritepost * call s:highlight() | |
au filetype help let b:badFmtTabsWithSpacesForAlignment = 'relaxed' | |
au filetype help let b:badFmtNoSwCheck = 1 | |
augroup end | |
endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment