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