06f749b23b715c47cd6346432a3f8611d9cefe28
[profile.git] / .vimrc
1 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
2 " Multi-version vimrc compatible with version 4 and above.   vim:set fdm=marker:
3 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
4
5 " Note that "if <condition> | call Something() | endif" syntax is unsupported 
6 " in Vim 4 so we write all our functions out the long way.  It does work in 
7 " autocommand definitions, however.
8
9 " Vim 4 complains if version isn't set in the configuration file.
10 version 4.0
11
12 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
13 " Handle options safe to use in version 4.  Vim 4 parses but ignores the 
14 " "if version" syntax used later in this file so we don't use it.  No attempt 
15 " is made to make this configuration compatible with Vim 3.
16 " Some of these settings should strictly be wrapped inside "if has()" blocks
17 " but that would cause them not to be ignored by Vim 4.
18 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
19 "{{{1
20 " No compatibility mode.
21 se nocp
22
23 " Tabstop 2.
24 se ts=2
25 " And use spaces not tabs.
26 se expandtab
27 " And << and >> indent by 2.
28 se sw=2
29 " Backspace deletes full tab width at the start of a line.
30 se smarttab
31
32 " Allow backspace to delete before start of line.
33 se bs=2
34
35 " Don't jump to the start of the line when using H, L etc.
36 se nosol
37
38 " Show the ruler.
39 se ruler
40 " Show partial commands in the ruler.
41 se showcmd
42 " And always show the status line.
43 se laststatus=2
44
45 " Use C indent style.
46 se cindent
47 se cinkeys=0{,0},0),:,!^F,o,O,e
48 se cinoptions=b1,c2
49
50 " GUI options.
51 se go=aglmr
52
53 " Don't be bugged by messages at the bottom of the screen.
54 se shm=aot
55
56 " Find as you type.
57 se incsearch
58
59 " Case-insensitive search.
60 se ignorecase
61 " But override by typing capitals.
62 se smartcase
63
64 " Look for ctags in home directory first.
65 se tags=~/.tags,./tags,tags
66
67 " Don't timeout waiting to interpet, eg, <ESC>OA as an escape code.
68 se ttimeoutlen=100
69
70 " Use ^B to search backward when completing.
71 inoremap <C-b> <C-p>
72 " Use ^L to show matching completions but don't select one.
73 inoremap <C-l> <C-n><C-p>
74
75 " Swap jump keys.
76 noremap ' `
77 noremap ` '
78 "}}}1
79
80 " Find stuff.
81 if (has("win32") || has("win64")) && version >= "504"
82   se rtp=~/.vim,$VIMRUNTIME
83 endif
84
85 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
86 " Handle options only available in Vim 5 and above.
87 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
88 if version >= "500" "{{{1
89 version 5.0
90
91 " Tell Vim we use dark backgrounds in our terminals.
92 if ! has("gui_running")
93   se bg=dark
94 endif
95
96 " Allow mouse use in a terminal but only if it can work.
97 if has("xterm_clipboard")
98   se mouse=nvir
99 endif
100
101 " Update more quickly.  For use with sign highlighting as polling for
102 " CursorMove makes redrawing slow.
103 if has("signs")
104   se updatetime=500
105 endif
106
107 " Enable tab-completion prompting for commands.
108 if has("wildmenu")
109   se wildmenu
110   " Don't list object files when globbing files to load.
111   se wildignore+=*.o,*.obj
112   " So there's no need to assign them low priority.
113   se suffixes-=*.o,*.obj
114 endif
115
116 " Save sessions in UNIX format with / as file separator.  This is
117 " cross-platform.
118 if has("mksession")
119   se ssop+=unix,slash
120 endif
121
122 " How often do we need to use ^A/^X on octals?
123 se nf=hex
124
125 " Nuke any pre-existing autocommands.
126 if has("autocmd")
127   augroup Display
128   autocmd!
129   augroup Mode
130   autocmd!
131   if has("signs")
132     augroup Signs
133     autocmd!
134   endif
135   augroup StatusLine
136   autocmd!
137   augroup File
138   autocmd!
139   augroup END
140 endif
141
142 " Save the current window dimensions so we can restore them when we quit.
143 if ! exists("g:oldcols")
144   let g:oldcols=&columns
145 endif
146 if ! exists("g:oldlines")
147   let g:oldlines=&lines
148 endif
149
150 " More GUI options.  Add icon and tearoffs.
151 if has("gui")
152   se go+=i
153   se go+=t
154 endif
155
156 " Allow dynamic window resize even if we aren't in an xterm.
157 se t_WS=\e[8;%p1%d;%p2%dt
158
159 " Highlight search results.
160 if has("extra_search")
161   se hlsearch
162 endif
163
164 " Syntax highlighting.  New versions will use syn enable instead.
165 if version < "600"
166   syn on
167 endif
168
169 if has("user_commands")
170   " Catch typos.
171   command! W :w
172   command! Wq :wq
173   command! Wqa :wqa
174 endif
175
176 " Forget the Ex mode mapping.
177 map Q <NOP>
178
179 if has("autocmd")
180   " Position the compview plugin window.
181   au Display BufEnter -SearchResults- set buftype=nowrite | set nonumber | wincmd J
182 endif
183 endif "}}}1
184
185 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
186 " Handle options only available in Vim 5.2 and above.
187 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
188 if version >= "502" "{{{1
189 version 5.2
190
191 " Helper to initialise a variable.
192 fun! Prep_Var(var, value) "{{{2
193   if exists(a:var)
194     return
195   endif
196   exe "let " . a:var . "=" . a:value
197 endfun "}}}2
198
199 " Set up our variables.
200 fun! Iain_Vars() "{{{2
201   call Prep_Var("w:iainlist", 0)
202   call Prep_Var("b:iainhex", 0)
203   call Prep_Var("b:iainverbose", 0)
204   " Window Flags: (F)ocused, (I)nsert mode, Cursor (H)old.
205   call Prep_Var("b:iainstatus", "'Fih'")
206   call Prep_Var("g:iainextracolumnsnumber", "''")
207   call Prep_Var("g:iainextracolumnslist", "''")
208   call Prep_Var("b:iaincul", 0)
209   call Prep_Var("b:iainalt", 0)
210   if has("signs")
211     call Prep_Var("g:marksigns", 0)
212     call Prep_Var("g:firstsign", 100)
213   endif
214   call Prep_Var("g:resizable", "''")
215 endfun "}}}2
216
217 " Show the window title.
218 fun! Show_TitleString() "{{{2
219   if bufname("") == ""
220     let l:ts1='Vim'
221   else
222     " Vim 5 doesn't have printf.
223     let l:ts1=bufnr("")
224     if l:ts1 < 10
225       let l:ts1=" " . l:ts1
226     endif
227     let l:ts1=l:ts1 . ": " . expand('%t')
228   endif
229   let l:ts1=l:ts1 . " (" .  getcwd() . ")"
230   if has("clientserver")
231     let l:ts1=l:ts1 . " " . v:servername
232   endif
233   return l:ts1
234 endfun "}}}2
235
236 " Toggle case-sensitivity.
237 fun! Invert_Case() "{{{2
238   let &ic = ! &ic
239 endfun "}}}2
240
241 " Can we resize this window?
242 fun! Can_Resize() "{{{2
243   call Iain_Vars()
244
245   if g:resizable == "0" || g:resizable == "1"
246     return g:resizable
247   endif
248
249   " Do we KNOW we can(not) resize?
250   if has("gui_running")
251     let g:resizable = 1
252   elseif $RESIZABLE == &term
253     let g:resizable = 1
254   elseif $RESIZABLE == "0"
255     let g:resizable = 0
256   else
257     " Assume we can.  Allow overriding.
258     let g:resizable = 1
259   endif
260   return g:resizable
261 endfun "}}}2
262
263 " Grow or shrink the window width.
264 fun! Resize_Columns(op, ...) "{{{2
265   if a:op == ""
266     return
267   endif
268
269   if ! Can_Resize()
270     return
271   endif
272
273   if a:0 == 0
274     " Vim 5 hardcodes the size of numbers column to 8.
275     if version >= "700" && has("linebreak")
276       let l:columns = &numberwidth
277     else
278       let l:columns = 8
279     endif
280   else
281     let l:columns = a:1
282   endif
283
284   exe "let l:resize=" . &columns . a:op . l:columns
285   let l:resize = "se columns=" . l:resize
286
287   " HACK: Inside screen there is an extra line for the status bar.  Vim
288   " manages the resize by sending an escape sequence to set the number of
289   " lines and number of columns in one action.  To do this it will first query
290   " the number of lines and then set <same number of lines> by <new number of
291   " columns>.  Because of the extra line for the status bar this results in
292   " the real terminal being shrunk by a line.  We ask for the terminal to grow
293   " by a line so it ends up actually being the same.
294   if &term =~ '^screen'
295     let l:resize = l:resize . " lines=" . (&lines + 1)
296   endif
297
298   exe l:resize
299 endfun "}}}2
300
301 " Grow or shrink the window height.
302 fun! Resize_Lines(op, lines) "{{{2
303   if a:op == ""
304     return
305   endif
306
307   if ! Can_Resize()
308     return
309   endif
310
311   exe "let l:resize=" . &lines . a:op . a:lines
312   if &term =~ '^screen'
313     let l:resize = l:resize + 1
314   endif
315   let l:resize = "se lines=" . l:resize
316
317   exe l:resize
318 endfun "}}}2
319
320 " Set extra columns depending on window status.
321 fun! Extra_Columns(extra, var, ...) "{{{2
322   " Vim 6 doesn't have winnr("$").  Determine which windows are open
323   " ourselves by using :windo to incremement a counter.  As Vim 5 
324   " doesn't have :windo we require Vim 6 for this.
325   if v:version < "600"
326     return ""
327   endif
328   if ! has("windows")
329     return ""
330   endif
331
332   " Remember which window we're in.
333   let l:winnr = winnr()
334   let l:num_windows = 0
335   windo let l:num_windows = l:num_windows + 1
336   " Switch back to the window we were in.
337   exe l:winnr . "wincmd w"
338
339   call Iain_Vars()
340
341   if a:0 == 0
342     let l:condition = ""
343   else
344     let l:condition = a:1
345   endif
346
347   let l:n = 0
348   let l:i = 1
349   let l:windows = ""
350   while l:n < l:num_windows
351     " If window w exists then getwinvar(w, "&modified") will be 0 or 1.
352     if getwinvar(l:i, "&modified") =~ '^\d'
353       let l:n = l:n + 1
354
355       let l:val = 0
356       exe "if getwinvar(" . l:i . ", '" . a:var . "') " . l:condition . " | let l:val = 1 | endif"
357       if l:val
358         exe "let l:windows = '" . l:windows . ":" . l:i . "'"
359       endif
360     endif
361     let l:i = l:i + 1
362   endwhile
363
364   let l:extra = "g:iainextracolumns" . a:extra
365   exe "let l:val = " . l:extra
366   exe "let " . l:extra . " = '" . l:windows . "'"
367
368   if l:windows == l:val
369     return ""
370   endif
371
372   if l:windows == ""
373     return "-"
374   elseif l:val == ""
375     return "+"
376   endif
377 endfun "}}}2
378
379 " Toggle number display.
380 fun! Number(resize) "{{{2
381   call Iain_Vars()
382   let &number = ! &number
383
384   " Ensure we keep track of any extra columns even if we aren't resizing.
385   " This prevents confusion when number is set at startup.
386   let l:extra = Extra_Columns("number", "&number")
387
388   if a:resize
389     call Resize_Columns(l:extra)
390   endif
391 endfun "}}}2
392
393 " Restore window size.
394 if has("autocmd") && ! has("gui_running")
395   au Display VimLeave * if exists("g:oldcols") | call Resize_Columns("-", (&columns - g:oldcols)) | endif
396   au Display VimLeave * if exists("g:oldlines") | call Resize_Lines("-", (&lines - g:oldlines)) | endif
397 endif
398
399 " Map Makefile mode.
400 if has("autocmd")
401   au Mode BufEnter * if &ft == "make" | call MakeMode_map() | endif
402   au Mode BufLeave * if &ft == "make" | call MakeMode_unmap() | endif
403 endif
404
405 " Entering Make mode.
406 fun! MakeMode_map() "{{{2
407   call Iain_Vars()
408   let w:iainlist=1
409   call Cycle_List()
410   set ts=8
411   set noexpandtab
412 endfun "}}}2
413
414 " Leaving Make mode.
415 fun! MakeMode_unmap() "{{{2
416   call Cycle_List()
417   set ts=2
418   set expandtab
419 endfun "}}}2
420
421 " Function to create mappings with either a hardcoded \ or <Leader>.
422 fun! Mapping(keysequence,mapping) "{{{2
423   if version < "600"
424     exec "map \\" . a:keysequence . " " . a:mapping
425   else
426     exec "map <Leader>" . a:keysequence . " " . a:mapping
427   endif
428 endfun "}}}2
429
430 " Use - and = to create underlines.
431 call Mapping("-", "yyp:s/./-/g<RETURN>:let @/=''<RETURN>:<RETURN>")
432 call Mapping("=", "yyp:s/./=/g<RETURN>:let @/=''<RETURN>:<RETURN>")
433
434 " Change to ts=2 with \2.
435 call Mapping("2", ":se ts=2<CR>:<CR>")
436 " Change to ts=4 with \4.
437 call Mapping("4", ":se ts=4<CR>:<CR>")
438 " Change to ts=8 with \8.
439 call Mapping("8", ":se ts=8<CR>:<CR>")
440 " Change to ts=16 with \6.
441 call Mapping("6", ":se ts=16<CR>:<CR>")
442 " Change to ts=32 with \3.
443 call Mapping("3", ":se ts=32<CR>:<CR>")
444 " Toggle paste mode with \p.
445 call Mapping("p", ":se paste!<CR>:<CR>")
446 " Swap case-sensitivity with \c.
447 call Mapping("C", ":call Invert_Case()<CR>:<CR>")
448 " Change number mode with \n.
449 call Mapping("n", ":call Number(1)<CR>:<CR>")
450 " Expand or shrink window size with \> and \<.
451 call Mapping(">", ":call Resize_Columns('+')<CR>:<CR>")
452 call Mapping("<", ":call Resize_Columns('-')<CR>:<CR>")
453 " Clear search pattern with \/.
454 call Mapping("/", ":let @/=\"\"<CR>:<CR>")
455 " Toggle alternate buffer name with \#.
456 call Mapping("#", ":call Cycle_Alt()<CR>:<CR>")
457
458 " Set graphical window title.
459 if has("win32") || has("win64")
460   " Windows taskbar entries are probably too small to show full titles.
461   se titlestring=%t
462 else
463   se titlestring=%{Show_TitleString()}
464 endif
465
466 " Vim tip 99: What's the highlighting group under the cursor?
467 call Mapping("h", ":echo \"hi<\" . synIDattr(synID(line(\".\"),col(\".\"),1),\"name\") . '> trans<' . synIDattr(synID(line(\".\"),col(\".\"),0),\"name\") . \"> lo<\" . synIDattr(synIDtrans(synID(line(\".\"),col(\".\"),1)),\"name\") . \">\"<CR>")
468
469 fun! Uncluttered_Buffer() "{{{2
470   if exists("uncluttered_buffer")
471     if uncluttered_buffer == 1
472       return 1
473     endif
474   endif
475
476   if version >= "600"
477     if &buftype != ''
478       return 1
479     endif
480   endif
481
482   if &ft == 'perforce'
483     return 1
484   endif
485
486   if &ft == 'svn'
487     return 1
488   endif
489
490   if &ft == 'gitcommit'
491     return 1
492   endif
493
494   return 0
495 endfun "}}}2
496
497 fun! Startup_Resize() "{{{2
498   let l:columns = 0
499
500   " Resize for numbers.
501   if &number
502     if version >= "700" && has("linebreak")
503       let l:columns = &numberwidth
504     else
505       let l:columns = 8
506     endif
507   endif
508
509   " Resize for signs.
510   if has("signs")
511     if g:marksigns
512       if version >= "600"
513         let l:columns = l:columns + 2
514       endif
515     endif
516   endif
517
518   if g:oldcols < (80 + l:columns)
519     call Resize_Columns("+", l:columns)
520   endif
521 endfun "}}}2
522
523 " Change status bar colour when various things happen.
524 " Flags: H/h: Cursor held/moved.
525 "        F/f: Focus gained/lost.
526 "        I/i: Insert mode entered/left.
527 fun! Highlight_StatusLine(flag) "{{{2
528   if ! has("statusline")
529     return
530   endif
531   " Get current status.
532   call Iain_Vars()
533
534   " Change the status based on the flag.  XXX: Does Vim let us to do flags?
535   let l:ic = &ic
536   set ic
537   let b:iainstatus = substitute(b:iainstatus, a:flag, a:flag, "")
538   let &ic = l:ic
539
540   let l:normalcolour = "darkblue"
541   let l:editingcolour = "darkmagenta"
542   let l:warningcolour = "darkred"
543   let l:readonlycolour = "red"
544
545   " Default colour.
546   let l:colour = l:normalcolour
547   " Maybe override depending on status.
548   if b:iainstatus =~# "H"
549     if b:iainstatus =~# "I"
550       " Held in insert mode.  Add extra highlight if we don't have focus.
551       if b:iainstatus =~# "f"
552         let l:colour = l:warningcolour
553       else
554         let l:colour = l:editingcolour
555       endif
556     endif
557   else
558     if b:iainstatus =~# "I"
559       " Regular insert mode.
560       let l:colour = l:editingcolour
561     endif
562   endif
563
564   " Override again if readonly.
565   if l:colour != l:normalcolour
566     if getbufvar("", "&ro")
567       let l:colour = l:readonlycolour
568     endif
569   endif
570
571   let l:termcolour = Iain_Colour(l:colour)
572
573   exec "highlight StatusLine gui=none term=none cterm=none guifg=white guibg=" . l:colour . " ctermfg=white ctermbg=" . l:termcolour
574   exec "highlight User1 gui=bold term=bold cterm=bold guifg=white guibg=" . l:colour . " ctermfg=white ctermbg=" . l:termcolour
575 endfun "}}}2
576
577 fun! Iain_Colour(colour) "{{{2
578   if &t_Co == 88
579     if a:colour == "darkblue"
580       return 17
581     elseif a:colour == "darkmagenta"
582       return 33
583     elseif a:colour == "darkred"
584       return 32
585     elseif a:colour == "red"
586       return 64
587     endif
588   elseif &t_Co == 256
589     if a:colour == "darkblue"
590       return 17
591     elseif a:colour == "darkmagenta"
592       return 90
593     elseif a:colour == "darkred"
594       return 88
595     elseif a:colour == "red"
596       return 196
597     endif
598   else
599     return a:colour
600   endif
601 endfun "}}}2
602
603 if has("autocmd")
604   au StatusLine VimEnter * call Highlight_StatusLine("")
605
606   " Show numbers by default.
607   au Display VimEnter * if ! Uncluttered_Buffer() | call Number(0) | endif
608 endif
609 endif "}}}1
610
611 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
612 " Handle options only available in Vim 5.4 and above.
613 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
614 if version >= "504" "{{{1
615 version 5.4
616
617 " Helper for status line.
618 " Show space, underscore or dollar sign depending on list mode.
619 fun! Show_List() "{{{2
620   call Iain_Vars()
621   if w:iainlist == 0
622     " No list.
623     return " "
624   elseif <SID>Has_Unicode()
625     if w:iainlist == 1
626       " Just tabs.
627       return "»"
628     else
629       " Full list.
630       return "¶"
631     endif
632   else
633     if w:iainlist == 1
634       return "_"
635     else
636       return "\$"
637     endif
638   endif
639 endfun "}}}2
640
641 " Helper for status line.
642 " Show c or C to denote case-sensitivity.
643 fun! Show_Case() "{{{2
644   if &ic
645     return "c"
646   else
647     return "C"
648   endif
649 endfun "}}}2
650
651 " Helper for status line.
652 " Show the size of the tabstop.
653 fun! Show_Tabstop() "{{{2
654   return &ts
655 endfun "}}}2
656
657 " Helper for status line.
658 " Show p when paste mode is on.
659 fun! Show_Paste() "{{{2
660   if &paste
661     return "p"
662   else
663     return ""
664   endif
665 endfun "}}}2
666
667 " Helper for status line.
668 " Show U when persistent undo is on.
669 " Show u when persistent undo is off but an undofile exists.
670 fun! Show_Undo() "{{{2
671   if ! exists("&undofile")
672     return ""
673   endif
674
675   if &undofile
676     return "U"
677   elseif filereadable(undofile(expand("%")))
678     return "u"
679   else
680     return ""
681   endif
682 endfun "}}}2
683
684 " Helper for status line.
685 " Show alternate buffer number and name.
686 fun! Show_Alt() "{{{2
687   let l:alt = bufnr("#")
688   if l:alt < 0 || l:alt == bufnr("") || ! b:iainalt
689     return ""
690   endif
691
692   return " " . l:alt . ": " . expand("#:t")
693 endfun "}}}2
694
695 " Show the status line.
696 fun! Show_StatusLine() "{{{2
697   if ! has("statusline")
698     return
699   endif
700   call Iain_Vars()
701   let l:sl1='%2n\:\ %<%1*%f%0*\ [%{Show_List()}%{Show_Case()}%{Show_Tabstop()}%{Show_Paste()}%{Show_Undo()}%Y%M%R]%{Show_Alt()}\ '
702   let l:sl3='L:%1*%4.6l%0*/%-4.6L\ C:%1*%3.6c%0*\ \|\ %P'
703   let l:hexformat='%b'
704   if b:iainhex
705     let l:hexformat='0\x%02B'
706   endif
707   if b:iainverbose
708     let l:sl1=l:sl1 . v:version . '\ %='
709     let l:sl2=l:hexformat . '\ \|\ P:%4.6o\ '
710   else
711     let l:sl1=l:sl1 . '%='
712     let l:sl2=''
713   endif
714   exec "set statusline=" . l:sl1 . l:sl2 . l:sl3
715 endfun "}}}2
716
717 " Show the status line for the first time.
718 call Show_StatusLine()
719 endif "}}}1
720
721 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
722 " Handle options only available in Vim 6 and above.
723 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
724 if version >= "600" "{{{1
725 version 6.0
726
727 if has("gui_win32")
728   se encoding=utf-8
729 endif
730
731 " Remember quickfix state.
732 if has("quickfix")
733   let g:quickfixing=0
734 endif
735
736 " Set indenting by filetype.
737 filetype indent on
738
739 " Less intrusive syntax highlighting.
740 if has("syntax")
741   syn enable
742 endif
743
744 " Set colours.
745 if has("gui_running")
746   if has("win32") || has("win64")
747     exe "silent se guifont=DejaVu_Sans_Mono:h10:cANSI"
748   else
749     exe "silent se guifont=DejaVu\\ Sans\\ Mono\\ 10"
750   endif
751 endif
752 if has("gui_running") || &t_Co > 16
753   exe "silent colo iain"
754 endif
755
756 " Ignore whitespace when diffing.
757 if has("diff")
758   se diffopt=filler,iwhite
759 endif
760
761 if has("autocmd")
762   if has("quickfix")
763     " Remember that we are opening the quickfix window.
764     au Mode BufWinEnter quickfix let g:quickfixing=1
765     au Mode BufUnload * if &ft == "qf" | let g:quickfixing=0 | endif
766   endif
767
768   " Allow in-place editing of crontabs.
769   au Mode FileType crontab set backupcopy=yes
770 endif
771
772 " Make * and # work the way you expect in visual mode.
773 vnoremap * y/\V<C-R>=substitute(escape(@@,"/\\"),"\n","\\\\n","ge")<CR><CR>
774 vnoremap # y?\V<C-R>=substitute(escape(@@,"?\\"),"\n","\\\\n","ge")<CR><CR>
775
776 " Set mark and update highlighting.
777 if has("signs")
778   au Signs BufReadPost * call <SID>Highlight_Signs()
779   au Signs CursorHold * call <SID>Highlight_Signs()
780 endif
781
782 " Helper to set buffer variable for a given sign.
783 fun! <SID>Prep_Sign(sign) "{{{2
784   if ! exists("b:sign" . a:sign) || ! g:marksigns
785     exe "let b:sign" . a:sign . "=0"
786    endif
787 endfun "}}}2
788
789 fun! <SID>Place_Sign(number, line, old, name) "{{{2
790   if a:line == a:old
791     return a:old
792   endif
793
794   exe "sign unplace " . (g:firstsign + a:number) . " buffer=" . bufnr("")
795   " Don't place the sign if it would conflict with the last change sign.
796   exe "sign place " . (g:firstsign + a:number) . " line=" . a:line . " name=" . a:name . " buffer=" . bufnr("")
797   return a:line
798 endfun "}}}2
799
800 fun! <SID>Highlight_Signs(...) "{{{2
801   if ! has("signs") || ! g:marksigns || Uncluttered_Buffer()
802     return
803   endif
804
805   let l:signs = g:iainsigns
806   let l:sign = ""
807   let l:i = 0
808   while strlen(l:signs)
809     let l:sign = matchstr(l:signs, '^[A-Za-z]\+\(:.\)*[.=-][^ ]\+')
810
811     let l:name = substitute(l:sign, '[:.=-].*', "", "")
812     let l:var = tolower(l:name)
813     let l:sign = substitute(l:sign, '^[A-Za-z]\+', "", "")
814     let l:ascii = matchstr(l:sign, '^:.')
815     let l:mark = substitute(l:sign, '^\(:.\)*[.=-]', "", "")
816     if strlen(l:ascii)
817       let l:ascii = substitute(l:ascii, '^:', "", "")
818     else
819       let l:ascii = l:mark
820     endif
821     let l:ascii = substitute(l:ascii, '"', '\\"', "")
822
823     call <SID>Prep_Sign(l:var)
824     exe "let " . l:var . " = <SID>Place_Sign(" . l:i . ", line(\"'" . l:ascii . "\"), b:sign" . l:var . ", \"Mark" . l:name . "\")"
825     let l:i = l:i + 1
826
827     let l:signs = substitute(l:signs, '^[^ ]\+ *', "", "")
828   endwhile
829 endfun "}}}2
830
831 " Toggle signs.
832 fun! <SID>Cycle_Signs(resize) "{{{2
833   if ! has("signs")
834     return
835   endif
836   call Iain_Vars()
837   let g:marksigns = ! g:marksigns
838
839   " Retrofit arrays on to Vim 6.
840   if ! exists("g:iainsigns")
841     " Signs are defined in g:iainsigns.  The syntax is as follows:
842     "
843     " Sign ::= Name (':' Mark)* Type Symbol
844     " Type ::= '=' | '-' | '.'
845     "
846     " Signs with Type '=' will be highlighted with the MarkSign group.
847     " Signs with Type '-' will be highlighted with the MarkLine group.
848     " Signs with Type '.' will be highlighted with the MarkDot group.
849     " Define the Mark where Symbol is not also the mark name, eg "']".
850     if <SID>Has_Unicode()
851       let g:iainsigns = "Dash:'=’ Dot:..• Quote:\"=” Caret:^.ʌ"
852     else
853       let g:iainsigns = "Dash=' Dot:..* Quote=\" Caret.^"
854     endif
855     let g:iainsigns = g:iainsigns . " Less=< Greater=> Left=( Right=) SquareLeft=[ SquareRight=] BraceLeft={ BraceRight=} a-a b-b c-c d-d e-e f-f A-A B-B C-C D-D E-E F-F"
856   endif
857
858   if g:marksigns
859     " Signs to highlight marks.
860     " Syntax won't work properly in Vim 6.
861     let l:signs = g:iainsigns
862     let l:sign = ""
863     while strlen(l:signs)
864       let l:sign = matchstr(l:signs, '^[A-Za-z]\+\(:.\)*[.=-][^ ]\+')
865
866       let l:sign = substitute(l:sign, ':.', "", "")
867       let l:sign = substitute(l:sign, '=', " texthl=MarkSign text=", "")
868       let l:sign = substitute(l:sign, '\.', " texthl=MarkDot text=", "")
869       let l:sign = substitute(l:sign, '-', " texthl=MarkLine linehl=MarkLine text=", "")
870
871       exe "sign define Mark" . l:sign
872
873       let l:signs = substitute(l:signs, '^[^ ]\+ *', "", "")
874     endwhile
875
876     if a:resize
877       call Resize_Columns("+", 2)
878     endif
879     call <SID>Highlight_Signs()
880   else
881     let l:i = 0
882     while l:i < 25
883       exe "sign unplace " . (g:firstsign + l:i)
884       let l:i = l:i + 1
885     endwhile
886
887     let l:signs = g:iainsigns
888     let l:sign = ""
889     while strlen(l:signs)
890       let l:sign = matchstr(l:signs, '^[A-Za-z]\+')
891
892       exe "sign undefine Mark" . l:sign
893       call <SID>Prep_Sign(tolower(l:sign))
894       let l:signs = substitute(l:signs, '^[^ ]\+ *', "", "")
895     endwhile
896
897     if a:resize
898       call Resize_Columns("-", 2)
899     endif
900   endif
901 endfun "}}}2
902
903 " Do we have Unicode?
904 fun! <SID>Has_Unicode() "{{{2
905   if ! has('multi_byte')
906     return 0
907   endif
908
909   if version < "602"
910     return 0
911   endif
912
913   if &tenc =~? '^u\(tf\|cs\)'
914     return 1
915   endif
916
917   if ! strlen(&tenc) && &enc =~? '^u\(tf\|cs\)'
918     return 1
919   endif
920
921   return 0
922 endfun "}}}2
923
924 " Change list mode.
925 fun! Cycle_List() "{{{2
926   " Pretty UTF-8 listchars.
927   if <SID>Has_Unicode()
928     let basic='tab:»·,trail:…,extends:«,precedes:»'
929     let eol='eol:¶'
930     if version >= "700"
931       let basic=basic . ',nbsp:•'
932     endif
933   else
934     let basic='tab:\\_,trail:_,extends:<,precedes:>'
935     let eol='eol:$'
936     if version >= "700"
937       let basic=basic . ',nbsp:+'
938     endif
939   endif
940   call Iain_Vars()
941   let w:iainlist = w:iainlist + 1
942   if w:iainlist > 2
943     let w:iainlist = 0
944   endif
945   if w:iainlist == 0
946     setlocal nolist
947   elseif w:iainlist == 1
948     exec "setlocal lcs=" . basic
949     setlocal list
950   else
951     exec "setlocal lcs=" . basic . "," . eol
952     setlocal list
953   endif
954
955   call Resize_Columns(Extra_Columns("list", "iainlist", " == 2"), 1)
956 endfun "}}}2
957
958 " Cycle between hex and decimal display of toolbar stuff.
959 fun! Cycle_HexStatusLine() "{{{2
960   call Iain_Vars()
961   let b:iainhex = ! b:iainhex
962   call Show_StatusLine()
963 endfun "}}}2
964
965 " Cycle verbose display of toolbar stuff.
966 fun! Cycle_VerboseStatusLine() "{{{2
967   call Iain_Vars()
968   let b:iainverbose = ! b:iainverbose
969   call Show_StatusLine()
970 endfun "}}}2
971
972 " Toggle quickfix window.
973 fun! Cycle_Quickfix() "{{{2
974   if ! has("quickfix")
975     return
976   endif
977   if g:quickfixing == 1
978     cclose
979     let g:quickfixing=0
980   else
981     copen
982   endif
983 endfun "}}}2
984
985 " Toggle showing alternate buffer information.
986 fun! Cycle_Alt() "{{{2
987   call Iain_Vars()
988   let b:iainalt = ! b:iainalt
989   call Show_StatusLine()
990 endfun "{{{2
991
992 " Swap hex/decimal statusline with \x.
993 call Mapping("x", ":call Cycle_HexStatusLine()<CR>:<CR>")
994 " Change statusline verbosity with \v.
995 call Mapping("V", ":call Cycle_VerboseStatusLine()<CR>:<CR>")
996 " Cycle list styles with \l.
997 call Mapping("l", ":call Cycle_List()<CR>:<CR>")
998 " Toggle tags with \t.
999 call Mapping("t", ":Tlist<CR>")
1000 " Change foldmethod with \f.
1001 call Mapping("f", ":se foldenable!<CR>:<CR>")
1002 " Toggle quickfix window with \q.
1003 call Mapping("q", ":call Cycle_Quickfix()<CR>:<CR>")
1004 " Rerun filetype detection with \s.  The s is for syntax, as this will be
1005 " updated as a side-effect.
1006 call Mapping("S", ":filetype detect<CR>:<CR>")
1007 " Toggle marks with \m.
1008 call Mapping("m", ":call <SID>Cycle_Signs(1)<CR>:<CR>")
1009
1010 if has("autocmd")
1011   " Show signs by default.
1012   au Display VimEnter * call <SID>Cycle_Signs(0)
1013 endif
1014 endif "}}}1
1015
1016 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
1017 " Handle options only available in Vim 7 and above.
1018 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
1019 if version >= "700" "{{{1
1020 version 7.0
1021
1022 " Helper to show tab name.
1023 fun! <SID>TabName(label, gui) "{{{2
1024   let l:label = a:label
1025   if l:label == ""
1026     let l:label = "No Name"
1027     if a:gui
1028       let l:label = "[" . l:label . "]"
1029     endif
1030   else
1031     let l:label = fnamemodify(l:label, ":t")
1032     if strlen(l:label) >= 18
1033       let l:label = l:label[0:17] . ".."
1034     endif
1035   endif
1036   return l:label
1037 endfun "}}}2
1038
1039 " Find out if any buffer was modified.
1040 fun! <SID>TabModified(buflist) "{{{2
1041   let l:i = 0
1042   while l:i < len(a:buflist)
1043     if getbufvar(a:buflist[l:i], "&modified") == 1
1044       return "+"
1045     endif
1046     let l:i = l:i + 1
1047   endwhile
1048   return ""
1049 endfun "}}}2
1050
1051 " Tab line.
1052 fun! Show_TabLine() "{{{2
1053   let l:s = "%#TabLineFill#Tabs:"
1054
1055   let l:i = 0
1056   while l:i < tabpagenr("$")
1057     let l:i = l:i + 1
1058     " Get the label.
1059     let l:buflist = tabpagebuflist(l:i)
1060     let l:winnr = tabpagewinnr(l:i)
1061     let l:n = tabpagewinnr(l:i, "$")
1062     let l:label = <SID>TabName(bufname(l:buflist[l:winnr - 1]), 0)
1063     let l:modified = <SID>TabModified(l:buflist)
1064
1065     " Choose highlighting.
1066     if l:i == tabpagenr()
1067       let l:s .= "%#TabLineSel#[" . l:n . l:modified . " " . l:label . "]"
1068     else
1069       let l:s .= "%#TabLine# " . l:n . l:modified . " " . l:label . " "
1070     endif
1071   endwhile
1072
1073   " Padding.
1074   let l:s .= "%#TabLine#%T"
1075   return l:s
1076 endfun "}}}2
1077
1078 " Per tab label for the GUI.
1079 fun! Show_GUITabLine() "{{{2
1080   let l:buflist = tabpagebuflist(v:lnum)
1081   let l:winnr = tabpagewinnr(v:lnum)
1082   let l:s = tabpagewinnr(v:lnum, "$")
1083   let l:label = <SID>TabName(bufname(l:buflist[l:winnr - 1]), 1)
1084   let l:modified = <SID>TabModified(l:buflist)
1085
1086   let l:s .= l:modified . " " . l:label
1087   return l:s
1088 endfun "}}}2
1089
1090 " Toggle highlighting cursor line when focus changes.
1091 fun! <SID>ToggleCursorLine() "{{{2
1092   call Iain_Vars()
1093
1094   if b:iainstatus =~# "f" && b:iainstatus =~# "H" && b:iainstatus =~# "I"
1095     " Focus lost while held in insert mode.
1096     let b:iaincul = getbufvar("", "&cursorline")
1097     setlocal cursorline
1098   elseif ! b:iaincul
1099     setlocal nocursorline
1100   endif
1101 endfun "}}}2
1102
1103 " Handle searching in a BufExplorer window.
1104 fun! <SID>BufExplorer_Search(n) "{{{2
1105   if a:n == 0
1106     let l:re = '^  *\d %'
1107   else
1108     let l:re = "^ *" . a:n
1109   endif
1110
1111   " Find matching line.
1112   let l:line = search(l:re, 'w')
1113   if ! l:line
1114     return
1115   endif
1116
1117   if a:n == 0
1118     return
1119   endif
1120
1121   " Peek ahead to the next matching line.
1122   let l:next = search(l:re, 'w')
1123
1124   " Select the buffer if the match is unambiguous.
1125   if l:next == l:line
1126     exe "normal \<CR>"
1127     return
1128   endif
1129
1130   " Go back.
1131   call cursor(l:line, 0)
1132 endfun! "}}}2
1133
1134 " Entering a BufExplorer window.
1135 fun! <SID>BufExplorer_Map() "{{{2
1136   for l:n in [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ]
1137     exec "nnoremap <buffer> <silent>" . l:n . " :call <SID>BufExplorer_Search(" . l:n . ")<CR>"
1138   endfor
1139 endfun "}}}2
1140
1141 if has("windows")
1142   se tabline=%!Show_TabLine()
1143   se guitablabel=%!Show_GUITabLine()
1144 endif
1145
1146 if has("autocmd")
1147   au StatusLine CursorHoldI * call Highlight_StatusLine("H")
1148   au StatusLine CursorMovedI * call Highlight_StatusLine("h")
1149   au StatusLine FocusGained * call Highlight_StatusLine("F")
1150   au StatusLine FocusLost * call Highlight_StatusLine("f")
1151   au StatusLine InsertEnter * call Highlight_StatusLine("I")
1152   au StatusLine InsertLeave * call Highlight_StatusLine("i")
1153
1154   if has("syntax")
1155     au Display FocusGained,FocusLost * call <SID>ToggleCursorLine()
1156   endif
1157
1158   if has("signs")
1159     au Signs InsertEnter * call <SID>Highlight_Signs()
1160     au Signs InsertLeave * call <SID>Highlight_Signs()
1161   endif
1162
1163   au Mode BufEnter \[BufExplorer\] call <SID>BufExplorer_Map()
1164 endif
1165
1166 " Limit the size of the popup menu when completing.
1167 if has("insert_expand")
1168   se pumheight=20
1169 endif
1170
1171 " Make diffs vertical by default.
1172 if has("diff")
1173   se diffopt+=vertical
1174 endif
1175
1176 " Set size of numbers column.
1177 if has("linebreak")
1178   se numberwidth=5
1179 endif
1180
1181 " Add "previous tab" mapping as gb.
1182 map gb :tabprevious<CR>:<CR>
1183
1184 " Transparency.
1185 if has("gui_macvim")
1186   se transparency=15
1187 endif 
1188
1189 " Yet more GUI options.  Add tabs.
1190 if has("gui")
1191   se go+=e
1192 endif
1193
1194 " Perforce.
1195 let g:p4EnableMenu=1
1196 let g:p4Presets='P4CONFIG'
1197
1198 " BufExplorer.
1199 let g:bufExplorerShowRelativePath=1
1200 let g:bufExplorerSplitOutPathName=0
1201 endif "}}}1
1202
1203 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
1204 " Handle options only available in Vim 7.3 and above.
1205 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
1206 if version >= "703" "{{{1
1207 version 7.3
1208
1209 " Toggle persistent undo with \u.
1210 call Mapping("u", ":call <SID>Cycle_Undo()<CR>:<CR>")
1211 " Remove persistent undo file with \U.
1212 call Mapping("U", ":call <SID>Clear_Undo()<CR>:<CR>")
1213
1214 " Use a persistent undo file if it exists.
1215 fun! <SID>Check_Undo() "{{{2
1216   if filereadable(undofile(expand("%")))
1217     setlocal undofile
1218   endif
1219 endfun "}}}2
1220
1221 " Toggle persistent undo for this buffer.
1222 fun! <SID>Cycle_Undo() "{{{2
1223   if has("persistent_undo")
1224     let &undofile = ! &undofile
1225   endif
1226 endfun "}}}2
1227
1228 " Remove the persistent undo file for this buffer.
1229 fun! <SID>Clear_Undo() "{{{2
1230   if ! has("persistent_undo")
1231     return
1232   endif
1233
1234   setlocal noundofile
1235
1236   let l:f = expand("%")
1237   if l:f == ""
1238     return
1239   endif
1240
1241   let l:u = undofile(l:f)
1242   if l:u == ""
1243     return
1244   endif
1245
1246   if ! filereadable(l:u) || ! filewritable(l:u)
1247     return
1248   endif
1249
1250   call delete(l:u)
1251 endfun "}}}2
1252
1253 " Toggle ColorColumn at cursor position.
1254 fun! <SID>Cycle_ColorColumn() "{{{2
1255   if ! has("syntax")
1256     return
1257   endif
1258
1259   let l:cc = &colorcolumn
1260   let l:column = col(".")
1261   let l:re = ",*\\<" . l:column . "\\>"
1262   if l:cc =~# l:re
1263     let l:cc = substitute(l:cc, l:re, "", "g")
1264   else
1265     let l:cc = l:cc . "," . l:column
1266   endif
1267   let &colorcolumn = substitute(l:cc, "^,*", "", "")
1268 endfun "}}}2
1269
1270 if has("syntax")
1271   " Enable showing ColorColumn at cursor position with \CC.
1272   call Mapping("CC", ":call <SID>Cycle_ColorColumn()<CR>:<CR>")
1273   " Remove last shown ColorColumn with \Cc.
1274   call Mapping("Cc", ":let &colorcolumn=substitute(&colorcolumn, \",*[0-9]*$\", \"\", \"\")<CR>:<CR>")
1275   " Remove all ColorColumns with \Cx.
1276   call Mapping("Cx", ":se colorcolumn=<CR>:<CR>")
1277 endif
1278
1279 " Use persistent undo if available.
1280 if has("autocmd")
1281   if has("persistent_undo")
1282     au File BufReadPost * call <SID>Check_Undo()
1283   endif
1284 endif
1285 endif "}}}1
1286
1287 " Resize after startup.
1288 if version >= "500" "{{{1
1289 if has("autocmd")
1290   au Display VimEnter * call Startup_Resize()
1291 endif
1292 endif "}}}1