296 lines
12 KiB
VimL
296 lines
12 KiB
VimL
|
" 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 <SID>WhitespaceInit()
|
||
|
call <SID>SetupAutoCommands()
|
||
|
call <SID>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 <SID>SetupAutoCommands()
|
||
|
call <SID>Echo("Whitespace Highlighting: Disabled")
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
" Toggle whitespace highlighting on/off
|
||
|
function! s:ToggleWhitespace()
|
||
|
if b:better_whitespace_enabled == 1
|
||
|
call <SID>DisableWhitespace()
|
||
|
else
|
||
|
call <SID>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 <SID>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 <SID>Echo("Current Line Hightlight Off (soft)")
|
||
|
endif
|
||
|
" Re-run auto commands with the new settings
|
||
|
call <SID>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 <SID>SetupAutoCommands()
|
||
|
call s:InAllWindows('syn clear ExtraWhitespace | match ExtraWhitespace "' . s:eol_whitespace_pattern . '"')
|
||
|
call <SID>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 <SID>Echo("Strip Whitespace On Save: Enabled")
|
||
|
call <SID>SetupAutoCommands()
|
||
|
endfunction
|
||
|
|
||
|
" Don't strip whitespace on file save
|
||
|
function! s:DisableStripWhitespaceOnSave()
|
||
|
let g:strip_whitespace_on_save = 0
|
||
|
call <SID>Echo("Strip Whitespace On Save: Disabled")
|
||
|
call <SID>SetupAutoCommands()
|
||
|
endfunction
|
||
|
|
||
|
" Strips whitespace on file save
|
||
|
function! s:ToggleStripWhitespaceOnSave()
|
||
|
if g:strip_whitespace_on_save == 1
|
||
|
call <SID>DisableStripWhitespaceOnSave()
|
||
|
else
|
||
|
call <SID>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 <SID>StripWhitespace( <line1>, <line2> )
|
||
|
" Run :EnableStripWhitespaceOnSave to enable whitespace stripping on save
|
||
|
command! EnableStripWhitespaceOnSave call <SID>EnableStripWhitespaceOnSave()
|
||
|
" Run :DisableStripWhitespaceOnSave to disable whitespace stripping on save
|
||
|
command! DisableStripWhitespaceOnSave call <SID>DisableStripWhitespaceOnSave()
|
||
|
" Run :ToggleStripWhitespaceOnSave to enable/disable whitespace stripping on save
|
||
|
command! ToggleStripWhitespaceOnSave call <SID>ToggleStripWhitespaceOnSave()
|
||
|
" Run :EnableWhitespace to enable whitespace highlighting
|
||
|
command! EnableWhitespace call <SID>EnableWhitespace()
|
||
|
" Run :DisableWhitespace to disable whitespace highlighting
|
||
|
command! DisableWhitespace call <SID>DisableWhitespace()
|
||
|
" Run :ToggleWhitespace to toggle whitespace highlighting on/off
|
||
|
command! ToggleWhitespace call <SID>ToggleWhitespace()
|
||
|
" Run :CurrentLineWhitespaceOff(level) to disable highlighting for the current
|
||
|
" line. Levels are: 'hard' and 'soft'
|
||
|
command! -nargs=* CurrentLineWhitespaceOff call <SID>CurrentLineWhitespaceOff( <f-args> )
|
||
|
" Run :CurrentLineWhitespaceOn to turn on whitespace for the current line
|
||
|
command! CurrentLineWhitespaceOn call <SID>CurrentLineWhitespaceOn()
|
||
|
|
||
|
" Process auto commands upon load, update local enabled on filetype change
|
||
|
autocmd FileType * let b:better_whitespace_enabled = !<SID>ShouldSkipHighlight() | call <SID>SetupAutoCommands()
|
||
|
autocmd WinEnter,BufWinEnter * call <SID>SetupAutoCommands()
|
||
|
autocmd ColorScheme * call <SID>WhitespaceInit()
|
||
|
|
||
|
function! s:PerformMatchHighlight(pattern)
|
||
|
call s:InitVariable('b:better_whitespace_enabled', !<SID>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', !<SID>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! <SID>SetupAutoCommands()
|
||
|
" Auto commands group
|
||
|
augroup better_whitespace
|
||
|
autocmd!
|
||
|
|
||
|
if g:better_whitespace_enabled == 1
|
||
|
if s:better_whitespace_initialized == 0
|
||
|
call <SID>WhitespaceInit()
|
||
|
endif
|
||
|
|
||
|
|
||
|
" Check if current line is disabled softly
|
||
|
if g:current_line_whitespace_disabled_soft == 0
|
||
|
" Highlight all whitespace upon entering buffer
|
||
|
call <SID>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 <SID>HighlightEOLWhitespaceExceptCurrentLine('match')
|
||
|
else
|
||
|
" When in insert mode, do not highlight whitespace on the current line
|
||
|
autocmd InsertEnter,CursorMovedI * call <SID>HighlightEOLWhitespaceExceptCurrentLine('match')
|
||
|
endif
|
||
|
" Highlight all whitespace when exiting insert mode
|
||
|
autocmd InsertLeave,BufReadPost * call <SID>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 <SID>HighlightEOLWhitespace('syntax')
|
||
|
autocmd InsertEnter * call <SID>HighlightEOLWhitespaceExceptCurrentLine('syntax')
|
||
|
autocmd InsertLeave,BufReadPost * call <SID>HighlightEOLWhitespace('syntax')
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
" Strip whitespace on save if enabled
|
||
|
if g:strip_whitespace_on_save == 1
|
||
|
autocmd BufWritePre * call <SID>StripWhitespace( 0, line("$") )
|
||
|
endif
|
||
|
|
||
|
augroup END
|
||
|
endfunction
|
||
|
|