"" My |vimrc| " TODO: Supply chain attacks are getting more common. We should use (mandate?) " commit hashes in `GitAdd`. Also, make sure to use a command format that " ignores tag/branch names (those can be named to look like hashes and are " mutable). Maybe we deem some "publishers" worthy of trust, Tim Pope tags " releases of many of his plugins for instance. " TODO: Do we want to try to integrate with Debian? There seems to be at least " two ways vim-related files are installed: " - Purely auxilliary files as part of some other package: Files are installed " to `/usr/share/vim/addons` which are referenced by files installed to " `/usr/share/vim/registry`. `vim-addons` from the `vim-addon-manager` can be " used to (presumably) symlink them into a path that is listed in " 'runtimepath'. " - As a standalone `vim-${addon}` package: Files are installed to " `/usr/share/vim-${addon}`, presumably symlinked into a `start` or `opt` " 'packpath' during package installation. " and the `dh_vim-addon` man page in " the `dh-vim-addon` package contains some further details. " TODO: |unix| says " " > Temporary files (for filtering) are put in "/tmp". If you want to place " > them somewhere else, set the environment variable $TMPDIR to the directory " > you prefer. " " and since we go to some effort to keep other intermediate files in " `~/.cache/vim` for privacy, we might want to create a shell alias that does " `alias vim='TMPDIR="$HOME/.cache/vim/tmp" vim'`, as well as making sure that " directory exists in shell startup files. " " Actually, I'm pretty sure we can do this from inside Vim (requires 'eval' " though), which might be cleaner (although some dotfiles for other programs " that do similar things do it in shell startup files). Do both? " " NOTE: This is an environment variable and affects child processes, including " ones run from the `:terminal`. """ Formatting " A |'textwidth'| of 79 is used throughout. " Comments are written in Vim's help |notation|, see |help-writing|. They can " be highlighted with " . " Section headings are not written in the help |notation|, but are instead " indicated with multiple contiguous comment characters. They can form folds " with . """ Compatibility " TODO: Test with `nvi`, a "bug-for-bug compatible" clone of the original BSD " `vi`. " TODO: Test with `VIM_POSIX=1 "$vim"` (for different `$vim`s?). See " |$VIM_POSIX|. " This vimrc should work with all configurations of Vim. Manually tested with: " " - Versions: TODO: Whatever some old {Debian,Ubuntu,Fedora} ships. " - Features: small, huge (Debian `apt-get install vim-{tiny,gtk3}`) " - Locales: C, UTF-8 (`LC_ALL=C{,.UFT-8}`) " - Colors: 1, 2, 8, 16, 256, termguicolors (`--cmd "set {t_Co=$colors,tgc}"`) " - UI: TUI, GUI (`{,g}vim`) " - Terminals: GUI, VTE, Linux, tmux with the correct `Ss` `terminal-override` " - Platforms: Unix-like " TODO: `man setfont` says: " " > Note: if a font has more than 256 glyphs, only 8 out of 16 colors can be " > used simultaneously. It can make console perception worse (loss of " > intensity and even some colors). " " The default font on my system has 512 glyphs (`showconsolefont -v`). " TODO: `man setfont` says, in section "CONSOLE MAPS": " " > Several mappings are involved in the path from user program output to " > console display. " " Might be worth reading up on that. If I already did, document. """ Features " |:version| says "tiny" features are always present and are therefore used in " favor other features whenever possible. "Tiny" features include: " " - |+multi_byte| " - |+mouse| " - |+tag_binary| " - |+user_commands| " - |+autocmd| " - |+localmap| " " TODO: What category features are placed in depends on Vim version. Look up " and create some table. " Note that trying to set (run-time, but not compile-time) unsupported options " is silently ignored, and so can be done without checking for support first " (which is good, since that requires |+eval|). Everything between |:if| and " |:endif| is also silently ignored if |+eval| is not available. See " |no-eval-feature|. """ Patches " TODO: Instead of checking for patches we might want to standardize on " `exists()` instead since it is more descriptive and takes the compile-time " |+feature-list| into account (which would otherwise require " `has('patch-{patch}') && has('{feature}')`). The version/patch does indicate " how old the feature is and so how likely to be supported. Use " `exists('+option')` (not `exists('&option')`, see e.g. |missing-options|) and " `exists('##event')` " See |has-patch|. " |:helpgrep| |c_CTRL-R_CTRL-A| (mapped to `K` below). " - 8.1.0081 """ Encoding " |'encoding'| is hard-coded to `utf-8`. However, only characters present in " Code Page 437 should be used in the interface, to ensure font support on most " terminals (in particular, the Linux console, via `CHARMAP` in " `/etc/default/console-setup`). See " - " - " - `man showconsolefont` " One can find characters by looking at |digraph-table| in a lowest common " denominator terminal. Some characters tested to work (not all from Code Page " 437) *myvimrc-characters*: " - Rectangular: ■█▒░ (not ▌▐▓) " - Triangular: (not ►◄▲▼) " - Circular: ●•∙· (not ○☼) " - Other: ‼︎… (not ⌂♦☺︎☻) " - Arrows: ‹›«»←→↑↓ (not ↔↕) " - Box: │─├┤┼ (not ║═) " - Math: ∩×∆∅ " - Greek: ΔΛλ """ Re-sourcing " |setglobal| is used where appropriate so that buffer/window-local options are " not overridden when re-sourcing. " A `vimrc` |augroup| is cleared and used for all |autocmd|s. At the time of " writing, |augroup| messes up the highlighting of |autocmd|s within it, so the " `vimrc` group name is added to every |autocmd| instead (the addition of the " group of course makes the highlighting misinterpret it as the " `vimAutoEventList` and the events instead get the erroneous " `VimAutoCmdSfxList` highlighting... file a bug?). This can be checked with " `:g/autocmd`. """ Mappings " Don't make any built-in mappings do something completely different! Another " Vimmer should never be surprised by what happens, unless it is pleasantly " surprised because the functionality is extended in useful and obvious ways. " This includes mappings from popular plugins, for which the defaults should be " kept as far as possible. " In this file, || is hard-coded to so that mappings work " without |+eval|. Setting |mapleader| to a different value after the mappings " have been defined does not change the mappings, so it is not possible to " "hot-swap" it for pair programming anyway. |mapleader| is still set though, " because some plugins expect it. """ Debugging " See |load-plugins|, |slow-start|. """ Novice " |myvimrc-novice| " The goal is to make it at least workable to pair program with a Vim novice " using this configuration. " From more heavy-handed to less: " - `$VIMRUNTIME/evim.vim`, |easy|, |evim-keys|, |i_CTRL-L| " - `$VIMRUNTIME/mswin.vim` " - |:behave| " TODO: Mark novice-unfriendly option settings as " |myvimrc-novice-unfriendly-$option|? (My original motivator for this was that " I thought setting 'hidden' was a bit dangerous, but it is set automatically " in easy mode!) "" Helpers """ Define and clear autocmd group " TODO: I seem to remember augroups being closed automatically at end of file, " in which case we could omit the `augroup END` and group name from our " `autocmd`s. augroup vimrc autocmd! augroup END """ Functions if has('eval') " See |has-patch|. " TODO: After and including 7.4.237 `has("patch-{major}.{minor}.{patch}")` " works and is nicer. If we never check for any version before that we might " remove this. function! s:has(major, minor, patch) abort let version = 100 * major + minor return v:version > version || (v:version == version && has('patch'.patch)) endfunction " `$VIMSRC/src/option.h:/P_COMMA/` " `$VIMSRC/src/option.h:/P_FLAGLIST/` endif "" Options " |:let-option| " Note that even options listed as local (only) have global variants. E.g. " 'fileencoding' is listed as "local to buffer" but 'fileencodings' says: "Note " that 'fileencodings' is not used for a new file, the global value of " 'fileencoding' is used instead. You can set it with: `:setglobal " fenc=iso-8859-2`". " `$VIMSRC/src/optiondefs.h:/Options local to a window/` " `$VIMSRC/src/structs.h:/Options local to a window/` " `$VIMSRC/src/structs.h:/options that are local to a window/` " TODO: Use |setglobal| for more things? Note that for options with a non-empty " default local value, `setglobal` does nothing useful. Worse, for options with " only a (buffer or window) local value, `setglobal` does nothing, literally. " Is that a problem, should we even set local values here? Maybe identifying " them and getting rid of them is a good idea? " TODO: Maybe source |defaults.vim|? Probably not, but add some documentation? " TODO: Look at |:options| and maybe follow the same grouping? """ Reset " Undoes changes to global options made by any |system-vimrc| or interactively " (if re-sourced). The value of 'compatible' determines what defaults are " loaded, but 'nocompatible' is set automatically at startup when a user vimrc " file (this file!) is found |compatible-default|. setglobal all& """ Encoding " Force Vim's internal encoding to a Unicode encoding. set encoding=utf-8 """ Buffers " Allow switching away from unsaved buffers. set hidden """ Clipboard " Integrate with any graphical environment's clipboard. set clipboard^=unnamedplus """ Editing set backspace=indent,eol,start set virtualedit=block """ Modeline " 'modeline' is local to buffer, 'modelines' is global. " set nomodeline set modelines=0 """ Navigation set nostartofline set sidescroll=1 set sidescrolloff=1 " set scrolloff=1 " Useful for |[[|. set display=lastline " : Cannot scroll by screen " line if a line wraps. Add the 'smoothscroll' option. if has('patch-9.0.0640') set smoothscroll " TODO: Local to window. endif """ Windows " Put newly opened windows below and to the right. " Use |:aboveleft| to override. set splitbelow set splitright """ Interface set showcmd " TODO: Also look a bit at ? Maybe " `flagship#tabcwds()` to summarize the tab working directory. " TODO: We could split the current `Statusline()` into " `Statusline{Left,Right}()` and have the new `Statusline()` join them with " 'fillchars', and `Ruler()` join them with `:`. Since the same functionality " is also used by 'titlestring' maybe name them something less statusline " centric? `Bufname(fill, right)`? " set ruler " set rulerformat=%=%(%{expand('%:t')}:%)%l set noruler set laststatus=1 set showtabline=1 set shortmess+=I " See |:intro|. set guioptions=cf " Console dialogs, foreground (no fork()) set numberwidth=1 " TODO: Local to window. """ Interface characters " See also |myvimrc-characters|. " If |'t_Co'| is empty (or set to 1) the default behavior of |'fillchars'| " `stl`/`stlnc` (`^`/`=`) will be used regardless of its setting. Other good " choices for |'listchars'| `fold` is ` ` and `tab` is: `→ `, `――>`, `├──`, " `──┤`, `├─┤`. " TODO: `:help 'fillchars'` says "for `stl` and `stlnc` only single-byte values " are supported". Test the current (non-ASCII) values against older versions of " Vim. See also . " TODO: If Vim cannot tell appart |hl-StatusLine| and |hl-StatusLineNC| (e.g. " because |hl-StatusLine| is a |hl-link|), (ordinary) spaces and `fillchars` " `stl` characters for the statusline of the focused window will be replaced " with `^` (i.e. the default `fillchars` `stl`). Note that this includes the " single character under the `fillchars` `vert`, which cannot be set with " |'statusline'|. set linespace=-1 set list " TODO: Local to window. set linebreak " TODO: Local to window. set breakindent " TODO: Local to window. set breakindentopt=sbr,shift:2 " TODO: Local to window. set showbreak=»  " TODO: Local to window (or global). set fillchars=diff: ,stl:─,stlnc:─,vert:│,fold:─ " set fillchars=diff: ,stl:_,stlnc:_,vert:│,fold:─ set listchars=tab:├─,trail:•,extends:›,precedes:‹,nbsp:· " : Showing two characters for " tab is limited. Allow for a third character for "tab:" in 'listchars'. if has('patch-8.1.0759') " set listchars+=tab:├─┤ " set listchars+=tab:├ ┤ set listchars+=tab:│ │ endif " TODO: `%f` still shows `[No Name]`, is there a way to remove that? set statusline=%(%f %) " TODO: Local to window (or global). if has('eval') " TODO: This works poorly with plugins that have windows with their own " statusbar, e.g. |undotree.txt|. " set statusline=%(%{expand('%:.s?^/??')} %) " `fillchar_status` function in `src/screen.c:4649` of Vim source. " TODO: Try to use some other non-standard space? Search for "\" in " |digraphs|. " set fillchars+=stl: ,stlnc:  set fillchars+=stl: ,stlnc:  " set fillchars+=stl:┘,stlnc:┘ " TODO: Standardize on global functions? Or |autoload|s (but that would break " our "single file" policy)? " function! s:statusline() abort function! s:opt(opt, key) abort return matchstr(a:opt, '.*\(^\|,\)' . key . ':\zs[^,]*') return split(a:opt, ) endfunction function! s:expand() abort endfunction function! Statusline() abort " TODO: The global CWD, `getcwd(-1)`, might be useful. Also indicate " `haslocaldir()` somehow? " TODO: Make this expansion relative to the window-local cwd? Also do other " substitutions, like `$HOME` to `~`, the expanded `$VIMRUMTIME` to the " string `$VIMRUNTIME`, etc. We used to have `s?^/??`, why? " TODO: Harmonize with `titlestring`. " TODO: Generalize `&filetype`, `&buftype` and the matched `bufname()` " `://` somehow? if &filetype ==# 'man' let title = &filetype . ':' . expand('%:t') " elseif &buftype =~# 'nofile\|nowrite' " let title = &filetype elseif &buftype ==# 'help' let title = &buftype . ':' . expand('%:t:s?.txt$??') elseif &buftype ==# 'terminal' " TODO: We sometimes want to use some variation of `expand('%')`, e.g. " when using the |terminal-debugger|. " TODO: 'statusline' is not re-evaluated when |term_gettitle()| changes, " can we do something like `let &statusline = &statusline` in some " |autocmd| (perhaps one that triggers when the terminal content " changes)? Worst case |CursorMoved|. let title = &buftype . ':' . substitute(term_gettitle(bufnr()), '[^:]*:', '', '') " TODO: Change the `&&` into nested `if`? Note that it has different " semantics because of the `if`/`elseif`/`else` chain. elseif &buftype ==# 'quickfix' && !empty(get(w:, 'quickfix_title')) " Remove leading colon (Ex commands) and trailing parenthesis (e.g. " |dispatch| job number). let title = w:quickfix_title let title = substitute(title, '^:', '', '') let title = substitute(title, '\s*([^)]\+)\s*$', '', '') let title = &buftype . ':' . title else let title = expand('%') " fugitive:///home/rcrnstn/repo/.git//hash/dir/file.ext " fugitive:///home/rcrnstn/repo/.git//hash/dir/file.ext " TODO: |split()| on `:` (info), `://` (fugitive) and `#` (info), do " processing, and then `join(filter(parts, '!empty(v:val)'), ':')`. " Replace names of the form `:///.//` with " `:` where any leading 40 character hex string (hash) in " `` is truncated to 7 characters. (Yes, this was designed for " |fugitive|.) let parts = matchlist(expand('%'), \ '^\%(\([^:]\+\)://\)\?\%(\(.*\)//\)\?\(.*\)' \ ) if !empty(parts) let [type, prefix, path] = parts[1:3] if !empty(prefix) while fnamemodify(prefix, ':t')[:0] ==# '.' let prefix = fnamemodify(prefix, ':h') endwhile let prefix = fnamemodify(prefix . '/', ':~:.:h:t:s?^\.$??') endif let path = substitute(path, \ '^\([0-9a-fA-F]\{7\}\)[0-9a-fA-F]\{33\}\(/.*\|$\)', '\1\2', '' \ ) let title = join(filter([type, prefix, path], '!empty(v:val)'), ':') endif endif if !empty(title) let title = substitute(title, ' *$', '', '') . ' ' endif let title = substitute(title, ' ', ' ', 'g') " NOTE: `matchstr` looks for the _first_ match. " TODO: This is slow. Cache the `matchstr` result? let fillchar = matchstr(&fillchars, '\(^\|,\)stl:\zs[^,]*') let pad = winwidth(0) - strdisplaywidth(title) return title . repeat(fillchar, pad) endfunction " : Cannot easily get the " script ID. Support expand(''). " if has('patch-8.2.1347') " let &statusline = '%{'.expandcmd('statusline()').'}' " else set statusline=%{Statusline()} " TODO: Local to window (or global). " function! g:Statusline() abort " return s:statusline() " endfunction " endif " TODO: This doesn't seem to do the trick. autocmd vimrc CursorMoved * \ if &buftype ==# 'terminal' | \ let &statusline = &statusline | \ endif | endif """ Colors " May be overritten later by Vim for terminals with |t_RB|. set background=dark set guioptions+=d if &t_Co > 16 set t_Co=16 " if has('nvim') lua ffi = require "ffi" ffi.cdef "int t_colors" ffi.C.t_colors = 16 endif endif set notermguicolors " if empty($COLORTERM) && !has('vcon') set notermguicolors endif if has('gui_running') set termguicolors endif """ Bell set belloff=error """ Title set title set titlelen=0 " set titlestring=vi:%{fnamemodify(getcwd(),':~:t:s?^$?/?')}%(:%<%{pathshorten(expand('%:.:s?^/??'))}%) " TODO: Break out into `Title()` function and harmonize with `statusline`. " TODO: Ideas from `tpope/vim-flagship`: `hostname()` and `v:servername`. set titlestring=vi:%{fnamemodify(getcwd(),':~:t:s?^$?/?')}%(:%<%{expand('%:.:s?^/??')}%) set titleold= function! s:cwdname() abort return fnamemodify(getcwd(), ':~:t:s?^$?/?') endfunction function! s:bufname() abort return expand('%:.:s?^/??') return pathshorten(expand('%:.:s?^/??')) endfunction """ Tabs " When reading files written by others, assume default `tabstop=8`. " When Writing files, use 4 space indents. set shiftwidth=4 " TODO: Local to buffer. set shiftround set softtabstop=-1 " TODO: Local to buffer. set expandtab " TODO: Local to buffer. """ Mouse " |scroll-mouse-wheel| is generally useful, the rest for |myvimrc-novice|. set mouse=a set mousemodel=popup set selectmode+=mouse """ Novice set keymodel=startsel,stopsel set selectmode+=key set whichwrap+=<,>,[,] """ Command-line " See also Readline's `menu-complete`, documented in `bash(1)`. set wildmenu set wildmode=longest:full,full " See also |'suffixes'|. " Source control. " set wildignore+=_* set wildignore+=.git " Programming language specific. set wildignore+=__pycache__,.venv,*.egg-info set wildignore+=node_modules " Relative to `$HOME`. set wildignore+=$HOME/projects/UPSTREAMS set wildignore+=$HOME/.vim/pack set wildignore+=$HOME/.config/vim/pack set wildignore+=$HOME/.config/nvim/pack set wildignore+=$HOME/.cache set wildignore+=$HOME/.local/lib set wildignore+=$HOME/.local/share/man set wildignore+=$HOME/.local/share/tldr set wildignore+=$HOME/.mozilla/firefox set wildignore+=$HOME/.ansible set wildignore+=$HOME/.vagrant set wildignore+=$HOME/.local/pipx set wildignore+=$HOME/.cargo/register set wildignore+=$HOME/.cargo set wildignore+=$HOME/.npm set wildignore+=$HOME/.wine/dosdevices set wildignore+=$HOME/.wine/drive_* set wildignore+=$HOME/snap " : 'wildmenu' only shows few " matches. Add the "pum" option: use a popup menu to show the matches. if has('patch-8.2.4325') set wildoptions+=pum endif """ Search set incsearch set shortmess-=S """ Timing set notimeout """ Terminal set ttimeout set ttimeoutlen=100 set ttyfast set lazyredraw " A |'ttyscroll'| of 0 is beneficial on local terminals (especially reduces " flickering on Linux VT), but might be worse on slow remote connections. Set " |'writedelay'| to a small value (like 1), and maybe |'redrawtime'| to a very " large value (like 20000), to see what difference this option makes. See also " |myvimrc-autocmd-ttyscroll|. set ttyscroll=0 """ Diffs set diffopt+=vertical set diffopt+=foldcolumn:0 " : Using an external diff " program is slow and inflexible. Include the xdiff library. Use it by default. if has('patch-8.1.0360') " set diffopt+=internal set diffopt+=algorithm:histogram set diffopt+=indent-heuristic endif """ Formatting " See |formatting|, |auto-format|, |format-comments|, and |fo-table|. set textwidth=79 " TODO: Local to buffer. " set winwidth=80 " set colorcolumn=+1 " TODO: Local to window. set autoindent " TODO: Local to buffer. set nojoinspaces " Don't autowrap text (non-comments), recognize lists, remove comment leader " when joining. set formatoptions-=t " TODO: Local to buffer. set formatoptions+=n set formatoptions+=j " See also |breakindent|, |breakindentopt|, |showbreak| set above. set nowrap " TODO: Local to window. " A custom 'formatprg' produces nicer results but is harder to replicate for " others and places undue burden on documentation contributors. Having simple " format rules is more important than slightly prettier formatting. " TODO: At least make the expressions valid (we're lacking spaces, no?). " TODO: Local to buffer (or global). " if executable('par') " let &formatprg = join(['par', 'T'.&tabstop, 'w'.&textwidth, 'e']) " let &formatprg = join(['par', 'T'.&tabstop, 'w'.&textwidth, 'e', 'j']) " elseif executable('fmt') " let &formatprg = join(['fmt', '-w'.&textwidth, '-g'.&textwidth]) " endif """ Comments " set commentstring=#%s " TODO: Local to buffer. """ Folds set foldlevelstart=999 " TODO: Local to window. set foldtext=substitute(getline(v:foldstart),'\\t',repeat(' ',&ts),'g').' ' """ Spelling " set spell set spelllang=en_us " TODO: Local to buffer. set thesaurus=~/.vim/thesaurus/en_us.txt " TODO: Local to buffer (or global). " TODO: We can probably do something better/cleaner for the thesaurus on our " own. In particular, publicly available, clearly licensed, version controlled, " code to generate the vim thesaurus from primary sources. " The current `~/.vim/thesaurus/en_us.txt` is downloaded from the URL " documented in |'thesaurus'|: " . This zip file " contains a patch to " and the results of running the patched code on the included files, as well as " the licenses. `MyThes-1.zip` is linked from " and seems to be " some version of . MyThes states in its " readme that it is based on WordNet 2.0. However, the latest version as of " this writing is 3.1. When generating a Vim version, it helps to have a " visualization to guide the heuristics that will probably be needed. Searching " for "thesaurus" gives " several projects. looks good (try e.g. "completion"). " Another search hit, " , states that " "WordNet's vocabulary is smaller than other "word" databases", so we might " want to use other sources as well, e.g. Roget's Thesaurus. " " WordNet " - " - " Data hosted on Project Gutenberg " - (2002) Moby Thesaurus List " - (2004) Roget's Thesaurus of English Words and Phrases " - (1991) Roget's Thesaurus " - (2011) A Dictionary of English Synonymes [...] " - (2016) A Complete Dictionary of Synonyms and Antonyms " For Swedish, there is " - " - " " Other assorted resources: " - " - """ Views " TODO: Per the documentation `curdir` is only supposed to save the " window-local directory as set by |:lcd|, which I wouldn't mind so much and " might even make use of. But currently it is being set apparently without my " involvement (perhaps by some plugin, probably |netrw|) far too often, and " since we do |:loadview| on every opened file this gets annoying fast. set viewoptions-=options set viewoptions-=curdir set viewoptions+=slash set viewoptions+=unix """ Files set swapfile " TODO: Local to buffer. set writebackup set backupcopy=yes " TODO: Local to buffer (or global). set undofile " TODO: Local to buffer. set directory=~/.cache/vim/swap// set backupdir=~/.cache/vim/backup// set undodir=~/.cache/vim/undo// set viewdir=~/.cache/vim/view// set viminfofile=~/.cache/vim/viminfo if has('eval') let $TMPDIR = $HOME . '/.cache/vim/tmp' call mkdir($TMPDIR, 'p') endif if has('nvim') set shadafile= endif """ Conceal set conceallevel=2 " TODO: Local to window. set concealcursor=n " TODO: Local to window. """ Platform set shellslash """ Filenames " I generally allow everything (except control codes) in filenames on the " filesystem. However, only media files (photos or videos) tend to take " advantage of that, to be more descriptive/preserve some upstream name. Files " I will want Vim to be able to cross-reference will be text (code or notes) " with more constrained names. Disallowing some punctuation makes things like " |gf| more useful. " NOTE: This is a global option, but some ftplugins (Perl) change it anyway. " `:grep -R 'isf\(name\)\?' /usr/share/vim/vim82/ftplugin/` " *myvimrc-isfname-bug* set isfname-=, " Common file separator. set isfname-=; " Common file separator. set isfname-=: " Common file separator (e.g. when using |gf|). set isfname-=# " URL fragment separator. """ External tools " Not POSIX: `-H` (suggested in 'grepprg'), `-I`. set grepprg=grep\ -nHI " TODO: Local to buffer (or global). """ Quickfix set switchbuf=useopen "" Mappings " TODO: Categorize into map modes. Use the nonspecific |:map| (|mapmode-nvo|) " and |:map!| (|mapmode-ic|) more often? """ Mapleader " Prefill command line with query to discover mapleader mappings. nnoremap ? :verbose nmap Space> nnoremap ? :verbose nmap Space>Space> """ Escape " Overwrites the default |i_CTRL-C|, |v_CTRL-C|. See " . inoremap xnoremap """ Novice " We """ Windows """" Focus nnoremap h nnoremap j nnoremap k nnoremap l tnoremap h tnoremap j tnoremap k tnoremap l """" Move if has('eval') function! s:winmove(dir) abort let prefix = \ dir ~=# '[hj]' ? 'leftabove' : \ dir ~=# '[kl]' ? 'belowright' winnr(a:dir) endfunction endif """" Empty vertical split " See also |CTRL-W_n|, which does |:new|. nnoremap N :vnew """" Resize " Resize height to number of lines in buffer. nnoremap ? line('$')."_" """ Clear and redraw " is overridden above, so use a mapping. nnoremap """ Movement " Up down dispaly lines (unless a count is given). " TODO: Mappings like these that extend builtin functionality (identify them " and put them in the same place) could be made more formally feature complete " by doing the same thing for any aliases (listed in `:help j` etc). If the " functinonality is implemented in other modes (insert and the various visual " modes) then that should probably be extended too. Document this general " principle. nnoremap j v:count ? 'j' : 'gj' nnoremap k v:count ? 'k' : 'gk' " When moving to the next/previous '{'/'}' in the first column (function " body/struct definition start/end), make visible the matching '}'/'{' " (function body/struct definition end/start) and paragraph containing '{' " (function prototype/struct name and preceeding comments). A prefix of 'g' " aligns the paragraph containing '{' to the top of the window. " TODO: Keep jumps somehow? `:keepjumps normal!`? " TODO: |]]| says "[count] sections forward or to the next '{' in the first " column". |section| says "a section begins after a form-feed () in the " first column and [...]". We completely ignore the form-feed aspect. It's not " commonly seen in code, but the GNU Coding Standards recommends them " . nnoremap ]] ]]%%m'vipo'' nnoremap g]] ]]%%m'vipozt'' nnoremap [[ [[%%m'vipo'' nnoremap g[[ [[%%m'vipozt'' nnoremap ][ ][m'%vipo'' nnoremap g][ ][m'%vipozt'' nnoremap [] []m'%vipo'' nnoremap g[] []m'%vipozt'' """ Search and edit file " See also |ctrlp|. nnoremap :edit **/** """ Visual line insert and append " TODO: This breaks text object that start with `A` or `I`. Ironically, those " two characters specifically are prefixes in `wellle/targets.vim`. " xnoremap A mode() !=# 'V' ? 'A' : ':normal A' " xnoremap I mode() !=# 'V' ? 'I' : ':normal I' " End of pair opened at end of current line. " TODO: These are overridden by `matchit`, use `%` instead? nnoremap g% :norm! $% onoremap g% :norm! $% xnoremap g% :norm! v$% """ Scrolling " Put paragraph containing cursor line at the top/bottom of the window. " TODO: Preserve jump list somehow? " TODO: If |+eval|, also account for |scrolloff|? nnoremap z{ {jzt nnoremap z} }kzb """ Visual mode repeat " See also `visualrepeat`. xnoremap . :normal! . """ Clipboard " Yank file and line number of cursor. nnoremap yy :let @+ = expand('%:p') . ':' . line('.') """ `$MYVIMRC` nnoremap ve :edit $MYVIMRC:lcd %:h nnoremap vs :source $MYVIMRC """ Keyword " nnoremap K :silent execute "normal! K" \| redraw! " nnoremap K :terminal ++close =&keywordprg " TODO: vnoremap " TODO: `set keywordprg=:help` """ Help " TODO: Make this filetype dependent? Could use |:grep| or |fugitive|'s " |:Ggrep|. On the other hand, there are other built-in mappings that does " keyword search in a codebase. " TODO: Here we use `g` as prefix. Do we do that in other places? Should we not " use (i.e. )? " TODO: We do have a `K` `FileType vim,help` mapping. nnoremap gK :helpgrep \<\> xnoremap gK y:helpgrep " """ Run " TODO: Standardize where the output goes. " File (with output in pager). nnoremap % :!%:p:S \| less -FR nnoremap # :!#:p:S \| less -FR " Command (with output in new window). nnoremap ! :new \| .! """ Quickfix """" Go to first/last valid entry " |:cfirst|, |:clast|, |[Q|, and |]Q| (the last ones being " `vim-unimpaired` mappings) go to the first/last entry regardless of whether " it is |quickfix-valid| (includes a file name). I prefer to go to the " first/last entry that includes a file name (even if I was already " before/after that entry). nnoremap [Q :cfirst \| silent! execute "cnext\|cprev" nnoremap ]Q :clast \| silent! execute "cprev\|cnext" """" Toggle Quickfix window " TODO: Do similar for location list? " TODO: Make the |botright| global with some |autocmd|? Is it implied by our " `set split{below,right}`? nnoremap q \ empty(filter(getwininfo(), \ 'getbufvar(v:val.bufnr, "&buftype") ==# "quickfix"' \ )) \ ? ':botright copen' \ : ':botright cclose' """ Make " TODO: |dispatch| provides default mappings, try to emulate them? " TODO: Should these be as well? " TODO: Use the |terminal-debugger| instead of a make target? nnoremap m% :!make %:r:S \| less -FR nnoremap m# :!make #:r:S \| less -FR nnoremap mm :!make \| less -FR nnoremap ma :!make all \| less -FR nnoremap mt :!make test \| less -FR nnoremap md :!make debug \| less -FR if has('quickfix') nnoremap m% :silent make! %:r:S \| redraw! nnoremap m# :silent make! #:r:S \| redraw! nnoremap mm :silent make! \| redraw! nnoremap ma :silent make! all \| redraw! nnoremap mt :silent make! test \| redraw! endif if has('terminal') nnoremap md :terminal make debug endif """ Improve default mappings """" Disable unconditional quit from Normal mode " As warned about in |zz| these may be typed accidentally when Caps Lock is " enabled and lose data. Redefining them is a bit hostile towards other users, " but deemed worth it. nnoremap ZZ :quit nnoremap ZQ :quit """" Yank to end of line, not entire line " As suggested in |Y|. Analogous with |D| does `d$` and |C| does `c$`. nnoremap Y y$ """" Don't include newline in Visual mode `$`. " TODO: Do you just want `set selection=old`? Nope, the builtin `matchit` " doesn't work correctly with `selection=old`, this is probably a bug though " and might get fixed. " set selection=old xnoremap $ $h """" Visual mode put that doesn't clobber unnamed register " See also . xnoremap P pgvy """ Visual mode """" Visually select last pasted text " TODO: Make a text object as well? " TODO: I use this relatively often, but it clobbers the built in |gp|. I never " use that, but it seems useful, so maybe I should? Find another natural " mapping? " Analogous with how |gv| visually selects last visually selected text. Default " to always using ordinary Visual mode. Linewise and blockwise with |+eval| " support. nnoremap gp `[v`] if has('eval') nnoremap gp '`[' . getregtype()[0] . '`]' endif """" Restrict Visual mode substitutions to the selected text xnoremap s :s/\%V """" Visual movement xnoremap hoho xnoremap jojo xnoremap koko xnoremap lolo """ Mouse """" Scroll vertically by single lines " As suggested in |scroll-mouse-wheel|. nnoremap xnoremap inoremap nnoremap xnoremap inoremap """" Scroll horizontally by single columns with nnoremap zh xnoremap zh inoremap zh nnoremap zl xnoremap zl inoremap zl nnoremap zh xnoremap zh inoremap zh nnoremap zl xnoremap zl inoremap zl """" Toggle folds with <2-RightMouse> " noremap za noremap <2-RightMouse> za " noremap <3-RightMouse> za " noremap <4-RightMouse> za """ Command-line " Take already written text into account when searching history. cnoremap cnoremap " Try not to interfere with |'wildmenu'|. if has('eval') cnoremap wildmenumode() ? "\" : "\" cnoremap wildmenumode() ? "\" : "\" endif """ Wildmenu " and moves the cursor, not the completion selection. As " suggested in 'wildmenu'. cnoremap cnoremap """ Terminal " TODO: Call a function that: " - Find (the first) buffer with `&buftype ==# 'terminal'` " - If it doesn't have window, create one and make it focused " - Switch to the terminal buffer " - If none, do `:terminal` " NOTE: The proceedure described above is more or less `:Start` from " `vim-dispatch`. nnoremap t :terminal """ Macros " Repeat the macro in register `q` on current line, lines covered by visual " selection, or line covered by text object. nnoremap QQ @q xnoremap Q :normal! @q nnoremap Q :set operatorfunc=Qg@ if has('eval') function! s:Q(...) abort '[,']normal! @q endfunction endif """ Diffs " Toggle 'diffopt' ignores " See also |unimpaired|'s |yod|. Mapping suffix based on the `diff` flags. " TODO: `&diffopt=~'iwhite'` will match if `&diffopt` contains e.g. " `iwhiteall`, use `'\(^\|,\)iwhite\(,\|$\)'` instead. Introduce a helper " function that does the wrapping. Update: We're trying out word boundaries. " TODO: Maybe even introduce a helper that does the toggling. Look at " `vim-unimpaired` implementation? nnoremap yoDB :set diffopt=&diffopt=~'\' ?'-':'+'=iblank nnoremap yoDi :set diffopt=&diffopt=~'\' ?'-':'+'=icase nnoremap yoDb :set diffopt=&diffopt=~'\' ?'-':'+'=iwhite nnoremap yoDw :set diffopt=&diffopt=~'\'?'-':'+'=iwhiteall nnoremap yoDZ :set diffopt=&diffopt=~'\'?'-':'+'=iwhiteeol nnoremap yoDB ':set diffopt'.(&diffopt=~'\' ?'-':'+').'=iblank' nnoremap yoDi ':set diffopt'.(&diffopt=~'\' ?'-':'+').'=icase' nnoremap yoDb ':set diffopt'.(&diffopt=~'\' ?'-':'+').'=iwhite' nnoremap yoDw ':set diffopt'.(&diffopt=~'\'?'-':'+').'=iwhiteall' nnoremap yoDZ ':set diffopt'.(&diffopt=~'\'?'-':'+').'=iwhiteeol' " Windows " This could be smarter. E.g. Look if *any* window has 'diff' set and save them " in a list before doing `:diffoff`; restore for all windows when doing " `:diffthis`. nnoremap dw :windo diff=&diff?'off':'this' " Current file. " Se also |:DiffOrig|. " TODO: Use a buffer? " TODO: `--old-group-format "$(TODO)"` " nnoremap dff :w ! \ diff -u --color=always %:S - \ \| tail -n +3 \ \| less -FR \ nnoremap dfw :w ! \ diff -u %:S - \ \| tail -n +3 \ \| wdiff -d -n \ -w "$([ "$(tput colors)" -ge 16 ] && tput setaf 9 \|\| { tput bold; tput setaf 1; })" \ -y "$([ "$(tput colors)" -ge 16 ] && tput setaf 10 \|\| { tput bold; tput setaf 2; })" \ -x "$([ "$(tput colors)" -ge 16 ] && tput setaf 15 \|\| { tput bold; tput setaf 7; })" \ -z "$([ "$(tput colors)" -ge 16 ] && tput setaf 15 \|\| { tput bold; tput setaf 7; })" \ \| less -FR \ " Requires `vim-fugitive`. nmap dg :Gdiffsplit " Analogous with |dp| |do| in Normal mode. " TODO: Is adding a `diffupdate` at the end useful? nnoremap dpp :.diffput nnoremap doo :.diffget xnoremap dp :diffput xnoremap do :diffget nnoremap dp :set operatorfunc=diffputg@ nnoremap do :set operatorfunc=diffgetg@ if has('eval') function! s:diffput(...) abort '[,']diffput endfunction function! s:diffget(...) abort '[,']diffget endfunction endif """ Formatting " Format comment (only). NOTE that this requires a `gc` comment text object " plugin. nmap gQ gqgc nmap gW gwgc """ Folds " Focus current fold. nnoremap zV zMzv " Focus next/previous fold. Overwrites default move to start/end of " next/previous fold. " TODO: |c_CTRL-R_=| requires |+eval|? nnoremap zj mgvzc'>zv nnoremap zk zvzckVzvV:=prevnonblank(line('.'))zvzcVoVzv " Open/close nested folds recursively. Overwrites default open/close fold under " cursor recursively. nnoremap zO zvzczO nnoremap zC zvzcV:foldclose!zvzc """ Spelling " Correct last misspelled word with first suggestion without moving the cursor. " See also |compl-spelling|. nnoremap z? [s1z= inoremap u[s1z=`]au """ Visual mode operators " Allows for visual selection of text objects that share a name with an " operator. nnoremap v :set operatorfunc=vg@ nnoremap V :set operatorfunc=Vg@ nnoremap :set operatorfunc=CVg@ if has('eval') function! s:v(...) abort execute 'normal!' '`[v`]' endfunction function! s:V(...) abort execute 'normal!' '`[V`]' endfunction function! s:CV(...) abort execute 'normal!' "`[\`]" endfunction endif """ Align operator " Requires the `column` program (in `bsdextrautils` on Debian). " See also |lion|. " TODO: Does not support |count|, |quote|. " TODO: When re-sourcing the vimrc, this overrides the previous |vim-lion| " mappings. xnoremap gl !column -t -o ' ' if has('eval') nnoremap gl :set operatorfunc=glg@ function! s:gl(...) abort '[,']!column -t -o ' ' endfunction endif """ Normalize date to ISO 8601 " Requires the `date` program (in `coreutils` on Debian). " See |:visual_example|. " See also |abolish-coercion|. " This is hacky but works without |+eval|. xnoremap crd `>a`!!date +'\%Y-\%m-\%d' -f -kJJ """ Go to string in file under cursor " Make |gF| support `filename:/search string/`. " " The built-in |gF|, and related |CTRL-W_F|, |CTRL-W_gF|, commands extend |gf| " by also parsing trailing `:{lineno}` (specifically, any non-filename " character optionally surrounded by whitespace, or the literal string " ` line `, followed by a decimal number). This corresponds to common output of " compilers/interpreters/linters. It also happens to roughly correspond to " _one_ of the common (or, for [POSIX.1-2017][], allowed) outputs of `ctags`. " It does not however allow the _other_ format: search strings. Let's fix that. " " Search strings are very useful when you're not sure what version of the file " someone else might have, so it's hard to give an accurate line number, but " the chance is high that a search string will yield the correct location. It " also conveys more information to someone not wanting to _follow_ the " reference right now than a line number would. " " Vim actually allows _any_ Ex command in tag files (subject to |'exrc'| and " |'secure'|, see |tag-security|), not just line numbers and search strings, " see |tags-file-format|. The mapping below only accepts what amounts to " possibly anchored non-regex search strings, for three reasons: 1) security, " 2) implementation simplicity, 3) it is what [POSIX.1-2017][] `ctags` / `ex` / " `vi` supports. " " It is important that we lean on the built-in mappings as much as possible " since they include functionality based on , |'isfname'|, |'path'|, " |'suffixesadd'|, and |'includeexpr'|, special handling of escaped spaces and " trailing punctuation, as well as home directory and environment variable " expansion (|expandcmd|) that would be hard to re-implement, see |gf|. Note " that the built-in mappings only trigger when the cursor is on or before the " _filename_, not on the address. |gF| falls back to |gf| functionality without " giving an error message if a trailing line number can't be found, which we " mimic. |gF| also doesn't give an error (or any) message if the given line " number is not present in the file (it goes to the closest one, i.e. the first " or last line), so we use a "soft" |:echo| instead of "hard" |:echoerr| to " tell the user if the search string was not found. " " [POSIX.1-2017]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ctags.html#tag_20_27_12 " TODO: I think the regex is not quite right, like it triggers even when the " cursor is not on the filename. Maybe we need to put the |/\%>| in a group, or " adjust the `col('.')-1`. I lost the test case, sorry. " TODO: Clarify/expand separators. POSIX mandates tabs as separators for tag " files, document that we use the |gF| rules instead, after we implement them " completely (` line `). Also hardcode to allow : as separator, because " ftplugin/perl.vim:/^set isfname/ adds : to the set of valid filenames " 'isfname' (a global option!). Document this too. " TODO: POSIX allows / and ? as pattern delimiters, we only allow /. Fix this " and document. " TODO: POSIX allows the anchors ^ and $ to be used independently. It looks " like we do too, but it is not clear from the documentation. " TODO: Also support `file:line:col`? Generalize the separator to conform to " the |gF| rules, but change ` line ` to ` col(umn)? `. " TODO: We are accruing features. Split into plugin? `vim-unobtrusive-gf`? " TODO: The excessive string concatenation is done for readability, but it " might be better (and faster) as comments? Those can get out of sync though... if has('eval') nnoremap gF :call gf("gF") nnoremap F :call gf("\C-W>F") nnoremap gF :call gf("\C-W>gF") let s:isfname = &isfname function! s:gf(cmd) abort let back = '\\\\' let slash = '\\\/' let dollar = '\$\/\@!' let other = '[^\/$]' let chr = '\%(' . join([back, slash, dollar, other], '\|') . '\)' let str = '\(' . chr . '\+\)' let start = '\(\^\?\)' let end = '\(\$\?\)' let addr = '\/' . start . str . end . '\/' let after = '\%>' . (col('.')-1) . 'c' let file = '[[:fname:]]' let sep = '[[:space:]]*[^[:fname:][:digit:]/][[:space:]]*' let pat = '\m' . after . file . sep . addr " echo pat let v:errmsg = "" try " See |myvimrc-isfname-bug|. Save the current 'isfname' and then set it " to the one we set in our vimrc earlier (i.e. our actual preference). let isfname = &isfname let &isfname = s:isfname let match = matchlist(getline('.'), pat) silent! execute 'normal!' (v:count1 . a:cmd) finally " If the above `execute` triggered a change in 'isfname' through a loaded " ftplugin, let that change stand. Otherwise revert our earlier override. if &isfname ==# s:isfname let &isfname = isfname endif endtry if v:errmsg != "" echohl Error | echomsg v:errmsg | echohl None elseif !empty(match) let start = match[1] let str = match[2] let end = match[3] let pat = '\C' . '\m' . start . '\V' . escape(str, '\') . '\m' . end call cursor(1, 1) if search(pat, 'c') normal! zz else echo "Can't find search string /" . start . str . end . "/" endif endif endfunction endif "" Commands """ Fill quickfix with output from system command " TODO: || does not seem to escape quotes, so things like `Cexpr echo " 'hello'` does not work. Probably passing it to a function so that we get a " argument variable to call |shellescape()| on is required? " TODO: How does this compare to |dispatch|? command! -bang -nargs=+ -complete=shellcmd Cexpr \ execute (empty()?'cexpr':'cgetexpr') 'system(expandcmd(' escape(, "'") '))' """ Run `git ls` and preview commits on cursor move " TODO: |fugitive|'s |Gclog| probably covers this use case. Remove? " Requires |fugitive| and a `ls`/`lsa` Git alias. command! -bar -nargs=0 Gls \ Git ls | \ execute 'nmap j j:silent vert Gpedit =' | \ execute 'nmap k k:silent vert Gpedit =' | \ execute 'autocmd vimrc BufUnload pclose' | command! -bar -nargs=0 Glsa \ Git lsa | \ execute 'nmap j j:silent vert Gpedit =' | \ execute 'nmap k k:silent vert Gpedit =' | \ execute 'autocmd vimrc BufUnload pclose' | """ Diff " See also |start-vimdiff|, |:DiffOrig|. " TODO: This is unfinished. if has('eval') command! -nargs=* -complete=file Diff call s:diff() function! s:diff(arglist) abort " windo diffoff " if a:0 " let args = map( " \ flatten(map( " \ copy(a:000), " \ 'expand(v:val, 1, 1)' " \ )), " \ 'fnameescape(v:val)' " \ ) " execute 'args' join(args) if a:arglist execute 'args' arglist vertical all windo diffthis else " let filetype = &filetype " let swapfile = &swapfile diffthis aboveleft vertical new diffthis " let &filetype = filetype " let &swapfile = swapfile let &filetype = getbufvar('#', '&filetype') let &swapfile = getbufvar('#', '&swapfile') let &buftype = 'nofile' let &bufhidden = 'wipe' let &modifiable = 1 " Even `bh=wipe` doesn't forget the `noma` below. execute 'file' 'diff://' . expand('#:p') read ++edit # 1 delete _ let &modifiable = 0 wincmd p endif endfunction endif "" Auto commands """ Options """" 'background' " Vim likes to automatically reset |'background'| at inopportune moments (like " at `$VIMRUNTIME/colors/default.vim:/set bg&/`). if has('eval') let s:background = &background autocmd vimrc OptionSet background let &background = s:background endif """" 'ttyscroll' " *myvimrc-autocmd-ttyscroll* " Unconditionally enable |'ttyscroll'| (by setting it to its default value " `999`) if there are no vertical splits (so terminal scrolling can actually be " used without downsides) and restore if there are vertical splits. Makes the " most noticeable difference when doing |CTRL-U| |CTRL-D| in a Linux virtual " terminal. " TODO: When we set it to `999` we could store the current value in " `s:ttyscrol` so that manual adjustments won't be lost. if has('eval') let s:ttyscroll = &ttyscroll autocmd vimrc VimEnter,WinEnter * \ let &ttyscroll = empty(filter(getwininfo(), 'v:val.wincol != 1')) \ ? 999 \ : s:ttyscroll endif """ Save/load view " Roughly as suggested in |:loadview|, load auto-saved view when opening " buffer. Better (TODO: how?) than |last-position-jump|, |restore-cursor|. See " also |'viewoptions'|. " TODO: Use a (configurable?) `[nr]` argument to the `{mk,load}view` and " reserve the use of the no argument version for the user. " TODO: We used to also match on `Buf{Write,Read}` but that generated "E32: No " file name" when e.g. discarding changes with `X` in the `vim-fugitive` `:Git` " window. autocmd vimrc BufWinLeave * \ if !empty(expand('')) && empty(&buftype) | \ mkview | \ endif | autocmd vimrc BufWinEnter * \ if !empty(expand('')) && empty(&buftype) | \ loadview | \ endif | """ Unclutter special buffers " TODO: This needs to be moved to after the plugins for it to work in e.g. " fugitive? if !has('nvim') autocmd vimrc BufReadPost,TerminalWinOpen * \ if !empty(&buftype) | \ silent setlocal nolist nospell | \ endif | endif """ Fixate terminal height autocmd vimrc TerminalWinOpen * \ set winfixheight | \ 15wincmd _ | """ QuickFix/Location list """" Open window automatically " See " - " - " - " TODO: These `vim-dispatch` issues might have been fixed? " TODO: Maybe this can be fixed by switching back to the previous window after " opening the quickfix window? Make sure to only switch to the previous if we " actually opened the window. " autocmd vimrc QuickFixCmdPost [^l]* nested botright cwindow " autocmd vimrc QuickFixCmdPost l* nested botright lwindow " autocmd vimrc QuickFixCmdPost {{make,{,vim}grep{,add}},c{,get,add}{expr,file,buffer}} nested botright cwindow " autocmd vimrc QuickFixCmdPost {l{make,{,vim}grep{,add}},l{,get,add}{expr,file,buffer}} nested botright lwindow """" Conceal column numbers autocmd vimrc BufReadPost quickfix \ setlocal conceallevel=2 concealcursor=nvic nonumber | \ syntax match qfColumnNr / col \d\+/ containedin=qfLineNr transparent conceal | """ Highlight all searches " |'incsearch'| only highlights the first match. if has('eval') autocmd vimrc CmdlineEnter /,\? let s:hlsearch = &hlsearch | set hlsearch autocmd vimrc CmdlineLeave /,\? let &hlsearch = s:hlsearch endif """ Terminal folding " If a line (like a shell prompt) starts with `│` it will define a fold start. " TODO: More "shell integrations": " - " - " - OSC 133: Prompt. " - " - OSC 7: Current directory. " - autocmd vimrc TerminalWinOpen * \ set foldlevel=0 | \ set foldmethod=expr | \ set foldexpr=getline(v:lnum)=~'^│'?'>1':'=' | autocmd vimrc CursorMoved * \ if &buftype ==# 'terminal' | \ let &foldmethod = &foldmethod | \ endif | """ Find other Vim instance when swap file exists " Only for Unix-likes. POSIX-compliant. Sends signal `USR1` which when received " outputs a `BEL` to the terminal, hopefully making the terminal emulator mark " the window as urgent, helping the user find it. Under X11 if `xdotool` is " installed one alternative might be `!xdotool set_window --urgency 1 " $WINDOWID`. |swapinfo| was added in `8.1.0313` and |SigUSR1| in `8.2.0952`. if has('eval') && executable('kill') autocmd vimrc SwapExists * \ let s:swapinfo = swapinfo(v:swapname) | \ if s:swapinfo['host'] == hostname() | \ call system('kill -USR1 ' . s:swapinfo['pid']) | \ endif | autocmd vimrc SigUSR1 * silent execute "!printf '\\a'" | silent redraw! endif "" Colors " See |cterm-colors|, |gui-colors|. " See |colortest.vim|, |hitest.vim|. " TODO: If/when we break this out to a separate file/plugin, we might want to " link to stuff like this: " - " - " This creates problems, we should just make sure files opened with " `vim.desktop` get the colors. It looks like `.desktop` files with " `Terminal=true` makes the terminal source `~/.profile` but not `~/.shrc` " (which makes sense in a way, it's `Terminal`, not `Shell`). if $_ ==# '/usr/bin/xdg-open' silent !. ~/.shrc.d/color.sh " redraw! endif " TODO: Document that |autocmd| is available in "tiny" (i.e. always) but " |+syntax| requires "normal", so doing it the way we're doing it makes sure it " works everywhere. This is especially important for interface highlights " (|listchars|). " TODO: This is getting ridiculous. |:syntax-on| suggests we can just use " |:highlight| outside any |autocmd|s and it will work. Look into this. " TODO: Support `has('gui_running')` and |'termguicolors'|. Look into e.g. " |g:terminal_ansi_colors|. """ General " Transparent background, grayscale interface. Sensible errors/warnings, " spellchecking, diffs, comments, and todos. See |:hi-normal| and " |:hi-normal-cterm|. if !has('gui_running') autocmd vimrc ColorScheme * nested \ highlight! Normal guibg=NONE | endif " TODO: Look at all in |'highlight'| (in particular |hl-Search|) and |highlight-default|. " TODO: This could be done by setting |'highlight'| instead of monkying around " with highlight groups. Unclear if better. " TODO: For all chromatic colors, use `Light*`. " TODO: Remove all `White` except `Normal` from this list and link them to `Normal`? " TODO: Remove all `Gray` except `Comment` from this list and link them to `Comment`? " NOTE: When |hl-StatusLine| is a |:hi-link| Vim cannot determine if it's equal " to |hl-StatusLineNC| and uses "^^^". Same for `StatusLineTerm{,NC}`. See " `$VIMSRC/src/drawscreen.c:550` (at the bottom of the function " `win_redr_status`) in the Vim source. " TODO: Since the Linux console cannot use `DarkGray` as a background, consider " using any other `Dark*` color (e.g. `DarkYellow`) as (non-`reverse`) `Visual` " `ctermbg` with `ctermfg=NONE`. NOTE: This requires that we standardize on " `__color_set_uniform_diff_low`. `__color_set_uniform_diff_high` works (in " fact is required) for `cterm=reverse ctermfg=NONE ctermbg=NONE`. " TODO: Why do we need the `term=NONE`? Is this tested ever? Is it used in " `vim.tiny`? " TODO: Vim requests the background color from the terinal with the escape " sequence |t_RB| and sets |'background'| when it gets the response " (|v:termrbgresp|). That response may come after |vimrc| has completed, so if " you want to do |:colorscheme| do it in a `autocmd vimrc OptionSet " background`. " autocmd vimrc ColorScheme * nested " \ highlight Normal font='Monospace Regular 10' " Emphasis levels, in ascending order: " " | Highlight | Use case | Example | " | `Comment` | Non-highlighted (interface, menus) | `StatusLineNC` | " | `Normal` | Non-highlighted (interface, menus) | `StatusLine` | " | `Visual` | Highlighted (buffer text) | `Search` | " | `cterm=reverse` | Highlighted (buffer text) | `IncSearch` | " \ set background=dark | runtime syntax/syncolor.vim | autocmd vimrc ColorScheme * nested \ highlight Normal term=NONE cterm=NONE gui=NONE ctermbg=NONE ctermfg=White | \ highlight Comment term=NONE cterm=NONE gui=NONE guibg=NONE ctermbg=NONE ctermfg=DarkGray | \ highlight Todo term=NONE cterm=NONE gui=NONE guibg=NONE ctermbg=NONE ctermfg=White | \ highlight Error term=NONE cterm=NONE gui=NONE guibg=NONE ctermbg=NONE ctermfg=LightRed | \ highlight SpellBad term=NONE cterm=NONE gui=NONE guibg=NONE ctermbg=NONE ctermfg=LightRed | \ highlight SpellOther term=NONE cterm=NONE gui=NONE guibg=NONE ctermbg=NONE ctermfg=LightRed | \ highlight Visual term=NONE cterm=NONE gui=NONE ctermbg=LightGray ctermfg=NONE | \ highlight Search term=NONE cterm=NONE gui=NONE ctermbg=DarkBlue ctermfg=NONE | \ highlight IncSearch term=NONE cterm=NONE gui=NONE ctermbg=DarkYellow ctermfg=NONE | \ highlight DiffAdd term=NONE cterm=NONE gui=NONE ctermbg=DarkGreen ctermfg=NONE | \ highlight DiffDelete term=NONE cterm=NONE gui=NONE ctermbg=DarkRed ctermfg=NONE | \ highlight DiffChange term=NONE cterm=NONE gui=NONE ctermbg=DarkBlue ctermfg=NONE | \ highlight DiffText term=NONE cterm=NONE gui=NONE ctermbg=DarkYellow ctermfg=NONE | \ highlight diffAdded term=NONE cterm=NONE gui=NONE guibg=NONE ctermbg=NONE ctermfg=LightGreen | \ highlight diffRemoved term=NONE cterm=NONE gui=NONE guibg=NONE ctermbg=NONE ctermfg=LightRed | \ highlight StatusLine term=NONE cterm=NONE gui=NONE ctermbg=NONE ctermfg=White | \ highlight StatusLineTerm term=NONE cterm=NONE gui=NONE ctermbg=NONE ctermfg=White | \ highlight StatusLineNC term=NONE cterm=NONE gui=NONE guibg=NONE ctermbg=NONE ctermfg=DarkGray | \ highlight StatusLineTermNC term=NONE cterm=NONE gui=NONE guibg=NONE ctermbg=NONE ctermfg=DarkGray | \ highlight Ignore term=NONE cterm=NONE gui=NONE guibg=NONE ctermbg=NONE ctermfg=Black | " \ highlight DiffAdd term=NONE cterm=NONE gui=NONE ctermbg=LightGreen ctermfg=Black | " \ highlight DiffDelete term=NONE cterm=NONE gui=NONE ctermbg=LightRed ctermfg=Black | " \ highlight DiffChange term=NONE cterm=NONE gui=NONE ctermbg=LightBlue ctermfg=Black | " \ highlight DiffText term=NONE cterm=NONE gui=NONE ctermbg=LightYellow ctermfg=Black | """ No bold " Remove all `cterm=bold` set by default in `$VIMRUNTIME/syntax/syncolor.vim`. " The Linux virtual console does typically not have a bold font. autocmd vimrc ColorScheme * nested \ highlight Identifier cterm=NONE ctermfg=LightCyan | """ No underline " Remove all `cterm=underline` set by default in `$VIMRUNTIME/syntax/syncolor.vim`. " `Underlined` is linked to by `htmlLink` and `mkdLink` by default and is too " cluttered for my taste. autocmd vimrc ColorScheme * nested \ highlight Underlined cterm=NONE | """ Wildmenu " set highlight-=s:StatusLine " set highlight-=S:StatusLineNC " set highlight-=z:StatusLineTerm " set highlight-=Z:StatusLineTermNC " set highlight+=s:Normal,z:Normal,S:Comment,Z:Comment autocmd vimrc ColorScheme * nested \ highlight! link TabLineSel Normal | \ highlight! link ToolbarButton Comment | " \ highlight! link StatusLine Normal | " \ highlight! link StatusLineTerm Normal | """ Interface autocmd vimrc ColorScheme * nested \ highlight! link TabLine Comment | \ highlight! link TabLineFill Comment | \ highlight! link ToolbarLine Comment | \ highlight! link VertSplit Comment | \ highlight! link LineNr Comment | \ highlight! link Folded Comment | \ highlight! link FoldColumn Comment | \ highlight! link SignColumn Comment | " \ highlight! link StatusLineNC Comment | " \ highlight! link StatusLineTermNC Comment | """ Errors/warnings autocmd vimrc ColorScheme * nested \ highlight! link ErrorMsg Error | \ highlight! link WarningMsg Error | """ Spell autocmd vimrc ColorScheme * nested \ highlight! link SpellCap SpellOther | \ highlight! link SpellRare SpellOther | \ highlight! link SpellLocal SpellOther | """ Visual autocmd vimrc ColorScheme * nested \ highlight! link VisualNOS Visual | \ highlight! link ColorColumn Visual | \ highlight! link CursorColumn Visual | \ highlight! link CursorLine Visual | \ highlight! link CursorLineNr Visual | """ Wildmenu autocmd vimrc ColorScheme * nested \ highlight! link WildMenu Search | """ Popup menu autocmd vimrc ColorScheme * nested \ highlight Pmenu ctermbg=LightGray ctermfg=DarkGray | \ highlight PmenuSel ctermbg=LightGray ctermfg=White | \ highlight PmenuSbar ctermbg=DarkGray | \ highlight PmenuThumb ctermbg=White | """ Ignore " See |'highlight'|. By default links to |NonText|. autocmd vimrc ColorScheme * nested \ highlight! link EndOfBuffer Ignore | """ Non-Ignore " By default links to |Ignore|. autocmd vimrc ColorScheme * nested \ highlight! link helpIgnore Comment | \ highlight! link helpBacktick helpIgnore | \ highlight! link helpBar helpIgnore | \ highlight! link helpStar helpIgnore | """ Non-document characters " See |'highlight'|, |'showbreak'|, |'listchars'| `extends` `precedes` `eol`. autocmd vimrc ColorScheme * nested \ highlight! link NonText Special | """ Document non-printables characters " See |'highlight'|, |'listchars'| `tab`, `space`, `trail`, `nbsp`. autocmd vimrc ColorScheme * nested \ highlight! link SpecialKey Comment | """ Document conceal replacement characters autocmd vimrc ColorScheme * nested \ highlight! link Conceal Identifier | """ Debug autocmd vimrc ColorScheme * nested \ highlight debugPC term=reverse cterm=NONE gui=NONE guibg=DarkBlue ctermbg=DarkBlue guifg=NONE ctermfg=NONE | \ highlight debugBreakpoint term=NONE cterm=NONE gui=NONE guibg=NONE ctermbg=NONE guifg=LightRed ctermfg=LightRed | " TODO: Filetype-specific customizations probably should trigger on some other " event. """ Markdown delimiters autocmd vimrc ColorScheme * nested \ highlight! link mkdDelimiter Comment | \ highlight! link mkdCodeDelimiter Comment | \ highlight! link mkdCodeStart Comment | \ highlight! link mkdCodeEnd Comment | """ Vim comments autocmd vimrc ColorScheme * nested \ highlight! link vimCommentString vimComment | \ highlight! link vimCommentTitle vimComment | """ Apply " TODO: Move `syntax enable` to someplace before this? " TODO: `doautocmd vimrc ColorScheme` worked for everything except when using " Vim as `$MANPAGER`. Not sure if this is a problem with `vimrc` or " `.vim/ftplugin/man.vim`. We don't always `has('eval')` though. " echom &background " if has('eval') " colorscheme default " endif " echom &background doautocmd vimrc ColorScheme " autocmd vimrc VimEnter * nested doautocmd vimrc ColorScheme " autocmd vimrc OptionSet background,t_Co nested doautocmd vimrc ColorScheme "" Plugins if has('eval') """ |mapleader| let g:mapleader = "\" let g:localmapleader = "\" """ GitAdd " " Make sure to not enable |:syntax| and |:filetype| until all plugins that " interact with them have been added! See |:packadd|. command! -bar -bang -nargs=+ GitAdd call s:GitAdd(, ) function! s:GitAdd(bang, url, ...) abort let name = split(a:url, '/')[-1] let dir = split(&packpath, ',')[0] . '/pack/gitadd/opt/' . name if !isdirectory(dir) silent execute '!git clone --recurse-submodules' join(a:000) a:url dir if isdirectory(dir . '/doc') execute 'helptags' dir . '/doc' endif endif if empty(a:bang) execute 'packadd!' name endif endfunction """ Interface """" `tpope/vim-flagship` " GitAdd https://github.com/tpope/vim-flagship """" `chrisbra/NrrwRgn` GitAdd https://github.com/chrisbra/NrrwRgn let g:nrrw_topbot_leftright = 'belowright' xmap nr NrrwrgnDo """ File type """" Built-in `vim` " See |ft-vim-indent|. let g:vim_indent_cont = 0 """" Built-in `sh` " See |ft-sh-syntax|. let g:is_posix = 1 """" Built-in `man` " See |ft-man-plugin|. let g:ft_man_folding_enable = 1 " TODO: Should be easy to create a |'foldexpr'| that's better than the " built-in `foldmethod=indent`. " function s:manfold() abort " foldlevel() " endfunction " We're using our own |:ManHelp| instead. " runtime ftplugin/man.vim " setglobal keywordprg=:Man """" Built-in `asm` " See |ft-asm-syntax|. let g:filetype_i = 'asm' """" `tpope/vim-markdown` " GitAdd https://github.com/tpope/vim-markdown """" `preservim/vim-markdown` GitAdd https://github.com/preservim/vim-markdown let g:vim_markdown_no_default_key_mappings = 1 let g:vim_markdown_toc_autofit = 1 let g:vim_markdown_math = 1 let g:vim_markdown_frontmatter = 1 let g:vim_markdown_no_extensions_in_markdown = 1 let g:vim_markdown_auto_insert_bullets = 0 let g:vim_markdown_new_list_item_indent = 0 " " Defaults. " " |vim-markdown-fenced-code-block-languages| " let g:vim_markdown_fenced_languages = [ " \ "c++=cpp", " \ "viml=vim", " \ "bash=sh", " \ "ini=dosini", " \ ] " " Additions. " call add(g:vim_markdown_fenced_languages, [ " \ "diff", " \ ]) " " let g:vim_markdown_new_list_item_indent = 0 " let g:vim_markdown_auto_insert_bullets = 0 """" `vim-pandoc/vim-pandoc-syntax` " GitAdd https://github.com/vim-pandoc/vim-pandoc-syntax " Roughly as recommended in the readme. " autocmd vimrc BufNewFile,BufFilePre,BufRead *.md set filetype=markdown.pandoc """" `gpanders/vim-medieval` GitAdd https://github.com/gpanders/vim-medieval " Roughly as suggested in `vim-medieval/README.md:/Create a mapping/` (but " not mentioned in |medieval.txt|...). autocmd vimrc FileType markdown \ nmap ! (medieval-eval) " TODO: Add `octave` (and `matlab`?). We probably need flags to prevent " opening a GUI, does medieval support flags? let g:medieval_langs = ['sh', 'bash', 'python=python3'] """" `sheerun/vim-polyglot` GitAdd https://github.com/sheerun/vim-polyglot let g:polyglot_disabled = [ \ 'sensible', \ 'autoindent', \ 'markdown', \ ] """" `tpope/vim-sleuth` GitAdd https://github.com/tpope/vim-sleuth """" `tpope/vim-apathy` " GitAdd https://github.com/tpope/vim-apathy """" `tpope/vim-scriptease` GitAdd https://github.com/tpope/vim-scriptease """" `jyscao/vim-greprtpscr` GitAdd! https://github.com/jyscao/vim-greprtpscr """" `vimwiki/vimwiki` " GitAdd https://github.com/vimwiki/vimwiki " let g:vimwiki_list = [{ " \ 'path': '~/notes/', " \ 'syntax': 'markdown', " \ 'ext': '.md', " \ }] """" `mhinz/vim-rfc` GitAdd https://github.com/mhinz/vim-rfc """" `HiPhish/info.vim` GitAdd https://gitlab.com/HiPhish/info.vim """ Normal mode """" Built-in `matchit` packadd! matchit """" `tpope/vim-unimpaired` GitAdd https://github.com/tpope/vim-unimpaired " Also search for `map[a-z]* \+\S*[][]` in this file. " " " nnoremap yoe :setlocal conceallevel==&conceallevel == 0 ? 2 : 0 nnoremap [oe :setlocal conceallevel==&conceallevel == 0 ? 0 : &conceallevel - 1 nnoremap ]oe :setlocal conceallevel==&conceallevel == 2 ? 2 : &conceallevel + 1 " See also `tpope/sleuth.vim` " function! s:textwidth() abort " return max(map(range(1, line('$')), 'len(getline(v:val))')) " endfunction " let g:textwidth = &textwidth " nnoremap yoT :setlocal textwidth==&textwidth == g:textwidth ? textwidth() : g:textwidth """" `tpope/vim-repeat` " Does `vim-repeat` have to go at the beginning to activate integrations with " other plugins (e.g. `vim-unimpaired`)? GitAdd https://github.com/tpope/vim-repeat """" `inkarkat/vim-visualrepeat` " NOTE: Requires GitAdd https://github.com/inkarkat/vim-visualrepeat """" `tpope/vim-characterize` GitAdd https://github.com/tpope/vim-characterize """" `chrisbra/unicode.vim` " GitAdd https://github.com/chrisbra/unicode.vim """" `haya14busa/vim-asterisk` GitAdd https://github.com/haya14busa/vim-asterisk " As suggested by |asterisk-key-mappings|, except the mappings that don't " move the cursor set |'hlsearch'|. map * (asterisk-*) map # (asterisk-#) map g* (asterisk-g*) map g# (asterisk-g#) map z* (asterisk-z*): set hlsearch map z# (asterisk-z#): set hlsearch map gz* (asterisk-gz*):set hlsearch map gz# (asterisk-gz#):set hlsearch """" `AndrewRadev/splitjoin.vim` GitAdd https://github.com/AndrewRadev/splitjoin.vim " TODO: According to |splitjoin_align| this requires either of the Tabular or " Align plugins. We currently prefer vim-lion. Create a pull request? " let g:splitjoin_align = 1 """" `AndrewRadev/switch.vim` GitAdd https://github.com/AndrewRadev/switch.vim " TODO: The ones with `\%#` |cursor-position| does not work, probably because " `switch.vim` tries to match it at some other position internally. Searching " manually yields the expected matches though. let g:switch_custom_definitions = [{ \ '\<0\>': '1', \ '\<1\>': '0', \ '\': 'ON', \ '\': 'On', \ '\': 'on', \ '\': 'OFF', \ '\': 'Off', \ '\': 'off', \ '\': 'YES', \ '\': 'Yes', \ '\': 'yes', \ '\': 'NO', \ '\': 'No', \ '\': 'no', \ '\(\w*\)FALSE\(\w*\)': '\1TRUE\2', \ '\(\w*\)False\(\w*\)': '\1True\2', \ '\(\w*\)false\(\w*\)': '\1true\2', \ '\(\w*\)TRUE\(\w*\)': '\1FALSE\2', \ '\(\w*\)True\(\w*\)': '\1False\2', \ '\(\w*\)true\(\w*\)': '\1false\2', \ '\(\ :call smooth_scroll#up( &scroll*1, 20, &scroll/4) " noremap :call smooth_scroll#down(&scroll*1, 20, &scroll/4) " noremap :call smooth_scroll#up( &scroll*2, 20, &scroll/2) " noremap :call smooth_scroll#down(&scroll*2, 20, &scroll/2) """ Insert mode """" `tpope/vim-endwise` GitAdd https://github.com/tpope/vim-endwise """" `jiangmiao/auto-pairs` GitAdd https://github.com/jiangmiao/auto-pairs " TODO: Look at "Swedish Character Conflict" in the documentation. " Disable meta mappings. let g:AutoPairsShortcutToggle = '' let g:AutoPairsShortcutFastWrap = '' let g:AutoPairsShortcutJump = '' let g:AutoPairsShortcutBackInsert = '' " Don't jump around too much. See |autopairs-options|. let g:AutoPairsCenterLine = 0 let g:AutoPairsMultilineClose = 0 """ Command-line mode """" `tpope/vim-rsi` " GitAdd https://github.com/tpope/vim-rsi """" `tpope/vim-abolish` GitAdd https://github.com/tpope/vim-abolish """ Visual mode """" `dahu/Severalections` GitAdd https://github.com/dahu/Severalections """ Operators """" `tpope/vim-surround` GitAdd https://github.com/tpope/vim-surround """" `tpope/vim-commentary` GitAdd https://github.com/tpope/vim-commentary """" `tommcdo/vim-lion` GitAdd https://github.com/tommcdo/vim-lion let g:lion_squeeze_spaces = 1 """" `tommcdo/vim-nowchangethat` GitAdd https://github.com/tommcdo/vim-nowchangethat """ Motions / text objects " TODO: Check that none of the later ones are not already defined by " `targets.vim`. """" `wellle/targets.vim` GitAdd https://github.com/wellle/targets.vim " `targets` just pairs up quotes from the beginning of line, which is often " not what we want (especially in shell scripts). xnoremap i" i" xnoremap i' i' xnoremap i` i` onoremap i" i" onoremap i' i' onoremap i` i` """" `bkad/CamelCaseMotion` GitAdd https://github.com/bkad/CamelCaseMotion let g:camelcasemotion_key = '' """" `tommcdo/vim-exchange` GitAdd https://github.com/tommcdo/vim-exchange """" `qstrahl/vim-dentures` " TODO: I'm not happy with this, replace. GitAdd https://github.com/qstrahl/vim-dentures """" `kana/vim-textobj-user` GitAdd https://github.com/kana/vim-textobj-user " All later plugins in the "Motions / text objects" category depend on this " plugin. See . """" `kana/vim-textobj-entire` GitAdd https://github.com/kana/vim-textobj-entire """" `kana/vim-textobj-line` GitAdd https://github.com/kana/vim-textobj-line " As suggested in |textobj-line-default-key-mappings|, except `{a,i}l` is " taken by `targets` "last", so we use uppercase `{a,i}L`. let g:textobj_line_no_default_key_mappings = 1 omap aL (textobj-line-a) omap iL (textobj-line-i) xmap aL (textobj-line-a) xmap iL (textobj-line-i) """" `kana/vim-textobj-fold` GitAdd https://github.com/kana/vim-textobj-fold """" `kana/vim-textobj-syntax` GitAdd https://github.com/kana/vim-textobj-syntax """" `kana/vim-textobj-function` GitAdd https://github.com/kana/vim-textobj-function """" `idbrii/textobj-word-column.vim` GitAdd https://github.com/idbrii/textobj-word-column.vim """" `adriaanzon/vim-textobj-matchit` GitAdd https://github.com/adriaanzon/vim-textobj-matchit """" `rhysd/vim-textobj-continuous-line` GitAdd https://github.com/rhysd/vim-textobj-continuous-line """" `rsrchboy/vim-textobj-heredocs` GitAdd https://github.com/rsrchboy/vim-textobj-heredocs """ Colors """" `gruvbox-community/gruvbox` " TODO: This is a stopgap untill we make a Vim colorscheme from " . GitAdd https://github.com/gruvbox-community/gruvbox let g:gruvbox_contrast_dark = 'hard' let g:gruvbox_invert_selection = 0 autocmd vimrc OptionSet termguicolors nested \ execute 'colorscheme' &termguicolors ? 'gruvbox' : 'default' | doautocmd OptionSet termguicolors """ Windows """" `moll/vim-bbye` GitAdd https://github.com/moll/vim-bbye """" `chrisbra/NrrwRgn` " GitAdd https://github.com/chrisbra/NrrwRgn " TODO: I have not evaluated this yet. If it isn't to our liking there is " also . """ Folds """" `rcrnstn/vim-unobtrusive-fold` GitAdd https://git.rcrnstn.net/rcrnstn/vim-unobtrusive-fold " As suggested in |unobtrusive_fold#text()|. set foldtext=unobtrusive_fold#text() " As suggested in |unobtrusive-fold-example|. " autocmd vimrc FileType * UnobtrusiveFoldComment " autocmd vimrc FileType markdown UnobtrusiveFoldChar # let g:vim_markdown_folding_disabled = 1 """ Undo """" `mbbill/undotree` GitAdd https://github.com/mbbill/undotree nnoremap u :UndotreeToggle " let g:undotree_HighlightChangedText = 0 " let g:undotree_DiffCommand = 'diff -u' """ QuickFix """" Built-in `cfilter` packadd! cfilter """" `romainl/vim-qf` " GitAdd https://github.com/romainl/vim-qf " let g:qf_mapping_ack_style = 1 " let g:qf_shorten_path = 1 " TODO: Check if this causes problems, see the "Open the QuickFix/Location " list window" section. " let g:qf_auto_open_quickfix = 0 """ Spell """" `inkarkat/vim-SpellCheck` " NOTE: Requires " GitAdd https://github.com/inkarkat/vim-SpellCheck """ Syntax """" `inkarkat/vim-SyntaxRange` " NOTE: Requires " GitAdd https://github.com/inkarkat/vim-SyntaxRange """" `ypcrts/securemodelines` " GitAdd https://github.com/ypcrts/securemodelines " TODO: Last updated 2019 as of this writing, can we be sure this is really " more secure than the built-in sandbox? Besides, we currently disable " modelines with `set modelines=0`. " let g:secure_modelines_verbose = 1 """ Modelines """" `ypcrts/securemodelines` " GitAdd https://github.com/ypcrts/securemodelines " TODO: Last updated 2019 as of this writing, can we be sure this is really " more secure than the built-in sandbox? Besides, we currently disable " modelines with `set modelines=0`. " let g:secure_modelines_verbose = 1 """ Environment interaction """" Built-in `netrw` let g:netrw_home = '~/.cache/vim/netrw' let g:netrw_banner = 0 let g:netrw_liststyle = 3 " Tree. " Netrw versions (roughly) 162h to 170 break `gx`. Never download the remote " file to a temporary. See " - " - " - let g:netrw_nogx = 1 nnoremap gx :call netrw#BrowseX(netrw#GX(), 0) xnoremap gx y:call netrw#BrowseX(@", 0) """" `bogado/file-line` GitAdd https://github.com/bogado/file-line """" `ctrlpvim/ctrlp.vim` GitAdd https://github.com/ctrlpvim/ctrlp.vim " " " " NOTE: Highly dependent on non-documented ctrlp internals. function! s:ctrlp_syntax() abort execute 'autocmd vimrc OptionSet cursorline' \ 'if winnr() == ' winnr() ' && &cursorline |' \ ' set nocursorline |' \ 'endif |' syntax region CtrlPLine start="^" end="$" syntax region CtrlPLineSel start="\%#" end="$" highlight! link CtrlPLine Comment highlight! link CtrlPLineSel Normal " TODO: `&term ==# 'linux'` does not do `underline`. highlight CtrlPPrtCursor term=underline cterm=underline endfunction " We need to define the `Syntax` `autocmd` after `ctrlp` has been loaded, but " also when we reload the `vimrc`. " TODO: This still does not work when reloading the `vimrc`. autocmd vimrc VimEnter * \ autocmd vimrc Syntax ctrlp call s:ctrlp_syntax() autocmd vimrc Syntax ctrlp call s:ctrlp_syntax() let g:ctrlp_working_path_mode = '' let g:ctrlp_match_current_file = 1 let g:ctrlp_follow_symlinks = 2 let g:ctrlp_show_hidden = 1 let g:ctrlp_status_func = '' let g:ctrlp_line_prefix = '' let g:ctrlp_use_caching = 0 let g:ctrlp_use_readdir = 0 " Respect 'wildignore'. let g:ctrlp_max_files = 0 " Default 10000. let g:ctrlp_max_depth = 40 " Default 40. let g:ctrlp_match_window = 'max:20' " Default 'max:10' " let g:ctrlp_user_command_async = 1 if has('unix') " TODO: Set `grepprg` to something similar, that skips things in " 'wildignore'. let s:wildignore = split(&wildignore, ',') let s:wildignore_name = filter(copy(s:wildignore), '!count(v:val, "/")') let s:wildignore_path = filter(copy(s:wildignore), ' count(v:val, "/")') " \ ' ' . join(map(s:wildignore_name, '"-o -name " . shellescape(v:val)')) . " \ ' ' . join(map(s:wildignore_path, '"-o -path " . shellescape(v:val)')) . let g:ctrlp_user_command = \ 'find' . \ (!g:ctrlp_follow_symlinks ? '' : ' -L') . \ ' %s' . \ ' -mount' . \ ' -maxdepth ' . g:ctrlp_max_depth . \ ' \( -false' . \ (g:ctrlp_show_hidden ? '' : ' -o -name ".*"') . \ ' ' . join(map(s:wildignore_name, '"-o -name " . v:val')) . \ ' ' . join(map(s:wildignore_path, '"-o -path " . v:val')) . \ ' \) -prune -o' . \ ' -type f -print' . \ ' 2> /dev/null' . \ (!g:ctrlp_max_files ? '' : ' | head -n ' . g:ctrlp_max_files) " \ ' -type d -exec test -d {}/.git \; -prune -o' . " \ ' -exec grep -Il . {} +' . " \ ' \(' . " \ (g:ctrlp_follow_symlinks == 2 ? ' -o -type l' : '') . " \ ' \)' . " function! s:ctrl_find_prefix(prefix, list) abort " return map(copy(a:list), '["' . a:prefix . '", shellescape(v:val)]') " endfunction " function! s:ctrl_find_join(join, list) abort " return ['\('] + eval(join(a:list, '+["' . a:join . '"]+')) + ['\)'] " endfunction " let g:ctrlp_user_command = join( " \ ['find', (!g:ctrlp_follow_symlinks ? '' : '-L'), '%s'] + " \ ['-maxdepth', g:ctrlp_max_depth] + " \ s:ctrl_find_join('-o', " \ s:ctrl_find_prefix('-name', g:ctrlp_show_hidden ? [] : ['.*']) + " \ s:ctrl_find_prefix('-name', s:wildignore_name) + " \ s:ctrl_find_prefix('-path', s:wildignore_path) " \ ) + ['-prune', '-o'] + " \ ['-type', 'f', '-print'] + " \ ['2>', '/dev/null'] + " \ (!g:ctrlp_max_files ? [] : ['|', 'head', '-n', g:ctrlp_max_files]) " \ ) endif """" `mhinz/vim-tree` " GitAdd https://github.com/mhinz/vim-tree " As suggesteed in the readme. " autocmd vimrc FileType tree " \ setlocal foldmethod=expr """" `tpope/vim-fugitive` GitAdd https://github.com/tpope/vim-fugitive " autocmd vimrc FileType fugitiveblame call fugitive#MapJumps() " http://vimcasts.org/episodes/fugitive-vim-browsing-the-git-object-database/ " TODO: Do we want `bufhidden=wipe`? autocmd vimrc BufReadPost fugitive://* setlocal bufhidden=delete autocmd vimrc FileType git set foldmethod=expr foldexpr=GitFoldexpr() function! GitFoldexpr() abort let line = getline(v:lnum) if line =~# '^diff --git' return '>1' elseif line =~# '@@ [-+0-9, ]\+ @@' return '>2' endif return '=' endfunction " TODO: Add some `git log -L` (see man page) mapping. """" `samoshkin/vim-mergetool` " GitAdd https://github.com/samoshkin/vim-mergetool """" `tpope/vim-rhubarb` " GitHub extension for `tpope/vim-fugitive`. We mostly use it for |:GBrowse|. GitAdd https://github.com/tpope/vim-rhubarb """" `tommcdo/vim-fugitive-blame-ext` GitAdd https://github.com/tommcdo/vim-fugitive-blame-ext """" `iberianpig/tig-explorer.vim` " GitAdd https://github.com/iberianpig/tig-explorer.vim """" `tpope/vim-dispatch` GitAdd https://github.com/tpope/vim-dispatch " TODO: Put this in a QuickFix section? " See also |dispatch-maps|. " TODO: Stick to the default mappings. nnoremap m% :Make %:r:S nnoremap m# :Make #:r:S nnoremap mm :Make nnoremap ma :Make all nnoremap mt :Make test " https://github.com/tpope/vim-dispatch/issues/203 function! s:focus_start_set() abort if get(b:, 'start_local', 1) let b:start_local = get(b:, 'start') endif let b:start = s:start endfunction function! s:focus_start_unset() abort if type(get(b:, 'start_local')) == type('') let b:start = b:start_local else unlet! b:start endif unlet! b:start_local endfunction function! s:focus_start(bang, command) abort if !empty(a:command) let s:start = a:command augroup vimrc_dispatch_start autocmd! augroup END silent bufdo call s:focus_start_set() augroup vimrc_dispatch_start autocmd BufEnter * call s:focus_start_set() augroup END echo 'Set global default to :Start' s:start elseif a:bang unlet! s:start augroup vimrc_dispatch_start autocmd! augroup END silent bufdo call s:focus_start_unset() if type(get(b:, 'start')) == type('') echo 'Reverted default to :Start' b:start else echo 'Reverted default to :Start' endif else if type(get(s:, 'start')) == type('') echo 'Global focus is :Start' s:start elseif type(get(b:, 'start')) == type('') echo 'Buffer default is :Start' b:start else echo 'Global default is :Start' endif endif endfunction command! -bang -nargs=* -range=-1 -complete=customlist,dispatch#command_complete FocusStart \ call s:focus_start(0, ) """" `tpope/vim-eunuch` GitAdd https://github.com/tpope/vim-eunuch """" `tpope/vim-projectionist` GitAdd https://github.com/tpope/vim-projectionist """" `tpope/vim-vinegar` " GitAdd https://github.com/tpope/vim-vinegar """ Debugging """" Built-in `termdebug` " See |terminal-debug|. packadd! termdebug " TODO: Add mappings. " TODO: Remove |:Winbar|. " TODO: Do some |termdebug-customizing|, especially |termdebug_shortcuts|. " TODO: Add some signs? See |myvimrc-characters|. " let g:termdebug_popup = 0 nnoremap dd :Termdebug " `do` conflicts with our |do| ("diff obtain", |:diffget|) " text-object. " nnoremap db :Break " nnoremap dB :Clear " nnoremap di :Step " nnoremap do :Over " nnoremap df :Finish " nnoremap dr :Run " nnoremap da :Arguments " nnoremap ds :Stop " nnoremap dc :Continue " nnoremap de :Evaluate " nnoremap dg :Gdb " nnoremap ds :Source " nnoremap da :Asm " nnoremap dw :Winbar """" `puremourning/vimspector` " GitAdd https://github.com/puremourning/vimspector " Debug Adapter Protocol (DAP) client. See " - " - " """" `vim-vdebug/vdebug` " GitAdd https://github.com/vim-vdebug/vdebug " Supports PHP, Python, Ruby, Perl, Tcl and NodeJS. " Common DeBugGer Protocol (DBGP) client. See " . """ LSP " We have not decided on a LSP/linting plugin. Wishlist: " - Compatible with at least Vim 8. " - Not require dozens of other plugins to configure/make usable. " Some things to check out, roughly in the order of looking like a good fit. " - " - " - endif " has('eval') "" Syntax and file type if has('gui_running') " See |'background'|. " TODO: Causes the GUI cursor to be misplaced? " gui endif if has('eval') filetype plugin indent on syntax enable endif "" File type detection " See |new-filetype|. if has('eval') autocmd! filetypedetect BufRead,BufNewFile *.Xresources setf xdefaults autocmd! filetypedetect BufRead,BufNewFile *.gdb*init setf gdb autocmd! filetypedetect BufRead,BufNewFile *.asy setf cpp autocmd! filetypedetect BufRead,BufNewFile *.gvpr setf c endif "" Language specific |help| if has('eval') function! s:help(cmd, arg, filetype) abort for i in range(len(a:cmd)) let a:cmd[i] = join( \ map(split(a:cmd[i], '%s', 1), 'shellescape(v:val)'), \ shellescape(a:arg) \ ) endfor silent help silent let old_shellredir = &shellredir silent let &shellredir = '>' silent setlocal buftype=nofile bufhidden=delete noswapfile silent setlocal noreadonly modifiable silent execute 'file' a:arg silent keepjumps normal! ggdG silent execute 'read' '!' join(a:cmd) silent keepjumps normal! ggdd silent execute 'setlocal' 'filetype=' . a:filetype silent setlocal readonly nomodifiable nomodified silent setlocal buftype=help " silent let &shellredir = old_shellredir endfunction endif command! -nargs=1 -complete=shellcmd ManHelp \ call s:help(['man', '%s'], , 'man') command! -nargs=1 PythonHelp \ call s:help(['python3', '-m', 'pydoc', '%s'], , 'python') command! -nargs=1 OctaveHelp \ call s:help(['octave', '--eval', 'help("%s")'], , 'octave') " TODO: Would be cool to define one for `filetype` `gitconfig` that does " `ManHelp git-config` and then `/^ {7}\zs` with the first two components of " section words and ``. "" File type overrides " TODO: We want 'path' entries to be in priority order. " TODO: It looks to me that this should be a global static default instead of a " local dynamic override. autocmd vimrc FileType * \ setlocal keywordprg=:ManHelp | " TODO: This needs work. We globally override `fillchars` `stl`/`stlnc` and " `statusline` but don't take into account file type plugins setting their own " `statusline`. autocmd vimrc FileType * \ setlocal statusline=%{Statusline()} | " See also |scriptease| (which sets both 'keywordprg' and 'path', TODO but " posssibly only in `vim` files, not `help` files). autocmd vimrc FileType vim,help \ execute "nnoremap K :helpgrep " | \ setlocal keywordprg=:help | \ setlocal path=.,$VIMRUNTIME,$VIMSRC,$HOME/.vim,$HOME/.vim/pack/*/* | \ if has('eval') | \ execute 'setlocal' 'path+=' . fnamemodify($MYVIMRC, ':h') | \ execute 'setlocal' 'path+=' . fnamemodify($MYVIMRC, ':h') . '/pack/*/*' | \ endif | \ setlocal path+=, autocmd vimrc FileType man \ setlocal textwidth=78 | autocmd vimrc FileType sh \ setlocal shiftwidth=2 | \ if has('eval') | \ execute 'setlocal' 'path=' . substitute($PATH, '[:;]', ',', 'g') | \ endif | " `path`s that start with `**` are great if you're in a project directory and " want to find stuff like CMake's " `_build/_deps/SOME_DEPENDENCY/include/SOME_PATH`, but not so great if you're " in `$HOME`. autocmd vimrc FileType c,cpp,lex,yacc,glsl \ setlocal commentstring=//\ %s | \ setlocal matchpairs=(:),{:},[:] | \ setlocal cinkeys-=0# cinoptions=L0,l1,g0,N-s,E-s,t0,c0,C1,(s,u0,W1s,m1,j1,J1,N999,*999 | \ setlocal path=.,src,src/*,include,*/_deps/*/include | autocmd vimrc FileType c,cpp,lex,yacc \ if has('eval') && executable('uname') | \ execute 'setlocal' 'path+=' . printf('/lib/modules/%s/build/include', trim(system('uname -r'))) | \ endif | \ setlocal path+=/usr/include,/usr/local/include | autocmd vimrc FileType cpp \ setlocal matchpairs+=<:> | \ setlocal path+=/usr/include/c++/* | autocmd vimrc FileType man \ setlocal nolist nospell | \ execute 'nnoremap / /^ \{4,\}\([-‐]\{2\}\S\+\, \+\)\?\zs[-‐]' | autocmd vimrc FileType dot \ setlocal commentstring=//\ %s | autocmd vimrc FileType gitcommit \ setlocal nolist spell | autocmd vimrc FileType markdown \ setlocal spell complete+=kspell | " \ setlocal formatoptions-=q | autocmd vimrc FileType python \ setlocal keywordprg=:PythonHelp | autocmd vimrc FileType octave \ setlocal keywordprg=:OctaveHelp | " TODO: Might be nice to query some external command for the `path`. autocmd vimrc FileType tex \ setlocal path=.,,/usr/share/texlive/texmf-dist/tex/latex/*/ | \ setlocal suffixesadd=.tex,.cls,.sty | " Don't insert comment leader after |i_|, |o|, or |O|. autocmd vimrc FileType * \ setlocal formatoptions-=r formatoptions-=o | " As suggested in |ft-syntax-omni|, use syntax completion if no other " completion has been defined. autocmd vimrc FileType * \ if &omnifunc ==# '' | \ setlocal omnifunc=syntaxcomplete#Complete | \ endif | " If 'filetype' is never set, "universal" autocommand configuration will not be " applied unless we explicitly trigger it. doautocmd vimrc FileType * " TODO: Add a match for `\` (and `\`?) unconditionally for all " file types. "" Terminal overrides " See |terminal-options|. """ Cursor " See |termcap-cursor-shape|, `:helpgrep t_SH`, and "Parameterized Strings" in " `terminfo(5)`. if has('cursorshape') set noshowmode " Cursor visible/invisible " On Linux the following is the default, which messes with our cursor " shape: " - `t_ve = "\033[?25h\033[?0c"` " - `t_vi = "\033[?25l\033[?1c"` " See " - " - `console_codes(4)` let &t_ve = "\033[?25h" let &t_vi = "\033[?25l" " if $TERM =~? '^xterm\(-\|$\)' " See " - " - `:helpgrep t_SH` let &t_EI = "\033[1 q" let &t_SI = "\033[5 q" let &t_SR = "\033[3 q" let &t_SH = "\033[%p1%d q" " endif if $TERM =~? '^linux\(-\|$\)' " See " - " - `console_codes(4)` let &t_EI = "\033[?6c" let &t_SI = "\033[?2c" let &t_SR = "\033[?2c" let &t_SH = "\033[?%?%p1%{3}%<%t%{6}%e%{2}%;%dc" endif endif """ True-color " See |xterm-true-color|. if has('termguicolors') && !has('nvim') " In earlier Vim versions, these are the defaults only if `$TERM` is `xterm`. let &t_8f = "\033[38;2;%lu;%lu;%lum" let &t_8b = "\033[48;2;%lu;%lu;%lum" " : Terminal window does not " have transparent background when 'termguicolors' is used. Fix the " background color. if !has('patch-8.2.3516') let s:termguicolors = &termguicolors autocmd vimrc OptionSet termguicolors \ let s:termguicolors = &termguicolors autocmd vimrc TerminalOpen,WinEnter * \ let s:newtermguicolors = \ s:termguicolors && \ empty(filter(getwininfo(), \ 'getbufvar(v:val.bufnr, "&buftype") ==# "terminal"' \ )) | \ if s:newtermguicolors != &termguicolors | \ execute 'set' (s:newtermguicolors ? '' : 'no') . 'termguicolors' | \ endif | endif endif