-
Notifications
You must be signed in to change notification settings - Fork 0
/
showmarks.vim
509 lines (474 loc) · 18.9 KB
/
showmarks.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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
" ==============================================================================
" Name: ShowMarks
" Description: Visually displays the location of marks.
" Authors: Anthony Kruize <[email protected]>
" B
" Michael Geddes <[email protected]>
" Version: 2.2
" Modified: 17 August 2004
" License: Released into the public domain.
" ChangeLog: See :help showmarks-changelog
"
" Usage: Copy this file into the plugins directory so it will be
" automatically sourced.
"
" Default keymappings are:
" <Leader>mt - Toggles ShowMarks on and off.
" <Leader>mo - Turns ShowMarks on, and displays marks.
" <Leader>mh - Clears a mark.
" <Leader>ma - Clears all marks.
" <Leader>mm - Places the next available mark.
"
" Hiding a mark doesn't actually remove it, it simply moves it
" to line 1 and hides it visually.
"
" Configuration: ***********************************************************
" * PLEASE read the included help file(showmarks.txt) for a *
" * more thorough explanation of how to use ShowMarks. *
" ***********************************************************
" The following options can be used to customize the behavior
" of ShowMarks. Simply include them in your vimrc file with
" the desired settings.
"
" showmarks_enable (Default: 1)
" Defines whether ShowMarks is enabled by default.
" Example: let g:showmarks_enable=0
" showmarks_include (Default: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'`^<>[]{}()\"")
" Defines all marks, in precedence order (only the highest
" precence will show on lines having more than one mark).
" Can be buffer-specific (set b:showmarks_include)
" showmarks_ignore_type (Default: "hq")
" Defines the buffer types to be ignored.
" Valid types are:
" h - Help p - preview
" q - quickfix r - readonly
" m - non-modifiable
" showmarks_textlower (Default: ">")
" Defines how the mark is to be displayed.
" A maximum of two characters can be displayed. To include
" the mark in the text use a tab(\t) character. A single
" character will display as the mark with the character
" suffixed (same as "\t<character>")
" Examples:
" To display the mark with a > suffixed:
" let g:showmarks_textlower="\t>"
" or
" let g:showmarks_textlower=">"
" To display the mark with a ( prefixed:
" let g:showmarks_textlower="(\t"
" To display two > characters:
" let g:showmarks_textlower=">>"
" showmarks_textupper (Default: ">")
" Same as above but for the marks A-Z.
" Example: let g:showmarks_textupper="**"
" showmarks_textother (Default: ">")
" Same as above but for all other marks.
" Example: let g:showmarks_textother="--"
" showmarks_hlline_lower (Default: 0)
" showmarks_hlline_upper (Default: 0)
" showmarks_hlline_other (Default: 0)
" Defines whether the entire line for a particular mark
" should be highlighted.
" Example: let g:showmarks_hlline_lower=1
"
" Setting Highlighting Colours
" ShowMarks uses the following highlighting groups:
" ShowMarksHLl - For marks a-z
" ShowMarksHLu - For marks A-Z
" ShowMarksHLo - For all other marks
" ShowMarksHLm - For multiple marks on the same line.
" (Highest precendece mark is shown)
"
" By default they are set to a bold blue on light blue.
" Defining a highlight for each of these groups will
" override the default highlighting.
" See the VIM help for more information about highlighting.
" ==============================================================================
let g:showmarks_enable=0
" Check if we should continue loading
if exists( "loaded_showmarks" )
finish
endif
let loaded_showmarks = 1
" Bail if Vim isn't compiled with signs support.
if has( "signs" ) == 0
echohl ErrorMsg
echo "ShowMarks requires Vim to have +signs support."
echohl None
finish
endif
" Options: Set up some nice defaults
if !exists('g:showmarks_enable' ) | let g:showmarks_enable = 1 | endif
if !exists('g:showmarks_textlower' ) | let g:showmarks_textlower = ">" | endif
if !exists('g:showmarks_textupper' ) | let g:showmarks_textupper = ">" | endif
if !exists('g:showmarks_textother' ) | let g:showmarks_textother = ">" | endif
if !exists('g:showmarks_ignore_type' ) | let g:showmarks_ignore_type = "hq" | endif
if !exists('g:showmarks_ignore_name' ) | let g:showmarks_ignore_name = "" | endif
if !exists('g:showmarks_hlline_lower') | let g:showmarks_hlline_lower = "0" | endif
if !exists('g:showmarks_hlline_upper') | let g:showmarks_hlline_upper = "0" | endif
if !exists('g:showmarks_hlline_other') | let g:showmarks_hlline_other = "0" | endif
" This is the default, and used in ShowMarksSetup to set up info for any
" possible mark (not just those specified in the possibly user-supplied list
" of marks to show -- it can be changed on-the-fly).
let s:all_marks = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'`^<>[]{}()\""
" Commands
com! -nargs=0 ShowMarksToggle :call <sid>ShowMarksToggle()
com! -nargs=0 ShowMarksOn :call <sid>ShowMarksOn()
com! -nargs=0 ShowMarksClearMark :call <sid>ShowMarksClearMark()
com! -nargs=0 ShowMarksClearAll :call <sid>ShowMarksClearAll()
com! -nargs=0 ShowMarksPlaceMark :call <sid>ShowMarksPlaceMark()
" Mappings (NOTE: Leave the '|'s immediately following the '<cr>' so the mapping does not contain any trailing spaces!)
if !hasmapto( '<Plug>ShowmarksShowMarksToggle' ) | map <silent> <unique> <leader>mt :ShowMarksToggle<cr>| endif
if !hasmapto( '<Plug>ShowmarksShowMarksOn' ) | map <silent> <unique> <leader>mo :ShowMarksOn<cr>| endif
if !hasmapto( '<Plug>ShowmarksClearMark' ) | map <silent> <unique> <leader>mh :ShowMarksClearMark<cr>| endif
if !hasmapto( '<Plug>ShowmarksClearAll' ) | map <silent> <unique> <leader>ma :ShowMarksClearAll<cr>| endif
if !hasmapto( '<Plug>ShowmarksPlaceMark' ) | map <silent> <unique> <leader>mm :ShowMarksPlaceMark<cr>| endif
noremap <unique> <script> \sm m
noremap <silent> m :exe 'norm \sm'.nr2char(getchar())<bar>call <sid>ShowMarks()<CR>
" AutoCommands: Only if ShowMarks is enabled
if g:showmarks_enable == 1
aug ShowMarks
au!
autocmd CursorHold * call s:ShowMarks()
aug END
endif
" Highlighting: Setup some nice colours to show the mark positions.
hi default ShowMarksHLl ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold
hi default ShowMarksHLu ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold
hi default ShowMarksHLo ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold
hi default ShowMarksHLm ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold
" Function: IncludeMarks()
" Description: This function returns the list of marks (in priority order) to
" show in this buffer. Each buffer, if not already set, inherits the global
" setting; if the global include marks have not been set; that is set to the
" default value.
fun! s:IncludeMarks()
if exists('b:showmarks_include') && exists('b:showmarks_previous_include') && b:showmarks_include != b:showmarks_previous_include
" The user changed the marks to include; hide all marks; change the
" included mark list, then show all marks. Prevent infinite
" recursion during this switch.
if exists('s:use_previous_include')
" Recursive call from ShowMarksHideAll()
return b:showmarks_previous_include
elseif exists('s:use_new_include')
" Recursive call from ShowMarks()
return b:showmarks_include
else
let s:use_previous_include = 1
call <sid>ShowMarksHideAll()
unlet s:use_previous_include
let s:use_new_include = 1
call <sid>ShowMarks()
unlet s:use_new_include
endif
endif
if !exists('g:showmarks_include')
let g:showmarks_include = s:all_marks
endif
if !exists('b:showmarks_include')
let b:showmarks_include = g:showmarks_include
endif
" Save this include setting so we can detect if it was changed.
let b:showmarks_previous_include = b:showmarks_include
return b:showmarks_include
endf
" Function: NameOfMark()
" Paramaters: mark - Specifies the mark to find the name of.
" Description: Convert marks that cannot be used as part of a variable name to
" something that can be. i.e. We cannot use [ as a variable-name suffix (as
" in 'placed_['; this function will return something like 63, so the variable
" will be something like 'placed_63').
" 10 is added to the mark's index to avoid colliding with the numeric marks
" 0-9 (since a non-word mark could be listed in showmarks_include in the
" first 10 characters if the user overrides the default).
" Returns: The name of the requested mark.
fun! s:NameOfMark(mark)
let name = a:mark
if a:mark =~# '\W'
let name = stridx(s:all_marks, a:mark) + 10
endif
return name
endf
" Function: VerifyText()
" Paramaters: which - Specifies the variable to verify.
" Description: Verify the validity of a showmarks_text{upper,lower,other} setup variable.
" Default to ">" if it is found to be invalid.
fun! s:VerifyText(which)
if strlen(g:showmarks_text{a:which}) == 0 || strlen(g:showmarks_text{a:which}) > 2
echohl ErrorMsg
echo "ShowMarks: text".a:which." must contain only 1 or 2 characters."
echohl None
let g:showmarks_text{a:which}=">"
endif
endf
" Function: ShowMarksSetup()
" Description: This function sets up the sign definitions for each mark.
" It uses the showmarks_textlower, showmarks_textupper and showmarks_textother
" variables to determine how to draw the mark.
fun! s:ShowMarksSetup()
" Make sure the textlower, textupper, and textother options are valid.
call s:VerifyText('lower')
call s:VerifyText('upper')
call s:VerifyText('other')
let n = 0
let s:maxmarks = strlen(s:all_marks)
while n < s:maxmarks
let c = strpart(s:all_marks, n, 1)
let nm = s:NameOfMark(c)
let text = '>'.c
let lhltext = ''
if c =~# '[a-z]'
if strlen(g:showmarks_textlower) == 1
let text=c.g:showmarks_textlower
elseif strlen(g:showmarks_textlower) == 2
let t1 = strpart(g:showmarks_textlower,0,1)
let t2 = strpart(g:showmarks_textlower,1,1)
if t1 == "\t"
let text=c.t2
elseif t2 == "\t"
let text=t1.c
else
let text=g:showmarks_textlower
endif
endif
let s:ShowMarksDLink{nm} = 'ShowMarksHLl'
if g:showmarks_hlline_lower == 1
let lhltext = 'linehl='.s:ShowMarksDLink{nm}.nm
endif
elseif c =~# '[A-Z]'
if strlen(g:showmarks_textupper) == 1
let text=c.g:showmarks_textupper
elseif strlen(g:showmarks_textupper) == 2
let t1 = strpart(g:showmarks_textupper,0,1)
let t2 = strpart(g:showmarks_textupper,1,1)
if t1 == "\t"
let text=c.t2
elseif t2 == "\t"
let text=t1.c
else
let text=g:showmarks_textupper
endif
endif
let s:ShowMarksDLink{nm} = 'ShowMarksHLu'
if g:showmarks_hlline_upper == 1
let lhltext = 'linehl='.s:ShowMarksDLink{nm}.nm
endif
else " Other signs, like ', ., etc.
if strlen(g:showmarks_textother) == 1
let text=c.g:showmarks_textother
elseif strlen(g:showmarks_textother) == 2
let t1 = strpart(g:showmarks_textother,0,1)
let t2 = strpart(g:showmarks_textother,1,1)
if t1 == "\t"
let text=c.t2
elseif t2 == "\t"
let text=t1.c
else
let text=g:showmarks_textother
endif
endif
let s:ShowMarksDLink{nm} = 'ShowMarksHLo'
if g:showmarks_hlline_other == 1
let lhltext = 'linehl='.s:ShowMarksDLink{nm}.nm
endif
endif
" Define the sign with a unique highlight which will be linked when placed.
exe 'sign define ShowMark'.nm.' '.lhltext.' text='.text.' texthl='.s:ShowMarksDLink{nm}.nm
let b:ShowMarksLink{nm} = ''
let n = n + 1
endw
endf
" Set things up
call s:ShowMarksSetup()
" Function: ShowMarksOn
" Description: Enable showmarks, and show them now.
fun! s:ShowMarksOn()
if g:showmarks_enable == 0
call <sid>ShowMarksToggle()
else
call <sid>ShowMarks()
endif
endf
" Function: ShowMarksToggle()
" Description: This function toggles whether marks are displayed or not.
fun! s:ShowMarksToggle()
if g:showmarks_enable == 0
let g:showmarks_enable = 1
call <sid>ShowMarks()
aug ShowMarks
au!
autocmd CursorHold * call s:ShowMarks()
aug END
else
let g:showmarks_enable = 0
call <sid>ShowMarksHideAll()
aug ShowMarks
au!
autocmd BufEnter * call s:ShowMarksHideAll()
aug END
endif
endf
" Function: ShowMarks()
" Description: This function runs through all the marks and displays or
" removes signs as appropriate. It is called on the CursorHold autocommand.
" We use the marked_{ln} variables (containing a timestamp) to track what marks
" we've shown (placed) in this call to ShowMarks; to only actually place the
" first mark on any particular line -- this forces only the first mark
" (according to the order of showmarks_include) to be shown (i.e., letters
" take precedence over marks like paragraph and sentence.)
fun! s:ShowMarks()
if g:showmarks_enable == 0
return
endif
if ((match(g:showmarks_ignore_type, "[Hh]") > -1) && (&buftype == "help" ))
\ || ((match(g:showmarks_ignore_type, "[Qq]") > -1) && (&buftype == "quickfix"))
\ || ((match(g:showmarks_ignore_type, "[Pp]") > -1) && (&pvw == 1 ))
\ || ((match(g:showmarks_ignore_type, "[Rr]") > -1) && (&readonly == 1 ))
\ || ((match(g:showmarks_ignore_type, "[Mm]") > -1) && (&modifiable == 0 ))
return
endif
let n = 0
let s:maxmarks = strlen(s:IncludeMarks())
while n < s:maxmarks
let c = strpart(s:IncludeMarks(), n, 1)
let nm = s:NameOfMark(c)
let id = n + (s:maxmarks * winbufnr(0))
let ln = line("'".c)
if ln == 0 && (exists('b:placed_'.nm) && b:placed_{nm} != ln)
exe 'sign unplace '.id.' buffer='.winbufnr(0)
elseif ln > 1 || c !~ '[a-zA-Z]'
" Have we already placed a mark here in this call to ShowMarks?
if exists('mark_at'.ln)
" Already placed a mark, set the highlight to multiple
if c =~# '[a-zA-Z]' && b:ShowMarksLink{mark_at{ln}} != 'ShowMarksHLm'
let b:ShowMarksLink{mark_at{ln}} = 'ShowMarksHLm'
exe 'hi link '.s:ShowMarksDLink{mark_at{ln}}.mark_at{ln}.' '.b:ShowMarksLink{mark_at{ln}}
endif
else
if !exists('b:ShowMarksLink'.nm) || b:ShowMarksLink{nm} != s:ShowMarksDLink{nm}
let b:ShowMarksLink{nm} = s:ShowMarksDLink{nm}
exe 'hi link '.s:ShowMarksDLink{nm}.nm.' '.b:ShowMarksLink{nm}
endif
let mark_at{ln} = nm
if !exists('b:placed_'.nm) || b:placed_{nm} != ln
exe 'sign unplace '.id.' buffer='.winbufnr(0)
exe 'sign place '.id.' name=ShowMark'.nm.' line='.ln.' buffer='.winbufnr(0)
let b:placed_{nm} = ln
endif
endif
endif
let n = n + 1
endw
endf
" Function: ShowMarksClearMark()
" Description: This function hides the mark at the current line.
" It simply moves the mark to line 1 and removes the sign.
" Only marks a-z and A-Z are supported.
fun! s:ShowMarksClearMark()
let ln = line(".")
let n = 0
let s:maxmarks = strlen(s:IncludeMarks())
while n < s:maxmarks
let c = strpart(s:IncludeMarks(), n, 1)
if c =~# '[a-zA-Z]' && ln == line("'".c)
let nm = s:NameOfMark(c)
let id = n + (s:maxmarks * winbufnr(0))
exe 'sign unplace '.id.' buffer='.winbufnr(0)
exe '1 mark '.c
let b:placed_{nm} = 1
endif
let n = n + 1
endw
endf
" Function: ShowMarksClearAll()
" Description: This function clears all marks in the buffer.
" It simply moves the marks to line 1 and removes the signs.
" Only marks a-z and A-Z are supported.
fun! s:ShowMarksClearAll()
let n = 0
let s:maxmarks = strlen(s:IncludeMarks())
while n < s:maxmarks
let c = strpart(s:IncludeMarks(), n, 1)
if c =~# '[a-zA-Z]'
let nm = s:NameOfMark(c)
let id = n + (s:maxmarks * winbufnr(0))
exe 'sign unplace '.id.' buffer='.winbufnr(0)
exe '1 mark '.c
let b:placed_{nm} = 1
endif
let n = n + 1
endw
endf
" Function: ShowMarksHideAll()
" Description: This function hides all marks in the buffer.
" It simply removes the signs.
fun! s:ShowMarksHideAll()
let n = 0
let s:maxmarks = strlen(s:IncludeMarks())
while n < s:maxmarks
let c = strpart(s:IncludeMarks(), n, 1)
let nm = s:NameOfMark(c)
if exists('b:placed_'.nm)
let id = n + (s:maxmarks * winbufnr(0))
exe 'sign unplace '.id.' buffer='.winbufnr(0)
unlet b:placed_{nm}
endif
let n = n + 1
endw
endf
" Function: ShowMarksPlaceMark()
" Description: This function will place the next unplaced mark (in priority
" order) to the current location. The idea here is to automate the placement
" of marks so the user doesn't have to remember which marks are placed or not.
" Hidden marks are considered to be unplaced.
" Only marks a-z are supported.
fun! s:ShowMarksPlaceMark()
" Find the first, next, and last [a-z] mark in showmarks_include (i.e.
" priority order), so we know where to "wrap".
let first_alpha_mark = -1
let last_alpha_mark = -1
let next_mark = -1
if !exists('b:previous_auto_mark')
let b:previous_auto_mark = -1
endif
" Find the next unused [a-z] mark (in priority order); if they're all
" used, find the next one after the previously auto-assigned mark.
let n = 0
let s:maxmarks = strlen(s:IncludeMarks())
while n < s:maxmarks
let c = strpart(s:IncludeMarks(), n, 1)
if c =~# '[a-z]'
if line("'".c) <= 1
" Found an unused [a-z] mark; we're done.
let next_mark = n
break
endif
if first_alpha_mark < 0
let first_alpha_mark = n
endif
let last_alpha_mark = n
if n > b:previous_auto_mark && next_mark == -1
let next_mark = n
endif
endif
let n = n + 1
endw
if next_mark == -1 && (b:previous_auto_mark == -1 || b:previous_auto_mark == last_alpha_mark)
" Didn't find an unused mark, and haven't placed any auto-chosen marks yet,
" or the previously placed auto-chosen mark was the last alpha mark --
" use the first alpha mark this time.
let next_mark = first_alpha_mark
endif
if (next_mark == -1)
echohl WarningMsg
echo 'No marks in [a-z] included! (No "next mark" to choose from)'
echohl None
return
endif
let c = strpart(s:IncludeMarks(), next_mark, 1)
let b:previous_auto_mark = next_mark
exe 'mark '.c
call <sid>ShowMarks()
endf
" -----------------------------------------------------------------------------
" vim:ts=4:sw=4:noet