Skip to content

Instantly share code, notes, and snippets.

@adscriven
Last active November 30, 2017 01:07
Show Gist options
  • Save adscriven/9c3fdb98f9bdd9924b236f4878ce435d to your computer and use it in GitHub Desktop.
Save adscriven/9c3fdb98f9bdd9924b236f4878ce435d to your computer and use it in GitHub Desktop.
" 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