author |
Steve Losh <steve@stevelosh.com> |
date |
Thu, 13 Jun 2024 12:30:10 -0400 |
parents |
4e0ee24c82a7 |
children |
(none) |
" .vimrc-minimal
" Author: Steve Losh <steve@stevelosh.com>
" Source: https://hg.stevelosh.com/dotfiles/file/tip/vim/vimrc
" A minimal subset of my vimrc settings, suitable for syncing on its own to
" a server so I have some basic settings, but don't have to install the whole
" hog.
" Preamble ---------------------------------------------------------------- {{{
set shell=/bin/bash\ --login
" }}}
" Basic options ----------------------------------------------------------- {{{
set modelines=0
set autoindent
set showmode
set showcmd
set hidden
set visualbell
set ttyfast
set ruler
set backspace=indent,eol,start
set nonumber
set norelativenumber
set laststatus=2
set history=1000
set undofile
set undoreload=10000
set list
set listchars=tab:▸\ ,eol:¬,extends:❯,precedes:❮
set lazyredraw
set matchtime=3
set showbreak=↪
set splitbelow
set splitright
set autowrite
set autoread
set shiftround
set title
set linebreak
set colorcolumn=+1
set diffopt+=vertical
" Don't try to highlight lines longer than 500 characters.
set synmaxcol=500
" Time out on key codes but not mappings.
" Basically this makes terminal Vim work sanely.
set notimeout
set ttimeout
set ttimeoutlen=10
" Make Vim able to edit crontab files again.
set backupskip=/tmp/*,/private/tmp/*"
" Better Completion
set complete=.,w,b,u,t
set completeopt=longest,menuone
inoremap <c-o> <c-x><c-o>
" Save when losing focus
au FocusLost * :silent! wall
" Leader
let mapleader = ","
let maplocalleader = "\\"
" Cursorline {{{
" Only show cursorline in the current window and in normal mode.
augroup cline
au!
au WinLeave,InsertEnter * set nocursorline
au WinEnter,InsertLeave * set cursorline
augroup END
" }}}
" cpoptions+=J, dammit {{{
" Something occasionally removes this. If I manage to find it I'm going to
" comment out the line and replace all its characters with 'FUCK'.
augroup twospace
au!
au BufRead * :set cpoptions+=J
augroup END
" }}}
" Trailing whitespace {{{
" Only shown when not in insert mode so I don't go insane.
augroup trailing
au!
au InsertEnter * :set listchars-=trail:⌴
au InsertLeave * :set listchars+=trail:⌴
augroup END
" }}}
" Wildmenu completion {{{
set wildmenu
set wildmode=list:longest
set wildignore+=.hg,.git,.svn " Version control
set wildignore+=*.aux,*.out,*.toc " LaTeX intermediate files
set wildignore+=*.jpg,*.bmp,*.gif,*.png,*.jpeg " binary images
set wildignore+=*.o,*.obj,*.exe,*.dll,*.manifest " compiled object files
set wildignore+=*.spl " compiled spelling word lists
set wildignore+=*.sw? " Vim swap files
set wildignore+=*.DS_Store " OSX bullshit
set wildignore+=*.luac " Lua byte code
set wildignore+=migrations " Django migrations
set wildignore+=*.pyc " Python byte code
set wildignore+=*.orig " Merge resolution files
set wildignore+=*.fasl " Lisp FASLs
set wildignore+=*.dx64fsl " CCL
set wildignore+=*.lx64fsl " CCL
" }}}
" Line Return {{{
" Make sure Vim returns to the same line when you reopen a file.
" Thanks, Amit
augroup line_return
au!
au BufReadPost *
\ if line("'\"") > 0 && line("'\"") <= line("$") |
\ execute 'normal! g`"zvzz' |
\ endif
augroup END
" }}}
" Tabs, spaces, wrapping {{{
set tabstop=8
set shiftwidth=4
set softtabstop=4
set expandtab
set wrap
set textwidth=80
set formatoptions=qrn1j
set colorcolumn=+1
" }}}
" Backups {{{
set backup " enable backups
set noswapfile " it's 2013, Vim.
set undodir=~/.vim/tmp/undo// " undo files
set backupdir=~/.vim/tmp/backup// " backups
set directory=~/.vim/tmp/swap// " swap files
" Make those folders automatically if they don't already exist.
if !isdirectory(expand(&undodir))
call mkdir(expand(&undodir), "p")
endif
if !isdirectory(expand(&backupdir))
call mkdir(expand(&backupdir), "p")
endif
if !isdirectory(expand(&directory))
call mkdir(expand(&directory), "p")
endif
" }}}
" Color scheme {{{
syntax on
set background=dark
" }}}
" }}}
" Abbreviations & Digraphs ------------------------------------------------ {{{
iabbrev todo TODO
silent! digr -. 8230 "U+2026=… HORIZONTAL ELLIPSIS
silent! digr !, 8816 "U+2270=≰ NEITHER LESS-THAN NOR EQUAL TO
silent! digr !. 8817 "U+2271=≱ NEITHER GREATER-THAN NOR EQUAL TO
silent! digr es 8337 "U+2091=ₑ SUBSCRIPT E
silent! digr xs 8339 "U+2093=ₓ SUBSCRIPT X
silent! digr ls 8343 "U+2097=ₗ SUBSCRIPT L
silent! digr ms 8344 "U+2098=ₗ SUBSCRIPT M
silent! digr ns 8345 "U+2099=ₙ SUBSCRIPT N
silent! digr ps 8346 "U+209A=ₚ SUBSCRIPT P
silent! digr ss 8347 "U+209B=ₛ SUBSCRIPT S
silent! digr ts 8348 "U+209C=ₜ SUBSCRIPT T
silent! digr >< 8652 "U+21cc=⇌ EQUILIBRIUM
silent! digr o+ 8853 "U+2295=⊕ CIRCLED PLUS
silent! digr -^ 8593 "U+2191=↑ UPWARDS ARROW
silent! digr -- 8212 "U+2014=— EM DASH
silent! digr // 9585 "U+2571=╱ BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT
silent! digr \\ 9586 "U+2572=╲ BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT
silent! digr \|\| 8214 "U+2016=‖ DOUBLE VERTICAL LINE
silent! digr ~~ 8967 "U+2307=⌇ WAVY LINE
" }}}
" Convenience mappings ---------------------------------------------------- {{{
" Fuck you, help key.
noremap <F1> :checktime<cr>
inoremap <F1> <esc>:checktime<cr>
" Stop it, hash key.
inoremap # X<BS>#
" Kill window
nnoremap K :q<cr>
" Save
nnoremap s :w<cr>
" Man
nnoremap M K
" Clean up windows
nnoremap - :wincmd =<cr>
" Toggle line numbers
nnoremap <leader>n :setlocal number!<cr>
" Sort lines
nnoremap <leader>s vip:sort<cr>
vnoremap <leader>s :sort<cr>
" Tabs
nnoremap <leader>( :tabprev<cr>
nnoremap <leader>) :tabnext<cr>
" My garbage brain can't ever remember digraph codes
inoremap <c-k><c-k> <esc>:help digraph-table<cr>
" Wrap
" mnemonic: less' -S command/option
nnoremap <leader>S :set wrap!<cr>
" Inserting blank lines
" I never use the default behavior of <cr> and this saves me a keystroke...
nnoremap <cr> o<esc>
" Delete to black hole register
nnoremap dD "_dd
vnoremap D "_d
" Yank to end of line
nnoremap Y y$
" Reselect last-pasted text
nnoremap gv `[v`]
" I constantly hit "u" in visual mode when I mean to "y". Use "gu" for those rare occasions.
" From https://github.com/henrik/dotfiles/blob/master/vim/config/mappings.vim
vnoremap u <nop>
vnoremap gu u
" Clean trailing whitespace
nnoremap <leader>ww mz:%s/\s\+$//<cr>:let @/=''<cr>`z
" Select entire buffer
nnoremap vaa ggvGg_
nnoremap Vaa ggVG
" Fix from spellcheck
" I can never remember if it's zg or z=, and the wrong one adds the word to
" the DB (lol), so fuck it, just add an easier mapping.
nnoremap zz z=
nnoremap z= :echo "use zz you idiot"<cr>
" "Uppercase word" mapping.
"
" This mapping allows you to press <c-u> in insert mode to convert the current
" word to uppercase. It's handy when you're writing names of constants and
" don't want to use Capslock.
"
" To use it you type the name of the constant in lowercase. While your
" cursor is at the end of the word, press <c-u> to uppercase it, and then
" continue happily on your way:
"
" cursor
" v
" max_connections_allowed|
" <c-u>
" MAX_CONNECTIONS_ALLOWED|
" ^
" cursor
"
" It works by exiting out of insert mode, recording the current cursor location
" in the z mark, using gUiw to uppercase inside the current word, moving back to
" the z mark, and entering insert mode again.
"
" Note that this will overwrite the contents of the z mark. I never use it, but
" if you do you'll probably want to use another mark.
inoremap <C-u> <esc>mzgUiw`za
" Wrap Toggle
nnoremap <f9> :set nowrap!<cr>
" zt is okay for putting something at the top of the screen, but when I'm
" writing prose I often want to put something at not-quite-the-top of the
" screen. zh is "zoom to head level"
nnoremap zh mzzt10<c-u>`z
" Diffoff
nnoremap <leader>D :diffoff!<cr>
" Formatting, TextMate-style
nnoremap Q gqip
vnoremap Q gq
" Reformat line.
" I never use l as a macro register anyway.
nnoremap ql gqq
" Indent/dedent/autoindent what you just pasted.
nnoremap <lt>> V`]<
nnoremap ><lt> V`]>
nnoremap =- V`]=
" Keep the cursor in place while joining lines
nnoremap J mzJ`z
" Join an entire paragraph.
"
" Useful for writing GitHub comments in actual Markdown and then translating it
" to their bastardized version of Markdown.
nnoremap <leader>j mzvipJ`z
" Split line (sister to [J]oin lines)
" The normal use of S is covered by cc, so don't worry about shadowing it.
nnoremap S i<cr><esc>^mwgk:silent! s/\v +$//<cr>:noh<cr>`w
" Substitute
nnoremap <c-s> :%s/
vnoremap <c-s> :s/
" Marks and Quotes
noremap ' `
noremap æ '
noremap ` <C-^>
" Select (charwise) the contents of the current line, excluding indentation.
" Great for pasting Python lines into REPLs.
nnoremap vv ^vg_
" Typos
command! -bang E e<bang>
command! -bang Q q<bang>
command! -bang W w<bang>
command! -bang QA qa<bang>
command! -bang Qa qa<bang>
command! -bang Wa wa<bang>
command! -bang WA wa<bang>
command! -bang Wq wq<bang>
command! -bang WQ wq<bang>
command! -bang Wqa wqa<bang>
" Unfuck my screen
nnoremap U :syntax sync fromstart<cr>:redraw!<cr>
" Zip Right
"
" Moves the character under the cursor to the end of the line. Handy when you
" have something like:
"
" foo
"
" And you want to wrap it in a method call, so you type:
"
" println()foo
"
" Once you hit escape your cursor is on the closing paren, so you can 'zip' it
" over to the right with this mapping.
"
" This should preserve your last yank/delete as well.
nnoremap zl :let @z=@"<cr>x$p:let @"=@z<cr>
" Diff Navigation
nnoremap ]d ]c
nnoremap [d [c
" Typo navigation
nnoremap ]z ]S
nnoremap [z [S
nnoremap ]Z ]Sz=
nnoremap [Z [Sz=
" Header Lines
nnoremap <leader>- o<esc>80a-<esc>kJ079lD
" Insert Mode Completion
inoremap <c-f> <c-x><c-f>
inoremap <c-]> <c-x><c-]>
inoremap <c-l> <c-x><c-l>
" Window Resizing
" right/up : bigger
" left/down : smaller
nnoremap <m-right> :vertical resize +3<cr>
nnoremap <m-left> :vertical resize -3<cr>
nnoremap <m-up> :resize +3<cr>
nnoremap <m-down> :resize -3<cr>
" Newline without having to go to the end of the line
inoremap <c-cr> <esc>o
" }}}
" Searching and movement -------------------------------------------------- {{{
" Use sane regexes.
nnoremap / /\v
vnoremap / /\v
set ignorecase
set smartcase
set incsearch
set showmatch
set hlsearch
set gdefault
set scrolloff=5
set sidescroll=1
set sidescrolloff=10
set virtualedit+=block
noremap <silent> <leader><space> :noh<cr>:call clearmatches()<cr>
runtime macros/matchit.vim
map <tab> %
silent! unmap [%
silent! unmap ]%
" Made D behave
nnoremap D d$
" Don't move on *
" I'd use a function for this but Vim clobbers the last search when you're in
" a function so fuck it, practicality beats purity.
nnoremap <silent> * :let stay_star_view = winsaveview()<cr>*:call winrestview(stay_star_view)<cr>
" Jumping to tags.
"
" Basically, <c-]> jumps to tags (like normal) and <c-\> opens the tag in a new
" split instead.
"
" Both of them will align the destination line to the upper middle part of the
" screen. Both will pulse the cursor line so you can see where the hell you
" are. <c-\> will also fold everything in the buffer and then unfold just
" enough for you to see the destination line.
"
function! JumpTo(jumpcommand)
execute a:jumpcommand
call FocusLine()
Pulse
endfunction
function! JumpToInSplit(jumpcommand)
execute "normal! \<c-w>v"
execute a:jumpcommand
Pulse
endfunction
function! JumpToTag()
call JumpTo("normal! \<c-]>")
endfunction
function! JumpToTagInSplit()
call JumpToInSplit("normal \<c-]>")
endfunction
nnoremap <c-]> :silent! call JumpToTag()<cr>
nnoremap <c-\> :silent! call JumpToTagInSplit()<cr>
" Keep search matches in the middle of the window.
nnoremap n nzzzv
nnoremap N Nzzzv
" Same when jumping around
nnoremap g; g;zz
nnoremap g, g,zz
nnoremap <c-o> <c-o>zz
" Easier to type, and I never use the default behavior.
noremap H ^
noremap L $
vnoremap L g_
" Heresy
inoremap <c-a> <esc>I
inoremap <c-e> <esc>A
cnoremap <c-a> <home>
cnoremap <c-e> <end>
" go indent
nnoremap gi mzVap=`z
nnoremap gI mzgg=G`z
" Fix linewise visual selection of various text objects
nnoremap VV V
nnoremap Vit vitVkoj
nnoremap Vat vatV
nnoremap Vab vabV
nnoremap VaB vaBV
" Directional Keys {{{
" It's 2013.
noremap j gj
noremap k gk
noremap gj j
noremap gk k
" Easy buffer navigation
noremap <C-h> <C-w>h
noremap <C-j> <C-w>j
noremap <C-k> <C-w>k
noremap <C-l> <C-w>l
noremap <leader>v <C-w>v
" }}}
" Visual Mode */# from Scrooloose {{{
function! s:VSetSearch()
let temp = @@
norm! gvy
let @/ = '\V' . substitute(escape(@@, '\'), '\n', '\\n', 'g')
let @@ = temp
endfunction
vnoremap * :<C-u>call <SID>VSetSearch()<CR>//<CR><c-o>
vnoremap # :<C-u>call <SID>VSetSearch()<CR>??<CR><c-o>
" }}}
" List navigation {{{
nnoremap <left> :cprev<cr>zvzz
nnoremap <right> :cnext<cr>zvzz
nnoremap <up> :lprev<cr>zvzz
nnoremap <down> :lnext<cr>zvzz
" }}}
" }}}
" Folding ----------------------------------------------------------------- {{{
set foldlevelstart=0
" Space to toggle folds.
nnoremap <Space> za
vnoremap <Space> za
" Make zO recursively open whatever fold we're in, even if it's partially open.
nnoremap zO zczO
" "Focus" the current line. Basically:
"
" 1. Close all folds.
" 2. Open just the folds containing the current line.
" 3. Move the line to a bit (25 lines) down from the top of the screen.
" 4. Pulse the line.
"
" This mapping wipes out the z mark, which I never use.
"
" I use :sus for the rare times I want to actually background Vim.
function! FocusLine()
let oldscrolloff = &scrolloff
set scrolloff=0
execute "keepjumps normal! mzzMzvzt25\<c-y>`z:Pulse\<cr>"
let &scrolloff = oldscrolloff
endfunction
nnoremap <c-z> :call FocusLine()<cr>
function! MyFoldText() " {{{
let line = getline(v:foldstart)
let nucolwidth = &fdc + &number * &numberwidth
let windowwidth = winwidth(0) - nucolwidth - 3
let foldedlinecount = v:foldend - v:foldstart
" expand tabs into spaces
let onetab = strpart(' ', 0, &tabstop)
let line = substitute(line, '\t', onetab, 'g')
let line = strpart(line, 0, windowwidth - 2 -len(foldedlinecount))
let fillcharcount = windowwidth - len(line) - len(foldedlinecount)
return line . '…' . repeat(" ",fillcharcount) . foldedlinecount . '…' . ' '
endfunction " }}}
set foldtext=MyFoldText()
" }}}
" Text objects ------------------------------------------------------------ {{{
" Folds {{{
onoremap if :<c-u>normal! [zv]z<cr>
onoremap af :<c-u>normal! [zV]z<cr>
vnoremap if :<c-u>normal! ]zv[z<cr>
vnoremap af :<c-u>normal! ]zV[z<cr>
" }}}
" Shortcut for [] {{{
onoremap ir i[
onoremap ar a[
vnoremap ir i[
vnoremap ar a[
" }}}
" Numbers {{{
" Motion for numbers. Great for CSS. Lets you do things like this:
"
" margin-top: 200px; -> daN -> margin-top: px;
" ^ ^
" TODO: Handle floats.
onoremap N :<c-u>call <SID>NumberTextObject(0)<cr>
xnoremap N :<c-u>call <SID>NumberTextObject(0)<cr>
onoremap aN :<c-u>call <SID>NumberTextObject(1)<cr>
xnoremap aN :<c-u>call <SID>NumberTextObject(1)<cr>
onoremap iN :<c-u>call <SID>NumberTextObject(1)<cr>
xnoremap iN :<c-u>call <SID>NumberTextObject(1)<cr>
function! s:NumberTextObject(whole)
let num = '\v[0-9]'
" If the current char isn't a number, walk forward.
while getline('.')[col('.') - 1] !~# num
normal! l
endwhile
" Now that we're on a number, start selecting it.
normal! v
" If the char after the cursor is a number, select it.
while getline('.')[col('.')] =~# num
normal! l
endwhile
" If we want an entire word, flip the select point and walk.
if a:whole
normal! o
while col('.') > 1 && getline('.')[col('.') - 2] =~# num
normal! h
endwhile
endif
endfunction
" }}}
" }}}
" Optional Remote-Local Vimrc --------------------------------------------- {{{
if filereadable(expand('~/.vimrc_remote_local'))
source ~/.vimrc_remote_local
endif
" }}}