" " Tom Ryder (tejr)'s vimrc " ------------------------ " " " " 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 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. " " " 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: " " " " 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 (ScrollNext) else nnoremap 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 (InsertCancel) endif " Map double Ctrl-K in insert mode to search digraph names imap (DigraphSearch) " Stack Ctrl-L to clear search highlight, make it work in insert mode too nnoremap :nohlsearch vnoremap :nohlsearchgv inoremap :nohlsearch " Remap normal/visual & and g& to preserve substitution flags nnoremap & :&& xnoremap & :&& nnoremap g& :%&& " Map g: as a 'colon operator' nmap g: (ColonOperator) " Cycle through argument list nnoremap [a :previous nnoremap ]a :next " Cycle through buffers nnoremap [b :bprevious nnoremap ]b :bnext " Cycle through quickfix list items nnoremap [c :cprevious nnoremap ]c :cnext " Cycle through location list items nnoremap [l :lprevious nnoremap ]l :lnext " Insert blank lines around current line nmap [ (PutBlankLinesAbove) nmap ] (PutBlankLinesBelow) " Set leader keys let mapleader = '\' let maplocalleader = ',' " \a toggles 'formatoptions' 'a' flag using a plugin nnoremap a :ToggleFlagLocal formatoptions a " \b toggles settings friendly to copying and pasting nmap b (CopyLinebreakToggle) " \c toggles 'cursorline'; no visual mode map as it doesn't work nnoremap c :setlocal cursorline! cursorline? " \C toggles 'cursorcolumn'; works in visual mode nnoremap C :setlocal cursorcolumn! cursorcolumn? xnoremap C :setlocal cursorcolumn! cursorcolumn?gv " \d inserts the local date (POSIX date) nnoremap d :read !date " \D inserts the UTC date (POSIX date) nnoremap D :read !date -u " \e forces a buffer to be editable nnoremap e :setlocal modifiable noreadonly " \f shows the current 'formatoptions' at a glance nnoremap f :setlocal formatoptions? " \F reloads filetype plugins nnoremap F :doautocmd filetypedetect BufRead " \g shows the current file's fully expanded path nnoremap g :echo expand('%:p') " \G changes directory to the current file's location nnoremap G :cd %:hpwd " \h toggles highlighting search results nnoremap h :set hlsearch! hlsearch? " \H shows command history nnoremap H :history : " \i toggles showing matches as I enter my pattern nnoremap i :set incsearch! incsearch? " \j jumps to buffers ("jetpack") nnoremap j :buffers:buffer " \k shows my marks nnoremap k :marks " \l toggles showing tab, end-of-line, and trailing white space nnoremap l :setlocal list! list? xnoremap l :setlocal list! list?gv " \L toggles 'colorcolumn' showing 'textwidth' nnoremap L :ToggleFlagLocal colorcolumn +1 xnoremap L :ToggleFlagLocal colorcolumn +1gv " \m shows normal maps nnoremap m :map " \M shows buffer-local normal maps nnoremap M :map " \n toggles line number display nnoremap n :setlocal number! number? xnoremap n :setlocal number! number?gv " \N toggles position display in bottom right nnoremap N :set ruler! ruler? xnoremap N :set ruler! ruler?gv " \o opens a line below in paste mode nmap o (PasteOpenBelow) " \O opens a line above in paste mode nmap O (PasteOpenAbove) " \p toggles paste mode nnoremap p :set paste! paste? " \P creates the path to the current file nnoremap P :call mkdir(expand('%:h'), 'p') " \q formats the current paragraph nnoremap q gqap " \r acts as a replacement operator nmap r (ReplaceOperator) xmap r (ReplaceOperator) " \R reloads ~/.vimrc nnoremap R :source $MYVIMRC " \s toggles spell checking nnoremap s :setlocal spell! spell? " \S shows loaded scripts nnoremap S :scriptnames " \t shows current filetype nnoremap t :setlocal filetype? " \T clears filetype nnoremap T :setlocal filetype= " \u sets US English spelling (compare \z) nnoremap u :setlocal spelllang=en_us " \v shows all global variables nnoremap v :let g: v: " \V shows all local variables nnoremap V :let b: t: w: " \w toggles wrapping nnoremap w :setlocal wrap! wrap? xnoremap w :setlocal wrap! wrap?gv " \x strips trailing whitespace via a custom plugin nnoremap x :StripTrailingWhitespace xnoremap x :StripTrailingWhitespace " \X squeezes repeated blank lines via a custom plugin nnoremap X :SqueezeRepeatBlanks xnoremap X :SqueezeRepeatBlanks " \y shows all registers nnoremap y :registers " \z sets NZ English spelling (compare \u) nnoremap z :setlocal spelllang=en_nz " \= runs the whole buffer through =, preserving position nnoremap = :KeepPosition normal! 1G=G " \+ runs the whole buffer through gq, preserving position nnoremap + :KeepPosition normal! 1GgqG " \. runs the configured make program into the location list nnoremap . :lmake! " \< and \> adjust indent of last edit; good for pasting nnoremap :'[,'] nnoremap > :'[,']> " \_ uses last changed or yanked text as an object onoremap _ :normal! `[v`] " \% uses entire buffer as an object onoremap % :normal! 1GVG " \{ and \} move to lines with non-space chars before current column map { (VerticalRegionUp) sunmap { map } (VerticalRegionDown) sunmap } " \/ types :vimgrep for me ready to enter a search pattern nnoremap / :vimgrep /\c/j ** " \? types :lhelpgrep for me ready to enter a search pattern nnoremap ? :lhelpgrep \c " \* escapes regex metacharacters nmap * (RegexEscape) xmap * (RegexEscape) " \\ jumps to the last edit position mark, like g;, but works as a motion " "Now, where was I?" (tap-tap) nnoremap \ `" xnoremap \ `" " \DEL deletes the current buffer nnoremap :bdelete " \INS edits a new buffer nnoremap :enew " \TAB toggles 'autoindent' nnoremap :setlocal autoindent! autoindent? " Some useful abbreviations inoreabbrev tr@ tom@sanctum.geek.nz inoreabbrev tr/ " 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