Cursor binding.
[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 " Do we have Unicode?
618 fun! Has_Unicode() "{{{2
619   if ! has('multi_byte')
620     return 0
621   endif
622
623   if version < "602"
624     return 0
625   endif
626
627   if &tenc =~? '^u\(tf\|cs\)'
628     return 1
629   endif
630
631   if ! strlen(&tenc) && &enc =~? '^u\(tf\|cs\)'
632     return 1
633   endif
634
635   return 0
636 endfun "}}}2
637
638 " Helper for status line.
639 " Show space, underscore or dollar sign depending on list mode.
640 fun! Show_List() "{{{2
641   call Iain_Vars()
642   if w:iainlist == 0
643     " No list.
644     return " "
645   elseif Has_Unicode()
646     if w:iainlist == 1
647       " Just tabs.
648       return "»"
649     else
650       " Full list.
651       return "¶"
652     endif
653   else
654     if w:iainlist == 1
655       return "_"
656     else
657       return "\$"
658     endif
659   endif
660 endfun "}}}2
661
662 " Helper for status line.
663 " Show c or C to denote case-sensitivity.
664 fun! Show_Case() "{{{2
665   if &ic
666     return "c"
667   else
668     return "C"
669   endif
670 endfun "}}}2
671
672 " Helper for status line.
673 " Show the size of the tabstop.
674 fun! Show_Tabstop() "{{{2
675   return &ts
676 endfun "}}}2
677
678 " Helper for status line.
679 " Show p when paste mode is on.
680 fun! Show_Paste() "{{{2
681   if &paste
682     return "p"
683   else
684     return ""
685   endif
686 endfun "}}}2
687
688 " Helper for status line.
689 " Show v when virtualedit mode is block, insert or onemore.
690 " Show V when virtualedit mode is all.
691 fun! Show_VirtualEdit() "{{{2
692   if ! has("virtualedit")
693     return ""
694   endif
695
696   if &ve == "all"
697     return "V"
698   elseif &ve
699     return "v"
700   else
701     return ""
702   endif
703 endfun "}}}2
704
705 " Helper for status line.
706 " Show U when persistent undo is on.
707 " Show u when persistent undo is off but an undofile exists.
708 fun! Show_Undo() "{{{2
709   if ! exists("&undofile")
710     return ""
711   endif
712
713   if &undofile
714     return "U"
715   elseif filereadable(undofile(expand("%")))
716     return "u"
717   else
718     return ""
719   endif
720 endfun "}}}2
721
722 " Helper for status line.
723 " Show alternate buffer number and name.
724 fun! Show_Alt() "{{{2
725   let l:alt = bufnr("#")
726   if l:alt < 0 || l:alt == bufnr("") || ! b:iainalt
727     return ""
728   endif
729
730   return " " . l:alt . ": " . expand("#:t")
731 endfun "}}}2
732
733 " Helper for status line.
734 " Show scrollbind or cursorbind.
735 fun! Show_Bind() "{{{2
736   if has("cursorbind")
737     if &cursorbind
738       if Has_Unicode()
739         return "⇄"
740       else
741         return ">"
742       endif
743     elseif &scrollbind
744       if Has_Unicode()
745         return "⇅"
746       else
747         return "^"
748       endif
749     endif
750   endif
751   return ""
752 endfun "}}}2
753
754 " Show the status line.
755 fun! Show_StatusLine() "{{{2
756   if ! has("statusline")
757     return
758   endif
759   call Iain_Vars()
760   let l:sl1='%2n\:\ %<%1*%f%0*\ [%{Show_List()}%{Show_Bind()}%{Show_Case()}%{Show_Tabstop()}%{Show_Paste()}%{Show_VirtualEdit()}%{Show_Undo()}%Y%M%R]%{Show_Alt()}\ '
761   let l:sl3='L:%1*%4.6l%0*/%-4.6L\ C:%1*%3.6c%0*\ \|\ %P'
762   let l:hexformat='%b'
763   if b:iainhex
764     let l:hexformat='0\x%02B'
765   endif
766   if b:iainverbose
767     let l:sl1=l:sl1 . v:version . '\ %='
768     let l:sl2=l:hexformat . '\ \|\ P:%4.6o\ '
769   else
770     let l:sl1=l:sl1 . '%='
771     let l:sl2=''
772   endif
773   exec "set statusline=" . l:sl1 . l:sl2 . l:sl3
774 endfun "}}}2
775
776 " Show the status line for the first time.
777 call Show_StatusLine()
778 endif "}}}1
779
780 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
781 " Handle options only available in Vim 6 and above.
782 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
783 if version >= "600" "{{{1
784 version 6.0
785
786 if has("gui_win32")
787   se encoding=utf-8
788 endif
789
790 " Remember quickfix state.
791 if has("quickfix")
792   let g:quickfixing=0
793 endif
794
795 " Set indenting by filetype.
796 filetype indent on
797
798 " Less intrusive syntax highlighting.
799 if has("syntax")
800   syn enable
801 endif
802
803 " Set colours.
804 if has("gui_running")
805   if has("win32") || has("win64")
806     exe "silent se guifont=DejaVu_Sans_Mono:h10:cANSI"
807   else
808     exe "silent se guifont=DejaVu\\ Sans\\ Mono\\ 10"
809   endif
810 endif
811 if has("gui_running") || &t_Co > 16
812   exe "silent colo iain"
813 endif
814
815 " Ignore whitespace when diffing.
816 if has("diff")
817   se diffopt=filler,iwhite
818 endif
819
820 if has("autocmd")
821   if has("quickfix")
822     " Remember that we are opening the quickfix window.
823     au Mode BufWinEnter quickfix let g:quickfixing=1
824     au Mode BufUnload * if &ft == "qf" | let g:quickfixing=0 | endif
825   endif
826
827   " Allow in-place editing of crontabs.
828   au Mode FileType crontab set backupcopy=yes
829 endif
830
831 " Make * and # work the way you expect in visual mode.
832 vnoremap * y/\V<C-R>=substitute(escape(@@,"/\\"),"\n","\\\\n","ge")<CR><CR>
833 vnoremap # y?\V<C-R>=substitute(escape(@@,"?\\"),"\n","\\\\n","ge")<CR><CR>
834
835 " Set mark and update highlighting.
836 if has("signs")
837   au Signs BufReadPost * call <SID>Highlight_Signs()
838   au Signs CursorHold * call <SID>Highlight_Signs()
839 endif
840
841 " Helper to set buffer variable for a given sign.
842 fun! <SID>Prep_Sign(sign) "{{{2
843   if ! exists("b:sign" . a:sign) || ! g:marksigns
844     exe "let b:sign" . a:sign . "=0"
845    endif
846 endfun "}}}2
847
848 fun! <SID>Place_Sign(number, line, old, name) "{{{2
849   if a:line == a:old
850     return a:old
851   endif
852
853   exe "sign unplace " . (g:firstsign + a:number) . " buffer=" . bufnr("")
854   " Don't place the sign if it would conflict with the last change sign.
855   exe "sign place " . (g:firstsign + a:number) . " line=" . a:line . " name=" . a:name . " buffer=" . bufnr("")
856   return a:line
857 endfun "}}}2
858
859 fun! <SID>Highlight_Signs(...) "{{{2
860   if ! has("signs") || ! g:marksigns || Uncluttered_Buffer()
861     return
862   endif
863
864   let l:signs = g:iainsigns
865   let l:sign = ""
866   let l:i = 0
867   while strlen(l:signs)
868     let l:sign = matchstr(l:signs, '^[A-Za-z]\+\(:.\)*[.=-][^ ]\+')
869
870     let l:name = substitute(l:sign, '[:.=-].*', "", "")
871     let l:var = tolower(l:name)
872     let l:sign = substitute(l:sign, '^[A-Za-z]\+', "", "")
873     let l:ascii = matchstr(l:sign, '^:.')
874     let l:mark = substitute(l:sign, '^\(:.\)*[.=-]', "", "")
875     if strlen(l:ascii)
876       let l:ascii = substitute(l:ascii, '^:', "", "")
877     else
878       let l:ascii = l:mark
879     endif
880     let l:ascii = substitute(l:ascii, '"', '\\"', "")
881
882     call <SID>Prep_Sign(l:var)
883     exe "let " . l:var . " = <SID>Place_Sign(" . l:i . ", line(\"'" . l:ascii . "\"), b:sign" . l:var . ", \"Mark" . l:name . "\")"
884     let l:i = l:i + 1
885
886     let l:signs = substitute(l:signs, '^[^ ]\+ *', "", "")
887   endwhile
888 endfun "}}}2
889
890 " Toggle signs.
891 fun! <SID>Cycle_Signs(resize) "{{{2
892   if ! has("signs")
893     return
894   endif
895   call Iain_Vars()
896   let g:marksigns = ! g:marksigns
897
898   " Retrofit arrays on to Vim 6.
899   if ! exists("g:iainsigns")
900     " Signs are defined in g:iainsigns.  The syntax is as follows:
901     "
902     " Sign ::= Name (':' Mark)* Type Symbol
903     " Type ::= '=' | '-' | '.'
904     "
905     " Signs with Type '=' will be highlighted with the MarkSign group.
906     " Signs with Type '-' will be highlighted with the MarkLine group.
907     " Signs with Type '.' will be highlighted with the MarkDot group.
908     " Define the Mark where Symbol is not also the mark name, eg "']".
909     if Has_Unicode()
910       let g:iainsigns = "Dash:'=’ Dot:..• Quote:\"=” Caret:^.ʌ"
911     else
912       let g:iainsigns = "Dash=' Dot:..* Quote=\" Caret.^"
913     endif
914     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"
915   endif
916
917   if g:marksigns
918     " Signs to highlight marks.
919     " Syntax won't work properly in Vim 6.
920     let l:signs = g:iainsigns
921     let l:sign = ""
922     while strlen(l:signs)
923       let l:sign = matchstr(l:signs, '^[A-Za-z]\+\(:.\)*[.=-][^ ]\+')
924
925       let l:sign = substitute(l:sign, ':.', "", "")
926       let l:sign = substitute(l:sign, '=', " texthl=MarkSign text=", "")
927       let l:sign = substitute(l:sign, '\.', " texthl=MarkDot text=", "")
928       let l:sign = substitute(l:sign, '-', " texthl=MarkLine linehl=MarkLine text=", "")
929
930       exe "sign define Mark" . l:sign
931
932       let l:signs = substitute(l:signs, '^[^ ]\+ *', "", "")
933     endwhile
934
935     if a:resize
936       call Resize_Columns("+", 2)
937     endif
938     call <SID>Highlight_Signs()
939   else
940     let l:i = 0
941     while l:i < 25
942       exe "sign unplace " . (g:firstsign + l:i)
943       let l:i = l:i + 1
944     endwhile
945
946     let l:signs = g:iainsigns
947     let l:sign = ""
948     while strlen(l:signs)
949       let l:sign = matchstr(l:signs, '^[A-Za-z]\+')
950
951       exe "sign undefine Mark" . l:sign
952       call <SID>Prep_Sign(tolower(l:sign))
953       let l:signs = substitute(l:signs, '^[^ ]\+ *', "", "")
954     endwhile
955
956     if a:resize
957       call Resize_Columns("-", 2)
958     endif
959   endif
960 endfun "}}}2
961
962 " Change list mode.
963 fun! Cycle_List() "{{{2
964   " Pretty UTF-8 listchars.
965   if Has_Unicode()
966     let basic='tab:»·,trail:…,extends:«,precedes:»'
967     let eol='eol:¶'
968     if version >= "700"
969       let basic=basic . ',nbsp:•'
970     endif
971   else
972     let basic='tab:\\_,trail:_,extends:<,precedes:>'
973     let eol='eol:$'
974     if version >= "700"
975       let basic=basic . ',nbsp:+'
976     endif
977   endif
978   call Iain_Vars()
979   let w:iainlist = w:iainlist + 1
980   if w:iainlist > 2
981     let w:iainlist = 0
982   endif
983   if w:iainlist == 0
984     setlocal nolist
985   elseif w:iainlist == 1
986     exec "setlocal lcs=" . basic
987     setlocal list
988   else
989     exec "setlocal lcs=" . basic . "," . eol
990     setlocal list
991   endif
992
993   call Resize_Columns(Extra_Columns("list", "iainlist", " == 2"), 1)
994 endfun "}}}2
995
996 " Cycle between hex and decimal display of toolbar stuff.
997 fun! Cycle_HexStatusLine() "{{{2
998   call Iain_Vars()
999   let b:iainhex = ! b:iainhex
1000   call Show_StatusLine()
1001 endfun "}}}2
1002
1003 " Cycle verbose display of toolbar stuff.
1004 fun! Cycle_VerboseStatusLine() "{{{2
1005   call Iain_Vars()
1006   let b:iainverbose = ! b:iainverbose
1007   call Show_StatusLine()
1008 endfun "}}}2
1009
1010 " Toggle quickfix window.
1011 fun! Cycle_Quickfix() "{{{2
1012   if ! has("quickfix")
1013     return
1014   endif
1015   if g:quickfixing == 1
1016     cclose
1017     let g:quickfixing=0
1018   else
1019     copen
1020   endif
1021 endfun "}}}2
1022
1023 " Toggle showing alternate buffer information.
1024 fun! Cycle_Alt() "{{{2
1025   call Iain_Vars()
1026   let b:iainalt = ! b:iainalt
1027   call Show_StatusLine()
1028 endfun "{{{2
1029
1030 " Swap hex/decimal statusline with \x.
1031 call Mapping("x", ":call Cycle_HexStatusLine()<CR>:<CR>")
1032 " Change statusline verbosity with \v.
1033 call Mapping("V", ":call Cycle_VerboseStatusLine()<CR>:<CR>")
1034 " Cycle list styles with \l.
1035 call Mapping("l", ":call Cycle_List()<CR>:<CR>")
1036 " Toggle tags with \t.
1037 call Mapping("t", ":Tlist<CR>")
1038 " Change foldmethod with \f.
1039 call Mapping("f", ":se foldenable!<CR>:<CR>")
1040 " Toggle quickfix window with \q.
1041 call Mapping("q", ":call Cycle_Quickfix()<CR>:<CR>")
1042 " Rerun filetype detection with \s.  The s is for syntax, as this will be
1043 " updated as a side-effect.
1044 call Mapping("S", ":filetype detect<CR>:<CR>")
1045 " Toggle marks with \m.
1046 call Mapping("m", ":call <SID>Cycle_Signs(1)<CR>:<CR>")
1047
1048 if has("autocmd")
1049   " Show signs by default.
1050   au Display VimEnter * call <SID>Cycle_Signs(0)
1051 endif
1052 endif "}}}1
1053
1054 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
1055 " Handle options only available in Vim 7 and above.
1056 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
1057 if version >= "700" "{{{1
1058 version 7.0
1059
1060 " Helper to show tab name.
1061 fun! <SID>TabName(label, gui) "{{{2
1062   let l:label = a:label
1063   if l:label == ""
1064     let l:label = "No Name"
1065     if a:gui
1066       let l:label = "[" . l:label . "]"
1067     endif
1068   else
1069     let l:label = fnamemodify(l:label, ":t")
1070     if strlen(l:label) >= 18
1071       let l:label = l:label[0:17] . ".."
1072     endif
1073   endif
1074   return l:label
1075 endfun "}}}2
1076
1077 " Find out if any buffer was modified.
1078 fun! <SID>TabModified(buflist) "{{{2
1079   let l:i = 0
1080   while l:i < len(a:buflist)
1081     if getbufvar(a:buflist[l:i], "&modified") == 1
1082       return "+"
1083     endif
1084     let l:i = l:i + 1
1085   endwhile
1086   return ""
1087 endfun "}}}2
1088
1089 " Tab line.
1090 fun! Show_TabLine() "{{{2
1091   let l:s = "%#TabLineFill#Tabs:"
1092
1093   let l:i = 0
1094   while l:i < tabpagenr("$")
1095     let l:i = l:i + 1
1096     " Get the label.
1097     let l:buflist = tabpagebuflist(l:i)
1098     let l:winnr = tabpagewinnr(l:i)
1099     let l:n = tabpagewinnr(l:i, "$")
1100     let l:label = <SID>TabName(bufname(l:buflist[l:winnr - 1]), 0)
1101     let l:modified = <SID>TabModified(l:buflist)
1102
1103     " Choose highlighting.
1104     if l:i == tabpagenr()
1105       let l:s .= "%#TabLineSel#[" . l:n . l:modified . " " . l:label . "]"
1106     else
1107       let l:s .= "%#TabLine# " . l:n . l:modified . " " . l:label . " "
1108     endif
1109   endwhile
1110
1111   " Padding.
1112   let l:s .= "%#TabLine#%T"
1113   return l:s
1114 endfun "}}}2
1115
1116 " Per tab label for the GUI.
1117 fun! Show_GUITabLine() "{{{2
1118   let l:buflist = tabpagebuflist(v:lnum)
1119   let l:winnr = tabpagewinnr(v:lnum)
1120   let l:s = tabpagewinnr(v:lnum, "$")
1121   let l:label = <SID>TabName(bufname(l:buflist[l:winnr - 1]), 1)
1122   let l:modified = <SID>TabModified(l:buflist)
1123
1124   let l:s .= l:modified . " " . l:label
1125   return l:s
1126 endfun "}}}2
1127
1128 " Toggle highlighting cursor line when focus changes.
1129 fun! <SID>ToggleCursorLine() "{{{2
1130   call Iain_Vars()
1131
1132   if b:iainstatus =~# "f" && b:iainstatus =~# "H" && b:iainstatus =~# "I"
1133     " Focus lost while held in insert mode.
1134     let b:iaincul = getbufvar("", "&cursorline")
1135     setlocal cursorline
1136   elseif ! b:iaincul
1137     setlocal nocursorline
1138   endif
1139 endfun "}}}2
1140
1141 " Handle searching in a BufExplorer window.
1142 fun! <SID>BufExplorer_Search(n) "{{{2
1143   if a:n == 0
1144     let l:re = '^  *\d %'
1145   else
1146     let l:re = "^ *" . a:n
1147   endif
1148
1149   " Find matching line.
1150   let l:line = search(l:re, 'w')
1151   if ! l:line
1152     return
1153   endif
1154
1155   if a:n == 0
1156     return
1157   endif
1158
1159   " Peek ahead to the next matching line.
1160   let l:next = search(l:re, 'w')
1161
1162   " Select the buffer if the match is unambiguous.
1163   if l:next == l:line
1164     exe "normal \<CR>"
1165     return
1166   endif
1167
1168   " Go back.
1169   call cursor(l:line, 0)
1170 endfun! "}}}2
1171
1172 " Entering a BufExplorer window.
1173 fun! <SID>BufExplorer_Map() "{{{2
1174   for l:n in [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ]
1175     exec "nnoremap <buffer> <silent>" . l:n . " :call <SID>BufExplorer_Search(" . l:n . ")<CR>"
1176   endfor
1177 endfun "}}}2
1178
1179 if has("windows")
1180   se tabline=%!Show_TabLine()
1181   se guitablabel=%!Show_GUITabLine()
1182 endif
1183
1184 if has("autocmd")
1185   au StatusLine CursorHoldI * call Highlight_StatusLine("H")
1186   au StatusLine CursorMovedI * call Highlight_StatusLine("h")
1187   au StatusLine FocusGained * call Highlight_StatusLine("F")
1188   au StatusLine FocusLost * call Highlight_StatusLine("f")
1189   au StatusLine InsertEnter * call Highlight_StatusLine("I")
1190   au StatusLine InsertLeave * call Highlight_StatusLine("i")
1191
1192   if has("syntax")
1193     au Display FocusGained,FocusLost * call <SID>ToggleCursorLine()
1194   endif
1195
1196   if has("signs")
1197     au Signs InsertEnter * call <SID>Highlight_Signs()
1198     au Signs InsertLeave * call <SID>Highlight_Signs()
1199   endif
1200
1201   au Mode BufEnter \[BufExplorer\] call <SID>BufExplorer_Map()
1202 endif
1203
1204 " Limit the size of the popup menu when completing.
1205 if has("insert_expand")
1206   se pumheight=20
1207 endif
1208
1209 " Make diffs vertical by default.
1210 if has("diff")
1211   se diffopt+=vertical
1212 endif
1213
1214 " Set size of numbers column.
1215 if has("linebreak")
1216   se numberwidth=5
1217 endif
1218
1219 " Add "previous tab" mapping as gb.
1220 map gb :tabprevious<CR>:<CR>
1221
1222 " Transparency.
1223 if has("gui_macvim")
1224   se transparency=15
1225 endif 
1226
1227 " Yet more GUI options.  Add tabs.
1228 if has("gui")
1229   se go+=e
1230 endif
1231
1232 " Perforce.
1233 let g:p4EnableMenu=1
1234 let g:p4Presets='P4CONFIG'
1235
1236 " BufExplorer.
1237 let g:bufExplorerShowRelativePath=1
1238 let g:bufExplorerSplitOutPathName=0
1239
1240 " NERDcommenter.
1241 let g:NERDSpaceDelims=1
1242 endif "}}}1
1243
1244 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
1245 " Handle options only available in Vim 7.3 and above.
1246 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
1247 if version >= "703" "{{{1
1248 version 7.3
1249
1250 " Toggle persistent undo with \u.
1251 call Mapping("u", ":call <SID>Cycle_Undo()<CR>:<CR>")
1252 " Remove persistent undo file with \U.
1253 call Mapping("U", ":call <SID>Clear_Undo()<CR>:<CR>")
1254
1255 " Use a persistent undo file if it exists.
1256 fun! <SID>Check_Undo() "{{{2
1257   if filereadable(undofile(expand("%")))
1258     setlocal undofile
1259   endif
1260 endfun "}}}2
1261
1262 " Toggle persistent undo for this buffer.
1263 fun! <SID>Cycle_Undo() "{{{2
1264   if has("persistent_undo")
1265     let &undofile = ! &undofile
1266   endif
1267 endfun "}}}2
1268
1269 " Remove the persistent undo file for this buffer.
1270 fun! <SID>Clear_Undo() "{{{2
1271   if ! has("persistent_undo")
1272     return
1273   endif
1274
1275   setlocal noundofile
1276
1277   let l:f = expand("%")
1278   if l:f == ""
1279     return
1280   endif
1281
1282   let l:u = undofile(l:f)
1283   if l:u == ""
1284     return
1285   endif
1286
1287   if ! filereadable(l:u) || ! filewritable(l:u)
1288     return
1289   endif
1290
1291   call delete(l:u)
1292 endfun "}}}2
1293
1294 " Toggle ColorColumn at cursor position.
1295 fun! <SID>Cycle_ColorColumn() "{{{2
1296   if ! has("syntax")
1297     return
1298   endif
1299
1300   let l:cc = &colorcolumn
1301   let l:column = col(".")
1302   let l:re = ",*\\<" . l:column . "\\>"
1303   if l:cc =~# l:re
1304     let l:cc = substitute(l:cc, l:re, "", "g")
1305   else
1306     let l:cc = l:cc . "," . l:column
1307   endif
1308   let &colorcolumn = substitute(l:cc, "^,*", "", "")
1309 endfun "}}}2
1310
1311 if has("syntax")
1312   " Enable showing ColorColumn at cursor position with \CC.
1313   call Mapping("CC", ":call <SID>Cycle_ColorColumn()<CR>:<CR>")
1314   " Remove last shown ColorColumn with \Cc.
1315   call Mapping("Cc", ":let &colorcolumn=substitute(&colorcolumn, \",*[0-9]*$\", \"\", \"\")<CR>:<CR>")
1316   " Remove all ColorColumns with \Cx.
1317   call Mapping("Cx", ":se colorcolumn=<CR>:<CR>")
1318 endif
1319
1320 " Use persistent undo if available.
1321 if has("autocmd")
1322   if has("persistent_undo")
1323     au File BufReadPost * call <SID>Check_Undo()
1324   endif
1325
1326   if has("cursorbind")
1327     au Display WinEnter * if &diff | se cursorbind | endif
1328   endif
1329 endif
1330 endif "}}}1
1331
1332 " Resize after startup.
1333 if version >= "500" "{{{1
1334 if has("autocmd")
1335   au Display VimEnter * call Startup_Resize()
1336 endif
1337 endif "}}}1