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