a589ea0464b2075d20d3e2516cd440e6db2dc8da
[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 END
138 endif
139
140 " Save the current window dimensions so we can restore them when we quit.
141 if ! exists("g:oldcols")
142   let g:oldcols=&columns
143 endif
144 if ! exists("g:oldlines")
145   let g:oldlines=&lines
146 endif
147
148 " More GUI options.  Add icon and tearoffs.
149 if has("gui")
150   se go+=i
151   se go+=t
152 endif
153
154 " Allow dynamic window resize even if we aren't in an xterm.
155 se t_WS=\e[8;%p1%d;%p2%dt
156
157 " Highlight search results.
158 if has("extra_search")
159   se hlsearch
160 endif
161
162 " Syntax highlighting.  New versions will use syn enable instead.
163 if version < "600"
164   syn on
165 endif
166
167 if has("user_commands")
168   " Catch typos.
169   command! W :w
170   command! Wq :wq
171   command! Wqa :wqa
172 endif
173
174 " Forget the Ex mode mapping.
175 map Q <NOP>
176
177 if has("autocmd")
178   " Position the compview plugin window.
179   au Display BufEnter -SearchResults- set buftype=nowrite | set nonumber | wincmd J
180 endif
181 endif "}}}1
182
183 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
184 " Handle options only available in Vim 5.2 and above.
185 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
186 if version >= "502" "{{{1
187 version 5.2
188
189 " Helper to initialise a variable.
190 fun! Prep_Var(var, value) "{{{2
191   if exists(a:var)
192     return
193   endif
194   exe "let " . a:var . "=" . a:value
195 endfun "}}}2
196
197 " Set up our variables.
198 fun! Iain_Vars() "{{{2
199   call Prep_Var("w:iainlist", 0)
200   call Prep_Var("b:iainhex", 0)
201   call Prep_Var("b:iainverbose", 0)
202   " Window Flags: (F)ocused, (I)nsert mode, Cursor (H)old.
203   call Prep_Var("b:iainstatus", "'Fih'")
204   call Prep_Var("g:iainextracolumnsnumber", "''")
205   call Prep_Var("g:iainextracolumnslist", "''")
206   call Prep_Var("b:iaincul", 0)
207   if has("signs")
208     call Prep_Var("g:marksigns", 0)
209     call Prep_Var("g:firstsign", 100)
210   endif
211   call Prep_Var("g:resizable", "''")
212 endfun "}}}2
213
214 " Show the window title.
215 fun! Show_TitleString() "{{{2
216   if bufname("") == ""
217     let l:ts1='Vim'
218   else
219     " Vim 5 doesn't have printf.
220     let l:ts1=bufnr("")
221     if l:ts1 < 10
222       let l:ts1=" " . l:ts1
223     endif
224     let l:ts1=l:ts1 . ": " . expand('%t')
225   endif
226   let l:ts1=l:ts1 . " (" .  getcwd() . ")"
227   if has("clientserver")
228     let l:ts1=l:ts1 . " " . v:servername
229   endif
230   return l:ts1
231 endfun "}}}2
232
233 " Toggle case-sensitivity.
234 fun! Invert_Case() "{{{2
235   let &ic = ! &ic
236 endfun "}}}2
237
238 " Can we resize this window?
239 fun! Can_Resize() "{{{2
240   call Iain_Vars()
241
242   if g:resizable == "0" || g:resizable == "1"
243     return g:resizable
244   endif
245
246   " Do we KNOW we can(not) resize?
247   if has("gui_running")
248     let g:resizable = 1
249   elseif $RESIZABLE == &term
250     let g:resizable = 1
251   elseif $RESIZABLE == "0"
252     let g:resizable = 0
253   else
254     " Assume we can.  Allow overriding.
255     let g:resizable = 1
256   endif
257   return g:resizable
258 endfun "}}}2
259
260 " Grow or shrink the window width.
261 fun! Resize_Columns(op, ...) "{{{2
262   if a:op == ""
263     return
264   endif
265
266   if ! Can_Resize()
267     return
268   endif
269
270   if a:0 == 0
271     " Vim 5 hardcodes the size of numbers column to 8.
272     if version >= "700" && has("linebreak")
273       let l:columns = &numberwidth
274     else
275       let l:columns = 8
276     endif
277   else
278     let l:columns = a:1
279   endif
280
281   exe "let l:resize=" . &columns . a:op . l:columns
282   let l:resize = "se columns=" . l:resize
283
284   " HACK: Inside screen there is an extra line for the status bar.  Vim
285   " manages the resize by sending an escape sequence to set the number of
286   " lines and number of columns in one action.  To do this it will first query
287   " the number of lines and then set <same number of lines> by <new number of
288   " columns>.  Because of the extra line for the status bar this results in
289   " the real terminal being shrunk by a line.  We ask for the terminal to grow
290   " by a line so it ends up actually being the same.
291   if &term =~ '^screen'
292     let l:resize = l:resize . " lines=" . (&lines + 1)
293   endif
294
295   exe l:resize
296 endfun "}}}2
297
298 " Grow or shrink the window height.
299 fun! Resize_Lines(op, lines) "{{{2
300   if a:op == ""
301     return
302   endif
303
304   if ! Can_Resize()
305     return
306   endif
307
308   exe "let l:resize=" . &lines . a:op . a:lines
309   if &term =~ '^screen'
310     let l:resize = l:resize + 1
311   endif
312   let l:resize = "se lines=" . l:resize
313
314   exe l:resize
315 endfun "}}}2
316
317 " Set extra columns depending on window status.
318 fun! Extra_Columns(extra, var, ...) "{{{2
319   " Vim 6 doesn't have winnr("$").  Determine which windows are open
320   " ourselves by using :windo to incremement a counter.  As Vim 5 
321   " doesn't have :windo we require Vim 6 for this.
322   if v:version < "600"
323     return ""
324   endif
325   if ! has("windows")
326     return ""
327   endif
328
329   " Remember which window we're in.
330   let l:winnr = winnr()
331   let l:num_windows = 0
332   windo let l:num_windows = l:num_windows + 1
333   " Switch back to the window we were in.
334   exe l:winnr . "wincmd w"
335
336   call Iain_Vars()
337
338   if a:0 == 0
339     let l:condition = ""
340   else
341     let l:condition = a:1
342   endif
343
344   let l:n = 0
345   let l:i = 1
346   let l:windows = ""
347   while l:n < l:num_windows
348     " If window w exists then getwinvar(w, "&modified") will be 0 or 1.
349     if getwinvar(l:i, "&modified") =~ '^\d'
350       let l:n = l:n + 1
351
352       let l:val = 0
353       exe "if getwinvar(" . l:i . ", '" . a:var . "') " . l:condition . " | let l:val = 1 | endif"
354       if l:val
355         exe "let l:windows = '" . l:windows . ":" . l:i . "'"
356       endif
357     endif
358     let l:i = l:i + 1
359   endwhile
360
361   let l:extra = "g:iainextracolumns" . a:extra
362   exe "let l:val = " . l:extra
363   exe "let " . l:extra . " = '" . l:windows . "'"
364
365   if l:windows == l:val
366     return ""
367   endif
368
369   if l:windows == ""
370     return "-"
371   elseif l:val == ""
372     return "+"
373   endif
374 endfun "}}}2
375
376 " Toggle number display.
377 fun! Number(resize) "{{{2
378   call Iain_Vars()
379   let &number = ! &number
380
381   " Ensure we keep track of any extra columns even if we aren't resizing.
382   " This prevents confusion when number is set at startup.
383   let l:extra = Extra_Columns("number", "&number")
384
385   if a:resize
386     call Resize_Columns(l:extra)
387   endif
388 endfun "}}}2
389
390 " Restore window size.
391 if has("autocmd") && ! has("gui_running")
392   au Display VimLeave * if exists("g:oldcols") | call Resize_Columns("-", (&columns - g:oldcols)) | endif
393   au Display VimLeave * if exists("g:oldlines") | call Resize_Lines("-", (&lines - g:oldlines)) | endif
394 endif
395
396 " Map Makefile mode.
397 if has("autocmd")
398   au Mode BufEnter * if &ft == "make" | call MakeMode_map() | endif
399   au Mode BufLeave * if &ft == "make" | call MakeMode_unmap() | endif
400 endif
401
402 " Entering Make mode.
403 fun! MakeMode_map() "{{{2
404   call Iain_Vars()
405   let w:iainlist=1
406   call Cycle_List()
407   set ts=8
408   set noexpandtab
409 endfun "}}}2
410
411 " Leaving Make mode.
412 fun! MakeMode_unmap() "{{{2
413   call Cycle_List()
414   set ts=2
415   set expandtab
416 endfun "}}}2
417
418 " Function to create mappings with either a hardcoded \ or <Leader>.
419 fun! Mapping(keysequence,mapping) "{{{2
420   if version < "600"
421     exec "map \\" . a:keysequence . " " . a:mapping
422   else
423     exec "map <Leader>" . a:keysequence . " " . a:mapping
424   endif
425 endfun "}}}2
426
427 " Use - and = to create underlines.
428 call Mapping("-", "yyp:s/./-/g<RETURN>:let @/=''<RETURN>:<RETURN>")
429 call Mapping("=", "yyp:s/./=/g<RETURN>:let @/=''<RETURN>:<RETURN>")
430
431 " Change to ts=2 with \2.
432 call Mapping("2", ":se ts=2<CR>:<CR>")
433 " Change to ts=4 with \4.
434 call Mapping("4", ":se ts=4<CR>:<CR>")
435 " Change to ts=8 with \8.
436 call Mapping("8", ":se ts=8<CR>:<CR>")
437 " Change to ts=16 with \6.
438 call Mapping("6", ":se ts=16<CR>:<CR>")
439 " Change to ts=32 with \3.
440 call Mapping("3", ":se ts=32<CR>:<CR>")
441 " Toggle paste mode with \p.
442 call Mapping("p", ":se paste!<CR>:<CR>")
443 " Swap case-sensitivity with \c.
444 call Mapping("C", ":call Invert_Case()<CR>:<CR>")
445 " Change number mode with \n.
446 call Mapping("n", ":call Number(1)<CR>:<CR>")
447 " Expand or shrink window size with \> and \<.
448 call Mapping(">", ":call Resize_Columns('+')<CR>:<CR>")
449 call Mapping("<", ":call Resize_Columns('-')<CR>:<CR>")
450 " Clear search pattern with \/.
451 call Mapping("/", ":let @/=\"\"<CR>:<CR>")
452
453 " Set graphical window title.
454 if has("win32") || has("win64")
455   " Windows taskbar entries are probably too small to show full titles.
456   se titlestring=%t
457 else
458   se titlestring=%{Show_TitleString()}
459 endif
460
461 " Vim tip 99: What's the highlighting group under the cursor?
462 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>")
463
464 fun! Uncluttered_Buffer() "{{{2
465   if exists("uncluttered_buffer")
466     if uncluttered_buffer == 1
467       return 1
468     endif
469   endif
470
471   if version >= "600"
472     if &buftype != ''
473       return 1
474     endif
475   endif
476
477   if &ft == 'perforce'
478     return 1
479   endif
480
481   if &ft == 'svn'
482     return 1
483   endif
484
485   if &ft == 'gitcommit'
486     return 1
487   endif
488
489   return 0
490 endfun "}}}2
491
492 fun! Startup_Resize() "{{{2
493   let l:columns = 0
494
495   " Resize for numbers.
496   if &number
497     if version >= "700" && has("linebreak")
498       let l:columns = &numberwidth
499     else
500       let l:columns = 8
501     endif
502   endif
503
504   " Resize for signs.
505   if has("signs")
506     if g:marksigns
507       if version >= "600"
508         let l:columns = l:columns + 2
509       endif
510     endif
511   endif
512
513   if g:oldcols < (80 + l:columns)
514     call Resize_Columns("+", l:columns)
515   endif
516 endfun "}}}2
517
518 " Change status bar colour when various things happen.
519 " Flags: H/h: Cursor held/moved.
520 "        F/f: Focus gained/lost.
521 "        I/i: Insert mode entered/left.
522 fun! Highlight_StatusLine(flag) "{{{2
523   if ! has("statusline")
524     return
525   endif
526   " Get current status.
527   call Iain_Vars()
528
529   " Change the status based on the flag.  XXX: Does Vim let us to do flags?
530   let l:ic = &ic
531   set ic
532   let b:iainstatus = substitute(b:iainstatus, a:flag, a:flag, "")
533   let &ic = l:ic
534
535   let l:normalcolour = "darkblue"
536   let l:editingcolour = "darkmagenta"
537   let l:warningcolour = "darkred"
538   let l:readonlycolour = "red"
539
540   " Default colour.
541   let l:colour = l:normalcolour
542   " Maybe override depending on status.
543   if b:iainstatus =~# "H"
544     if b:iainstatus =~# "I"
545       " Held in insert mode.  Add extra highlight if we don't have focus.
546       if b:iainstatus =~# "f"
547         let l:colour = l:warningcolour
548       else
549         let l:colour = l:editingcolour
550       endif
551     endif
552   else
553     if b:iainstatus =~# "I"
554       " Regular insert mode.
555       let l:colour = l:editingcolour
556     endif
557   endif
558
559   " Override again if readonly.
560   if l:colour != l:normalcolour
561     if getbufvar("", "&ro")
562       let l:colour = l:readonlycolour
563     endif
564   endif
565
566   let l:termcolour = Iain_Colour(l:colour)
567
568   exec "highlight StatusLine gui=none term=none cterm=none guifg=white guibg=" . l:colour . " ctermfg=white ctermbg=" . l:termcolour
569   exec "highlight User1 gui=bold term=bold cterm=bold guifg=white guibg=" . l:colour . " ctermfg=white ctermbg=" . l:termcolour
570 endfun "}}}2
571
572 fun! Iain_Colour(colour) "{{{2
573   if &t_Co == 88
574     if a:colour == "darkblue"
575       return 17
576     elseif a:colour == "darkmagenta"
577       return 33
578     elseif a:colour == "darkred"
579       return 32
580     elseif a:colour == "red"
581       return 64
582     endif
583   elseif &t_Co == 256
584     if a:colour == "darkblue"
585       return 17
586     elseif a:colour == "darkmagenta"
587       return 90
588     elseif a:colour == "darkred"
589       return 88
590     elseif a:colour == "red"
591       return 196
592     endif
593   else
594     return a:colour
595   endif
596 endfun "}}}2
597
598 if has("autocmd")
599   au StatusLine VimEnter * call Highlight_StatusLine("")
600
601   " Show numbers by default.
602   au Display VimEnter * if ! Uncluttered_Buffer() | call Number(0) | endif
603 endif
604 endif "}}}1
605
606 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
607 " Handle options only available in Vim 5.4 and above.
608 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
609 if version >= "504" "{{{1
610 version 5.4
611
612 " Helper for status line.
613 " Show space, underscore or dollar sign depending on list mode.
614 fun! Show_List() "{{{2
615   call Iain_Vars()
616   if w:iainlist == 0
617     " No list.
618     return " "
619   elseif <SID>Has_Unicode()
620     if w:iainlist == 1
621       " Just tabs.
622       return "»"
623     else
624       " Full list.
625       return "¶"
626     endif
627   else
628     if w:iainlist == 1
629       return "_"
630     else
631       return "\$"
632     endif
633   endif
634 endfun "}}}2
635
636 " Helper for status line.
637 " Show c or C to denote case-sensitivity.
638 fun! Show_Case() "{{{2
639   if &ic
640     return "c"
641   else
642     return "C"
643   endif
644 endfun "}}}2
645
646 " Helper for status line.
647 " Show the size of the tabstop.
648 fun! Show_Tabstop() "{{{2
649   return &ts
650 endfun "}}}2
651
652 " Helper for status line.
653 " Show p when paste mode is on.
654 fun! Show_Paste() "{{{2
655   if &paste
656     return "p"
657   else
658     return ""
659   endif
660 endfun "}}}2
661
662 " Show the status line.
663 fun! Show_StatusLine() "{{{2
664   if ! has("statusline")
665     return
666   endif
667   call Iain_Vars()
668   let l:sl1='%2n\:\ %<%1*%f%0*\ [%{Show_List()}%{Show_Case()}%{Show_Tabstop()}%{Show_Paste()}%Y%M%R]\ '
669   let l:sl3='L:%1*%4.6l%0*/%-4.6L\ C:%1*%3.6c%0*\ \|\ %P'
670   let l:hexformat='%b'
671   if b:iainhex
672     let l:hexformat='0\x%02B'
673   endif
674   if b:iainverbose
675     let l:sl1=l:sl1 . v:version . '\ %='
676     let l:sl2=l:hexformat . '\ \|\ P:%4.6o\ '
677   else
678     let l:sl1=l:sl1 . '%='
679     let l:sl2=''
680   endif
681   exec "set statusline=" . l:sl1 . l:sl2 . l:sl3
682 endfun "}}}2
683
684 " Show the status line for the first time.
685 call Show_StatusLine()
686 endif "}}}1
687
688 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
689 " Handle options only available in Vim 6 and above.
690 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
691 if version >= "600" "{{{1
692 version 6.0
693
694 if has("gui_win32")
695   se encoding=utf-8
696 endif
697
698 " Remember quickfix state.
699 if has("quickfix")
700   let g:quickfixing=0
701 endif
702
703 " Set indenting by filetype.
704 filetype indent on
705
706 " Less intrusive syntax highlighting.
707 if has("syntax")
708   syn enable
709 endif
710
711 " Set colours.
712 if has("gui_running")
713   if has("win32") || has("win64")
714     exe "silent se guifont=DejaVu_Sans_Mono:h10:cANSI"
715   else
716     exe "silent se guifont=DejaVu\\ Sans\\ Mono\\ 10"
717   endif
718 endif
719 if has("gui_running") || &t_Co > 16
720   exe "silent colo iain"
721 endif
722
723 " Ignore whitespace when diffing.
724 if has("diff")
725   se diffopt=filler,iwhite
726 endif
727
728 if has("autocmd")
729   if has("quickfix")
730     " Remember that we are opening the quickfix window.
731     au Mode BufWinEnter quickfix let g:quickfixing=1
732     au Mode BufUnload * if &ft == "qf" | let g:quickfixing=0 | endif
733   endif
734
735   " Allow in-place editing of crontabs.
736   au Mode FileType crontab set backupcopy=yes
737 endif
738
739 " Make * and # work the way you expect in visual mode.
740 vnoremap * y/\V<C-R>=substitute(escape(@@,"/\\"),"\n","\\\\n","ge")<CR><CR>
741 vnoremap # y?\V<C-R>=substitute(escape(@@,"?\\"),"\n","\\\\n","ge")<CR><CR>
742
743 " Set mark and update highlighting.
744 if has("signs")
745   au Signs BufReadPost * call <SID>Highlight_Signs()
746   au Signs CursorHold * call <SID>Highlight_Signs()
747 endif
748
749 " Helper to set buffer variable for a given sign.
750 fun! <SID>Prep_Sign(sign) "{{{2
751   if ! exists("b:sign" . a:sign) || ! g:marksigns
752     exe "let b:sign" . a:sign . "=0"
753    endif
754 endfun "}}}2
755
756 fun! <SID>Place_Sign(number, line, old, name) "{{{2
757   if a:line == a:old
758     return a:old
759   endif
760
761   exe "sign unplace " . (g:firstsign + a:number) . " buffer=" . bufnr("")
762   " Don't place the sign if it would conflict with the last change sign.
763   exe "sign place " . (g:firstsign + a:number) . " line=" . a:line . " name=" . a:name . " buffer=" . bufnr("")
764   return a:line
765 endfun "}}}2
766
767 fun! <SID>Highlight_Signs(...) "{{{2
768   if ! has("signs") || ! g:marksigns || Uncluttered_Buffer()
769     return
770   endif
771
772   let l:signs = g:iainsigns
773   let l:sign = ""
774   let l:i = 0
775   while strlen(l:signs)
776     let l:sign = matchstr(l:signs, '^[A-Za-z]\+\(:.\)*[.=-][^ ]\+')
777
778     let l:name = substitute(l:sign, '[:.=-].*', "", "")
779     let l:var = tolower(l:name)
780     let l:sign = substitute(l:sign, '^[A-Za-z]\+', "", "")
781     let l:ascii = matchstr(l:sign, '^:.')
782     let l:mark = substitute(l:sign, '^\(:.\)*[.=-]', "", "")
783     if strlen(l:ascii)
784       let l:ascii = substitute(l:ascii, '^:', "", "")
785     else
786       let l:ascii = l:mark
787     endif
788     let l:ascii = substitute(l:ascii, '"', '\\"', "")
789
790     call <SID>Prep_Sign(l:var)
791     exe "let " . l:var . " = <SID>Place_Sign(" . l:i . ", line(\"'" . l:ascii . "\"), b:sign" . l:var . ", \"Mark" . l:name . "\")"
792     let l:i = l:i + 1
793
794     let l:signs = substitute(l:signs, '^[^ ]\+ *', "", "")
795   endwhile
796 endfun "}}}2
797
798 " Toggle signs.
799 fun! <SID>Cycle_Signs(resize) "{{{2
800   if ! has("signs")
801     return
802   endif
803   call Iain_Vars()
804   let g:marksigns = ! g:marksigns
805
806   " Retrofit arrays on to Vim 6.
807   if ! exists("g:iainsigns")
808     " Signs are defined in g:iainsigns.  The syntax is as follows:
809     "
810     " Sign ::= Name (':' Mark)* Type Symbol
811     " Type ::= '=' | '-' | '.'
812     "
813     " Signs with Type '=' will be highlighted with the MarkSign group.
814     " Signs with Type '-' will be highlighted with the MarkLine group.
815     " Signs with Type '.' will be highlighted with the MarkDot group.
816     " Define the Mark where Symbol is not also the mark name, eg "']".
817     if <SID>Has_Unicode()
818       let g:iainsigns = "Dash:'=’ Dot:..• Quote:\"=” Caret:^.ʌ"
819     else
820       let g:iainsigns = "Dash=' Dot:..* Quote=\" Caret.^"
821     endif
822     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"
823   endif
824
825   if g:marksigns
826     " Signs to highlight marks.
827     " Syntax won't work properly in Vim 6.
828     let l:signs = g:iainsigns
829     let l:sign = ""
830     while strlen(l:signs)
831       let l:sign = matchstr(l:signs, '^[A-Za-z]\+\(:.\)*[.=-][^ ]\+')
832
833       let l:sign = substitute(l:sign, ':.', "", "")
834       let l:sign = substitute(l:sign, '=', " texthl=MarkSign text=", "")
835       let l:sign = substitute(l:sign, '\.', " texthl=MarkDot text=", "")
836       let l:sign = substitute(l:sign, '-', " texthl=MarkLine linehl=MarkLine text=", "")
837
838       exe "sign define Mark" . l:sign
839
840       let l:signs = substitute(l:signs, '^[^ ]\+ *', "", "")
841     endwhile
842
843     if a:resize
844       call Resize_Columns("+", 2)
845     endif
846     call <SID>Highlight_Signs()
847   else
848     let l:i = 0
849     while l:i < 25
850       exe "sign unplace " . (g:firstsign + l:i)
851       let l:i = l:i + 1
852     endwhile
853
854     let l:signs = g:iainsigns
855     let l:sign = ""
856     while strlen(l:signs)
857       let l:sign = matchstr(l:signs, '^[A-Za-z]\+')
858
859       exe "sign undefine Mark" . l:sign
860       call <SID>Prep_Sign(tolower(l:sign))
861       let l:signs = substitute(l:signs, '^[^ ]\+ *', "", "")
862     endwhile
863
864     if a:resize
865       call Resize_Columns("-", 2)
866     endif
867   endif
868 endfun "}}}2
869
870 " Do we have Unicode?
871 fun! <SID>Has_Unicode() "{{{2
872   if ! has('multi_byte')
873     return 0
874   endif
875
876   if version < "602"
877     return 0
878   endif
879
880   if &tenc =~? '^u\(tf\|cs\)'
881     return 1
882   endif
883
884   if ! strlen(&tenc) && &enc =~? '^u\(tf\|cs\)'
885     return 1
886   endif
887
888   return 0
889 endfun "}}}2
890
891 " Change list mode.
892 fun! Cycle_List() "{{{2
893   " Pretty UTF-8 listchars.
894   if <SID>Has_Unicode()
895     let basic='tab:»·,trail:…,extends:«,precedes:»'
896     let eol='eol:¶'
897     if version >= "700"
898       let basic=basic . ',nbsp:•'
899     endif
900   else
901     let basic='tab:\\_,trail:_,extends:<,precedes:>'
902     let eol='eol:$'
903     if version >= "700"
904       let basic=basic . ',nbsp:+'
905     endif
906   endif
907   call Iain_Vars()
908   let w:iainlist = w:iainlist + 1
909   if w:iainlist > 2
910     let w:iainlist = 0
911   endif
912   if w:iainlist == 0
913     setlocal nolist
914   elseif w:iainlist == 1
915     exec "setlocal lcs=" . basic
916     setlocal list
917   else
918     exec "setlocal lcs=" . basic . "," . eol
919     setlocal list
920   endif
921
922   call Resize_Columns(Extra_Columns("list", "iainlist", " == 2"), 1)
923 endfun "}}}2
924
925 " Cycle between hex and decimal display of toolbar stuff.
926 fun! Cycle_HexStatusLine() "{{{2
927   call Iain_Vars()
928   let b:iainhex = ! b:iainhex
929   call Show_StatusLine()
930 endfun "}}}2
931
932 " Cycle verbose display of toolbar stuff.
933 fun! Cycle_VerboseStatusLine() "{{{2
934   call Iain_Vars()
935   let b:iainverbose = ! b:iainverbose
936   call Show_StatusLine()
937 endfun "}}}2
938
939 " Toggle quickfix window.
940 fun! Cycle_Quickfix() "{{{2
941   if ! has("quickfix")
942     return
943   endif
944   if g:quickfixing == 1
945     cclose
946     let g:quickfixing=0
947   else
948     copen
949   endif
950 endfun "}}}2
951
952 " Swap hex/decimal statusline with \x.
953 call Mapping("x", ":call Cycle_HexStatusLine()<CR>:<CR>")
954 " Change statusline verbosity with \v.
955 call Mapping("V", ":call Cycle_VerboseStatusLine()<CR>:<CR>")
956 " Cycle list styles with \l.
957 call Mapping("l", ":call Cycle_List()<CR>:<CR>")
958 " Toggle tags with \t.
959 call Mapping("t", ":Tlist<CR>")
960 " Change foldmethod with \f.
961 call Mapping("f", ":se foldenable!<CR>:<CR>")
962 " Toggle quickfix window with \q.
963 call Mapping("q", ":call Cycle_Quickfix()<CR>:<CR>")
964 " Rerun filetype detection with \s.  The s is for syntax, as this will be
965 " updated as a side-effect.
966 call Mapping("S", ":filetype detect<CR>:<CR>")
967 " Toggle marks with \m.
968 call Mapping("m", ":call <SID>Cycle_Signs(1)<CR>:<CR>")
969
970 if has("autocmd")
971   " Show signs by default.
972   au Display VimEnter * call <SID>Cycle_Signs(0)
973 endif
974 endif "}}}1
975
976 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
977 " Handle options only available in Vim 7 and above.
978 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
979 if version >= "700" "{{{1
980 version 7.0
981
982 " Helper to show tab name.
983 fun! <SID>TabName(label, gui) "{{{2
984   let l:label = a:label
985   if l:label == ""
986     let l:label = "No Name"
987     if a:gui
988       let l:label = "[" . l:label . "]"
989     endif
990   else
991     let l:label = fnamemodify(l:label, ":t")
992     if strlen(l:label) >= 18
993       let l:label = l:label[0:17] . ".."
994     endif
995   endif
996   return l:label
997 endfun "}}}2
998
999 " Find out if any buffer was modified.
1000 fun! <SID>TabModified(buflist) "{{{2
1001   let l:i = 0
1002   while l:i < len(a:buflist)
1003     if getbufvar(a:buflist[l:i], "&modified") == 1
1004       return "+"
1005     endif
1006     let l:i = l:i + 1
1007   endwhile
1008   return ""
1009 endfun "}}}2
1010
1011 " Tab line.
1012 fun! Show_TabLine() "{{{2
1013   let l:s = "%#TabLineFill#Tabs:"
1014
1015   let l:i = 0
1016   while l:i < tabpagenr("$")
1017     let l:i = l:i + 1
1018     " Get the label.
1019     let l:buflist = tabpagebuflist(l:i)
1020     let l:winnr = tabpagewinnr(l:i)
1021     let l:n = tabpagewinnr(l:i, "$")
1022     let l:label = <SID>TabName(bufname(l:buflist[l:winnr - 1]), 0)
1023     let l:modified = <SID>TabModified(l:buflist)
1024
1025     " Choose highlighting.
1026     if l:i == tabpagenr()
1027       let l:s .= "%#TabLineSel#[" . l:n . l:modified . " " . l:label . "]"
1028     else
1029       let l:s .= "%#TabLine# " . l:n . l:modified . " " . l:label . " "
1030     endif
1031   endwhile
1032
1033   " Padding.
1034   let l:s .= "%#TabLine#%T"
1035   return l:s
1036 endfun "}}}2
1037
1038 " Per tab label for the GUI.
1039 fun! Show_GUITabLine() "{{{2
1040   let l:buflist = tabpagebuflist(v:lnum)
1041   let l:winnr = tabpagewinnr(v:lnum)
1042   let l:s = tabpagewinnr(v:lnum, "$")
1043   let l:label = <SID>TabName(bufname(l:buflist[l:winnr - 1]), 1)
1044   let l:modified = <SID>TabModified(l:buflist)
1045
1046   let l:s .= l:modified . " " . l:label
1047   return l:s
1048 endfun "}}}2
1049
1050 " Toggle highlighting cursor line when focus changes.
1051 fun! <SID>ToggleCursorLine() "{{{2
1052   call Iain_Vars()
1053
1054   if b:iainstatus =~# "f" && b:iainstatus =~# "H" && b:iainstatus =~# "I"
1055     " Focus lost while held in insert mode.
1056     let b:iaincul = getbufvar("", "&cursorline")
1057     setlocal cursorline
1058   elseif ! b:iaincul
1059     setlocal nocursorline
1060   endif
1061 endfun "}}}2
1062
1063 if has("windows")
1064   se tabline=%!Show_TabLine()
1065   se guitablabel=%!Show_GUITabLine()
1066 endif
1067
1068 if has("autocmd")
1069   au StatusLine CursorHoldI * call Highlight_StatusLine("H")
1070   au StatusLine CursorMovedI * call Highlight_StatusLine("h")
1071   au StatusLine FocusGained * call Highlight_StatusLine("F")
1072   au StatusLine FocusLost * call Highlight_StatusLine("f")
1073   au StatusLine InsertEnter * call Highlight_StatusLine("I")
1074   au StatusLine InsertLeave * call Highlight_StatusLine("i")
1075
1076   if has("syntax")
1077     au Display FocusGained,FocusLost * call <SID>ToggleCursorLine()
1078   endif
1079
1080   if has("signs")
1081     au Signs InsertEnter * call <SID>Highlight_Signs()
1082     au Signs InsertLeave * call <SID>Highlight_Signs()
1083   endif
1084 endif
1085
1086 " Limit the size of the popup menu when completing.
1087 if has("insert_expand")
1088   se pumheight=20
1089 endif
1090
1091 " Make diffs vertical by default.
1092 if has("diff")
1093   se diffopt+=vertical
1094 endif
1095
1096 " Set size of numbers column.
1097 if has("linebreak")
1098   se numberwidth=5
1099 endif
1100
1101 " Add "previous tab" mapping as gb.
1102 map gb :tabprevious<CR>:<CR>
1103
1104 " Transparency.
1105 if has("gui_macvim")
1106   se transparency=15
1107 endif 
1108
1109 " Yet more GUI options.  Add tabs.
1110 if has("gui")
1111   se go+=e
1112 endif
1113
1114 " Perforce.
1115 let g:p4EnableMenu=1
1116 let g:p4Presets='P4CONFIG'
1117
1118 " BufExplorer.
1119 let g:bufExplorerShowRelativePath=1
1120 let g:bufExplorerSplitOutPathName=0
1121 endif "}}}1
1122
1123 " Resize after startup.
1124 if version >= "500" "{{{1
1125 if has("autocmd")
1126   au Display VimEnter * call Startup_Resize()
1127 endif
1128 endif "}}}1