Skip to content

Instantly share code, notes, and snippets.

@Raimondi
Created July 24, 2010 07:55
Show Gist options
  • Save Raimondi/488509 to your computer and use it in GitHub Desktop.
Save Raimondi/488509 to your computer and use it in GitHub Desktop.
" Type :so % to run VimLint.
" {{{1
" ============================================================================
" File: vimlint.vim
" Description: Vim plugin that checks your Vim environment, settings and
" loaded scripts for conflicts, omissions and ill-advised
" configurations.
" Author: Barry Arthur <barry.arthur at gmail dot com>
" Last Change: 22 July, 2010
" Website: http://github.com/dahu/VimLint
"
" See vimlint.txt for help. This can be accessed by doing:
"
" :helptags ~/.vim/doc
" :help vimlint
"
" Licensed under the same terms as Vim itself.
" ============================================================================
let s:VimLint_version = '0.0.5' " alpha, unreleased
" History:{{{2
" v.0.0.5 changes:
" * replaced awful 'redirect to temporary file and run ex commands' with the
" approach of redirecting to a register and using vimscript. (thanks,
" godlygeek)
" * replaced method of collecting All Options by using :help option-list
" (thanks, jamessan)
" * fixed a bug that assumed 'hidden' was enabled. (thanks, Raimondi)
"
" v.0.0.4 changes:
" * check &runtimepath for sane entries
" * show the current :filetype settings in the vimlint report
" * Tried to DRY up the way temporary redirections are done.
"
" v.0.0.3 changes:
" * environment variables check list now allows multiple {:reason, :fail_expr}
" sets
" * limit the set of -feature highlights in vimlint report
" * checks for ~/.vimrc / ~/_vimrc
" * removed checks against $TERM - just showing its value now
" * verify that $VIM and $VIMRUNTIME dirs exist
" * change way All Options are collected and displayed - now uses
" :verbose set to show where each option was last set
"
" v0.0.2 changes:
" * only check 'tabstop' when 'expandtab' is set
" * use :new to clear 'filetype' is
" * add version to report header.
"
" v0.0.1:
" * initial release
" TODO / Issues:{{{2
"
" [Features]
" * dump :scriptnames to a register and parse it for 'bad scripts', adding !!
" and ! as appropriate.
" * add lots more help in the doc/vimlint.txt file explaining *why* these
" recommendations are made.
" * add tags to easily jump from the report to the help entries.
" * should autocmds be dumped?
"
" [Script Robustness]
" * learn what needs protecting:
" ** if not running under Vim 7.
" ** given the possibility of missing features - should I wrap has('feature')
" checks around everything?
"
" [Code Style]
" * see the various TODO's throughout
" allow line continuation
let s:old_cpo = &cpo
set cpo&vim
" Error Messages:{{{2
" Repeatedly used error messages (used by the s:E() function below)
let s:vl_error_messages = {
\ 'critical_error' : "Something must be very wrong with your Vim installation.",
\ 'help' : " |VL-%s|",
\ 'indent_reason' : "Use 'filetype indent on' instead, for smart per-filetpe indenting.",
\ 'env_var_missing' : "You have an invalid %s environment variable.",
\ 'env_var_invalid' : "Your %s environment variable points to an invalid directory.",
\ 'after_dir_missing' : "%s/after needs to be added to your runtimepath because it contains %s and a corresponding '/after' directory exists on disk."
\}
" Error Message Expander
function! s:E(code, ...)
if a:0 > 0
let params = [s:vl_error_messages[a:code]] + a:000
return call (function('printf'), params)
else
return s:vl_error_messages[a:code]
endif
endfunction
" Essential Options: {{{2
let indent_reason = ''
let s:chk_opt = {
\ 'cindent' : {
\ 'reason' : s:E('indent_reason'),
\ 'fail-expr' : ['&cindent == 1']
\ },
\ 'compatible' : {
\ 'reason' : "Use Vim, not vi.",
\ 'fail-expr' : ['&compatible == 1']
\ },
\ 'cpoptions' : {
\ 'reason' : "Controls how 'vi' compatible Vim is. Set with care.",
\ 'warn-expr' : ['&cpoptions != "aABceFs"']
\ },
\ 'edcompatible' : {
\ 'reason' : "Makes the 'g' and 'c' flags of \":substitute\" toggle, rather than acting for that call only.",
\ 'warn-expr' : ['&edcompatible == 1']
\ },
\ 'exrc' : {
\ 'reason' : "Allows reading .vimrc/.exrc/.gvimrc in the current directory. This is a potential security risk!",
\ 'fail-expr' : ['&exrc == 1']
\ },
\ 'gdefault' : {
\ 'reason' : "Sets the 'g' flag for \":substitute\" by default.",
\ 'warn-expr' : ['&gdefault == 1']
\ },
\ 'hidden' : {
\ 'reason' : "Prevents having unsaved files open in Vim. Setting this on is highly recommended.",
\ 'warn-expr' : ['&hidden == 0']
\ },
\ 'insertmode' : {
\ 'reason' : "Use Insert mode by default. This is not the Vim way.",
\ 'warn-expr' : ['&insertmode == 1']
\ },
\ 'lisp' : {
\ 'reason' : s:E('indent_reason'),
\ 'fail-expr' : ['&lisp == 1']
\ },
\ 'loadplugins' : {
\ 'reason' : "Prevents loading plugin scripts when starting Vim. Setting this on is highly recommended.",
\ 'warn-expr' : ['&loadplugins == 0']
\ },
\ 'magic' : {
\ 'reason' : "Changes the special characters in search patterns. To avoid compatibility problems, always leave this on.",
\ 'warn-expr' : ['&magic == 0']
\ },
\ 'modeline' : {
\ 'reason' : "Evaluates settings from modelines when reading files. Disable modelines before editing untrusted text.",
\ 'warn-expr' : ['&modeline == 1']
\ },
\ 'smartindent' : {
\ 'reason' : s:E('indent_reason'),
\ 'fail-expr' : ['&smartindent == 1']
\ },
\ 'tabstop' : {
\ 'reason' : "Don't change 'tabstop' when using 'expandtab'.",
\ 'fail-expr' : ['(&tabstop != 8) && (&expandtab == 1)']
\ },
\}
" Essential Environment Variables: {{{2
" TODO: either decide to keep the consistent data structure (allowing the
" hideous [{}]), or change the VL_CheckEnvironmentVars() function to allow
" single entry {...} or multiple entry [{..},{...}] variants.
"
" NOTE: It seems that Vim defaults the $VIM and $VIMRUNTIME env vars if
" they're empty, so that test is probably moot.
let s:chk_env_vars = {
\ 'SHELL' : [{
\ 'reason' : "Vim requires a POSIX shell.",
\ 'fail-expr' : ["s:VL_Include(['\\<fish\\>'], $SHELL)"]
\ }],
\ 'TERM' : [{}],
\ 'VIM' : [
\ {
\ 'reason' : s:E('env_var_missing', '$VIM') . ' ' . s:E('critical_error'),
\ 'fail-expr' : ["$VIM == ''"]
\ },
\ {
\ 'reason' : s:E('env_var_invalid', '$VIM') . ' ' . s:E('critical_error'),
\ 'fail-expr' : ["! isdirectory($VIM)"]
\ }
\ ],
\ 'VIMRUNTIME' : [
\ {
\ 'reason' : s:E('env_var_missing', '$VIMRUNTIME') . ' ' . s:E('critical_error'),
\ 'fail-expr' : ["$VIMRUNTIME == ''"]
\ },
\ {
\ 'reason' : s:E('env_var_invalid', '$VIM') . ' ' . s:E('critical_error'),
\ 'fail-expr' : ["! isdirectory($VIMRUNTIME)"]
\ }
\ ],
\}
" Private Functions: {{{2
let s:vl_pass_status = ' '
let s:vl_fail_status = '!! '
let s:vl_warn_status = '! '
" helper function for checking if a var matches any of a set of regex patterns
function! s:VL_Include(array, item)
return len(filter(map(a:array, 'a:item =~ v:val'), 'v:val == 1'))
endfunction
" helper function for expanding environment vars and vim options without
" having to litter the code with exe "let..." statements
function! s:VL_Expand(var_type, var_name)
exe "let val = " . a:var_type . a:var_name
return val
endfunction
" helper function to trim leading whitespace from strings
function! s:VL_TrimLeft(string)
return substitute(a:string, '^\_.\{-}\(\w\)', '\1', '')
endfunction
" helper wrapper for temporarily redirecting output to the 'a' register for
" capturing info.
" Example: call s:VL_Execute('filetype')
" NOTE: This re-sets redirection and resets it back to the Vim Report afterwards.
function! s:VL_Execute(command)
let save_reg = @a
redir @a
exe a:command
redir END
exe "redir >> " . s:vimlintreport
let ret_val = @a
let @a = save_reg
return ret_val
endfunction
function! s:VL_CheckVimVersion()
if v:version < 700
silent echo s:vl_fail_status . " NOT Running Vim 7!"
endif
echo "\n== Version =="
version
endfunction
" Check a set of 'fail' and then 'warn' expressions, short-circuiting at the
" first successful failure.
function! s:VL_EvaluateExpressions(var_inf)
let status = s:vl_pass_status
for check_type in ['fail', 'warn']
exe "let trigger_status = s:vl_" . check_type . "_status"
let check_expr = check_type . '-expr'
if has_key(a:var_inf, check_expr)
for expr in a:var_inf[check_expr]
exe "if " . expr . " | let status = '" . trigger_status . "' | endif"
if status !~ s:vl_pass_status | break | endif
endfor
endif
endfor
return status
endfunction
function! s:VL_FailReason(status, reason)
return (a:status !~ s:vl_pass_status ) ? " " . escape(a:reason, "'\"") : ''
endfunction
" Complain if the environment variable doesn't match the vim variable
function! s:VL_CheckEnvVsVimVar(env_var, vim_var)
let env_val = s:VL_Expand('$', a:env_var)
let vim_val = s:VL_Expand('&', a:vim_var)
if env_val != vim_val
exe "echo \"\n" . s:vl_fail_status . "$" . a:env_var . " != &" . a:vim_var . " => " . env_val . " != " . vim_val . "\""
endif
endfunction
" compares environment variables with corresponding vim options
function! s:VL_CrossCheckEnvVarsAgainstVimOpts()
if "builtin_gui" != &term
call s:VL_CheckEnvVsVimVar('TERM', 'term')
endif
call s:VL_CheckEnvVsVimVar('SHELL', 'shell')
endfunction
" checks important environment variables
function! s:VL_CheckEnvironmentVars()
echo "\n== Environment Variables ==\n"
for [env_var, var_inf_list] in sort(items(s:chk_env_vars))
let env_val = s:VL_Expand('$', env_var)
for var_inf in var_inf_list
let status = s:VL_EvaluateExpressions(var_inf)
let reason = has_key(var_inf, 'reason') ? s:VL_FailReason(status, var_inf['reason']) : ''
if status !~ s:vl_pass_status | break | endif
endfor
exe "echo \"" . status . env_var . "=" . env_val . reason . "\""
endfor
call s:VL_CrossCheckEnvVarsAgainstVimOpts()
endfunction
" checks for the presence of ~/.vimrc or ~/_vimrc
function! s:VL_CheckVimrc()
if exists('$MYVIMRC')
let vimrc = expand('$MYVIMRC')
if ! filereadable(vimrc)
" I imagine this to be a very improbable edge case - it's Vim who sets
" the $MYVIMRC variable when it finds and loads a personal vimrc, so for
" it to be set but missing on disk would mean that it was deleted/moved
" since starting Vim.
echo s:vl_fail_status . " Your personal vimrc file (" . vimrc . ") doesn't exist!"
endif
else
" Although the two variants (.vimrc and _vimrc) are actually tolerated on
" each platform, I advise the 'more correct' version only.
if has('win32') || has('dos32') || has('win16') || has('dos16') || has('win95')
let platform_vimrc = '$HOME/_vimrc'
elseif has('unix') || has('macunix')
let platform_vimrc = '$HOME/.vimrc'
else
echo s:vl_warn_status . " Can't detect what operating system you're using. Kindly let the developer know your OS, thanks. :)"
endif
echo s:vl_fail_status . " You don't have a personal vimrc file! You really should create a '" . platform_vimrc . "' file."
endif
endfunction
" checks for sane entries in &runtimepath
function! s:VL_CheckVimRuntimePath()
" TODO: I have the feeling that DRYing the next two checks would be more
" hassle than it's worth, and more verbose than this simple but ugly way.
if finddir($VIM, &rtp) == ''
echo s:vl_fail_status . " $VIM is not in your runtimepath! " . s:E('critical_error')
endif
if finddir($VIMRUNTIME, &rtp) == ''
echo s:vl_fail_status . " $VIMRUNTIME is not in your runtimepath! " . s:E('critical_error')
endif
let started_afters = 0
for v_dir in split(&runtimepath, '\\\@<!,')
if v_dir =~# '/after$'
let started_afters = 1
else
if started_afters
echo s:vl_fail_status . " Must not have normal directories following '/after' directories in runtimepath: " . v_dir
endif
if isdirectory(v_dir . "/after") && finddir(v_dir . "/after", &rtp) == ''
" TODO: this seems clumsy... What is the alternative? Is there a way
" for printf() to repeat the final argument if not enough are supplied...?
echo s:vl_fail_status . s:E('after_dir_missing', v_dir, v_dir)
endif
endif
endfor
endfunction
" look for and warn about /off/i within :filetype output
function! s:VL_CheckFiletypeSettings()
echo "\n== Filetype Settings ==\n"
let ft = s:VL_TrimLeft(s:VL_Execute('filetype'))
let status = s:vl_pass_status
let help = ''
if match(ft, '\coff') != -1
let status = s:vl_fail_status
let help = s:E('help', 'filetype')
endif
echo status . ft . help
endfunction
" checks important vim options
function! s:VL_CheckEssentialOptions()
echo "\n== Essential Options ==\n"
for [v_opt, v_inf] in sort(items(s:chk_opt))
let val = s:VL_Expand('&', v_opt)
if val =~ '^[01]$'
let s_opt = (val ? '' : 'no') . v_opt
let e_val = ''
else
let s_opt = v_opt
let e_val = ' = ' . escape(val, "'\"")
end
let status = s:VL_EvaluateExpressions(v_inf)
let reason = s:VL_FailReason(status, v_inf['reason'])
exe "echo \"" . status . s_opt . e_val . reason . "\""
endfor
endfunction
function! s:VL_CheckScripts()
if has('eval')
echo "\n== Scripts ==\n"
silent scriptnames
endif
endfunction
function! s:VL_CheckAllOptions()
let save_reg = @@
call s:VL_Execute("help option-list | .,/^---/y | close")
" wrap all options in '' and separate with commas
" strip leading guff and open the array
" strip trailing guff and close the array
exe "let g:VL_all_options = " . substitute(substitute(substitute(@@,
\ '\(''\w\+''\).\{-}\n', '\1,', 'g'),
\ '^.\{-}''', '[''', ''),
\ ',----*', ']', '')
echo "\n== All Settings ==\n"
echo "--- Options ---"
for v_opt in g:VL_all_options
try
silent exe "verbose set " . v_opt . "?"
catch
endtry
endfor
let @@ = save_reg
endfunction
function! s:VL_CheckTermOptions()
echo "\n== Termcap Settings ==\n"
silent set termcap
endfunction
function! s:VL_CollectData()
call s:VL_CheckVimVersion()
call s:VL_CheckEssentialOptions()
call s:VL_CheckEnvironmentVars()
call s:VL_CheckVimRuntimePath()
call s:VL_CheckVimrc()
call s:VL_CheckFiletypeSettings()
call s:VL_CheckScripts()
call s:VL_CheckAllOptions()
call s:VL_CheckTermOptions()
endfunction
function! s:VL_RunReport()
echo "= Vim Lint v" . s:VimLint_version . " ="
echo "\nThis is a summary of your current Vim configuration, with suggestions to correct bad or dangerous options.\n"
echo "warnings are shown in red on white background (usually with ! at the start of the line)."
echo "errors are shown in white on red background (usually with !! at the start of the line)."
call s:VL_CollectData()
echo "\n= END of Vim Lint ="
echo " vim: set ft=vimlint:"
endfunction
function! s:VL_Syntax()
syn sync fromstart
hi def vimlintCompilerString term=bold ctermfg=6 guifg=DarkCyan
hi def vimlintOption term=bold ctermfg=5 guifg=Purple
hi def vimlintError term=standout ctermfg=15 ctermbg=1 guifg=White guibg=Red
hi def vimlintWarning term=standout ctermfg=1 guifg=Red
hi def vimlintFeatures term=none cterm=bold ctermfg=0 guifg=LightGray
hi def vimlintPresentFeature term=bold ctermfg=2 gui=bold guifg=SeaGreen
hi def vimlintTitle term=none cterm=bold ctermfg=4 guifg=Blue
hi def vimlintComment term=none cterm=bold ctermfg=0 guifg=SlateGray
syn match vimlintEvilScript 'mswin\.vim'
syn match vimlintErrorWord '^errors'
syn match vimlintWarningWord '^warnings'
syn match vimlintError '^!! \@='
syn match vimlintWarning '^! \@='
syn match vimlintFeatures '^[-+].*' contains=vimlintPresentFeature,vimlintMissingFeatures
syn match vimlintPresentFeature contained '+\w\+'
syn match vimlintCompilerString '^Compilation:.*$'
syn match vimlintCompilerString '^Linking:.*$'
syn match vimlintH1 '^= .* =$'
syn match vimlintH2 '^== .* ==$'
syn match vimlintH3 '^--- .* ---$'
syn match vimlintComment ' .*'
syn match vimlintMissingFeatures contained '-\<autocmd\>\|-\<cindent\>\|-\<clipboard\>\|-\<cmdline_compl\>\|-\<cmdline_hist\>\|-\<cmdline_info\>\|-\<comments\>\|-\<diff\>\|-\<digraphs\>\|-\<eval\>\|-\<ex_extra\>\|-\<extra_search\>\|-\<file_in_path\>\|-\<find_in_path\>\|-\<folding\>\|-\<iconv\>\|-\<insert_expand\>\|-\<jumplist\>\|-\<keymap\>\|-\<listcmds\>\|-\<localmap\>\|-\<modify_fname\>\|-\<mouse\>\|-\<multi_byte\>\|-\<multi_lang\>\|-\<path_extra\>\|-\<quickfix\>\|-\<scrollbind\>\|-\<statusline\>\|-\<syntax\>\|-\<tag_binary\>\|-\<textobjects\>\|-\<title\>\|-\<user_commands\>\|-\<vertsplit\>\|-\<visual\>\|-\<visualextra\>'
if has('unix') || has('macunix')
syn match vimlintMissingFeatures contained '-\<terminfo\>\|-\<termresponse\>\|-\<mouse_xterm\>\|-\<X11\>'
endif
syn region vimlintOptionRegion matchgroup=vimlintH2 start=/^== Essential Options ==$/ end=/^== Scripts ==$/ skipwhite contains=vimlintOption,vimlintComment,vimlintError,vimlintWarning
syn region vimlintOptionRegion matchgroup=vimlintH2 start=/^--- Options ---$/ end=/^== Termcap Settings ==$/ skipwhite contains=vimlintOption,vimlintComment,vimlintEvilOption,vimlintWarningOption
" TODO: Find a nicer way to highlight Vim options. I would like all options in
" the vimlint report to start with a ' char so that <F1> :help map works
" properly.
syn match vimlintOption contained '\(\<aleph\>\|\<allowrevins\>\|\<altkeymap\>\|\<ambiwidth\>\|\<arabic\>\|\<arabicshape\>\|\<autochdir\>\|\<autoindent\>\|\<autoread\>\|\<autowrite\>\|\<autowriteall\>\|\<background\>\|\<backspace\>\|\<backup\>\|\<backupcopy\>\|\<backupdir\>\|\<backupext\>\|\<backupskip\>\|\<balloondelay\>\|\<ballooneval\>\|\<balloonexpr\>\|\<binary\>\|\<bomb\>\|\<breakat\>\|\<browsedir\>\|\<bufhidden\>\|\<buflisted\>\|\<buftype\>\|\<casemap\>\|\<cdpath\>\|\<cedit\>\|\<charconvert\>\|\<cindent\>\|\<cinkeys\>\|\<cinoptions\>\|\<cinwords\>\|\<clipboard\>\|\<cmdheight\>\|\<cmdwinheight\>\|\<columns\>\|\<comments\>\|\<commentstring\>\|\<compatible\>\|\<complete\>\|\<completefunc\>\|\<completeopt\>\|\<confirm\>\|\<copyindent\>\|\<cpoptions\>\|\<cscopepathcomp\>\|\<cscopeprg\>\|\<cscopequickfix\>\|\<cscopetag\>\|\<cscopetagorder\>\|\<cscopeverbose\>\|\<cursorcolumn\>\|\<cursorline\>\|\<debug\>\|\<define\>\|\<delcombine\>\|\<dictionary\>\|\<diff\>\|\<diffexpr\>\|\<diffopt\>\|\<digraph\>\|\<directory\>\)'
syn match vimlintOption contained '\(\<display\>\|\<eadirection\>\|\<edcompatible\>\|\<encoding\>\|\<endofline\>\|\<equalalways\>\|\<equalprg\>\|\<errorbells\>\|\<errorfile\>\|\<errorformat\>\|\<esckeys\>\|\<eventignore\>\|\<expandtab\>\|\<exrc\>\|\<fileencoding\>\|\<fileencodings\>\|\<fileformat\>\|\<fileformats\>\|\<filetype\>\|\<fillchars\>\|\<fkmap\>\|\<foldclose\>\|\<foldcolumn\>\|\<foldenable\>\|\<foldexpr\>\|\<foldignore\>\|\<foldlevel\>\|\<foldlevelstart\>\|\<foldmarker\>\|\<foldmethod\>\|\<foldminlines\>\|\<foldnestmax\>\|\<foldopen\>\|\<foldtext\>\|\<formatexpr\>\|\<formatlistpat\>\|\<formatoptions\>\|\<formatprg\>\|\<fsync\>\|\<gdefault\>\|\<grepformat\>\|\<grepprg\>\|\<guicursor\>\|\<guifont\>\|\<guifontwide\>\|\<guiheadroom\>\|\<guioptions\>\|\<guipty\>\|\<guitablabel\>\|\<guitabtooltip\>\|\<helpfile\>\|\<helpheight\>\|\<helplang\>\|\<hidden\>\|\<highlight\>\|\<history\>\|\<hkmap\>\|\<hkmapp\>\|\<hlsearch\>\|\<icon\>\|\<iconstring\>\|\<ignorecase\>\|\<imactivatekey\>\|\<imcmdline\>\|\<imdisable\>\)'
syn match vimlintOption contained '\(\<iminsert\>\|\<imsearch\>\|\<include\>\|\<includeexpr\>\|\<incsearch\>\|\<indentexpr\>\|\<indentkeys\>\|\<infercase\>\|\<insertmode\>\|\<isfname\>\|\<isident\>\|\<iskeyword\>\|\<isprint\>\|\<joinspaces\>\|\<keymap\>\|\<keymodel\>\|\<keywordprg\>\|\<langmap\>\|\<langmenu\>\|\<laststatus\>\|\<lazyredraw\>\|\<linebreak\>\|\<lines\>\|\<linespace\>\|\<lisp\>\|\<lispwords\>\|\<list\>\|\<listchars\>\|\<loadplugins\>\|\<magic\>\|\<makeef\>\|\<makeprg\>\|\<matchpairs\>\|\<matchtime\>\|\<maxcombine\>\|\<maxfuncdepth\>\|\<maxmapdepth\>\|\<maxmem\>\|\<maxmempattern\>\|\<maxmemtot\>\|\<menuitems\>\|\<mkspellmem\>\|\<modeline\>\|\<modelines\>\|\<modifiable\>\|\<modified\>\|\<more\>\|\<mouse\>\|\<mousefocus\>\|\<mousehide\>\|\<mousemodel\>\|\<mouseshape\>\|\<mousetime\>\|\<nrformats\>\|\<number\>\|\<numberwidth\>\|\<omnifunc\>\|\<operatorfunc\>\|\<paragraphs\>\|\<paste\>\|\<pastetoggle\>\|\<patchexpr\>\|\<patchmode\>\|\<path\>\|\<preserveindent\>\|\<previewheight\>\|\<previewwindow\>\)'
syn match vimlintOption contained '\(\<printdevice\>\|\<printencoding\>\|\<printexpr\>\|\<printfont\>\|\<printheader\>\|\<printmbcharset\>\|\<printmbfont\>\|\<printoptions\>\|\<pumheight\>\|\<quoteescape\>\|\<readonly\>\|\<redrawtime\>\|\<remap\>\|\<report\>\|\<revins\>\|\<rightleft\>\|\<rightleftcmd\>\|\<ruler\>\|\<rulerformat\>\|\<runtimepath\>\|\<scroll\>\|\<scrollbind\>\|\<scrolljump\>\|\<scrolloff\>\|\<scrollopt\>\|\<sections\>\|\<secure\>\|\<selection\>\|\<selectmode\>\|\<sessionoptions\>\|\<shell\>\|\<shellcmdflag\>\|\<shellpipe\>\|\<shellquote\>\|\<shellredir\>\|\<shelltemp\>\|\<shellxquote\>\|\<shiftround\>\|\<shiftwidth\>\|\<shortmess\>\|\<shortname\>\|\<showbreak\>\|\<showcmd\>\|\<showfulltag\>\|\<showmatch\>\|\<showmode\>\|\<showtabline\>\|\<sidescroll\>\|\<sidescrolloff\>\|\<smartcase\>\|\<smartindent\>\|\<smarttab\>\|\<softtabstop\>\|\<spell\>\|\<spellcapcheck\>\|\<spellfile\>\|\<spelllang\>\|\<spellsuggest\>\|\<splitbelow\>\|\<splitright\>\|\<startofline\>\|\<statusline\>\|\<suffixes\>\)'
syn match vimlintOption contained '\(\<suffixesadd\>\|\<swapfile\>\|\<swapsync\>\|\<switchbuf\>\|\<synmaxcol\>\|\<syntax\>\|\<tabline\>\|\<tabpagemax\>\|\<tabstop\>\|\<tagbsearch\>\|\<taglength\>\|\<tagrelative\>\|\<tags\>\|\<tagstack\>\|\<term\>\|\<termbidi\>\|\<termencoding\>\|\<terse\>\|\<textauto\>\|\<textmode\>\|\<textwidth\>\|\<thesaurus\>\|\<tildeop\>\|\<timeout\>\|\<timeoutlen\>\|\<title\>\|\<titlelen\>\|\<titleold\>\|\<titlestring\>\|\<toolbar\>\|\<toolbariconsize\>\|\<ttimeout\>\|\<ttimeoutlen\>\|\<ttybuiltin\>\|\<ttyfast\>\|\<ttymouse\>\|\<ttyscroll\>\|\<ttytype\>\|\<undolevels\>\|\<updatecount\>\|\<updatetime\>\|\<verbose\>\|\<verbosefile\>\|\<viewdir\>\|\<viewoptions\>\|\<viminfo\>\|\<virtualedit\>\|\<visualbell\>\|\<warn\>\|\<weirdinvert\>\|\<whichwrap\>\|\<wildchar\>\|\<wildcharm\>\|\<wildignore\>\|\<wildmenu\>\|\<wildmode\>\|\<winaltkeys\>\|\<winfixheight\>\|\<winfixwidth\>\|\<winheight\>\|\<winminheight\>\|\<winminwidth\>\|\<winwidth\>\|\<wrap\>\|\<wrapmargin\>\|\<wrapscan\>\|\<write\>\|\<writeany\>\|\<writebackup\>\|\<writedelay\>\)'
" These are the turn-off setting variants
syn match vimlintOption contained '\(\<noacd\>\|\<noallowrevins\>\|\<noantialias\>\|\<noarabic\>\|\<noarshape\>\|\<noautoread\>\|\<noaw\>\|\<noballooneval\>\|\<nobinary\>\|\<nobk\>\|\<nobuflisted\>\|\<nocin\>\|\<noconfirm\>\|\<nocopyindent\>\|\<nocscopeverbose\>\|\<nocuc\>\|\<nocursorline\>\|\<nodg\>\|\<nodisable\>\|\<noeb\>\|\<noedcompatible\>\|\<noendofline\>\|\<noequalalways\>\|\<noesckeys\>\|\<noex\>\|\<noexrc\>\|\<nofk\>\|\<nofoldenable\>\|\<nogdefault\>\|\<nohid\>\|\<nohk\>\|\<nohkmapp\>\|\<nohls\>\|\<noic\>\|\<noignorecase\>\|\<noimc\>\|\<noimd\>\|\<noinf\>\|\<noinsertmode\>\|\<nojoinspaces\>\|\<nolazyredraw\>\|\<nolinebreak\>\|\<nolist\>\|\<nolpl\>\|\<noma\>\|\<nomagic\>\|\<noml\>\|\<nomodeline\>\|\<nomodified\>\|\<nomousef\>\|\<nomousehide\>\|\<nonumber\>\|\<noopendevice\>\|\<nopi\>\|\<nopreviewwindow\>\|\<nopvw\>\|\<noremap\>\|\<norevins\>\|\<norightleft\>\|\<norl\>\|\<noro\>\|\<noru\>\|\<nosb\>\|\<noscb\>\|\<noscs\>\|\<nosft\>\|\<noshelltemp\>\|\<noshortname\>\|\<noshowfulltag\>\|\<noshowmode\>\|\<nosm\>\|\<nosmartindent\>\|\<nosmd\>\|\<nosol\>\|\<nosplitbelow\>\|\<nospr\>\|\<nossl\>\|\<nostartofline\>\|\<noswapfile\>\|\<nota\>\|\<notagrelative\>\|\<notbi\>\|\<notbs\>\|\<noterse\>\|\<notextmode\>\|\<notgst\>\|\<notimeout\>\|\<noto\>\|\<notr\>\|\<nottybuiltin\>\|\<notx\>\|\<novisualbell\>\|\<nowarn\>\|\<noweirdinvert\>\|\<nowfw\>\|\<nowinfixheight\>\|\<nowiv\>\|\<nowrap\>\|\<nowrite\>\|\<nowritebackup\>\)'
syn match vimlintOption contained '\(\<noai\>\|\<noaltkeymap\>\|\<noar\>\|\<noarabicshape\>\|\<noautochdir\>\|\<noautowrite\>\|\<noawa\>\|\<nobeval\>\|\<nobiosk\>\|\<nobl\>\|\<nocf\>\|\<nocindent\>\|\<noconsk\>\|\<nocp\>\|\<nocst\>\|\<nocul\>\|\<nodeco\>\|\<nodiff\>\|\<noea\>\|\<noed\>\|\<noek\>\|\<noeol\>\|\<noerrorbells\>\|\<noet\>\|\<noexpandtab\>\|\<nofen\>\|\<nofkmap\>\|\<nogd\>\|\<noguipty\>\|\<nohidden\>\|\<nohkmap\>\|\<nohkp\>\|\<nohlsearch\>\|\<noicon\>\|\<noim\>\|\<noimcmdline\>\|\<noincsearch\>\|\<noinfercase\>\|\<nois\>\|\<nojs\>\|\<nolbr\>\|\<nolisp\>\|\<noloadplugins\>\|\<nolz\>\|\<nomacatsui\>\|\<nomh\>\|\<nomod\>\|\<nomodifiable\>\|\<nomore\>\|\<nomousefocus\>\|\<nonu\>\|\<noodev\>\|\<nopaste\>\|\<nopreserveindent\>\|\<noprompt\>\|\<noreadonly\>\|\<norestorescreen\>\|\<nori\>\|\<norightleftcmd\>\|\<norlc\>\|\<nors\>\|\<noruler\>\|\<nosc\>\|\<noscrollbind\>\|\<nosecure\>\|\<noshellslash\>\|\<noshiftround\>\|\<noshowcmd\>\|\<noshowmatch\>\|\<nosi\>\|\<nosmartcase\>\|\<nosmarttab\>\|\<nosn\>\|\<nospell\>\|\<nosplitright\>\|\<nosr\>\|\<nosta\>\|\<nostmp\>\|\<noswf\>\|\<notagbsearch\>\|\<notagstack\>\|\<notbidi\>\|\<notermbidi\>\|\<notextauto\>\|\<notf\>\|\<notildeop\>\|\<notitle\>\|\<notop\>\|\<nottimeout\>\|\<nottyfast\>\|\<novb\>\|\<nowa\>\|\<nowb\>\|\<nowfh\>\|\<nowildmenu\>\|\<nowinfixwidth\>\|\<nowmnu\>\|\<nowrapscan\>\|\<nowriteany\>\|\<nows\>\)'
syn match vimlintOption contained '\(\<noakm\>\|\<noanti\>\|\<noarab\>\|\<noari\>\|\<noautoindent\>\|\<noautowriteall\>\|\<nobackup\>\|\<nobin\>\|\<nobioskey\>\|\<nobomb\>\|\<noci\>\|\<nocompatible\>\|\<noconskey\>\|\<nocscopetag\>\|\<nocsverb\>\|\<nocursorcolumn\>\|\<nodelcombine\>\|\<nodigraph\>\)'
"TODO: put more evil options here
syn match vimlintEvilOption '\(\<compatible\>\|\<edcompatible\>\|\<exrc\>\|\<gdefault\>\|\<nohidden\>\|\<insertmode\>\|\<lisp\>\|\<noloadplugins\>\|\<nomagic\>\|\<smartindent\>\)' contained
"TODO: put more warning-worthy options here
syn match vimlintWarningOption '\(\<cindent\>\|\<autochdir\>\|\<autoread\>\|\<autowrite\>\|\<autowriteall\>\|\<modeline\>\|\<nomodifiable\>\|\<readonly\>\|\<paste\>\|\<secure\>\|\<noswapfile\>\|\<nottyfast\>\|\<nowrite\>\|\<writeany\>\)' contained
hi def link vimlintEvilOption vimlintError
hi def link vimlintEvilScript vimlintError
hi def link vimlintWarningOption vimlintWarning
hi def link vimlintErrorWord vimlintError
hi def link vimlintWarningWord vimlintWarning
hi def link vimlintMissingFeatures vimlintWarning
hi def link vimlintH1 vimlintTitle
hi def link vimlintH2 vimlintTitle
hi def link vimlintH3 vimlintTitle
let b:current_syntax = "vimlint"
endfunction
" Public Interface: {{{2
function! VimLint()
let s:vimlintreport = tempname()
new " use a new window / buffer so that filetype is clear
exe "redir > " . s:vimlintreport
silent call s:VL_RunReport()
redir END
silent exe "edit " . s:vimlintreport
silent set filetype=vimlint
call s:VL_Syntax()
" nicer to see the report in a full window if we can
if &hidden == 1
only
endif
echo "Vim Lint Report saved in " . s:vimlintreport
endfunction
" Teardown:{{{2
"reset &cpo back to users setting
let &cpo = s:old_cpo
call VimLint()
" Credits:{{{2
"
" Thanks to godlygeek, jamessan, spiiph and Raimondi for contributing ideas,
" suggestions, algorithms and corrections.
"
" vim: set sw=2 sts=2 et fdm=marker:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment