├── .travis.yml ├── autoload ├── high │ ├── light │ │ ├── mixed_eol.vim │ │ ├── mixed_indent.vim │ │ ├── trailing_whitespace.vim │ │ ├── unite_directory.vim │ │ ├── invisible_space.vim │ │ ├── inactive_window.vim │ │ ├── deep_indent.vim │ │ ├── long_line.vim │ │ ├── indent.vim │ │ └── words.vim │ ├── utils.vim │ ├── commandline.vim │ ├── match.vim │ └── group.vim └── high.vim ├── test ├── high │ ├── utils.vimspec │ ├── match.vimspec │ └── group.vimspec ├── .themisrc └── high.vimspec ├── LICENSE ├── plugin └── high.vim └── README.adoc /.travis.yml: -------------------------------------------------------------------------------- 1 | install: 2 | - git clone --depth 1 --single-branch https://github.com/thinca/vim-themis 3 | 4 | script: 5 | - vim --version 6 | - ./vim-themis/bin/themis 7 | -------------------------------------------------------------------------------- /autoload/high/light/mixed_eol.vim: -------------------------------------------------------------------------------- 1 | " Highlight mixed EOL (mixed end-of-line), highlight ^M 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | 7 | function! high#light#mixed_eol#Define() 8 | return { 9 | \ 'pattern': '\r', 10 | \ } 11 | endfunction 12 | -------------------------------------------------------------------------------- /autoload/high/light/mixed_indent.vim: -------------------------------------------------------------------------------- 1 | " Highlight mixed indentation (mixed tabs and spaces), highlight mixed indent 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | 7 | function! high#light#mixed_indent#Define() 8 | return { 9 | \ 'pattern': '^ .*\n\+\zs\t\+\|^\t.*\n\+\zs \+\|^ \+\zs\t\+\s*\|^\t\+\zs \+\s*', 10 | \ } 11 | endfunction 12 | -------------------------------------------------------------------------------- /autoload/high/light/trailing_whitespace.vim: -------------------------------------------------------------------------------- 1 | " Highlight trailing whitespace, highlight whitespace on end of line 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | " 7 | " Inspired by: 8 | " https://github.com/ntpeters/vim-better-whitespace 9 | 10 | function! high#light#trailing_whitespace#Define() 11 | return { 12 | \ 'pattern': '\s\+$', 13 | \ } 14 | endfunction 15 | -------------------------------------------------------------------------------- /autoload/high/light/unite_directory.vim: -------------------------------------------------------------------------------- 1 | " Highlight directories in Unite and Denite buffer (`Unite file`) 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | 7 | function! high#light#unite_directory#Define() 8 | return { 9 | \ 'hlgroup': 'Directory', 10 | \ 'whitelist': ['unite', 'denite'], 11 | \ 'pattern': '^\s\(file\s\|directory\s\)\?\zs.*/$', 12 | \ } 13 | endfunction 14 | -------------------------------------------------------------------------------- /test/high/utils.vimspec: -------------------------------------------------------------------------------- 1 | Describe high#utils 2 | Before 3 | call ResetSettings() 4 | End 5 | 6 | Describe #Clone 7 | It returns a clone of default settings 8 | Assert Equals(g:high.defaults, high#utils#Clone()) 9 | End 10 | 11 | It returns a clone of argument 12 | let base = high#utils#Clone() 13 | let base.hlgroup = 'Normal' 14 | let clone = high#utils#Clone(base) 15 | Assert Equals(base, clone) 16 | Assert NotSame(base, clone) 17 | End 18 | End 19 | End 20 | -------------------------------------------------------------------------------- /autoload/high/light/invisible_space.vim: -------------------------------------------------------------------------------- 1 | " Highlight invisible space, non-breaking space 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | " 7 | " Inspired by: 8 | " https://www.reddit.com/r/vim/comments/5ltoq2/display_nonspace_and_nontab_whitespace_in_file/ 9 | 10 | function! high#light#invisible_space#Define() 11 | return { 12 | \ 'pattern': '\%u00A0\|\%u1680\|\%u180E\|\%u2000\|\%u2001\|\%u2002\|\%u2003\|\%u2004\|\%u2005\|\%u2006\|\%u2007\|\%u2008\|\%u2009\|\%u200A\|\%u200B\|\%u202F\|\%u205F\|\%u3000\|\%uFEFF', 13 | \ } 14 | endfunction 15 | -------------------------------------------------------------------------------- /autoload/high/utils.vim: -------------------------------------------------------------------------------- 1 | " Utility functions, helpers 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | 7 | function! high#utils#Clone(...) "{{{ 8 | return deepcopy(a:0 ? a:1 : g:high.defaults) 9 | endfunction "}}} 10 | 11 | function! high#utils#ListOfGroupNames() "{{{ 12 | let autoloaded = map( 13 | \ split(globpath(&runtimepath, 'autoload/high/light/*'), '\n'), 14 | \ 'fnamemodify(v:val, ":p:t:r")') 15 | 16 | if exists('g:high_lighters') 17 | let user_defined = keys(g:high_lighters) 18 | call filter(user_defined, 'index(autoloaded, v:val) < 0') 19 | else 20 | let user_defined = [] 21 | endif 22 | return sort(autoloaded + user_defined) 23 | endfunction "}}} 24 | -------------------------------------------------------------------------------- /autoload/high/light/inactive_window.vim: -------------------------------------------------------------------------------- 1 | " Make the current window more visible, dim inactive windows 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | " 7 | " Inspired by: 8 | " https://github.com/blueyed/vim-diminactive 9 | 10 | function! high#light#inactive_window#Define() 11 | return { 12 | \ 'hlgroup': 'Comment', 13 | \ 'pattern': '.*', 14 | \ '__init_function': function('s:Init'), 15 | \ '__auto_highlight': 0, 16 | \ } 17 | endfunction 18 | 19 | function! s:Init(options) "{{{ 20 | call high#group#AddMember(a:options) 21 | 22 | augroup high_inactive_window 23 | autocmd! 24 | autocmd WinEnter * call high#LightGroup(high#group#GetSettings('inactive_window'), 0) 25 | autocmd WinLeave * call high#LightGroup(high#group#GetSettings('inactive_window'), 1) 26 | augroup END 27 | endfunction "}}} 28 | -------------------------------------------------------------------------------- /autoload/high/light/deep_indent.vim: -------------------------------------------------------------------------------- 1 | " Highlight deep indentation, highlight deeply indented code 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | " 7 | " Inspired by: 8 | " https://github.com/dodie/vim-disapprove-deep-indentation 9 | 10 | function! high#light#deep_indent#Define() 11 | return { 12 | \ 'hlgroup': 'CursorLine', 13 | \ '_min_levels': 5, 14 | \ '__update_function': function('s:Update'), 15 | \ } 16 | endfunction 17 | 18 | function! s:Update(options) "{{{ 19 | if exists('w:high_deep_indent_prev_sw') && (w:high_deep_indent_prev_sw == &shiftwidth) 20 | let w:high_deep_indent_prev_sw = &shiftwidth 21 | return 0 22 | endif 23 | let w:high_deep_indent_prev_sw = &shiftwidth 24 | 25 | let a:options.pattern = '\v^\s{'.&shiftwidth*a:options._min_levels.',}|^\t{'.a:options._min_levels.',}' 26 | return 1 27 | endfunction "}}} 28 | -------------------------------------------------------------------------------- /test/.themisrc: -------------------------------------------------------------------------------- 1 | " Force English messages 2 | language messages C 3 | 4 | call themis#helper('command').with(themis#helper('assert')) 5 | call themis#option('recursive', 1) 6 | call themis#option('reporter', 'spec') 7 | 8 | function! ResetSettings() "{{{ 9 | " Drop every buffer and window. 10 | " IT DOES NOT REMOVES THE MATCHES (added by matchadd()) 11 | silent! %bwipeout! 12 | call clearmatches() 13 | " Reinitialize the whole plugin to clear the loaded lighters. 14 | unlet g:loaded_high 15 | silent! unlet g:high_lighters 16 | source plugin/high.vim 17 | endfunction "}}} 18 | 19 | " FIXTURES 20 | " ============================================================================ 21 | 22 | let g:activator = '' 23 | function! UpdatePatternIfActivatorNotEmpty(group_settings) 24 | if empty(g:activator) 25 | return 0 26 | endif 27 | let a:group_settings.pattern = g:activator 28 | return 1 29 | endfunction 30 | -------------------------------------------------------------------------------- /autoload/high/commandline.vim: -------------------------------------------------------------------------------- 1 | " Command line interface for vim-high, a Vim custom highlighter plugin 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | 7 | function! high#commandline#Completion(arg_lead, cmd_line, cursor_pos) "{{{ 8 | return filter(high#utils#ListOfGroupNames(), 'v:val =~ "^'.a:arg_lead.'"') 9 | endfunction "}}} 10 | 11 | function! high#commandline#Toggle(enabled, ...) "{{{ 12 | for group_name in (a:0 ? a:000 : high#utils#ListOfGroupNames()) 13 | if !high#group#IsRegistered(group_name) 14 | let settings = high#group#Register(group_name) 15 | else 16 | let settings = high#group#GetSettings(group_name) 17 | endif 18 | let settings.enabled = (a:enabled >= 0 ? a:enabled : !settings.enabled) 19 | let original_win = winnr() 20 | windo call high#Light(settings) 21 | exe original_win.'wincmd w' 22 | endfor 23 | endfunction "}}} 24 | -------------------------------------------------------------------------------- /autoload/high/light/long_line.vim: -------------------------------------------------------------------------------- 1 | " Highlight long lines, highlight part of line exceeding textwidth 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | " 7 | " Inspired by: 8 | " https://github.com/whatyouhide/vim-lengthmatters 9 | 10 | function! high#light#long_line#Define() 11 | return { 12 | \ '_length': 0, 13 | \ '_single_column': 0, 14 | \ '__init_function': function('s:Init'), 15 | \ } 16 | endfunction 17 | 18 | function! s:Init(options) "{{{ 19 | if a:options._length 20 | let a:options.pattern = 21 | \ '\%'.(a:options._length+1).'v.'.(a:options._single_column ? '' : '\+') 22 | else 23 | let a:options.__update_function = function('s:Update') 24 | endif 25 | call high#group#AddMember(a:options) 26 | endfunction "}}} 27 | 28 | function! s:Update(options) "{{{ 29 | let a:options.pattern = 30 | \ &textwidth > 0 ? '\%'.(&textwidth+1).'v.'.(a:options._single_column ? '' : '\+') : '' 31 | endfunction "}}} 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Bimba Laszlo, github.com/bimlas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /autoload/high.vim: -------------------------------------------------------------------------------- 1 | " Main functions, interface of the plugin 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | 7 | function! high#Light(group_settings) "{{{ 8 | if a:group_settings.__auto_highlight 9 | call high#LightGroup(a:group_settings, 1) 10 | endif 11 | endfunction "}}} 12 | 13 | function! high#LightGroup(group_settings, enabled) "{{{ 14 | call high#match#InitIDs() 15 | if a:enabled && high#group#IsEnabled(a:group_settings) 16 | if !high#group#IsInitialized(a:group_settings.__group_name) 17 | call high#group#Init(a:group_settings.__group_name) 18 | endif 19 | let have_to_update = high#group#HaveToUpdate(a:group_settings) 20 | for lighter in high#group#GetMembers(a:group_settings.__group_name) 21 | if have_to_update 22 | call high#match#Clear(lighter) 23 | endif 24 | call high#match#Add(lighter) 25 | endfor 26 | else 27 | for lighter in high#group#GetMembers(a:group_settings.__group_name) 28 | call high#match#Clear(lighter) 29 | endfor 30 | endif 31 | endfunction "}}} 32 | 33 | function! high#UpdateGroups() "{{{ 34 | for group_settings in values(g:high.registered_groups) 35 | if empty(group_settings.__update_function) 36 | continue 37 | endif 38 | call high#Light(group_settings) 39 | endfor 40 | endfunction "}}} 41 | -------------------------------------------------------------------------------- /autoload/high/match.vim: -------------------------------------------------------------------------------- 1 | " Core of vim-high custom highlighter Vim plugin 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | 7 | function! high#match#Highlight(lighter, enabled) "{{{ 8 | call high#match#InitIDs() 9 | if a:enabled && high#group#IsEnabled(a:lighter) 10 | call high#match#Add(a:lighter) 11 | else 12 | call high#match#Clear(a:lighter) 13 | endif 14 | endfunction "}}} 15 | 16 | function! high#match#Add(lighter) "{{{ 17 | if high#match#GetID(a:lighter) < 0 18 | call high#match#SetID( 19 | \ a:lighter, 20 | \ matchadd(a:lighter.hlgroup, a:lighter.pattern, a:lighter.priority)) 21 | endif 22 | endfunction "}}} 23 | 24 | function! high#match#Clear(lighter) "{{{ 25 | let id = high#match#GetID(a:lighter) 26 | if id >= 0 27 | call matchdelete(id) 28 | call high#match#SetID(a:lighter, -1) 29 | endif 30 | endfunction "}}} 31 | 32 | function! high#match#InitIDs() "{{{ 33 | if !exists('w:high_match_ids') 34 | let w:high_match_ids = {} 35 | endif 36 | endfunction "}}} 37 | 38 | function! high#match#GetID(lighter) "{{{ 39 | if !exists('w:high_match_ids['.a:lighter.__match_id_index.']') 40 | return -1 41 | endif 42 | return w:high_match_ids[a:lighter.__match_id_index] 43 | endfunction "}}} 44 | 45 | function! high#match#SetID(lighter, id) "{{{ 46 | let w:high_match_ids[a:lighter.__match_id_index] = a:id 47 | endfunction "}}} 48 | -------------------------------------------------------------------------------- /plugin/high.vim: -------------------------------------------------------------------------------- 1 | " Highlight anything, create custom highlight in Vim 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | 7 | if exists('g:loaded_high') 8 | finish 9 | endif 10 | let g:loaded_high = 1 11 | 12 | let g:high = { 13 | \ 'registered_groups': {}, 14 | \ 'group_members': {}, 15 | \ 'defaults': { 16 | \ 'enabled': 1, 17 | \ 'whitelist': [], 18 | \ 'blacklist': ['help', 'qf'], 19 | \ 'hlgroup': 'ErrorMsg', 20 | \ 'priority': -1, 21 | \ 'pattern': '', 22 | \ '__group_name': '', 23 | \ '__init_function': '', 24 | \ '__update_function': '', 25 | \ '__auto_highlight': 1, 26 | \ '__match_id_index': -1, 27 | \ }, 28 | \ } 29 | 30 | if exists('g:high_lighters') 31 | if has_key(g:high_lighters, '_') 32 | call extend(g:high.defaults, remove(g:high_lighters, '_')) 33 | endif 34 | for group in keys(g:high_lighters) 35 | call high#group#Register(group) 36 | endfor 37 | endif 38 | 39 | command! -nargs=* -complete=customlist,high#commandline#Completion 40 | \ HighDisable call high#commandline#Toggle(0, ) 41 | command! -nargs=* -complete=customlist,high#commandline#Completion 42 | \ HighEnable call high#commandline#Toggle(1, ) 43 | command! -nargs=* -complete=customlist,high#commandline#Completion 44 | \ HighToggle call high#commandline#Toggle(-1, ) 45 | 46 | augroup high 47 | autocmd! 48 | autocmd WinEnter,BufWinEnter,FileType * 49 | \ for group in values(g:high.registered_groups) 50 | \ | call high#Light(group) 51 | \ | endfor 52 | augroup END 53 | -------------------------------------------------------------------------------- /autoload/high/light/indent.vim: -------------------------------------------------------------------------------- 1 | " Highlight the levels of indentation with different colors 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | " 7 | " Inspired by: 8 | " https://github.com/nathanaelkane/vim-indent-guides 9 | 10 | function! high#light#indent#Define() 11 | return { 12 | \ 'priority': -2, 13 | \ '_levels': 15, 14 | \ '_start_level': 0, 15 | \ '_size': 0, 16 | \ '_hlgroupA': 'PmenuSel', 17 | \ '_hlgroupB': 'CursorLine', 18 | \ '__init_function': function('s:Init'), 19 | \ '__update_function': function('s:Update'), 20 | \ } 21 | endfunction 22 | 23 | function! s:Init(options) "{{{ 24 | for nr in range(a:options._start_level, a:options._levels-1) 25 | call high#group#AddMember(high#utils#Clone(a:options)) 26 | endfor 27 | endfunction "}}} 28 | 29 | function! s:Update(options) "{{{ 30 | if exists('w:high_indent_prev_sw') && (w:high_indent_prev_sw == &shiftwidth) 31 | let w:high_indent_prev_sw = &shiftwidth 32 | return 0 33 | endif 34 | let w:high_indent_prev_sw = &shiftwidth 35 | 36 | let lighters = high#group#GetMembers('indent') 37 | for nr in range(a:options._start_level, a:options._levels-1) 38 | call s:UpdateLighter(lighters[nr], nr) 39 | endfor 40 | return 1 41 | endfunction "}}} 42 | 43 | function! s:UpdateLighter(lighter, nr) "{{{ 44 | let a:lighter.pattern = 45 | \ '\v^( {'.&sw.'}|\t){'.a:nr.'}\zs( {'.(a:lighter._size > 0 ? a:lighter._size : &sw).'}|\t)' 46 | let a:lighter.hlgroup = 47 | \ a:lighter[a:nr%2 ? '_hlgroupB' : '_hlgroupA'] 48 | return a:lighter 49 | endfunction "}}} 50 | -------------------------------------------------------------------------------- /autoload/high/light/words.vim: -------------------------------------------------------------------------------- 1 | " Highlight matching words, highlight word under the cursor 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | " 7 | " Inspired by: 8 | " https://github.com/lfv89/vim-interestingwords 9 | " 10 | " An example setup to get nicer colors: 11 | " 12 | " let g:high_lighters = {'words': {'_hlgroups': []}} 13 | " for color in ['8ccbea', 'a4e57e', 'ffdb72', 'ff7272', 'ffb3ff', '9999ff'] 14 | " exe 'autocmd ColorScheme,VimEnter * 15 | " \ highlight! HighWords'.color.' guibg=#'.color.' guifg=#000000' 16 | " let g:high_lighters.words._hlgroups += ['HighWords'.color] 17 | " endfor 18 | 19 | function! high#light#words#Define() 20 | return { 21 | \ '_hlgroups': ['Pmenu', 'PmenuSel', 'PmenuSbar'], 22 | \ '_map_add': 'k', 23 | \ '_map_clear': 'K', 24 | \ '__auto_highlight': 0, 25 | \ '__init_function': function('s:Init'), 26 | \ } 27 | endfunction 28 | 29 | function! s:Init(options) "{{{ 30 | exe 'nnoremap '.a:options._map_add.' :call high#light#words#AddWord(expand(""))' 31 | exe 'nnoremap '.a:options._map_clear.' :call high#light#words#ClearWords()' 32 | let s:hlgroups_index = 0 33 | endfunction "}}} 34 | 35 | function! high#light#words#AddWord(cword) "{{{ 36 | " TODO: return if group not enabled 37 | let words = high#group#GetSettings('words') 38 | let clone = high#utils#Clone(words) 39 | call high#group#AddMember(clone) 40 | 41 | let clone.pattern = '\<'.a:cword.'\>' 42 | 43 | " Set up the highlight group and switch to the next one. 44 | let clone.hlgroup = words._hlgroups[s:hlgroups_index] 45 | let s:hlgroups_index += 1 46 | if s:hlgroups_index >= len(words._hlgroups) 47 | let s:hlgroups_index = 0 48 | endif 49 | 50 | call high#match#Highlight(clone, 1) 51 | endfunction "}}} 52 | 53 | function! high#light#words#ClearWords() "{{{ 54 | let words = high#group#GetSettings('words') 55 | call high#LightGroup(words, 0) 56 | endfunction "}}} 57 | -------------------------------------------------------------------------------- /test/high.vimspec: -------------------------------------------------------------------------------- 1 | Describe high 2 | Before 3 | call ResetSettings() 4 | 5 | let group = high#group#Register('group', {'pattern': 'regex'}) 6 | End 7 | 8 | Describe #Light 9 | It highlights a registered group 10 | Assert Empty(getmatches()) 11 | call high#Light(group) 12 | let lighter = high#group#GetMembers('group')[0] 13 | Assert LengthOf(getmatches(), 1) 14 | Assert Equals(group.pattern, getmatches()[0].pattern) 15 | End 16 | 17 | It does nothing if the group has to highlight by script 18 | let group.__auto_highlight = 0 19 | Assert Empty(getmatches()) 20 | call high#Light(group) 21 | Assert Empty(getmatches()) 22 | End 23 | End 24 | 25 | Describe #LightGroup 26 | It highlights a registered group if enabled 27 | Assert Empty(getmatches()) 28 | call high#LightGroup(group, 1) 29 | let lighter = high#group#GetMembers('group')[0] 30 | Assert LengthOf(getmatches(), 1) 31 | Assert Equals(group.pattern, getmatches()[0].pattern) 32 | End 33 | 34 | It does nothing if disabled 35 | Assert Empty(getmatches()) 36 | call high#LightGroup(group, 0) 37 | Assert Empty(getmatches()) 38 | End 39 | 40 | It removes the highlight of a disabled, but previously enabled group 41 | Assert Empty(getmatches()) 42 | call high#LightGroup(group, 1) 43 | let lighter = high#group#GetMembers('group')[0] 44 | Assert LengthOf(getmatches(), 1) 45 | Assert Equals(group.pattern, getmatches()[0].pattern) 46 | call high#LightGroup(group, 0) 47 | Assert Empty(getmatches()) 48 | End 49 | End 50 | 51 | Describe #UpdateGroups 52 | It does nothing if the group does not have update function 53 | let group = high#group#Register('group', {'pattern': 'regex'}) 54 | call high#Light(group) 55 | Assert LengthOf(getmatches(), 1) 56 | Assert Equals(getmatches()[0].pattern, 'regex') 57 | call high#UpdateGroups() 58 | Assert LengthOf(getmatches(), 1) 59 | Assert Equals(getmatches()[0].pattern, 'regex') 60 | End 61 | 62 | It updates the highlighting of the group if the update function returns true 63 | let group = high#group#Register('group', { 64 | \ 'pattern': 'regex', 65 | \ '__update_function': function('UpdatePatternIfActivatorNotEmpty'), 66 | \ }) 67 | let g:activator = '' 68 | call high#Light(group) 69 | Assert LengthOf(getmatches(), 1) 70 | Assert Equals(getmatches()[0].pattern, 'regex') 71 | let g:activator = 'foo bar' 72 | call high#UpdateGroups() 73 | Assert LengthOf(getmatches(), 1) 74 | Assert Equals(getmatches()[0].pattern, 'foo bar') 75 | End 76 | End 77 | End 78 | -------------------------------------------------------------------------------- /test/high/match.vimspec: -------------------------------------------------------------------------------- 1 | Describe high#match 2 | Before 3 | call ResetSettings() 4 | 5 | let group = high#group#Register('group', {'pattern': 'regex'}) 6 | call high#group#Init('group') 7 | let lighter = high#group#GetMembers('group')[0] 8 | End 9 | 10 | Describe #Highlight 11 | It adds a match for lighter 12 | Assert Empty(getmatches()) 13 | call high#match#Highlight(lighter, 1) 14 | Assert Equals(len(getmatches()), 1) 15 | Assert Equals(getmatches()[0].id, high#match#GetID(lighter)) 16 | Assert Equals(getmatches()[0].pattern, lighter.pattern) 17 | End 18 | 19 | It removes the match of lighter 20 | Assert Empty(getmatches()) 21 | call high#match#Highlight(lighter, 1) 22 | Assert NotEmpty(getmatches()) 23 | call high#match#Highlight(lighter, 0) 24 | Assert Empty(getmatches()) 25 | Assert Equals(high#match#GetID(lighter), -1) 26 | End 27 | End 28 | 29 | Describe #Add 30 | It highlights the lighter 31 | Assert Empty(getmatches()) 32 | Assert Equals(high#match#GetID(lighter), -1) 33 | call high#match#Add(lighter) 34 | Assert LengthOf(getmatches(), 1) 35 | Assert NotEquals(high#match#GetID(lighter), -1) 36 | Assert Equals(getmatches()[0].id, high#match#GetID(lighter)) 37 | Assert Equals(getmatches()[0].pattern, lighter.pattern) 38 | End 39 | 40 | It does nothing if the lighter is already highlighted 41 | Assert Empty(getmatches()) 42 | call high#match#Add(lighter) 43 | Assert LengthOf(getmatches(), 1) 44 | let id = high#match#GetID(lighter) 45 | call high#match#Add(lighter) 46 | Assert LengthOf(getmatches(), 1) 47 | Assert Equals(high#match#GetID(lighter), id) 48 | End 49 | End 50 | 51 | Describe #Clear 52 | It removes the highlighting of the lighter 53 | Assert Empty(getmatches()) 54 | call high#match#Add(lighter) 55 | Assert NotEquals(high#match#GetID(lighter), -1) 56 | Assert LengthOf(getmatches(), 1) 57 | call high#match#Clear(lighter) 58 | Assert Empty(getmatches()) 59 | Assert Equals(high#match#GetID(lighter), -1) 60 | End 61 | 62 | It does nothing if the highlighting is not exist 63 | Assert Empty(getmatches()) 64 | Assert Equals(high#match#GetID(lighter), -1) 65 | call high#match#Clear(lighter) 66 | Assert Empty(getmatches()) 67 | Assert Equals(high#match#GetID(lighter), -1) 68 | End 69 | End 70 | 71 | Describe #GetID #SetID 72 | It stores the ID of lighter returned by `matchadd()` 73 | Assert Equals(high#match#GetID(lighter), -1) 74 | call high#match#SetID(lighter, 2) 75 | Assert Equals(high#match#GetID(lighter), 2) 76 | End 77 | End 78 | End 79 | -------------------------------------------------------------------------------- /autoload/high/group.vim: -------------------------------------------------------------------------------- 1 | " Group related functions 2 | " 3 | " Author: Bimba Laszlo 4 | " Source: https://github.com/bimlas/vim-high 5 | " License: MIT license 6 | 7 | let s:match_id_index = 0 8 | 9 | function! high#group#Register(group_name, ...) abort "{{{ 10 | if a:0 11 | let new = extend(high#utils#Clone(), a:1) 12 | else 13 | let new = high#group#LoadSettings(a:group_name) 14 | endif 15 | " TODO: if settings not changed, then it's an invalid group name. 16 | " else 17 | " throw '[high] No such group: '.a:group_name 18 | " endif 19 | let new.__group_name = a:group_name 20 | let g:high.registered_groups[a:group_name] = new 21 | " If the group controlls the highlight by self (manual highlight), then 22 | " initialization would never reach. 23 | if !new.__auto_highlight 24 | call high#group#Init(a:group_name) 25 | endif 26 | return new 27 | endfunction "}}} 28 | 29 | function! high#group#LoadSettings(group_name) abort "{{{ 30 | let autoloaded = 1 31 | let user_defined = 1 32 | let settings = high#utils#Clone() 33 | try 34 | call extend(settings, high#light#{a:group_name}#Define()) 35 | catch /.*/ 36 | let autoloaded = 0 37 | endtry 38 | try 39 | call extend(settings, g:high_lighters[a:group_name]) 40 | catch /.*/ 41 | let user_defined = 0 42 | endtry 43 | if !(autoloaded || user_defined) 44 | throw '[high] No such group: '.a:group_name 45 | endif 46 | return settings 47 | endfunction "}}} 48 | 49 | function! high#group#Init(group_name) "{{{ 50 | let settings = high#group#GetSettings(a:group_name) 51 | let g:high.group_members[a:group_name] = [] 52 | if !empty(settings.__init_function) 53 | call call(settings.__init_function, [settings]) 54 | else 55 | call high#group#AddMember(settings) 56 | endif 57 | endfunction "}}} 58 | 59 | function! high#group#AddMember(lighter) "{{{ 60 | let a:lighter.__match_id_index = s:match_id_index 61 | let s:match_id_index += 1 62 | call extend(g:high.group_members[a:lighter.__group_name], [a:lighter]) 63 | endfunction "}}} 64 | 65 | function! high#group#IsRegistered(group_name) "{{{ 66 | return has_key(g:high.registered_groups, a:group_name) 67 | endfunction "}}} 68 | 69 | function! high#group#IsInitialized(group_name) "{{{ 70 | return has_key(g:high.group_members, a:group_name) 71 | endfunction "}}} 72 | 73 | function! high#group#IsEnabled(group_settings) "{{{ 74 | return a:group_settings.enabled && high#group#IsEnabledForFiletype(a:group_settings, &filetype) 75 | endfunction "}}} 76 | 77 | function! high#group#IsEnabledForFiletype(group_settings, filetype) "{{{ 78 | return (empty(a:group_settings.whitelist) || index(a:group_settings.whitelist, a:filetype) >= 0) 79 | \ && (empty(a:group_settings.blacklist) || index(a:group_settings.blacklist, a:filetype) < 0) 80 | endfunction "}}} 81 | 82 | function! high#group#GetSettings(group_name) "{{{ 83 | return get(g:high.registered_groups, a:group_name, {}) 84 | endfunction "}}} 85 | 86 | function! high#group#GetMembers(group_name) "{{{ 87 | return get(g:high.group_members, a:group_name, []) 88 | endfunction "}}} 89 | 90 | function! high#group#HaveToUpdate(group_settings) "{{{ 91 | return empty(a:group_settings.__update_function) 92 | \ ? 0 93 | \ : a:group_settings.__update_function(a:group_settings) 94 | endfunction "}}} 95 | -------------------------------------------------------------------------------- /test/high/group.vimspec: -------------------------------------------------------------------------------- 1 | Describe high#group 2 | Before 3 | call ResetSettings() 4 | End 5 | 6 | Describe #Register 7 | It registers user defined group 8 | let g:high_lighters = {'custom': {'hlgroup': 'Normal'}} 9 | call high#group#Register('custom') 10 | Assert Equals(high#group#GetSettings('custom')['hlgroup'], 'Normal') 11 | End 12 | 13 | It registers autoloaded group 14 | call high#group#Register('mixed_eol') 15 | Assert Equals(high#group#GetSettings('mixed_eol')['pattern'], '\r') 16 | End 17 | 18 | It registers passed settings as a new group 19 | call high#group#Register('passed', {'hlgroup': 'Normal'}) 20 | Assert Equals(high#group#GetSettings('passed')['hlgroup'], 'Normal') 21 | End 22 | 23 | It fails if group settings are not defined at all 24 | Throws /\[high\] No such group: not_exists/ high#group#Register('not_exists') 25 | End 26 | 27 | It applies customization 28 | let g:high_lighters = {'mixed_eol': {'hlgroup': 'Normal'}} 29 | call high#group#Register('mixed_eol') 30 | Assert Equals(high#group#GetSettings('mixed_eol')['hlgroup'], 'Normal') 31 | End 32 | End 33 | 34 | Describe #LoadSettings 35 | It returns the settings of user defined group 36 | let g:high_lighters = {'custom': {'hlgroup': 'Normal'}} 37 | Assert Equals(high#group#LoadSettings('custom')['hlgroup'], 'Normal') 38 | End 39 | 40 | It returns the settings of autoloaded group 41 | call high#group#Register('mixed_eol') 42 | Assert Equals(high#group#LoadSettings('mixed_eol')['pattern'], '\r') 43 | End 44 | 45 | It fails if group settings are not defined at all 46 | Throws /\[high\] No such group: not_exists/ high#group#LoadSettings('not_exists') 47 | End 48 | 49 | It applies customization 50 | let g:high_lighters = {'mixed_eol': {'hlgroup': 'Normal'}} 51 | Assert Equals(high#group#LoadSettings('mixed_eol')['hlgroup'], 'Normal') 52 | End 53 | End 54 | 55 | Describe #Init 56 | It calls the init function of autoloaded groups 57 | call high#group#Register('mixed_eol') 58 | Assert Empty(high#group#GetMembers('mixed_eol')) 59 | call high#group#Init('mixed_eol') 60 | Assert NotEmpty(high#group#GetMembers('mixed_eol')) 61 | End 62 | 63 | It adds a lighter if the group has no init function 64 | call high#group#Register('user_defined', {}) 65 | Assert Empty(high#group#GetMembers('user_defined')) 66 | call high#group#Init('user_defined') 67 | Assert LengthOf(high#group#GetMembers('user_defined'), 1) 68 | End 69 | End 70 | 71 | Describe #AddMember 72 | Before 73 | let group = high#group#Register('group', {}) 74 | call high#group#Init('group') 75 | let lighter = high#utils#Clone(group) 76 | End 77 | 78 | It adds a lighter to the group 79 | Assert LengthOf(high#group#GetMembers('group'), 1) 80 | call high#group#AddMember(lighter) 81 | Assert LengthOf(high#group#GetMembers('group'), 2) 82 | Assert Same(high#group#GetMembers('group')[1], lighter) 83 | End 84 | 85 | It can add more lighters to the same group 86 | Assert LengthOf(high#group#GetMembers('group'), 1) 87 | let a = high#utils#Clone(group) 88 | let a.pattern = 'pattern a' 89 | call high#group#AddMember(a) 90 | let b = high#utils#Clone(group) 91 | let b.pattern = 'pattern b' 92 | call high#group#AddMember(b) 93 | Assert LengthOf(g:high.group_members['group'], 3) 94 | Assert Same(high#group#GetMembers('group')[1], a) 95 | Assert Same(high#group#GetMembers('group')[2], b) 96 | End 97 | End 98 | 99 | Describe #IsRegistered 100 | It checks that group is registered 101 | Assert False(high#group#IsRegistered('group')) 102 | call high#group#Register('group', {}) 103 | Assert True(high#group#IsRegistered('group')) 104 | End 105 | End 106 | 107 | Describe #IsInitialized 108 | It checks that group initialization is done 109 | call high#group#Register('mixed_eol') 110 | Assert False(high#group#IsInitialized('mixed_eol')) 111 | call high#group#Init('mixed_eol') 112 | Assert True(high#group#IsInitialized('mixed_eol')) 113 | End 114 | End 115 | 116 | Describe #IsEnabled 117 | It checks that white/blacklist and the group itself is enabled 118 | let group = high#group#Register('group', {'whitelist': ['typeA'], 'enabled': 1}) 119 | set filetype=typeA 120 | let group.enabled = 1 121 | Assert True(high#group#IsEnabled(group)) 122 | set filetype=typeB 123 | let group.enabled = 1 124 | Assert False(high#group#IsEnabled(group)) 125 | set filetype=typeA 126 | let group.enabled = 0 127 | Assert False(high#group#IsEnabled(group)) 128 | End 129 | End 130 | 131 | Describe #IsEnabledForFiletype 132 | Before 133 | let group = high#group#Register('group', {}) 134 | End 135 | 136 | It enabled for every filetype by default 137 | let group.whitelist = [] 138 | let group.blacklist = [] 139 | Assert Equals(high#group#IsEnabledForFiletype(group, 'text'), 1) 140 | Assert Equals(high#group#IsEnabledForFiletype(group, 'asciidoc'), 1) 141 | End 142 | 143 | It enabled only for whitelisted filetypes 144 | let group.whitelist = ['text'] 145 | let group.blacklist = [] 146 | Assert Equals(high#group#IsEnabledForFiletype(group, 'text'), 1) 147 | Assert Equals(high#group#IsEnabledForFiletype(group, 'asciidoc'), 0) 148 | End 149 | 150 | It disabled only for blacklisted filetypes 151 | let group.whitelist = [] 152 | let group.blacklist = ['text'] 153 | Assert Equals(high#group#IsEnabledForFiletype(group, 'text'), 0) 154 | Assert Equals(high#group#IsEnabledForFiletype(group, 'asciidoc'), 1) 155 | End 156 | 157 | It disabled for both blacklisted and whitelisted filetypes 158 | let group.whitelist = ['text'] 159 | let group.blacklist = ['text'] 160 | Assert Equals(high#group#IsEnabledForFiletype(group, 'text'), 0) 161 | End 162 | End 163 | 164 | Describe #HaveToUpdate 165 | It returns false if the group does not have update function 166 | let group = high#group#Register('group', {}) 167 | Assert False(high#group#HaveToUpdate(group)) 168 | End 169 | 170 | It returns true if the highlighting of the group has to be updated 171 | let group = high#group#Register('group', { 172 | \ 'pattern': 'regex', 173 | \ '__update_function': function('UpdatePatternIfActivatorNotEmpty'), 174 | \ }) 175 | let g:activator = '' 176 | Assert False(high#group#HaveToUpdate(group)) 177 | let g:activator = 'foo bar' 178 | Assert True(high#group#HaveToUpdate(group)) 179 | Assert Equals(group.pattern, 'foo bar') 180 | End 181 | End 182 | End 183 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Vim-High: all-in-one Vim highlighter plugin 2 | 3 | A Vim plugin to highlight custom patterns on any buffer (filetype 4 | whitelist/blacklist supported), for example highlight indentation, inactive 5 | window, word under the cursor or even user made Vim highlighting. 6 | 7 | * https://github.com/bimlas/vim-high (please star if you like it) 8 | 9 | image:https://img.shields.io/travis/bimlas/vim-high/master.svg?label=Travis%20CI["Travis CI", link="https://travis-ci.org/bimlas/vim-high"] 10 | image:https://img.shields.io/github/license/bimlas/vim-high.svg["License", link="LICENSE"] 11 | 12 | [NOTE] 13 | ==== 14 | It's in beta version (API and defaults may change) while I don't get enough 15 | response that everything works as expected. 16 | ==== 17 | 18 | image::https://imgs.xkcd.com/comics/standards.png["Philosophy of the plugin", link="https://xkcd.com/927/"] 19 | 20 | image::http://i.imgur.com/oFgLo29.png["Vim-High in action, showing the example config", width="100%"] 21 | 22 | To try out, install in your preferred way, then enable a lighter by 23 | `:HighEnable `. 24 | 25 | To enable lighters by default, add the preferred ones to `g:high_lighter` as a 26 | dictionary in your _.vimrc_, like this: 27 | 28 | [source,viml] 29 | ---- 30 | let g:high_lighters = { 31 | \ '_': { <1> 32 | \ 'blacklist': ['help', 'qf', 'lf', 'vim-plug'], <2> 33 | \ }, 34 | \ 'inactive_window': {}, <3> 35 | \ 'indent': {'_hlgroupA': 'HighIndentA', '_hlgroupB': 'HighIndentB'}, <4> 36 | \ 'long_line': {'hlgroup': 'DiffAdd'}, 37 | \ 'unite_directory': {}, 38 | \ 'your_custom_lighter': {'pattern': 'TODO\|NOTE', 'hlgroup': 'ErrorMsg'} <5> 39 | \ } 40 | ---- 41 | <1> The `_` key means these settings will affect every lighter, 42 | <2> for example all of them will be disabled in these filetypes. 43 | <3> You can add predefined lighters, whose can be found in 44 | link:autoload/high/light/[] directory. 45 | <4> To override the global settings, pass the lighter-specific ones in the 46 | dictionary. 47 | <5> You can create your own lighters as you want. 48 | 49 | == Override default settings 50 | 51 | By default, every lighter in `g:high_lighters` are enabled at Vim startup, but 52 | passing `'enabled': 0` will disable it. To use the lighter, call `:HighEnable 53 | lighter` or `:HighToggle lighter`. 54 | 55 | The available configuration parameters can be found in link:plugin/high.vim[] 56 | as `g:high.defaults`. Options starting with double underscore 57 | (`__init_function` for example) are private and you shouldn't override those. 58 | See `:help matchadd` for `pattern` and `priority`; `:highlight` for 59 | possible values of `hlgroup`. 60 | 61 | Some lighters have specific settings, starting with an underscore (`_length` 62 | of link:autoload/high/light/long_line.vim[long_line] for example) are 63 | lighter-specific, the underscore is used only to prevent conflicts with global 64 | settings, but you can safely override those. 65 | 66 | Do not fear to view the source files to get the possibilities, because there 67 | is no help file for the plugin, link:autoload/high/light[source codes] and 68 | link:test[test files] contains everything. 69 | 70 | == Custom colors 71 | 72 | To define your own `hlgroup`, take a look at `:help highlight`. Here are the 73 | highlight groups of the example config, place it to your _.vimrc_: 74 | 75 | [source,viml] 76 | ---- 77 | autocmd ColorScheme,VimEnter * 78 | \ highlight! HighIndentA guibg=#002029 guifg=#063642 | 79 | \ highlight! HighIndentB guibg=#003542 guifg=#063642 80 | ---- 81 | 82 | == Dynamic update of highlighters 83 | 84 | Some lighters are based on Vim settings, for example 85 | link:autoload/high/light/indent.vim[indent] uses `shiftwidth` to highlight the 86 | indentation. The highlighting will follow the change of it only on certain 87 | events (jumping to another window, switching buffer, etc.). To apply the new 88 | settings automatically, you have to write an autocommand in your _.vimrc_: 89 | 90 | [source,viml] 91 | ---- 92 | autocmd CursorHold * 93 | \ let pos = winnr() 94 | \ | windo call high#UpdateGroups() 95 | \ | exe pos.'wincmd w' 96 | ---- 97 | 98 | It will update every lighter where the `__update_function` is set. 99 | 100 | == Examples of user-defined highlight in Vim 101 | 102 | For example, a very basic implentation of 103 | https://github.com/Valloric/vim-operator-highlight[Valloric/vim-operator-highlight] 104 | should looks like this: 105 | 106 | [source,viml] 107 | ---- 108 | let g:high_lighters = { 109 | \ 'operator': { <1> 110 | \ 'pattern': '[-?+|*;:,<>&|!~%=)({}.\[\]]', <2> 111 | \ 'blacklist': ['help', 'markdown', 'qf', 'conque_term', 'diff', 'html', <3> 112 | \ 'css', 'less', 'xml', 'sh', 'bash', 'notes', 'jinja'], 113 | \ 'hlgroup': 'Error', <4> 114 | \ }} 115 | ---- 116 | <1> Add a name to the lighter (which is not in use), 117 | <2> define the pattern to match, 118 | <3> add whitelist/blacklist, 119 | <4> choose a hlgroup from the existing ones. 120 | 121 | === Vim Netrw filetype coloring 122 | 123 | The plugin can be used in another plugins, for example if you want to colorize 124 | files by extension in Netrw (`:Explore`, `:edit ./`), then you can do 125 | something like this: 126 | 127 | [source,viml] 128 | ---- 129 | let g:high_lighters = { 130 | \ 'netrw_yaml': { 131 | \ 'whitelist': ['netrw'], 132 | \ 'pattern': '\v^([|│] )*\zs\f+\.yml', 133 | \ 'hlgroup': 'HighNetrwYaml', 134 | \ }, 135 | \ 'netrw_asciidoc': { 136 | \ 'whitelist': ['netrw'], 137 | \ 'pattern': '\v^([|│] )*\zs\f+\.adoc', 138 | \ 'hlgroup': 'HighNetrwAsciidoc', 139 | \ }} 140 | 141 | autocmd ColorScheme,VimEnter * 142 | \ highlight! HighNetrwYaml guifg=#ae9400 | 143 | \ highlight! HighNetrwAsciidoc guifg=#dd3a00 144 | ---- 145 | 146 | Note that `^([|│] )*` part is needed by tree view (most right picture on the 147 | screenshot). 148 | 149 | image::http://i.imgur.com/JkVorP9.png["Vim Netrw filetype coloring"] 150 | 151 | == Plugins that inspired 152 | 153 | |=== 154 | h| Name of lighter h| Original plugin 155 | 156 | | link:autoload/high/light/deep_indent.vim[deep_indent] 157 | | https://github.com/dodie/vim-disapprove-deep-indentation[dodie/vim-disapprove-deep-indentation] 158 | 159 | | link:autoload/high/light/inactive_window.vim[inactive_window] 160 | | https://github.com/blueyed/vim-diminactive[blueyed/vim-diminactive] 161 | 162 | | link:autoload/high/light/indent.vim[indent] 163 | | https://github.com/nathanaelkane/vim-indent-guides[nathanaelkane/vim-indent-guides] 164 | 165 | | link:autoload/high/light/long_line.vim[long_line] 166 | | https://github.com/whatyouhide/vim-lengthmatters[whatyouhide/vim-lengthmatters] 167 | 168 | | link:autoload/high/light/trailing_whitespace.vim[trailing_whitespace] 169 | | https://github.com/ntpeters/vim-better-whitespace[ntpeters/vim-better-whitespace] 170 | 171 | | link:autoload/high/light/words.vim[words] 172 | | https://github.com/lfv89/vim-interestingwords[lfv89/vim-interestingwords] 173 | |=== 174 | --------------------------------------------------------------------------------