aboutsummaryrefslogtreecommitdiff
path: root/vim/vimrc
blob: 15365dde6d07dded35b1d09c4739ad77e457973e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
" Don't make any effort to be compatible with vi, use more sensible settings
set nocompatible

" If our version isn't ancient and Pathogen is available, call it to load all
" the plugins in .vim/bundle; these are saved as submodules
if v:version >= 701
  silent! call pathogen#infect()
  silent! call pathogen#helptags()
endif

" Load plugins and indentation for file types
if has('autocmd')
  filetype indent plugin on

  " Shortcuts to quickly switch to common file types; handy when using
  " editing abstractions like sudoedit(8)
  nnoremap _ap :setlocal filetype=apache<CR>
  nnoremap _bi :setlocal filetype=bindzone<CR>
  nnoremap _cs :setlocal filetype=css<CR>
  nnoremap _ht :setlocal filetype=html<CR>
  nnoremap _js :setlocal filetype=javascript<CR>
  nnoremap _md :setlocal filetype=markdown<CR>
  nnoremap _pl :setlocal filetype=perl<CR>
  nnoremap _ph :setlocal filetype=php<CR>
  nnoremap _py :setlocal filetype=python<CR>
  nnoremap _rb :setlocal filetype=ruby<CR>
  nnoremap _sh :setlocal filetype=sh<CR>
  nnoremap _vi :setlocal filetype=vim<CR>
  nnoremap _xm :setlocal filetype=xml<CR>
endif

" Use backup features if on a UNIX-like system and not using sudo(8)
if !strlen($SUDO_USER) && has('unix')

  " Keep backups with a .bak extension in ~/.vim/backup; the double-slash at
  " the end of the directory is supposed to prod Vim into keeping the full
  " path to the file in its backup filename to avoid collisions, but I don't
  " think it actually works for backups, just undo and swap files
  set backup
  set backupext=.bak
  set backupdir^=~/.vim/backup//

  " This option already includes various temporary directories, but we
  " append to it so that we don't back up anything in a shared memory
  " filesystem either
  set backupskip+=*/shm/*

  " Create the backup directory if necessary and possible
  if !isdirectory($HOME . '/.vim/backup') && exists('*mkdir')
    call mkdir($HOME . '/.vim/backup', 'p', 0700)
  endif

" Don't use backups at all otherwise
else
  set nobackup
  set nowritebackup
endif

" Options dependent on the syntax feature
if has('syntax')

  " Use syntax highlighting
  syntax enable

  " Use my custom color scheme if possible, otherwise I'm happy with whatever
  " the default is, and it usually cares about my background
  set background=dark
  silent! colorscheme sahara
endif

" Command-line based features
if has('cmdline_info')

  " Show my current position in the status bar
  set ruler

  " Show the keystrokes being entered in the screen
  set showcmd

  " Show the mode we're using if not normal mode (e.g. --INSERT--)
  set showmode
endif

" Don't try to complete strings from included files, just use the strings in
" the open buffers; I'll open the file if I want to complete from it
set complete-=i

" Rebind Ctrl-C in insert mode to undo the current insert operation
inoremap <C-c> <C-c>u

" A few very important custom digraphs
if has('digraphs')
  digraph ./ 8230  " Ellipsis (HORIZONTAL ELLIPSIS U+2026)
  digraph %% 8984  " Mac command key (PLACE OF INTEREST SIGN U+2318)
  digraph 8: 9731  " Snowman (SNOWMAN U+2603)
endif

" Try Mac line-endings if UNIX or DOS don't make sense; this has never
" happened to me but who knows, it might one day
set fileformats+=mac

" Use UTF-8 by default wherever possible
if has('multi_byte')
  set encoding=utf-8
endif

" Adopt the indent of the last line on new lines; interestingly, plugins that
" do clever things with indenting will often assume this is set
set autoindent

" Use spaces instead of tabs
set expandtab

" Indent with four spaces when an indent operation is used
set shiftwidth=4

" Insert four spaces when Tab is pressed
set softtabstop=4

" How many spaces to show for a literal tab when 'list' is unset
set tabstop=4

" Indent intelligently to 'shiftwidth' at the starts of lines with Tab, but
" use 'tabstop' everywhere else
set smarttab

" When indenting lines with < or >, round the indent to a multiple of
" 'shiftwidth', so even if the line is indented by one space it will indent
" up to 4 and down to 0, for example
set shiftround

" Don't join lines with two spaces at the end of sentences; I don't two-space,
" despite the noble Steve Losh's exhortations
set nojoinspaces

" Don't jump my screen around when I join lines, keep my cursor in the same
" place; this is done by dropping a mark first and then immediately returning
" to it; note that it wipes out your z mark, if you happen to use it
nnoremap J mzJ`z

" If we can, add j to the format options to get rid of comment leaders when
" joining lines
if v:version > 703 || v:version == 703 && has('patch541')
  set formatoptions+=j
endif

"
" Quick way to toggle flags in 'formatoptions' that I often want to change;
" specifically:
"
" a - Automatically format paragraphs, reapplying the wrap on every text
"     insertion or deletion; sometimes I want this and sometimes I
"     don't, it particularly varies when typing prose in Markdown that
"     includes headings and code
" c - Automatically wrap comments at 'textwidth' (which I allow the filetypes
"     to set for me)
" t - Automatically wrap text at 'textwidth' (as above)
"
" So I just have to type e.g. \a to toggle the auto-format flag on and off;
" very handy
"
if has('eval')
  function! ToggleFormatFlag(flag)
    let l:operation = (&formatoptions =~ a:flag) ? '-=' : '+='
    silent! exec 'setlocal formatoptions' . l:operation . a:flag
    setlocal formatoptions?
  endfunction
  nnoremap <silent> <leader>a :<C-U>call ToggleFormatFlag('a')<CR>
  nnoremap <silent> <leader>c :<C-U>call ToggleFormatFlag('c')<CR>
  nnoremap <silent> <leader>t :<C-U>call ToggleFormatFlag('t')<CR>
endif

" Strip trailing whitespace with \x
if has('eval')
  function! StripTrailingWhitespace()
    let l:search = @/
    %substitute/\s\+$//e
    let @/ = l:search
    nohlsearch
  endfunction
  nnoremap <silent> <leader>x :<C-U>call StripTrailingWhitespace()<CR>
endif

" Keep plenty of command and search history, because disk space is cheap
set history=2000

" Don't show whitespace characters or end-of-line characters visually by
" default, but make \l toggle between them
set nolist
nnoremap <leader>l :setlocal list!<CR>

" Try to run the version of matchit.vim included in the distribution, if there
" is one; extends % to match more than it does by default
silent! runtime macros/matchit.vim

" Match all forms of brackets in pairs (including angle brackets)
set matchpairs=(:),{:},[:],<:>

" Don't show the Vim startup message, I have registered Vim and donated to
" Uganda
set shortmess+=I

" Let me backspace over pretty much anything, even if it's not text I inserted
" in the current session
set backspace=indent,eol,start

" Don't use modelines at all, they're apparently potential security problems
" and I've never used them anyway
set nomodeline

" Don't assume a number with a leading zero is octal; it's far more likely a
" zero-padded decimal, so increment and decrement with ^A and ^X on that basis
set nrformats-=octal

" Always tell me the number of lines changed by a command
set report=0

" Always use forward slashes, I very seldom need to use Vim on Windows for
" more than scratch space anyway
set shellslash

" Don't show line numbers by default, but \n toggles them
set nonumber
nnoremap <leader>n :setlocal number!<CR>

" Start paste mode with F10 to prevent console Vim from confusing a swathe of
" pre-formatted pasted text with actual keyboard input, and thereby attempting
" to indent it inappropriately. If unimpaired.vim is available, it's generally
" nicer to use yo or yO.
set nopaste
set pastetoggle=<F10>

" If the Vim buffer for a file doesn't have any changes and Vim detects the
" file has been altered, quietly update it
set autoread

" Save a file automatically if I change buffers or perform operations with the
" argument list; this is particularly helpful for me as I don't use 'hidden'
set autowrite

" Allow the cursor to get to the top or bottom of the screen before scrolling
" vertically, but set a reasonably wide gutter for scrolling horizontally; no
" particular reason, just suits me better
set scrolloff=0
set sidescrolloff=16

" Some special settings for searching, if available
if has('extra_search')

  " Searching as I enter my pattern, \i toggles this
  set incsearch
  nnoremap <leader>i :set incsearch!<CR>

  " Highlight search results, \h toggles this
  set hlsearch
  nnoremap <leader>h :set hlsearch!<CR>

  " Pressing ^L will clear highlighting until the next search-related
  " operation; quite good because the highlighting gets distracting after
  " you've found what you wanted
  nnoremap <silent> <C-l> :nohlsearch<CR><C-l>

  " Clear search highlighting as soon as I enter insert mode, and restore it
  " once I leave it
  if has('autocmd')
    augroup highlight
      autocmd!
      silent! autocmd InsertEnter * set nohlsearch
      silent! autocmd InsertLeave * set hlsearch
    augroup END
  endif
endif

" Configure spell checking features, if available
if has('spell')

  " Don't check spelling by default, but bind \s to toggle this
  set nospell
  nnoremap <leader>s :setlocal spell!<CR>

  " Use New Zealand English for spelling by default (it's almost identical
  " to British English), but bind \u to switch to US English and \z to
  " switch back
  set spelllang=en_nz
  nnoremap <leader>u :setlocal spelllang=en_us<CR>
  nnoremap <leader>z :setlocal spelllang=en_nz<CR>
endif

" Don't keep .viminfo information for files in temporary directories or shared
" memory filesystems; this is because they're used as scratch spaces for tools
" like sudoedit(8) and pass(1) and hence could present a security problem
if has('viminfo') && has('autocmd')
  augroup viminfoskip
    autocmd!
    silent! autocmd BufNewFile,BufReadPre
        \ /tmp/*,$TMPDIR/*,$TMP/*,$TEMP/*,*/shm/*
        \ setlocal viminfo=
  augroup END
endif

" Preserve the flags for a pattern when repeating a substitution with &; I don't
" really understand why this isn't a default, but there it is
nnoremap & :&&<CR>
vnoremap & :&&<CR>

" Swap files are used if using Unix and not using sudo(8); I very seldom need
" them, but they are occasionally useful after a crash, and they don't really
" get in the way if kept in their own directory
if !strlen($SUDO_USER) && has('unix')

  " Use swap files but keep them in ~/.vim/swap; the double-slash at the end
  " of the directory prods Vim into keeping the full path to the file in its
  " undo filename to avoid collisions; the same thing works for undo files
  set swapfile
  set directory^=~/.vim/swap//

  " Create the ~/.vim/swap directory if necessary and possible
  if !isdirectory($HOME . '/.vim/swap') && exists('*mkdir')
    call mkdir($HOME . '/.vim/swap', 'p', 0700)
  endif

  " Don't keep swap files for files in temporary directories or shared memory
  " filesystems; this is because they're used as scratch spaces for tools
  " like sudoedit(8) and pass(1) and hence could present a security problem
  if has('autocmd')
    augroup swapskip
      autocmd!
      silent! autocmd BufNewFile,BufReadPre
          \ /tmp/*,$TMPDIR/*,$TMP/*,$TEMP/*,*/shm/*
          \ setlocal noswapfile
    augroup END
  endif

" Otherwise, don't use swap files at all
else
  set noswapfile
endif

" Don't bother about checking whether Escape is being used as a means to enter
" a Meta-key combination, just register Escape immediately
set noesckeys

" Don't bother drawing the screen while executing macros or other automated or
" scripted processes, just draw the screen as it is when the operation
" completes
set lazyredraw

" Improve redrawing smoothness by assuming that my terminal is reasonably
" fast
set ttyfast

" Never use any kind of bell, visual or not
set visualbell t_vb=

" Require less than one second between keys for mappings to work correctly
set timeout
set timeoutlen=1000

" Require less than a twentieth of a second between keys for key codes to work
" correctly; I don't use Escape as a meta key anyway
set ttimeout
set ttimeoutlen=50

" Tolerate typos like :Wq, :Q, or :Qa and do what I mean, including any
" arguments or modifiers; I fat-finger these commands a lot because I type
" them so rapidly, and they don't correspond to any other commands I use
if has('user_commands')
  command! -bang -complete=file -nargs=? E e<bang> <args>
  command! -bang -complete=file -nargs=? W w<bang> <args>
  command! -bang -complete=file -nargs=? WQ wq<bang> <args>
  command! -bang -complete=file -nargs=? Wq wq<bang> <args>
  command! -bang Q q<bang>
  command! -bang Qa qa<bang>
  command! -bang QA qa<bang>
  command! -bang Wa wa<bang>
  command! -bang WA wa<bang>
endif

" Keep screeds of undo history
set undolevels=2000

" Keep undo history in a separate file if the feature is available, we're on
" Unix, and not using sudo(8); this goes really well with undo visualization
" plugins like Gundo or Undotree.
if !strlen($SUDO_USER) && has('unix') && has('persistent_undo')

  " Keep per-file undo history in ~/.vim/undo; the double-slash at the end
  " of the directory prods Vim into keeping the full path to the file in its
  " undo filename to avoid collisions; the same thing works for swap files
  set undofile
  set undodir^=~/.vim/undo//

  " Create the ~/.vim/undo directory if necessary and possible
  if !isdirectory($HOME . '/.vim/undo') && exists('*mkdir')
    call mkdir($HOME . '/.vim/undo', 'p', 0700)
  endif

  " Don't track changes to sensitive files
  if has('autocmd')
    augroup undoskip
      autocmd!
      silent! autocmd BufWritePre
          \ /tmp/*,$TMPDIR/*,$TMP/*,$TEMP/*,*/shm/*
          \ setlocal noundofile
    augroup END
  endif
endif

" When in visual block mode, let me move the cursor anywhere in the buffer;
" don't restrict me only to regions with text
if has('virtualedit')
  set virtualedit+=block
endif

" Configuration for the command completion feature; rather than merely cycling
" through possible completions with Tab, show them above the command line
if has('wildmenu')

  " Use the wild menu, both completing and showing all possible completions
  " with a single Tab press, just as I've configured Bash to do
  set wildmenu
  set wildmode=longest:list

  " Don't complete certain files that I'm not likely to want to manipulate
  " from within Vim:
  if has('wildignore')
    set wildignore+=*.a,*.o
    set wildignore+=*.bmp,*.gif,*.ico,*.jpg,*.png
    set wildignore+=.DS_Store,.git,.hg,.svn
    set wildignore+=*~,*.swp,*.tmp
  endif

  " Complete files without case sensitivity, if the option is available
  if exists('&wildignorecase')
    set wildignorecase
  endif
endif

" Configuration for window features
if has('windows')

  " Show the status in a distinct bar above the command line only if there's
  " more than one window on the screen or in the current tab
  set laststatus=1

  " Don't resize windows we're not splitting (Tmux-like; think Mondrian)
  set noequalalways

  " New split windows appear below or to the right of the existing window,
  " not above or to the left per the default
  set splitbelow
  if has('vertsplit')
    set splitright
  endif

  " Only show the tab bar if there's more than one tab
  if exists('&showtabline')
    set showtabline=1
  endif

  " Get rid of visually noisy folding characters
  if has('folding')
    let &fillchars = 'diff: ,fold: ,vert: '
  endif
endif

" Use the tilde as an operator with motions, rather than just swapping the
" case of the character under the cursor
set tildeop

" When wrapping text, if a line is so long that not all of it can be shown on
" the screen, show as much as possible anyway; by default Vim fills the left
" column with @ symbols instead, which I don't find very helpful
set display=lastline

" Don't wrap by default, but use \w to toggle it on or off quickly
set nowrap
nnoremap <leader>w :set wrap!<CR>

" Clearly show when the start or end of the row does not correspond to the
" start and end of the line
set listchars+=precedes:<,extends:>

" Don't write the output of :make to the terminal
set shellpipe=>

" When wrapping, j and k should move by screen row, and not to the same
" column number in the previous logical line, which feels very clumsy and is
" seldom particularly helpful; you can use n| to jump to the nth column in a
" line anyway if you need to
nnoremap j gj
nnoremap k gk

" Break lines at word boundaries if possible and not simply at the last
" character that will fit on the screen, preceding the next line with three
" periods to make it obvious that it's a continuation of the previous line
if has('linebreak')
  set linebreak
  set showbreak=...

  " Bind \b to turn off linebreak and toggle the showbreak characters on and
  " off for convenience of copypasting multiple lines from terminal emulators.
  if has('eval')
    function! ToggleBreak()
      if &linebreak
        set nolinebreak
        set showbreak=
      else
        set linebreak
        set showbreak=...
      endif
    endfunction
    nnoremap <silent> <leader>b :<C-U>call ToggleBreak()<CR>
  endif
endif

" I really like ZZ and ZQ, so I wrote a couple more mappings; ZW forces a
" write of the current buffer, but doesn't quit, and ZA forces a write of all
" buffers but doesn't quit
nnoremap ZW :w!<CR>
nnoremap ZA :wa!<CR>

" Change and delete with C and D both cut off the remainder of the line from
" the cursor, but Y yanks the whole line, which is inconsistent (and can be
" done with yy anyway); this fixes it so it only yanks the rest of the line
nnoremap Y y$

" Allow jumping between windows and tabs to find an open instance of a given
" buffer with :sbuffer.
if v:version >= 701
  set switchbuf=useopen,usetab
else
  set switchbuf=useopen
endif

" Fedora's default environment adds a few auto commands that I don't like,
" including the 'return to previous position in buffer' one; fortunately
" they're nice enough to group the commands, so I can just clear them
if has('autocmd')
  augroup fedora
    autocmd!
  augroup END
endif

" When opening a large file, take some measures to keep things loading quickly
if has('eval') && has('autocmd')

  " Threshold is 10 MiB
  let g:bigfilesize = 10 * 1024 * 1024

  " Declare function for turning off slow options
  function! BigFileMeasures()
    let l:file = expand('<afile>')
    if getfsize(l:file) > g:bigfilesize
      setlocal nobackup
      setlocal nowritebackup
      setlocal noswapfile
      if has('persistent_undo')
        setlocal noundofile
      endif
      if exists('&synmaxcol')
        setlocal synmaxcol=256
      endif
    endif
  endfunction

  " Define autocmd for calling to check filesize
  augroup bigfilesize
    autocmd!
    autocmd BufReadPre * call BigFileMeasures()
  augroup end
endif