dotfiles/vim/plugins/vim-better-whitespace/plugin/better-whitespace.vim
2018-04-05 13:06:54 +02:00

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