-
Notifications
You must be signed in to change notification settings - Fork 0
/
highlights.vim
303 lines (288 loc) · 9.41 KB
/
highlights.vim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
" Plugin to highlight multiple words in different colors.
" Version 2008-11-19 from http://vim.wikia.com/wiki/VimTip1572
" File highlights.csv (in same directory as script) defines the highlights.
"
" Type '\m' to toggle mapping of keypad on/off (assuming \ leader).
" Type '\f' to find the next match; '\F' to find backwards.
" Can also type '\n' or '\N' for search; then n or N will find next.
" On the numeric keypad, press:
" 1 to highlight visually selected text or current word
" using highlight group hl1 (defined below)
" 2 for highlight hl2, 3 for highlight hl3, etc
" (can press 1 to 9 on keypad for highlights hl1 to hl9)
" 0 to remove highlight from current word
" - to remove all highlights in current window
" + to restore highlights cleared with '-' in current window
" * to restore highlights (possibly from another window)
" Can press 1 or 2 on main keyboard before keypad 1..9 for more highlights.
" Commands:
" ':Highlight' list all highlights.
" ':Highlight [n [pattern]]' set highlight.
" ':Hsample' display all highlights in a scratch buffer.
" ':Hclear [hlnum|pattern|*]' clear highlights.
" ':Hsave x', ':Hrestore x' save/restore highlights (x any name).
" Saving current highlights requires '!' in 'viminfo' option.
if v:version < 702 || exists('loaded_highlightmultiple') || &cp
finish
endif
let loaded_highlightmultiple = 1
" On first call, read file highlights.csv in same directory as script.
" For example, line "5,white,blue,black,green" executes:
" highlight hl5 ctermfg=white ctermbg=blue guifg=black guibg=green
let s:data_file = expand('<sfile>:p:r').'.csv'
let s:loaded_data = 0
function! LoadHighlights()
if !s:loaded_data
if filereadable(s:data_file)
let names = ['hl', 'ctermfg=', 'ctermbg=', 'guifg=', 'guibg=']
for line in readfile(s:data_file)
let fields = split(line, ',', 1)
if len(fields) == 5 && fields[0] =~ '^\d\+$'
let cmd = range(5)
call map(cmd, 'names[v:val].fields[v:val]')
call filter(cmd, 'v:val!~''=$''')
execute 'silent highlight '.join(cmd)
endif
endfor
let s:loaded_data = 1
endif
if !s:loaded_data
echo 'Error: Could not read highlight data from '.s:data_file
endif
endif
endfunction
" Return last visually selected text or '\<cword\>'.
" what = 1 (selection), or 2 (cword), or 0 (guess if 1 or 2 is wanted).
function! s:Pattern(what)
if a:what == 2 || (a:what == 0 && histget(':', -1) =~# '^H')
let result = expand("<cword>")
if !empty(result)
let result = '\<'.result.'\>'
endif
else
let old_reg = getreg('"')
let old_regtype = getregtype('"')
normal! gvy
let result = substitute(escape(@@, '\.*$^~['), '\_s\+', '\\_s\\+', 'g')
normal! gV
call setreg('"', old_reg, old_regtype)
endif
return result
endfunction
" Remove any highlighting for hlnum then highlight pattern (if not empty).
" If pat is numeric, use current word or visual selection and
" increase hlnum by count*10 (if count [1..9] is given).
function! s:DoHighlight(hlnum, pat, decade)
call LoadHighlights()
let hltotal = a:hlnum
if 0 < a:decade && a:decade < 10
let hltotal += a:decade * 10
endif
if type(a:pat) == type(0)
let pattern = s:Pattern(a:pat)
else
let pattern = a:pat
endif
let id = hltotal + 100
silent! call matchdelete(id)
if !empty(pattern)
try
call matchadd('hl'.hltotal, pattern, -1, id)
catch /E28:/
echo 'Highlight hl'.hltotal.' is not defined'
endtry
endif
endfunction
" Remove all matches for pattern.
function! s:UndoHighlight(pat)
if type(a:pat) == type(0)
let pattern = s:Pattern(a:pat)
else
let pattern = a:pat
endif
for m in getmatches()
if m.pattern ==# pattern
call matchdelete(m.id)
endif
endfor
endfunction
" Return pattern to search for next match, and do search.
function! s:Search(backward)
let patterns = []
for m in getmatches()
call add(patterns, m.pattern)
endfor
if empty(patterns)
let pat = ''
else
let pat = join(patterns, '\|')
call search(pat, a:backward ? 'b' : '')
endif
return pat
endfunction
" Enable or disable mappings and any current matches.
function! s:MatchToggle()
if exists('g:match_maps') && g:match_maps
let g:match_maps = 0
for i in range(0, 9)
execute 'unmap <k'.i.'>'
endfor
nunmap <kMinus>
nunmap <kPlus>
nunmap <kMultiply>
nunmap <Leader>f
nunmap <Leader>F
nunmap <Leader>n
nunmap <Leader>N
else
let g:match_maps = 1
for i in range(1, 9)
execute 'vnoremap <silent> <k'.i.'> :<C-U>call <SID>DoHighlight('.i.', 1, v:count)<CR>'
execute 'nnoremap <silent> <k'.i.'> :<C-U>call <SID>DoHighlight('.i.', 2, v:count)<CR>'
endfor
vnoremap <silent> <k0> :<C-U>call <SID>UndoHighlight(1)<CR>
nnoremap <silent> <k0> :<C-U>call <SID>UndoHighlight(2)<CR>
nnoremap <silent> <kMinus> :call <SID>WindowMatches(0)<CR>
nnoremap <silent> <kPlus> :call <SID>WindowMatches(1)<CR>
nnoremap <silent> <kMultiply> :call <SID>WindowMatches(2)<CR>
nnoremap <silent> <Leader>f :call <SID>Search(0)<CR>
nnoremap <silent> <Leader>F :call <SID>Search(1)<CR>
nnoremap <silent> <Leader>n :let @/=<SID>Search(0)<CR>
nnoremap <silent> <Leader>N :let @/=<SID>Search(1)<CR>
endif
call s:WindowMatches(g:match_maps)
echo 'Mappings for matching:' g:match_maps ? 'ON' : 'off'
endfunction
nnoremap <silent> <Leader>m :call <SID>MatchToggle()<CR>
" Remove and save current matches, or restore them.
function! s:WindowMatches(action)
call LoadHighlights()
if a:action == 1
if exists('w:last_matches')
call setmatches(w:last_matches)
endif
elseif a:action == 2
if exists('g:last_matches')
call setmatches(g:last_matches)
else
call s:Hrestore('')
endif
else
let m = getmatches()
if !empty(m)
let w:last_matches = m
let g:last_matches = m
call s:Hsave('')
call clearmatches()
endif
endif
endfunction
" Return name of global variable to save value ('' if invalid).
function! s:NameForSave(name)
if a:name =~# '^\w*$'
return 'HI_SAVE_'.toupper(a:name)
endif
echo 'Error: Invalid name "'.a:name.'"'
return ''
endfunction
" Return custom completion string (match patterns).
function! s:MatchPatterns(A, L, P)
return join(sort(map(getmatches(), 'v:val.pattern')), "\n")
endfunction
" Return custom completion string (saved highlight names).
function! s:SavedNames(A, L, P)
let l = filter(keys(g:), 'v:val =~# ''^HI_SAVE_\w''')
return tolower(join(sort(map(l, 'strpart(v:val, 8)')), "\n"))
endfunction
" Save current highlighting in a global variable.
function! s:Hsave(name)
let sname = s:NameForSave(a:name)
if !empty(sname)
let l = getmatches()
call map(l, 'join([v:val.group, v:val.pattern, v:val.priority, v:val.id], "\t")')
let g:{sname} = join(l, "\n")
endif
endfunction
command! -nargs=? -complete=custom,s:SavedNames Hsave call s:Hsave('<args>')
" Restore current highlighting from a global variable.
function! s:Hrestore(name)
call LoadHighlights()
let sname = s:NameForSave(a:name)
if !empty(sname)
if exists('g:{sname}')
let matches = []
for l in split(g:{sname}, "\n")
let f = split(l, "\t", 1)
call add(matches, {'group':f[0], 'pattern':f[1], 'priority':f[2], 'id':f[3]})
endfor
call setmatches(matches)
else
echo 'No such global variable: '.sname
endif
endif
endfunction
command! -nargs=? -complete=custom,s:SavedNames Hrestore call s:Hrestore('<args>')
" Clear a match, or clear all current matches. Example args:
" '14' = hl14, '*' = all, '' = visual selection or cword,
" 'pattern' = all matches for pattern
function! s:Hclear(pattern) range
if empty(a:pattern)
call s:UndoHighlight(0)
elseif a:pattern == '*'
call s:WindowMatches(0)
elseif a:pattern =~ '^[1-9][0-9]\?$'
call s:DoHighlight(str2nr(a:pattern), '', 0)
else
call s:UndoHighlight(a:pattern)
endif
endfunction
command! -nargs=* -complete=custom,s:MatchPatterns -range Hclear call s:Hclear('<args>')
" Create a scratch buffer with sample text, and apply all highlighting.
function! s:Hsample()
call LoadHighlights()
new
setlocal buftype=nofile bufhidden=hide noswapfile
let lines = []
let items = []
for hl in filter(range(1, 99), 'v:val % 10 > 0')
if hlexists('hl'.hl)
let sample = printf('Sample%2d', hl)
call s:DoHighlight(hl, sample, 0)
else
let sample = ' '
endif
call add(items, sample)
if len(items) >= 3
call insert(lines, substitute(join(items), '\s\+$', '', ''))
let items = []
endif
endfor
call append(0, filter(lines, 'len(v:val) > 0'))
$d
%s/\d3$/&\r/e
endfunction
command! Hsample call s:Hsample()
" Set a match, or display all current matches. Example args:
" '14' = set hl14 for visual selection or cword,
" '14 pattern' = set hl14 for pattern, '' = display all
function! s:Highlight(args) range
if empty(a:args)
echo 'Highlight groups and patterns:'
for m in getmatches()
echo m.group m.pattern
endfor
return
endif
let l = matchlist(a:args, '^\s*\([1-9][0-9]\?\)\%($\|\s\+\(.*\)\)')
if len(l) >= 3
let hlnum = str2nr(l[1])
let pattern = l[2]
if empty(pattern)
let pattern = s:Pattern(0)
endif
call s:DoHighlight(hlnum, pattern, 0)
return
endif
echo 'Error: First argument must be highlight number 1..99'
endfunction
command! -nargs=* -range Highlight call s:Highlight('<args>')