aboutsummaryrefslogtreecommitdiff
path: root/vim/vimrc
blob: a526c1f27a947ead64b487b24b25532a9ae032b9 (plain) (blame)
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
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
"
" Tom Ryder (tejr)'s vimrc
" ------------------------
"
" <https://sanctum.geek.nz/cgit/dotfiles.git>
"
" This is a 'literate vimrc', in the Donald Knuth tradition.  It's long, and
" comments abound.
"
" This file should be saved as "vimrc" in the user runtime directory. (UNIX
" ~/.vim, Windows ~/vimfiles).  It requires Vim 7.0 or newer with +eval, not
" running in &compatible mode.  The vimrc stub (UNIX ~/.vimrc, Windows
" ~/_vimrc) that loads this file checks that these two conditions are met.
"
" > And I was lifted up in heart, and thought
" > Of all my late-shown prowess in the lists,
" > How my strong lance had beaten down the knights,
" > So many and famous names; and never yet
" > Had heaven appeared so blue, nor earth so green,
" > For all my blood danced in me, and I knew
" > That I should light upon the Holy Grail.
" > --Tennyson
"

" Set an environment variable MYVIM for the user runtime directory, if such
" a variable does not already exist in the environment, and there's a value in
" 'runtimepath' from which to glean a useable path.  We'll use the path
" nominated in the MYVIM variable as the root of our 'backupdir', 'directory',
" 'undodir', and 'viminfofile' caches.
"
" I think the absence of a variable like this is a glaring omission from Vim.
" We have $VIM, $VIMRUNTIME, and $MYVIMRC, so why is there not an environment
" variable for the first runtime directory?  It's a mystery, and that's why so
" is mankind.
"
if !exists('$MYVIM') && &runtimepath !=# ''

  " We'll use the first path specified in 'runtimepath', rather like Vim
  " itself does for spelling database files in the absence of a setting for
  " 'spellfile'.
  "
  let s:runtimepath_paths = vimrc#SplitOption(&runtimepath)
  let $MYVIM = s:runtimepath_paths[0]

endif

" Global indent settings go here.  Filetype indent plugins will often refine
" these settings for individual buffers.  For example, 'expandtab' is not
" appropriate for Makefiles, nor for the Go programming language.  For
" another, two-space indents are more traditional for Vim script.
"
" In general, however, I prefer spaces to tabs as a default, and I like to use
" four of them, for a more distinct visual structure.  Should you happen to
" disagree with this, I cordially invite you to fite me irl.
"
" <https://sanctum.geek.nz/blinkenlights/spaces.webm>
"
set autoindent    " Use indent of previous line on new lines
set expandtab     " Use spaces instead of tabs
set shiftwidth=4  " Indent with four spaces

" Apply 'softtabstop' option to make a tab key press in insert mode insert the
" same number of spaces as defined by the indent depth in 'shiftwidth'.  If
" Vim is new enough to support it (v7.3.693), apply a negative value to do
" this dynamically if 'shiftwidth' changes.
"
let &softtabstop = vimrc#Version('7.3.693') ? -1 : &shiftwidth

" Relax traditional vi's harsh standards over what regions of the buffer can
" be removed with backspace in insert mode.  While this admittedly allows bad
" habits to continue, since insert mode by definition is not really intended
" for deleting text, I feel the convenience outweighs that in this case.
"
set backspace+=eol     " Line breaks
set backspace+=indent  " Leading whitespace characters created by 'autoindent'
set backspace+=start   " Text before the start of the current insertion

" Enable automatic backups of most file buffers.  In practice, I don't need
" these backups very much if I'm using version control sensibly, but they have
" still saved my bacon a few times.
set backup

" Try to keep the aforementioned backup files in a dedicated cache directory,
" to stop them proliferating next to their prime locations, and thereby
" getting accidentally committed to Git repositories.
"
" If Vim is new enough (v8.1.251), add two trailing slashes to the path we're
" inserting, which prompts Vim to incorporate the full escaped path in the
" backup filename, avoiding collisions.
"
" As a historical note, other similar directory path list options supported
" this trailing slashes hint for a long time before 'backupdir' caught up to
" them.  The 'directory' option for swapfiles has supported it at least as far
" back as v5.8.0 (2001), and 'undodir' appears to have supported it since its
" creation in v7.2.438.  Even though the :help for 'backupdir' didn't say so,
" people assumed it would work the same way, when in fact Vim simply ignored
" it until v8.1.251.
"
" I don't want to add the slashes to the option value in older versions of Vim
" where they don't do anything, so I check the version before I add them.
"
" It's all so awkward.  Surely options named something like 'backupfullpath',
" 'swapfilefullpath', and 'undofullpath' would have been clearer.
"
let s:backupdir = $MYVIM.'/cache/backup'
if vimrc#Version('8.1.251')
  let s:backupdir .= '//'
endif
execute 'set backupdir^='.vimrc#EscapeSetPart(s:backupdir)

" Create the first path in the 'backupdir' list, the one we just added, if it
" doesn't already exist.  It isn't created automatically, which is by design.
"
call vimrc#Ensure(&backupdir)

" Files in certain directories on UNIX-compatible filesystems should not be
" backed up for reasons of privacy, or an intentional ephemerality, or both.
" On the systems I use, this is particularly important if editing temporary
" files created by sudoedit(8).  We add a few paths to the default value
" of 'backupskip' to prevent the creation of such undesired backup files.
"
if has('unix')

  " * /dev/shm: RAM disk, default path for password-store's temporary files
  " * /usr/tmp: Hard-coded path for sudoedit(8) [1/2]
  " * /var/tmp: Hard-coded path for sudoedit(8) [2/2]
  "
  let s:backupskip_patterns = [
        \ '/dev/shm/*'
        \,'/usr/tmp/*'
        \,'/var/tmp/*'
        \ ]

  " Vim doesn't seem to check patterns added to 'backupskip' for uniqueness,
  " so adding them repeatedly if this file is reloaded results in duplicates.
  " This might be a bug in Vim.  To work around this, we attempt to remove
  " each pattern before we add it.
  "
  " We sort and add them backwards only so that they're in alphabetical order
  " in the final option!
  "
  for s:pattern in reverse(sort(s:backupskip_patterns))
    execute 'set backupskip-='.vimrc#EscapeSetPart(s:pattern)
    execute 'set backupskip^='.vimrc#EscapeSetPart(s:pattern)
  endfor

endif

" The visual structure of code provided by indents breaks down if a lot of the
" lines wrap.  Ideally, most if not all lines would be kept below 80
" characters, but in cases where this isn't possible, soft-wrapping longer
" lines when 'wrap' is on so that the indent is preserved in the following
" line mitigates this somewhat.
"
" This option wasn't added until v7.4.338, so we need to check it exists
" before we set it.
"
if exists('+breakindent')
  set breakindent
endif

" vi was often used for development in the C programming language.  The
" default values for a lot of Vim's options still reflect this common use
" pattern.  In this case, the 'comments' and 'commentstring' options reflect
" the C syntax for comments:
"
"     /*
"      * This is an ANSI C comment.
"      */
"
" Similarly, the 'define' and 'include' options default to C preprocessor
" directives:
"
"     #define FOO "bar"
"     #include "baz.h"
"
" Times change, however, and I don't get to work with C nearly as much as I'd
" like; the defaults for these options no longer make sense, and so we blank
" them, compelling filetype plugins to set them as they need instead.
"
set comments= commentstring= define= include=

" Rather than rejecting operations like :write or :saveas when 'readonly' is
" set, and other situations in which data might be lost or I'm acting against
" an option, Vim should give me a prompt to allow me to confirm that I know
" what I'm doing.
"
set confirm

" After staunchly opposing it for years, I have converted to two-spacing.  You
" can blame Steve Losh:
"
" <http://stevelosh.com/blog/2012/10/why-i-two-space/>
"
" Consequently, we specify that sentence objects for the purposes of the 's'
" text object, the '(' and ')' sentence motions, and formatting with the 'gq'
" command must be separated by *two* spaces.  One space does not suffice.
"
" My defection to the two-spacers is the reason I now also leave 'joinspaces'
" set, per its default, so that two spaces are inserted when consecutive
" sentences separated by a line break are joined onto one line by the 'J'
" command.
"
set cpoptions+=J

" For word completion in insert mode with CTRL-X CTRL-K, or if 'complete'
" includes the 'k' flag, this specifies the path to the system dictionary to
" find words.  This makes the dictionary completion work consistently, even if
" 'spell' isn't set at that moment.
"
" At some point, I may end up having to set this option along with 'spellfile'
" a bit more intelligently to ensure that spell checking and dictionary
" function consistently with reference to the same resources.
"
set dictionary^=/usr/share/dict/words

" Keep swap files for file buffers in a dedicated directory, rather than the
" default of writing them to the same directory as the buffer file.  Add two
" trailing slashes to the path to prompt Vim to use the full escaped path in
" its name, in order to avoid filename collisions.
"
let s:directory = $MYVIM.'/cache/swap'.'//'
execute 'set directory^='.vimrc#EscapeSetPart(s:directory)

" Create the first path in the 'directory' swapfile path list, the one we just
" added, if it doesn't already exist.  It isn't created automatically, which
" is by design.
"
call vimrc#Ensure(&directory)

" On Unix, I keep LANG defined in my environment, and it's almost always set
" to a multibyte (UTF-8) locale.  This informs Vim's choice of internal
" character encoding, but the default for the 'encoding' option is latin1,
" which is seldom what I want, and if I do want it, I'll specify it with LANG
" or possibly a manual :set command.  UTF-8 makes much more sense as a default
" encoding if Vim can't glean what I want from LANG.
"
if !exists('$LANG')
  set encoding=utf-8
endif

" If Vim receives an Escape key code in insert mode, it shouldn't wait to see
" if it's going to be followed by another key code, despite this being how the
" function keys and Meta/Alt modifier are implemented for many terminal types.
" Otherwise, if I press Escape, there's an annoying delay before 'showmode'
" stops showing "--INSERT--".
"
" This breaks the function keys and the Meta/Alt modifier in insert mode in
" most or maybe all of the terminals I use, but I don't want those keys in
" insert mode anyway.  It all works fine in the GUI, of course.
"
" There's no such option as 'esckeys' in Neovim, which I gather has completely
" overhauled its method of keyboard event handling, so we need to check
" whether the option exists before we try to set it.
"
if exists('+esckeys')
  set noesckeys
endif

" By default, figuring out where a region of text to fold away should be done
" by the indent level of its lines, since I tend to be careful about my
" indentation even in languages where it has no structure significance.
"
set foldmethod=indent

" That said, I don't want any folding to actually take place unless
" I specifically ask for it.  I think of a Vim window with a file buffer
" loaded as a two-dimensional planar view of the file, so that moving down one
" screen line means moving down one buffer line, at least when 'wrap' is
" unset.  Folds break that mental model, and so I usually enable them
" explicitly only when I'm struggling to grasp some in-depth code with very
" long functions or loops.
"
" Therefore, we set the depth level at which folds should automatically start
" as closed to a rather high number, per the documentation's recommendations.
"
set foldlevelstart=99

" Automatic text wrapping options using flags in the 'formatoptions' option
" begin here.  I allow filetypes to set 't' and 'c' to configure whether text
" or comments should be wrapped, and don't mess with it here.
"
" If a line is already longer than 'textwidth' would otherwise limit when
" editing of that line begins in insert mode, don't suddenly automatically
" wrap it.
"
set formatoptions+=l

" Don't wrap a line in such a way that a single-letter word like "I" or "a" is
" at the end of it.  Typographically, as far as I can tell, this seems to be
" a stylistic preference rather than a rule like avoiding "widow" and "orphan"
" lines in typesetting.  I think it generally looks better to have the short
" word start the line.
"
set formatoptions+=1

"
if vimrc#Version('7.3.541')
  set formatoptions+=j  " Delete comment leaders when joining lines
endif
if vimrc#Version('8.1.728')
  set formatoptions+=p  " Don't break a single space after a period
endif

" Don't load GUI menus; set here before GUI starts or any filetype or syntax
" logic is performed
if has('gui_running')
  set guioptions+=M
endif

" Allow buffers to have changes without being displayed
set hidden

" Keep much more command and search history
set history=2000

" Highlight completed searches; clear on reload
set hlsearch
nohlsearch

" Don't assume I'm editing C; let the filetype set this

" Show search matches as I type my pattern
set incsearch

" Don't show a status line if there's only one window
" This is Vim's default, but not Neovim's
set laststatus=1

" Don't redraw the screen during batch execution
set lazyredraw

" Break lines at word boundaries
set linebreak

" Define extra 'list' display characters
set listchars&vi  " Neovim adds duplicates otherwise
set listchars+=tab:>-      " Tab characters, preserve width
set listchars+=trail:-     " Trailing spaces
set listchars+=extends:>   " Unwrapped text to screen right
set listchars+=precedes:<  " Unwrapped text to screen left
set listchars+=nbsp:+      " Non-breaking spaces

" Show matching brackets a bit more briefly
set matchtime=3

" Don't allow setting options via buffer content
set nomodeline

" Treat numbers with a leading zero as decimal, not octal
set nrformats-=octal

" Don't search /usr/include by default
set path-=/usr/include

" Disable command line display of file position if a system vimrc or Neovim
" has switched it on
set noruler

" Remove Debian's 'runtimepath' addenda if present
set runtimepath-=/var/lib/vim/addons
set runtimepath-=/var/lib/vim/addons/after

" Make sessions usable
set sessionoptions-=localoptions  " No buffer options or mappings
set sessionoptions-=options       " No global options or mappings

" Don't show startup splash screen (I donated)
set shortmess+=I

" Prefix wrapped rows with three dots
set showbreak=...

" Jump to matching bracket when typed in insert mode
set showmatch

" New window positioning
set splitbelow  " Below the current window, not above
set splitright  " Right of the current window, not left

" Don't try to syntax highlight run-on lines
set synmaxcol=500

" Add thesaurus; install with `make install-vim-thesaurus`
execute 'set thesaurus^='.vimrc#EscapeSetPart($MYVIM.'/ref/thesaurus.txt')

" PuTTY is a fast terminal, but Vim doesn't know that yet
if &term =~# '^putty'
  set ttyfast
endif

" Don't use terminal mouse support, even if it would work; the manual says to
" set 't_RV' to do this, but that doesn't seem to work
if exists('+ttymouse')  " No such option in Neovim
  set ttymouse=
endif

" Keep persistent undo files in dedicated directory, named with full path
if has('persistent_undo')  " v7.2.438
  set undofile
  execute 'set undodir^='.vimrc#EscapeSetPart($MYVIM.'/cache/undo//')
  call vimrc#Ensure(&undodir)
endif

" Keep the viminfo file in the home Vim directory, mostly to stop history
" getting clobbered when something runs Vim without using this vimrc
if exists('+viminfofile')  " Use new option method if we can (v8.1.716)
  set viminfofile=$MYVIM/cache/viminfo
else  " Resort to clunkier method with 'viminfo' option flag
  execute 'set viminfo+='.vimrc#EscapeSet('n'.$MYVIM.'/cache/viminfo')
endif

" Let me move beyond buffer text in visual block mode
set virtualedit+=block

" Never beep at me
set visualbell t_vb=

" Tab completion settings
set wildignore=*~,#*#,*.7z,.DS_Store,.git,.hg,.svn,*.a,*.adf,*.asc,*.au,*.aup
      \,*.avi,*.bin,*.bmp,*.bz2,*.class,*.db,*.dbm,*.djvu,*.docx,*.exe
      \,*.filepart,*.flac,*.gd2,*.gif,*.gifv,*.gmo,*.gpg,*.gz,*.hdf,*.ico
      \,*.iso,*.jar,*.jpeg,*.jpg,*.m4a,*.mid,*.mp3,*.mp4,*.o,*.odp,*.ods,*.odt
      \,*.ogg,*.ogv,*.opus,*.pbm,*.pdf,*.png,*.ppt,*.psd,*.pyc,*.rar,*.rm
      \,*.s3m,*.sdbm,*.sqlite,*.swf,*.swp,*.tar,*.tga,*.ttf,*.wav,*.webm,*.xbm
      \,*.xcf,*.xls,*.xlsx,*.xpm,*.xz,*.zip
if exists('+wildignorecase')  " v7.3.072
  set wildignorecase  " Case insensitive tab completion
endif
set wildmode=list:longest  " Tab press completes and lists

" Load filetype settings, plugins, and maps
filetype plugin indent on

" Use syntax highlighting
if !exists('syntax_on')
  syntax enable
endif

" Try to use sahara color scheme with 'cursorline' set; otherwise, use the
" default color scheme with a dark background
try
  colorscheme sahara
  set cursorline
catch
  syntax reset
  set background=dark
  set nocursorline
endtry

" Space bar scrolls down a page, :next at buffer's end if plugin available
if vimrc#PluginReady('scroll_next')
  nmap <Space> <Plug>(ScrollNext)
else
  nnoremap <Space> <PageDown>
endif

" Remap insert Ctrl-C to undo the escaped insert operation, but don't break
" the key if the plugin isn't there
if vimrc#PluginReady('insert_cancel')
  imap <C-C> <Plug>(InsertCancel)
endif

" Map double Ctrl-K in insert mode to search digraph names
imap <C-K><C-K> <Plug>(DigraphSearch)

" Stack Ctrl-L to clear search highlight, make it work in insert mode too
nnoremap <C-L> :<C-U>nohlsearch<CR><C-L>
vnoremap <C-L> :<C-U>nohlsearch<CR>gv<C-L>
inoremap <C-L> <C-O>:<C-U>nohlsearch<CR><C-O><C-L>

" Remap normal/visual & and g& to preserve substitution flags
nnoremap & :&&<CR>
xnoremap & :&&<CR>
nnoremap g& :<C-U>%&&<CR>

" Map g: as a 'colon operator'
nmap g: <Plug>(ColonOperator)

" Cycle through argument list
nnoremap [a :previous<CR>
nnoremap ]a :next<CR>
" Cycle through buffers
nnoremap [b :bprevious<CR>
nnoremap ]b :bnext<CR>
" Cycle through quickfix list items
nnoremap [c :cprevious<CR>
nnoremap ]c :cnext<CR>
" Cycle through location list items
nnoremap [l :lprevious<CR>
nnoremap ]l :lnext<CR>

" Insert blank lines around current line
nmap [<Space> <Plug>(PutBlankLinesAbove)
nmap ]<Space> <Plug>(PutBlankLinesBelow)

" Set leader keys
let mapleader = '\'
let maplocalleader = ','

" \a toggles 'formatoptions' 'a' flag using a plugin
nnoremap <Leader>a :<C-U>ToggleFlagLocal formatoptions a<CR>

" \b toggles settings friendly to copying and pasting
nmap <Leader>b <Plug>(CopyLinebreakToggle)

" \c toggles 'cursorline'; no visual mode map as it doesn't work
nnoremap <Leader>c :<C-U>setlocal cursorline! cursorline?<CR>
" \C toggles 'cursorcolumn'; works in visual mode
nnoremap <Leader>C :<C-U>setlocal cursorcolumn! cursorcolumn?<CR>
xnoremap <Leader>C :<C-U>setlocal cursorcolumn! cursorcolumn?<CR>gv

" \d inserts the local date (POSIX date)
nnoremap <Leader>d :read !date<CR>
" \D inserts the UTC date (POSIX date)
nnoremap <Leader>D :read !date -u<CR>

" \e forces a buffer to be editable
nnoremap <Leader>e :<C-U>setlocal modifiable noreadonly<CR>

" \f shows the current 'formatoptions' at a glance
nnoremap <Leader>f :<C-U>setlocal formatoptions?<CR>

" \F reloads filetype plugins
nnoremap <Leader>F :<C-U>doautocmd filetypedetect BufRead<CR>

" \g shows the current file's fully expanded path
nnoremap <Leader>g :<C-U>echo expand('%:p')<CR>
" \G changes directory to the current file's location
nnoremap <Leader>G :<C-U>cd %:h<Bar>pwd<CR>

" \h toggles highlighting search results
nnoremap <Leader>h :<C-U>set hlsearch! hlsearch?<CR>

" \H shows command history
nnoremap <Leader>H :<C-U>history :<CR>

" \i toggles showing matches as I enter my pattern
nnoremap <Leader>i :<C-U>set incsearch! incsearch?<CR>

" \j jumps to buffers ("jetpack")
nnoremap <Leader>j :<C-U>buffers<CR>:buffer<Space>

" \k shows my marks
nnoremap <Leader>k :<C-U>marks<CR>

" \l toggles showing tab, end-of-line, and trailing white space
nnoremap <Leader>l :<C-U>setlocal list! list?<CR>
xnoremap <Leader>l :<C-U>setlocal list! list?<CR>gv

" \L toggles 'colorcolumn' showing 'textwidth'
nnoremap <Leader>L :<C-U>ToggleFlagLocal colorcolumn +1<CR>
xnoremap <Leader>L :<C-U>ToggleFlagLocal colorcolumn +1<CR>gv

" \m shows normal maps
nnoremap <Leader>m :<C-U>map<CR>
" \M shows buffer-local normal maps
nnoremap <Leader>M :<C-U>map <buffer><CR>

" \n toggles line number display
nnoremap <Leader>n :<C-U>setlocal number! number?<CR>
xnoremap <Leader>n :<C-U>setlocal number! number?<CR>gv
" \N toggles position display in bottom right
nnoremap <Leader>N :<C-U>set ruler! ruler?<CR>
xnoremap <Leader>N :<C-U>set ruler! ruler?<CR>gv

" \o opens a line below in paste mode
nmap <Leader>o <Plug>(PasteOpenBelow)
" \O opens a line above in paste mode
nmap <Leader>O <Plug>(PasteOpenAbove)

" \p toggles paste mode
nnoremap <Leader>p :<C-U>set paste! paste?<CR>

" \P creates the path to the current file
nnoremap <Leader>P :<C-U>call mkdir(expand('%:h'), 'p')<CR>

" \q formats the current paragraph
nnoremap <Leader>q gqap

" \r acts as a replacement operator
nmap <Leader>r <Plug>(ReplaceOperator)
xmap <Leader>r <Plug>(ReplaceOperator)

" \R reloads ~/.vimrc
nnoremap <Leader>R :<C-U>source $MYVIMRC<CR>

" \s toggles spell checking
nnoremap <Leader>s :<C-U>setlocal spell! spell?<CR>

" \S shows loaded scripts
nnoremap <Leader>S :<C-U>scriptnames<CR>

" \t shows current filetype
nnoremap <Leader>t :<C-U>setlocal filetype?<CR>
" \T clears filetype
nnoremap <Leader>T :<C-U>setlocal filetype=<CR>

" \u sets US English spelling (compare \z)
nnoremap <Leader>u :<C-U>setlocal spelllang=en_us<CR>

" \v shows all global variables
nnoremap <Leader>v :<C-U>let g: v:<CR>
" \V shows all local variables
nnoremap <Leader>V :<C-U>let b: t: w:<CR>

" \w toggles wrapping
nnoremap <Leader>w :<C-U>setlocal wrap! wrap?<CR>
xnoremap <Leader>w :<C-U>setlocal wrap! wrap?<CR>gv

" \x strips trailing whitespace via a custom plugin
nnoremap <Leader>x :StripTrailingWhitespace<CR>
xnoremap <Leader>x :StripTrailingWhitespace<CR>

" \X squeezes repeated blank lines via a custom plugin
nnoremap <Leader>X :SqueezeRepeatBlanks<CR>
xnoremap <Leader>X :SqueezeRepeatBlanks<CR>

" \y shows all registers
nnoremap <Leader>y :<C-U>registers<CR>

" \z sets NZ English spelling (compare \u)
nnoremap <Leader>z :<C-U>setlocal spelllang=en_nz<CR>

" \= runs the whole buffer through =, preserving position
nnoremap <Leader>= :<C-U>KeepPosition normal! 1G=G<CR>
" \+ runs the whole buffer through gq, preserving position
nnoremap <Leader>+ :<C-U>KeepPosition normal! 1GgqG<CR>

" \. runs the configured make program into the location list
nnoremap <Leader>. :<C-U>lmake!<CR>

" \< and \> adjust indent of last edit; good for pasting
nnoremap <Leader><lt> :<C-U>'[,']<lt><CR>
nnoremap <Leader>> :<C-U>'[,']><CR>

" \_ uses last changed or yanked text as an object
onoremap <Leader>_ :<C-U>normal! `[v`]<CR>

" \% uses entire buffer as an object
onoremap <Leader>% :<C-U>normal! 1GVG<CR>

" \{ and \} move to lines with non-space chars before current column
map <Leader>{ <Plug>(VerticalRegionUp)
sunmap <Leader>{
map <Leader>} <Plug>(VerticalRegionDown)
sunmap <Leader>}

" \/ types :vimgrep for me ready to enter a search pattern
nnoremap <Leader>/ :<C-U>vimgrep /\c/j **<S-Left><S-Left><Right>
" \? types :lhelpgrep for me ready to enter a search pattern
nnoremap <Leader>? :<C-U>lhelpgrep \c<S-Left>

" \* escapes regex metacharacters
nmap <Leader>* <Plug>(RegexEscape)
xmap <Leader>* <Plug>(RegexEscape)

" \\ jumps to the last edit position mark, like g;, but works as a motion
" "Now, where was I?" (tap-tap)
nnoremap <Leader>\ `"
xnoremap <Leader>\ `"

" \DEL deletes the current buffer
nnoremap <Leader><Delete> :bdelete<CR>
" \INS edits a new buffer
nnoremap <Leader><Insert> :<C-U>enew<CR>

" \TAB toggles 'autoindent'
nnoremap <Leader><Tab> :<C-U>setlocal autoindent! autoindent?<CR>

" Some useful abbreviations
inoreabbrev tr@ tom@sanctum.geek.nz
inoreabbrev tr/ <https://sanctum.geek.nz/>

" Things I almsot always type wrnog
inoreabbrev almsot almost
inoreabbrev wrnog wrong
inoreabbrev Fielding Feilding
inoreabbrev THe the
inoreabbrev THere there

" Reload this file when I save it, modified or nay
augroup vimrc
  autocmd!
  autocmd BufWritePost $MYVIMRC,$MYVIM/vimrc
        \ source $MYVIMRC
augroup END