]> git.r.bdr.sh - rbdr/dotfiles/blob - vim/plugin/showmarks.vim
Relative line numbers for vim
[rbdr/dotfiles] / vim / plugin / showmarks.vim
1 " ==============================================================================
2 " Name: ShowMarks
3 " Description: Visually displays the location of marks.
4 " Authors: Anthony Kruize <trandor@labyrinth.net.au>
5 " Michael Geddes <michaelrgeddes@optushome.com.au>
6 " Version: 2.2
7 " Modified: 17 August 2004
8 " License: Released into the public domain.
9 " ChangeLog: See :help showmarks-changelog
10 "
11 " Usage: Copy this file into the plugins directory so it will be
12 " automatically sourced.
13 "
14 " Default keymappings are:
15 " <Leader>mt - Toggles ShowMarks on and off.
16 " <Leader>mo - Turns ShowMarks on, and displays marks.
17 " <Leader>mh - Clears a mark.
18 " <Leader>ma - Clears all marks.
19 " <Leader>mm - Places the next available mark.
20 "
21 " Hiding a mark doesn't actually remove it, it simply moves it
22 " to line 1 and hides it visually.
23 "
24 " Configuration: ***********************************************************
25 " * PLEASE read the included help file(showmarks.txt) for a *
26 " * more thorough explanation of how to use ShowMarks. *
27 " ***********************************************************
28 " The following options can be used to customize the behavior
29 " of ShowMarks. Simply include them in your vimrc file with
30 " the desired settings.
31 "
32 " showmarks_enable (Default: 1)
33 " Defines whether ShowMarks is enabled by default.
34 " Example: let g:showmarks_enable=0
35 " showmarks_include (Default: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'`^<>[]{}()\"")
36 " Defines all marks, in precedence order (only the highest
37 " precence will show on lines having more than one mark).
38 " Can be buffer-specific (set b:showmarks_include)
39 " showmarks_ignore_type (Default: "hq")
40 " Defines the buffer types to be ignored.
41 " Valid types are:
42 " h - Help p - preview
43 " q - quickfix r - readonly
44 " m - non-modifiable
45 " showmarks_textlower (Default: ">")
46 " Defines how the mark is to be displayed.
47 " A maximum of two characters can be displayed. To include
48 " the mark in the text use a tab(\t) character. A single
49 " character will display as the mark with the character
50 " suffixed (same as "\t<character>")
51 " Examples:
52 " To display the mark with a > suffixed:
53 " let g:showmarks_textlower="\t>"
54 " or
55 " let g:showmarks_textlower=">"
56 " To display the mark with a ( prefixed:
57 " let g:showmarks_textlower="(\t"
58 " To display two > characters:
59 " let g:showmarks_textlower=">>"
60 " showmarks_textupper (Default: ">")
61 " Same as above but for the marks A-Z.
62 " Example: let g:showmarks_textupper="**"
63 " showmarks_textother (Default: ">")
64 " Same as above but for all other marks.
65 " Example: let g:showmarks_textother="--"
66 " showmarks_hlline_lower (Default: 0)
67 " showmarks_hlline_upper (Default: 0)
68 " showmarks_hlline_other (Default: 0)
69 " Defines whether the entire line for a particular mark
70 " should be highlighted.
71 " Example: let g:showmarks_hlline_lower=1
72 "
73 " Setting Highlighting Colours
74 " ShowMarks uses the following highlighting groups:
75 " ShowMarksHLl - For marks a-z
76 " ShowMarksHLu - For marks A-Z
77 " ShowMarksHLo - For all other marks
78 " ShowMarksHLm - For multiple marks on the same line.
79 " (Highest precendece mark is shown)
80 "
81 " By default they are set to a bold blue on light blue.
82 " Defining a highlight for each of these groups will
83 " override the default highlighting.
84 " See the VIM help for more information about highlighting.
85 " ==============================================================================
86
87 " Check if we should continue loading
88 if exists( "loaded_showmarks" )
89 finish
90 endif
91 let loaded_showmarks = 1
92
93 " Bail if Vim isn't compiled with signs support.
94 if has( "signs" ) == 0
95 echohl ErrorMsg
96 echo "ShowMarks requires Vim to have +signs support."
97 echohl None
98 finish
99 endif
100
101 " Options: Set up some nice defaults
102 if !exists('g:showmarks_enable' ) | let g:showmarks_enable = 1 | endif
103 if !exists('g:showmarks_textlower' ) | let g:showmarks_textlower = ">" | endif
104 if !exists('g:showmarks_textupper' ) | let g:showmarks_textupper = ">" | endif
105 if !exists('g:showmarks_textother' ) | let g:showmarks_textother = ">" | endif
106 if !exists('g:showmarks_ignore_type' ) | let g:showmarks_ignore_type = "hq" | endif
107 if !exists('g:showmarks_ignore_name' ) | let g:showmarks_ignore_name = "" | endif
108 if !exists('g:showmarks_hlline_lower') | let g:showmarks_hlline_lower = "0" | endif
109 if !exists('g:showmarks_hlline_upper') | let g:showmarks_hlline_upper = "0" | endif
110 if !exists('g:showmarks_hlline_other') | let g:showmarks_hlline_other = "0" | endif
111
112 " This is the default, and used in ShowMarksSetup to set up info for any
113 " possible mark (not just those specified in the possibly user-supplied list
114 " of marks to show -- it can be changed on-the-fly).
115 let s:all_marks = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'`^<>[]{}()\""
116
117 " Commands
118 com! -nargs=0 ShowMarksToggle :call <sid>ShowMarksToggle()
119 com! -nargs=0 ShowMarksOn :call <sid>ShowMarksOn()
120 com! -nargs=0 ShowMarksClearMark :call <sid>ShowMarksClearMark()
121 com! -nargs=0 ShowMarksClearAll :call <sid>ShowMarksClearAll()
122 com! -nargs=0 ShowMarksPlaceMark :call <sid>ShowMarksPlaceMark()
123
124 " Mappings (NOTE: Leave the '|'s immediately following the '<cr>' so the mapping does not contain any trailing spaces!)
125 if !hasmapto( '<Plug>ShowmarksShowMarksToggle' ) | map <silent> <unique> <leader>mt :ShowMarksToggle<cr>| endif
126 if !hasmapto( '<Plug>ShowmarksShowMarksOn' ) | map <silent> <unique> <leader>mo :ShowMarksOn<cr>| endif
127 if !hasmapto( '<Plug>ShowmarksClearMark' ) | map <silent> <unique> <leader>mh :ShowMarksClearMark<cr>| endif
128 if !hasmapto( '<Plug>ShowmarksClearAll' ) | map <silent> <unique> <leader>ma :ShowMarksClearAll<cr>| endif
129 if !hasmapto( '<Plug>ShowmarksPlaceMark' ) | map <silent> <unique> <leader>mm :ShowMarksPlaceMark<cr>| endif
130 noremap <unique> <script> \sm m
131 noremap <silent> m :exe 'norm \sm'.nr2char(getchar())<bar>call <sid>ShowMarks()<CR>
132
133 " AutoCommands: Only if ShowMarks is enabled
134 if g:showmarks_enable == 1
135 aug ShowMarks
136 au!
137 autocmd CursorHold * call s:ShowMarks()
138 aug END
139 endif
140
141 " Highlighting: Setup some nice colours to show the mark positions.
142 hi default ShowMarksHLl ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold
143 hi default ShowMarksHLu ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold
144 hi default ShowMarksHLo ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold
145 hi default ShowMarksHLm ctermfg=darkblue ctermbg=blue cterm=bold guifg=blue guibg=lightblue gui=bold
146
147 " Function: IncludeMarks()
148 " Description: This function returns the list of marks (in priority order) to
149 " show in this buffer. Each buffer, if not already set, inherits the global
150 " setting; if the global include marks have not been set; that is set to the
151 " default value.
152 fun! s:IncludeMarks()
153 if exists('b:showmarks_include') && exists('b:showmarks_previous_include') && b:showmarks_include != b:showmarks_previous_include
154 " The user changed the marks to include; hide all marks; change the
155 " included mark list, then show all marks. Prevent infinite
156 " recursion during this switch.
157 if exists('s:use_previous_include')
158 " Recursive call from ShowMarksHideAll()
159 return b:showmarks_previous_include
160 elseif exists('s:use_new_include')
161 " Recursive call from ShowMarks()
162 return b:showmarks_include
163 else
164 let s:use_previous_include = 1
165 call <sid>ShowMarksHideAll()
166 unlet s:use_previous_include
167 let s:use_new_include = 1
168 call <sid>ShowMarks()
169 unlet s:use_new_include
170 endif
171 endif
172
173 if !exists('g:showmarks_include')
174 let g:showmarks_include = s:all_marks
175 endif
176 if !exists('b:showmarks_include')
177 let b:showmarks_include = g:showmarks_include
178 endif
179
180 " Save this include setting so we can detect if it was changed.
181 let b:showmarks_previous_include = b:showmarks_include
182
183 return b:showmarks_include
184 endf
185
186 " Function: NameOfMark()
187 " Paramaters: mark - Specifies the mark to find the name of.
188 " Description: Convert marks that cannot be used as part of a variable name to
189 " something that can be. i.e. We cannot use [ as a variable-name suffix (as
190 " in 'placed_['; this function will return something like 63, so the variable
191 " will be something like 'placed_63').
192 " 10 is added to the mark's index to avoid colliding with the numeric marks
193 " 0-9 (since a non-word mark could be listed in showmarks_include in the
194 " first 10 characters if the user overrides the default).
195 " Returns: The name of the requested mark.
196 fun! s:NameOfMark(mark)
197 let name = a:mark
198 if a:mark =~# '\W'
199 let name = stridx(s:all_marks, a:mark) + 10
200 endif
201 return name
202 endf
203
204 " Function: VerifyText()
205 " Paramaters: which - Specifies the variable to verify.
206 " Description: Verify the validity of a showmarks_text{upper,lower,other} setup variable.
207 " Default to ">" if it is found to be invalid.
208 fun! s:VerifyText(which)
209 if strlen(g:showmarks_text{a:which}) == 0 || strlen(g:showmarks_text{a:which}) > 2
210 echohl ErrorMsg
211 echo "ShowMarks: text".a:which." must contain only 1 or 2 characters."
212 echohl None
213 let g:showmarks_text{a:which}=">"
214 endif
215 endf
216
217 " Function: ShowMarksSetup()
218 " Description: This function sets up the sign definitions for each mark.
219 " It uses the showmarks_textlower, showmarks_textupper and showmarks_textother
220 " variables to determine how to draw the mark.
221 fun! s:ShowMarksSetup()
222 " Make sure the textlower, textupper, and textother options are valid.
223 call s:VerifyText('lower')
224 call s:VerifyText('upper')
225 call s:VerifyText('other')
226
227 let n = 0
228 let s:maxmarks = strlen(s:all_marks)
229 while n < s:maxmarks
230 let c = strpart(s:all_marks, n, 1)
231 let nm = s:NameOfMark(c)
232 let text = '>'.c
233 let lhltext = ''
234 if c =~# '[a-z]'
235 if strlen(g:showmarks_textlower) == 1
236 let text=c.g:showmarks_textlower
237 elseif strlen(g:showmarks_textlower) == 2
238 let t1 = strpart(g:showmarks_textlower,0,1)
239 let t2 = strpart(g:showmarks_textlower,1,1)
240 if t1 == "\t"
241 let text=c.t2
242 elseif t2 == "\t"
243 let text=t1.c
244 else
245 let text=g:showmarks_textlower
246 endif
247 endif
248 let s:ShowMarksDLink{nm} = 'ShowMarksHLl'
249 if g:showmarks_hlline_lower == 1
250 let lhltext = 'linehl='.s:ShowMarksDLink{nm}.nm
251 endif
252 elseif c =~# '[A-Z]'
253 if strlen(g:showmarks_textupper) == 1
254 let text=c.g:showmarks_textupper
255 elseif strlen(g:showmarks_textupper) == 2
256 let t1 = strpart(g:showmarks_textupper,0,1)
257 let t2 = strpart(g:showmarks_textupper,1,1)
258 if t1 == "\t"
259 let text=c.t2
260 elseif t2 == "\t"
261 let text=t1.c
262 else
263 let text=g:showmarks_textupper
264 endif
265 endif
266 let s:ShowMarksDLink{nm} = 'ShowMarksHLu'
267 if g:showmarks_hlline_upper == 1
268 let lhltext = 'linehl='.s:ShowMarksDLink{nm}.nm
269 endif
270 else " Other signs, like ', ., etc.
271 if strlen(g:showmarks_textother) == 1
272 let text=c.g:showmarks_textother
273 elseif strlen(g:showmarks_textother) == 2
274 let t1 = strpart(g:showmarks_textother,0,1)
275 let t2 = strpart(g:showmarks_textother,1,1)
276 if t1 == "\t"
277 let text=c.t2
278 elseif t2 == "\t"
279 let text=t1.c
280 else
281 let text=g:showmarks_textother
282 endif
283 endif
284 let s:ShowMarksDLink{nm} = 'ShowMarksHLo'
285 if g:showmarks_hlline_other == 1
286 let lhltext = 'linehl='.s:ShowMarksDLink{nm}.nm
287 endif
288 endif
289
290 " Define the sign with a unique highlight which will be linked when placed.
291 exe 'sign define ShowMark'.nm.' '.lhltext.' text='.text.' texthl='.s:ShowMarksDLink{nm}.nm
292 let b:ShowMarksLink{nm} = ''
293 let n = n + 1
294 endw
295 endf
296
297 " Set things up
298 call s:ShowMarksSetup()
299
300 " Function: ShowMarksOn
301 " Description: Enable showmarks, and show them now.
302 fun! s:ShowMarksOn()
303 if g:showmarks_enable == 0
304 call <sid>ShowMarksToggle()
305 else
306 call <sid>ShowMarks()
307 endif
308 endf
309
310 " Function: ShowMarksToggle()
311 " Description: This function toggles whether marks are displayed or not.
312 fun! s:ShowMarksToggle()
313 if g:showmarks_enable == 0
314 let g:showmarks_enable = 1
315 call <sid>ShowMarks()
316 aug ShowMarks
317 au!
318 autocmd CursorHold * call s:ShowMarks()
319 aug END
320 else
321 let g:showmarks_enable = 0
322 call <sid>ShowMarksHideAll()
323 aug ShowMarks
324 au!
325 autocmd BufEnter * call s:ShowMarksHideAll()
326 aug END
327 endif
328 endf
329
330 " Function: ShowMarks()
331 " Description: This function runs through all the marks and displays or
332 " removes signs as appropriate. It is called on the CursorHold autocommand.
333 " We use the marked_{ln} variables (containing a timestamp) to track what marks
334 " we've shown (placed) in this call to ShowMarks; to only actually place the
335 " first mark on any particular line -- this forces only the first mark
336 " (according to the order of showmarks_include) to be shown (i.e., letters
337 " take precedence over marks like paragraph and sentence.)
338 fun! s:ShowMarks()
339 if g:showmarks_enable == 0
340 return
341 endif
342
343 if ((match(g:showmarks_ignore_type, "[Hh]") > -1) && (&buftype == "help" ))
344 \ || ((match(g:showmarks_ignore_type, "[Qq]") > -1) && (&buftype == "quickfix"))
345 \ || ((match(g:showmarks_ignore_type, "[Pp]") > -1) && (&pvw == 1 ))
346 \ || ((match(g:showmarks_ignore_type, "[Rr]") > -1) && (&readonly == 1 ))
347 \ || ((match(g:showmarks_ignore_type, "[Mm]") > -1) && (&modifiable == 0 ))
348 return
349 endif
350
351 let n = 0
352 let s:maxmarks = strlen(s:IncludeMarks())
353 while n < s:maxmarks
354 let c = strpart(s:IncludeMarks(), n, 1)
355 let nm = s:NameOfMark(c)
356 let id = n + (s:maxmarks * winbufnr(0))
357 let ln = line("'".c)
358
359 if ln == 0 && (exists('b:placed_'.nm) && b:placed_{nm} != ln)
360 exe 'sign unplace '.id.' buffer='.winbufnr(0)
361 elseif ln > 1 || c !~ '[a-zA-Z]'
362 " Have we already placed a mark here in this call to ShowMarks?
363 if exists('mark_at'.ln)
364 " Already placed a mark, set the highlight to multiple
365 if c =~# '[a-zA-Z]' && b:ShowMarksLink{mark_at{ln}} != 'ShowMarksHLm'
366 let b:ShowMarksLink{mark_at{ln}} = 'ShowMarksHLm'
367 exe 'hi link '.s:ShowMarksDLink{mark_at{ln}}.mark_at{ln}.' '.b:ShowMarksLink{mark_at{ln}}
368 endif
369 else
370 if !exists('b:ShowMarksLink'.nm) || b:ShowMarksLink{nm} != s:ShowMarksDLink{nm}
371 let b:ShowMarksLink{nm} = s:ShowMarksDLink{nm}
372 exe 'hi link '.s:ShowMarksDLink{nm}.nm.' '.b:ShowMarksLink{nm}
373 endif
374 let mark_at{ln} = nm
375 if !exists('b:placed_'.nm) || b:placed_{nm} != ln
376 exe 'sign unplace '.id.' buffer='.winbufnr(0)
377 exe 'sign place '.id.' name=ShowMark'.nm.' line='.ln.' buffer='.winbufnr(0)
378 let b:placed_{nm} = ln
379 endif
380 endif
381 endif
382 let n = n + 1
383 endw
384 endf
385
386 " Function: ShowMarksClearMark()
387 " Description: This function hides the mark at the current line.
388 " It simply moves the mark to line 1 and removes the sign.
389 " Only marks a-z and A-Z are supported.
390 fun! s:ShowMarksClearMark()
391 let ln = line(".")
392 let n = 0
393 let s:maxmarks = strlen(s:IncludeMarks())
394 while n < s:maxmarks
395 let c = strpart(s:IncludeMarks(), n, 1)
396 if c =~# '[a-zA-Z]' && ln == line("'".c)
397 let nm = s:NameOfMark(c)
398 let id = n + (s:maxmarks * winbufnr(0))
399 exe 'sign unplace '.id.' buffer='.winbufnr(0)
400 exe '1 mark '.c
401 let b:placed_{nm} = 1
402 endif
403 let n = n + 1
404 endw
405 endf
406
407 " Function: ShowMarksClearAll()
408 " Description: This function clears all marks in the buffer.
409 " It simply moves the marks to line 1 and removes the signs.
410 " Only marks a-z and A-Z are supported.
411 fun! s:ShowMarksClearAll()
412 let n = 0
413 let s:maxmarks = strlen(s:IncludeMarks())
414 while n < s:maxmarks
415 let c = strpart(s:IncludeMarks(), n, 1)
416 if c =~# '[a-zA-Z]'
417 let nm = s:NameOfMark(c)
418 let id = n + (s:maxmarks * winbufnr(0))
419 exe 'sign unplace '.id.' buffer='.winbufnr(0)
420 exe '1 mark '.c
421 let b:placed_{nm} = 1
422 endif
423 let n = n + 1
424 endw
425 endf
426
427 " Function: ShowMarksHideAll()
428 " Description: This function hides all marks in the buffer.
429 " It simply removes the signs.
430 fun! s:ShowMarksHideAll()
431 let n = 0
432 let s:maxmarks = strlen(s:IncludeMarks())
433 while n < s:maxmarks
434 let c = strpart(s:IncludeMarks(), n, 1)
435 let nm = s:NameOfMark(c)
436 if exists('b:placed_'.nm)
437 let id = n + (s:maxmarks * winbufnr(0))
438 exe 'sign unplace '.id.' buffer='.winbufnr(0)
439 unlet b:placed_{nm}
440 endif
441 let n = n + 1
442 endw
443 endf
444
445 " Function: ShowMarksPlaceMark()
446 " Description: This function will place the next unplaced mark (in priority
447 " order) to the current location. The idea here is to automate the placement
448 " of marks so the user doesn't have to remember which marks are placed or not.
449 " Hidden marks are considered to be unplaced.
450 " Only marks a-z are supported.
451 fun! s:ShowMarksPlaceMark()
452 " Find the first, next, and last [a-z] mark in showmarks_include (i.e.
453 " priority order), so we know where to "wrap".
454 let first_alpha_mark = -1
455 let last_alpha_mark = -1
456 let next_mark = -1
457
458 if !exists('b:previous_auto_mark')
459 let b:previous_auto_mark = -1
460 endif
461
462 " Find the next unused [a-z] mark (in priority order); if they're all
463 " used, find the next one after the previously auto-assigned mark.
464 let n = 0
465 let s:maxmarks = strlen(s:IncludeMarks())
466 while n < s:maxmarks
467 let c = strpart(s:IncludeMarks(), n, 1)
468 if c =~# '[a-z]'
469 if line("'".c) <= 1
470 " Found an unused [a-z] mark; we're done.
471 let next_mark = n
472 break
473 endif
474
475 if first_alpha_mark < 0
476 let first_alpha_mark = n
477 endif
478 let last_alpha_mark = n
479 if n > b:previous_auto_mark && next_mark == -1
480 let next_mark = n
481 endif
482 endif
483 let n = n + 1
484 endw
485
486 if next_mark == -1 && (b:previous_auto_mark == -1 || b:previous_auto_mark == last_alpha_mark)
487 " Didn't find an unused mark, and haven't placed any auto-chosen marks yet,
488 " or the previously placed auto-chosen mark was the last alpha mark --
489 " use the first alpha mark this time.
490 let next_mark = first_alpha_mark
491 endif
492
493 if (next_mark == -1)
494 echohl WarningMsg
495 echo 'No marks in [a-z] included! (No "next mark" to choose from)'
496 echohl None
497 return
498 endif
499
500 let c = strpart(s:IncludeMarks(), next_mark, 1)
501 let b:previous_auto_mark = next_mark
502 exe 'mark '.c
503 call <sid>ShowMarks()
504 endf
505
506 " -----------------------------------------------------------------------------
507 " vim:ts=4:sw=4:noet