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