" Author: Nate Peterson " Repository: https://github.com/ntpeters/vim-better-whitespace " Prevent loading the plugin multiple times if exists('g:loaded_better_whitespace_plugin') finish endif let g:loaded_better_whitespace_plugin = 1 " Initializes a given variable to a given value. The variable is only " initialized if it does not exist prior. function! s:InitVariable(var, value) if !exists(a:var) execute 'let ' . a:var . ' = ' . string(a:value) endif endfunction " Set this to enable/disable whitespace highlighting call s:InitVariable('g:better_whitespace_enabled', 1) " Set this to disable highlighting on the current line in all modes " WARNING: This checks for current line on cursor move, which can significantly " impact the performance of Vim (especially on large files) call s:InitVariable('g:current_line_whitespace_disabled_hard', 0) " Set this to disable highlighting of the current line in all modes " This setting will not have the performance impact of the above, but " highlighting throughout the file may be overridden by other highlight " patterns with higher priority. call s:InitVariable('g:current_line_whitespace_disabled_soft', 0) " Set this to enable stripping whitespace on file save call s:InitVariable('g:strip_whitespace_on_save', 0) " Set this to blacklist specific filetypes let default_blacklist=['diff', 'gitcommit', 'unite', 'qf', 'help', 'markdown'] call s:InitVariable('g:better_whitespace_filetypes_blacklist', default_blacklist) " Disable verbosity by default call s:InitVariable('g:better_whitespace_verbosity', 0) " Define custom whitespace character group to include all horizontal unicode " whitespace characters. Vim's '\s' class only includes ASCII spaces and tabs. let s:whitespace_group='[\u0009\u0020\u00a0\u1680\u180e\u2000-\u200b\u202f\u205f\u3000\ufeff]' let s:eol_whitespace_pattern = s:whitespace_group . '\+$' " Only init once let s:better_whitespace_initialized = 0 " Like windo but restore the current window. function! s:Windo(command) let currwin=winnr() execute 'windo ' . a:command execute currwin . 'wincmd w' endfunction " Like tabdo but restore the current tab. function! s:Tabdo(command) let currTab=tabpagenr() execute 'tabdo ' . a:command execute 'tabn ' . currTab endfunction " Execute command in all windows (across tabs). function! s:InAllWindows(command) call s:Tabdo("call s:Windo('".substitute(a:command, "'", "''", 'g')."')") endfunction " Ensure the 'ExtraWhitespace' highlight group has been defined function! s:WhitespaceInit() " Check if the user has already defined highlighting for this group if hlexists("ExtraWhitespace") == 0 || synIDattr(synIDtrans(hlID("ExtraWhitespace")), "bg") == -1 highlight ExtraWhitespace ctermbg = red guibg = #FF0000 endif let s:better_whitespace_initialized = 1 endfunction " Like 'echo', but only outputs the message when verbosity is enabled function! s:Echo(message) if g:better_whitespace_verbosity == 1 echo a:message endif endfunction " Enable the whitespace highlighting function! s:EnableWhitespace() if b:better_whitespace_enabled == 0 let b:better_whitespace_enabled = 1 call WhitespaceInit() call SetupAutoCommands() call Echo("Whitespace Highlighting: Enabled") endif endfunction " Disable the whitespace highlighting function! s:DisableWhitespace() if b:better_whitespace_enabled == 1 let b:better_whitespace_enabled = 0 call SetupAutoCommands() call Echo("Whitespace Highlighting: Disabled") endif endfunction " Toggle whitespace highlighting on/off function! s:ToggleWhitespace() if b:better_whitespace_enabled == 1 call DisableWhitespace() else call EnableWhitespace() endif endfunction " This disabled whitespace highlighting on the current line in all modes " Options: " hard - Disables highlighting for current line and maintains high priority " highlighting for the entire file. Caution: may cause slowdown in Vim! " soft - No potential slowdown as with 'hard' option, but other highlighting " rules of higher priority may overwrite these whitespace highlights. function! s:CurrentLineWhitespaceOff( level ) if g:better_whitespace_enabled == 1 " Set current line whitespace level if a:level == 'hard' let g:current_line_whitespace_disabled_hard = 1 let g:current_line_whitespace_disabled_soft = 0 call s:InAllWindows('syn clear ExtraWhitespace | match ExtraWhitespace "' . s:eol_whitespace_pattern . '"') call Echo("Current Line Hightlight Off (hard)") elseif a:level == 'soft' let g:current_line_whitespace_disabled_soft = 1 let g:current_line_whitespace_disabled_hard = 0 call s:InAllWindows("match ExtraWhitespace ''") call Echo("Current Line Hightlight Off (soft)") endif " Re-run auto commands with the new settings call SetupAutoCommands() endif endfunction " Enables whitespace highlighting for the current line function! s:CurrentLineWhitespaceOn() if g:better_whitespace_enabled == 1 let g:current_line_whitespace_disabled_hard = 0 let g:current_line_whitespace_disabled_soft = 0 call SetupAutoCommands() call s:InAllWindows('syn clear ExtraWhitespace | match ExtraWhitespace "' . s:eol_whitespace_pattern . '"') call Echo("Current Line Hightlight On") endif endfunction " Removes all extraneous whitespace in the file function! s:StripWhitespace( line1, line2 ) " Save the current search and cursor position let _s=@/ let l = line(".") let c = col(".") " Strip the whitespace silent! execute ':' . a:line1 . ',' . a:line2 . 's/' . s:eol_whitespace_pattern . '//e' " Restore the saved search and cursor position let @/=_s call cursor(l, c) endfunction " Strip whitespace on file save function! s:EnableStripWhitespaceOnSave() let g:strip_whitespace_on_save = 1 call Echo("Strip Whitespace On Save: Enabled") call SetupAutoCommands() endfunction " Don't strip whitespace on file save function! s:DisableStripWhitespaceOnSave() let g:strip_whitespace_on_save = 0 call Echo("Strip Whitespace On Save: Disabled") call SetupAutoCommands() endfunction " Strips whitespace on file save function! s:ToggleStripWhitespaceOnSave() if g:strip_whitespace_on_save == 1 call DisableStripWhitespaceOnSave() else call EnableStripWhitespaceOnSave() endif endfunction " Determines if whitespace highlighting should currently be skipped function! s:ShouldSkipHighlight() return &buftype == 'nofile' || index(g:better_whitespace_filetypes_blacklist, &ft) >= 0 endfunction " Run :StripWhitespace to remove end of line whitespace command! -range=% StripWhitespace call StripWhitespace( , ) " Run :EnableStripWhitespaceOnSave to enable whitespace stripping on save command! EnableStripWhitespaceOnSave call EnableStripWhitespaceOnSave() " Run :DisableStripWhitespaceOnSave to disable whitespace stripping on save command! DisableStripWhitespaceOnSave call DisableStripWhitespaceOnSave() " Run :ToggleStripWhitespaceOnSave to enable/disable whitespace stripping on save command! ToggleStripWhitespaceOnSave call ToggleStripWhitespaceOnSave() " Run :EnableWhitespace to enable whitespace highlighting command! EnableWhitespace call EnableWhitespace() " Run :DisableWhitespace to disable whitespace highlighting command! DisableWhitespace call DisableWhitespace() " Run :ToggleWhitespace to toggle whitespace highlighting on/off command! ToggleWhitespace call ToggleWhitespace() " Run :CurrentLineWhitespaceOff(level) to disable highlighting for the current " line. Levels are: 'hard' and 'soft' command! -nargs=* CurrentLineWhitespaceOff call CurrentLineWhitespaceOff( ) " Run :CurrentLineWhitespaceOn to turn on whitespace for the current line command! CurrentLineWhitespaceOn call CurrentLineWhitespaceOn() " Process auto commands upon load, update local enabled on filetype change autocmd FileType * let b:better_whitespace_enabled = !ShouldSkipHighlight() | call SetupAutoCommands() autocmd WinEnter,BufWinEnter * call SetupAutoCommands() autocmd ColorScheme * call WhitespaceInit() function! s:PerformMatchHighlight(pattern) call s:InitVariable('b:better_whitespace_enabled', !ShouldSkipHighlight()) if b:better_whitespace_enabled == 1 exe 'match ExtraWhitespace "' . a:pattern . '"' else match ExtraWhitespace '' endif endfunction function! s:PerformSyntaxHighlight(pattern) syn clear ExtraWhitespace call s:InitVariable('b:better_whitespace_enabled', !ShouldSkipHighlight()) if b:better_whitespace_enabled == 1 exe 'syn match ExtraWhitespace excludenl "' . a:pattern . '"' endif endfunction function! s:HighlightEOLWhitespace(type) if (a:type == 'match') call s:PerformMatchHighlight(s:eol_whitespace_pattern) elseif (a:type == 'syntax') call s:PerformSyntaxHighlight(s:eol_whitespace_pattern) endif endfunction function! s:HighlightEOLWhitespaceExceptCurrentLine(type) let a:exclude_current_line_eol_whitespace_pattern = '\%<' . line(".") . 'l' . s:eol_whitespace_pattern . '\|\%>' . line(".") . 'l' . s:eol_whitespace_pattern if (a:type == 'match') call s:PerformMatchHighlight(a:exclude_current_line_eol_whitespace_pattern) elseif (a:type == 'syntax') call s:PerformSyntaxHighlight(a:exclude_current_line_eol_whitespace_pattern) endif endfunction " Executes all auto commands function! SetupAutoCommands() " Auto commands group augroup better_whitespace autocmd! if g:better_whitespace_enabled == 1 if s:better_whitespace_initialized == 0 call WhitespaceInit() endif " Check if current line is disabled softly if g:current_line_whitespace_disabled_soft == 0 " Highlight all whitespace upon entering buffer call PerformMatchHighlight(s:eol_whitespace_pattern) " Check if current line highglighting is disabled if g:current_line_whitespace_disabled_hard == 1 " Never highlight whitespace on current line autocmd InsertEnter,CursorMoved,CursorMovedI * call HighlightEOLWhitespaceExceptCurrentLine('match') else " When in insert mode, do not highlight whitespace on the current line autocmd InsertEnter,CursorMovedI * call HighlightEOLWhitespaceExceptCurrentLine('match') endif " Highlight all whitespace when exiting insert mode autocmd InsertLeave,BufReadPost * call HighlightEOLWhitespace('match') " Clear whitespace highlighting when leaving buffer autocmd BufWinLeave * match ExtraWhitespace '' else " Highlight extraneous whitespace at the end of lines, but not the " current line. call HighlightEOLWhitespace('syntax') autocmd InsertEnter * call HighlightEOLWhitespaceExceptCurrentLine('syntax') autocmd InsertLeave,BufReadPost * call HighlightEOLWhitespace('syntax') endif endif " Strip whitespace on save if enabled if g:strip_whitespace_on_save == 1 autocmd BufWritePre * call StripWhitespace( 0, line("$") ) endif augroup END endfunction