" vim: set noexpandtab :miv " "!!! makes use of marker ' set nocompatible """""""""""""""" " Sessions set sessionoptions=blank,buffers,curdir,folds,help,options,tabpages set foldmethod=marker " some conditional configs if has('mouse') set mouse=a endif if &t_Co > 2 || has("gui_running") syntax on set hlsearch "Highlight search results endif if v:version >= 800 set cm=blowfish2 elseif v:version >= 703 set cm=blowfish end " set linespace=0 set scrolloff=6 set history=50 " keep 50 lines of command line history set nonumber " set relativenumber set langmenu=en_UK let $LANG = 'en_UK' source $VIMRUNTIME/delmenu.vim source $VIMRUNTIME/menu.vim set guioptions-=r set guioptions-=R set guioptions-=l set guioptions-=L try set undodir=$HOME/.vimundo set undofile catch echom "Undofile doesn't work :(" endtry filetype plugin on filetype indent on set ruler set backspace=eol,start,indent set path+=** " Enable fuzzy search " STAAAAAARS set wildmenu "Menu for tab completion set enc=utf8 " Search Stuff set ignorecase set smartcase noh set incsearch set lazyredraw set magic "Who doesn't want to be a vim-wizard? set showmatch " Backup and file stuff set nobackup set nowb " set noswapfile set swapfile " Indentation, etc. set tabstop=2 set softtabstop=2 set shiftwidth=2 set noexpandtab set smarttab set autoindent set smartindent set smarttab set shiftwidth=2 set gdefault set wrap au BufEnter,BufRead * set linebreak set breakat=\ .,{ set display+=lastline if v:version>=800 set breakindent set breakindentopt=sbr au WinNew * set breakindentopt=sbr set showbreak=.\ else set showbreak=+->\ end set listchars=eol:¶,tab:»\ ,trail:.,nbsp:. set modeline " Allows setting vim options in other files set statusline=(%n)\ %f\ [%M%R]\ [%Y]%=%l,%c%V\ %4.P set laststatus=2 set cmdheight=1 set timeoutlen=1200 " Clipboard and Copy/Paste things if has('unnamedplus') " Allow copying to and from OS clipboard set clipboard=unnamedplus else set clipboard=unnamed end " === GENERAL UTILITIES === function! s:autoClose_HelperOpen(open, close) let next_c = getline(".")[col(".")-1] if match(next_c, "\s") return a:open.a:close."\" else return a:open end endfunc function! s:autoClose_HelperClose(open, close) if getline(".")[col(".")-1] ==# a:close return "\" elseif getline(line(".")+1) if match(getline(line(".")+1), "\M^\s*".escape(a:close, "\\")) return "\\\f".a:close."\" end else return a:close end endfunc function! s:autoClose_HelperDouble(open) if getline(".")[col(".")-1] ==# a:open " Step over return "\" else return a:open.a:open."\" end endfunc function! s:autoClose_HelperEnter() if exists("b:autoClose_Pairs") let next_c = getline(".")[col(".")-1] let prev_c = getline(".")[col(".")-2] if (next_c !=# "") && (prev_c !=# "") if exists("b:autoClose_Pairs[prev_c]") if (next_c ==# b:autoClose_Pairs[prev_c]) return "\m'\\`'\" end end end end return "\" endfunc function! s:autoClose_HelperSpace() if exists("b:autoClose_Pairs") let next_c = getline(".")[col(".")-1] let prev_c = getline(".")[col(".")-2] if (next_c !=# "") && (prev_c !=# "") if exists("b:autoClose_Pairs[prev_c]") if (next_c ==# b:autoClose_Pairs[prev_c]) return "\\h\" end end end end return "\" endfunc function! s:autoClose_AddPair(open, close) "TODO: Improve with expand('') if !exists("b:autoClose_Pairs") let b:autoClose_Pairs = {} end let b:autoClose_Pairs[a:open] = a:close if a:open!=#a:close exe "inoremap ".a:open." autoClose_HelperOpen('".a:open."', '".a:close."')" exe "inoremap ".a:close." autoClose_HelperClose('".a:open."', '".a:close."')" else exe "inoremap ".a:open." autoClose_HelperDouble('".a:open."')" end inoremap autoClose_HelperEnter() inoremap autoClose_HelperSpace() endfunc function! MatchingLines(pattern) let list = [] let pattern = a:pattern exec "g/".pattern."/ call add(list, expand('%').'('.line('.').') : '.matchstr(getline('.'), '".pattern."'))" return list endfunc function! s:mld_helper(list, pattern) " Helper function for MatchingLinesDict call add(a:list, {'filename': expand("%"), 'lnum': line("."), 'col': match(getline("."), a:pattern)+1, 'text': matchstr(getline("."), a:pattern)}) endfunc function! MatchingLinesDict(pattern) let list = [] silent! exec "g/".a:pattern."/ call s:mld_helper(list, a:pattern)" return list endfunc function! LocationAddLineCol(filename, lnum, text, col) call setloclist(0, [{'filename': a:filename, 'lnum': a:lnum, 'desc': a:text, 'col': a:col}], 'a') endfunction function! QuickfixAddLineCol(filename, lnum, text, col) call setqflist([{'filename': a:filename, 'lnum': a:lnum, 'desc': a:text, 'col': a:col}], 'a') endfunction function! LocationAddLine(filename, lnum, text) call setloclist(0, [{'filename': a:filename, 'lnum': a:lnum, 'desc': a:text}], 'a') endfunction function! QuickfixAddLine(filename, lnum, text) call setqflist([{'filename': a:filename, 'lnum': a:lnum, 'desc': a:text}], 'a') endfunction " Original implementation: https://stackoverflow.com/a/6271254/4984564 function! VisualSelection() if mode()=="v" let [line_start, column_start] = getpos("v")[1:2] let [line_end, column_end] = getpos(".")[1:2] else let [line_start, column_start] = getpos("'<")[1:2] let [line_end, column_end] = getpos("'>")[1:2] end if (line2byte(line_start)+column_start) > (line2byte(line_end)+column_end) let [line_start, column_start, line_end, column_end] = \ [line_end, column_end, line_start, column_start] end let lines = getline(line_start, line_end) if len(lines) == 0 return '' endif let lines[-1] = lines[-1][: column_end - 1] let lines[0] = lines[0][column_start - 1:] return join(lines, "\n") endfunction function! StringReverse(str) return join(reverse(split(str, ".\\zs")), "") endfunc function! ShiftMarker(m,n) let [bufn,line,column,offset]=getpos("'".a:m) call setpos("'".a:m,[bufn,line,column+a:n,offset]) endfunc function! ShiftSelection(n) call ShiftMarker("<", a:n) call ShiftMarker(">", a:n) endfunc " Auto-close quickfix list when leaving it function! s:autobd() au! WinLeave bd! endfun " === GENERAL COMMANDS === " General Purpose command! Closeall bufdo bdelete command! Context bufdo bdelete | e . command! Kontext Context command! L lopen | set number | set norelativenumber command! LAddLine call LocationAddLine(expand("%"), line("."), getline(".")) command! QAddLine call QuickfixAddLine(expand("%"), line("."), getline(".")) command! LAddCursor call LocationAddLineCol(expand("%"), line("."), getline("."), col(".")) command! QAddCursor call QuickfixAddLineCol(expand("%"), line("."), getline("."), col(".")) command! Fixme call setloclist(0, MatchingLinesDict("\\c\\)) command! -nargs=1 QFind call setqflist(MatchingLinesDict()) function! s:hex(...) if !(a:000 == [""]) let l:args = map(copy(a:000), {i,val -> "".val}) else let l:args = [] end if &filetype != "xxd" silent exec '%!xxd '.join(l:args, " ") set filetype=xxd nnoremap i i echo "A witch turned your file into a hexadecimal toad!" else nunmap i silent exec '%!xxd -r '.join(l:args, " ") filetype detect echo "The witch turned your file back into binary data" end endfunction command! -nargs=* Hex call hex() " === GIT STUFF === " function! s:uncommitted(...) if a:0 let l:commit = a:1 else let l:commit = "HEAD" end let l:filetype = &filetype below new set modifiable exec "r!git show ".l:commit.":./#" 1,1del au BufUnload diffoff! let &filetype = l:filetype silent exec "file §".expand("#:t")."@".l:commit set buftype=nofile set bufhidden=delete set nomodifiable diffthis exec "normal \k" diffthis set foldlevel=999 endfun command! -nargs=? Uncommitted call uncommitted() function! s:git_history() if exists("b:git_original_file") " Is this already a file@revision buffer? let l:fname = b:git_original_file else let l:fname = expand("%") end let l:commits = system('git log --format="%h" --follow '.l:fname) return split(l:commits, "\n") endfun function! s:git_first() if &modified echo "Save your changes first!" return end let l:history = s:git_history() call s:file_at_revision(get(l:history, -1, "HEAD")) endfun function! s:git_last() if &modified echo "Save your changes first!" return end let l:history = s:git_history() call s:file_at_revision(get(l:history, 1, "HEAD")) endfun function! s:git_info() if !exists("b:git_revision_hash") || !exists("b:git_original_file") echo "Error 01: Not a file@revision buffer!" return end echo system("git show --no-patch ".b:git_revision_hash) endfun function! s:git_next() if !exists("b:git_revision_hash") || !exists("b:git_original_file") echo "Error 01: Not a file@revision buffer!" return end let l:history = s:git_history() let l:idx = index(l:history, b:git_revision_hash) if l:idx == -1 echo "Error 02" return end let l:new_revision = get(l:history, l:idx-1, "LAST") if l:new_revision=="LAST" echo "Already at latest revision! ".l:new_revision return else call s:file_at_revision(l:new_revision) end endfun function! s:git_prev() if !exists("b:git_revision_hash") || !exists("b:git_original_file") echo "Error 01: Not a file@revision buffer!" return end let l:history = s:git_history() let l:idx = index(l:history, b:git_revision_hash) if l:idx == -1 echo "Error 02" return end let l:new_revision = get(l:history, l:idx+1, "FIRST") if l:new_revision=="FIRST" echo "Already at earliest revision! ".l:new_revision return else call s:file_at_revision(l:new_revision) end endfun function! s:file_at_revision(rev) let l:pos = getpos(".") if exists("b:git_original_file") " Is this already a file@revision buffer? let l:fname = b:git_original_file let l:ftail = fnamemodify(b:git_original_file, ":t") else let l:fname = expand("%:t") let l:ftail = expand("%:t") end let l:ftype = &filetype ene! silent exec "file ".l:ftail."@".a:rev exec "r!git show ".a:rev.":".l:fname setl nomodifiable setl buftype=nofile setl bufhidden=delete let &filetype = l:ftype let b:git_original_file = l:fname let b:git_revision_hash = a:rev let l:pos[0] = bufnr('.') call setpos('.', l:pos) redraw call s:git_info() endfun command! GitNext call git_next() command! GitPrev call git_prev() command! GitFirst call git_first() command! GitLast call git_last() command! GitInfo call git_info() " command! -nargs=1 GitAt call s:file_at_revision() " Doesn't work for talos knows what reason function! s:unsaved() if &mod let l:filetype = &filetype diffthis below new set modifiable r # 1,1del diffthis au BufUnload diffoff! let &filetype = l:filetype set nomodifiable set buftype=nofile set bufhidden=delete silent exec "file =".expand("#:t")."@".strftime("%H:%M") exec "normal \k" set foldlevel=999 else echom "No changes to show :)" end endfun command! Unsaved call unsaved() function! s:snapshot() let l:filetype = &filetype let l:clipboard = @" let l:pos = getpos(".") silent 0,$yank " below new set modifiable silent put " 1,1del let &filetype = l:filetype set nomodifiable set buftype=nofile set bufhidden=hide call setpos(".", l:pos) silent exec "file ¬".expand("#:t")."@".strftime("%H:%M") exec "normal \k" set foldlevel=999 let @" = l:clipboard endfun command! Snapshot call snapshot() command! -nargs=? Scratch new | set buftype=nofile | set filetype= " ┌──────────────────────────┐ " ├─┬──────────────────────┐ │ " ├─┤ GENERAL KEY MAPPINGS ├─┤ " │ └──────────────────────┴─┤ " └──────────────────────────┘ let mapleader = "\\" " --- Moving Between Buffers --- nnoremap n :next:args nnoremap p :previous:args let g:jmp_dist = 8 map :exec "normal ".g:jmp_dist."j" map :exec "normal ".g:jmp_dist."k" " Yes, not 'noremap', do whatever is mapped to J and K assuming " it is some sort of custom up-down motion, but g:jmp_dist times " --- Windows, Tabs and More -- nnoremap :e %:p:h " --- modes --- nnoremap " --- /dev/null --- noremap d "_d noremap d "_d noremap "_x noremap 0"_x$ " --- Numbers --- nnoremap - nnoremap = " --- Text --- nnoremap U ~h " --- MOVEMENT --- noremap j gj noremap k gk noremap gj j noremap gk k " --- CLIPBOARD --- nnoremap Y y$ " --- VISUAL EXECUTE --- vnoremap ""y \ :call setreg("\"", substitute(getreg("\""), "\n", "", ""), "v") \ :"`< let $LUA_PATH = expand(":p:h")."/lua/?.lua" let g:mooncompile = "!moonc ".expand(":p:h")."/lua" command! Mooncompile silent exec g:mooncompile let g:exe_prg = "moonc -- \| lua -l vim -" vnoremap :exec "'<,'>!".g:exe_prg inoremap 0v$:exec "'<,'>!".g:exe_prg " --- OTHER --- " Don't exit visual mode when "shifting" vnoremap < >gv vnoremap " `>a"`<":call ShiftSelection(1)gv vnoremap ' `>a'`<':call ShiftSelection(1)gv vnoremap ( `>a)`<(:call ShiftSelection(1)gv vnoremap [ `>a]`<[:call ShiftSelection(1)gv vnoremap { `>a}`<{:call ShiftSelection(1)gv nnoremap :L noremap : noremap @: noremap Q @q nnoremap gQ " This part is just supposed to make saving as inconvenient as possible " because I have a tendency to just save stuff pretty much as soon as I start " typing because I'm bored and possibly a bit paranoid. function! s:saveprompt() if &swapfile echo "You have swap files enabled, stop in-between-saving all the time!" end if input("Type 'save' to save: ") ==? "save" write echo "File saved, but was it really necessary?" else echo "Calm the fuck down man!" end endfun noremap :call saveprompt() nnoremap :bnext nnoremap :bprevious nnoremap j :lnext nnoremap k :lNext nnoremap j :cnext nnoremap k :cNext nnoremap Bi i nnoremap Ea a " This one does nothing, but I'm adding it to remember not to remap the tab key nnoremap nnoremap noremap :setl number! noremap :setl relativenumber! noremap :setl autowriteall!:setl autowriteall? noremap :setl list! nnoremap ge nnoremap gE com! SetWD :cd %:p:h com! SetLWD :lcd %:p:h com! Trailing let _s=@/ | %s/\v(\\@ :copy . nnoremap dx 0"_d$ nnoremap dcx 0d$ nnoremap : :let @* = @: nnoremap ":%s/\\<".expand("")."\\>/" vnoremap ":%s/".VisualSelection()."/" " Put in new line with indentation nnoremap ]p :let [content, type]= \[getreg(v:register), getregtype(v:register)] \| \call setreg(v:register, content, "V")]p \:call setreg(v:register, content, type) nnoremap [p :let [content, type]= \[getreg(v:register), getregtype(v:register)] \| \call setreg(v:register, content, "V")[p \:call setreg(v:register, content, type) " Empty Lines nnoremap :call Enter(0) nnoremap :call Enter(1) function! s:Enter(shift) if !a:shift silent exe "normal o\0\"_d$" else silent exe "normal O\0\"_d$j" endif endfunction " Markdown Stuff vnoremap * `>a*` vnoremap _ `>a__` " === GENERAL ABBREVIATIONS === cabbr rcpath fnamemodify($MYVIMRC, ":p:h") cabbr %% expand('%:p:h') digraph <3 9829 digraph ue 252 digraph UE 220 digraph ae 228 digraph AE 196 digraph oe 246 digraph OE 214 digraph ss 223 " === GENERAL AUTOCOMMANDS === command! HLProgress syntax match Comment /\_.*\ze\n.*\%#/ nnoremap h :call toggleWUC() function! s:updateWUC() if exists("b:hlwuc") if b:hlwuc > 1 call matchdelete(b:hlwuc) end end if exists("b:word_hl") let hl = b:word_hl else let hl = "Underlined" endif let str = "\\<".escape(expand(""), "\\")."\\>" let b:hlwuc = matchadd(hl, str) "echom str endfunc function! s:toggleWUC() augroup hlwuc if exists("b:hlwuc") autocmd! if b:hlwuc > 1 call matchdelete(b:hlwuc) end unlet b:hlwuc else call updateWUC() autocmd CursorMoved call updateWUC() autocmd CursorMovedI call updateWUC() endif augroup END endfunction " Autosave when vim loses focus :) function! TryAutosave(warn, mode) if a:mode == 0 if &autowriteall || &autowrite silent wall if a:warn echo "Autosaving all buffers..." end end elseif a:mode == 1 if &autowriteall if &mod silent write if a:warn echo "Autosaving current buffer..." end end end end redraw endfunction augroup autosave autocmd! autocmd FocusLost * call TryAutosave(0, 0) autocmd BufLeave * call TryAutosave(0, 1) autocmd CursorHold * call TryAutosave(0, 1) augroup END vnoremap g :call GrepOperator(visualmode()) nnoremap g :set operatorfunc=GrepOperatorg@ function! s:GrepOperator(type) let reg1 = @@ if a:type==# 'v' execute "normal! `y" elseif a:type==# 'char' execute "normal! `[y`]" else return end echom "vimgrep! /\\M".escape(@@, "\\")."/ *" silent! execute "vimgrep /\\M".escape(@@, "\\")."/j *" let @@ = reg1 copen set nowrap endfunction " Window Height stuff command! EqualH call Equal() command! -nargs=1 WinHeight call SetWinMinHeight() function! Equal() set winminheight=0 set winheight=1 set equalalways! set equalalways! endfunc function! SetWinMinHeight(num) execute "set winminheight=".0 if a:num>=0 execute "set winheight=".(a:num+1) execute "set winminheight=".a:num endif execute "set winheight=".9999 endfunc " call SetWinMinHeight(2) function! AddWinMinHeight(num) let a:new = &winminheight + a:num call SetWinMinHeight(a:new) set winminheight? endfunc " Window Width Stuff command! EqualW silent! call EqualW() command! -nargs=1 WinWidth call SetWinMinWidth() function! EqualW() set winminwidth=0 set winwidth=1 set equalalways! set equalalways! endfunc function! SetWinMinWidth(num) execute "set winminwidth=".0 if a:num>=0 execute "set winwidth=".(a:num+1) execute "set winminwidth=".a:num endif execute "set winwidth=".9999 endfunc function! AddWinMinWidth(num) let a:new = &winminwidth + a:num call SetWinMinWidth(a:new) set winminwidth? endfunc " === GENERIC AUTOCOMMANDS === if has("autocmd") " Enable file type detection. " Use the default filetype settings, so that mail gets 'tw' set to 72, " 'cindent' is on in C files, etc. " Also load indent files, to automatically do language-dependent indenting. filetype plugin indent on " Put these in an autocmd group, so that we can delete them easily. " For all text files set 'textwidth' to 78 characters. " autocmd FileType text setlocal textwidth=78 " When editing a file, always jump to the last known cursor position. " Don't do it when the position is invalid or when inside an event handler " (happens when dropping a file on gvim). autocmd BufReadPost * \ if line("'\"") >= 1 && line("'\"") <= line("$") | \ exe "normal! g`\"" | \ endif endif " === FILETYPE SPECIFIC STUFF === " --- GENERIC STUFF --- au BufNewFile,BufRead * :call init_generic_file() function! s:init_generic_file() call s:autoClose_AddPair("[", "]") call s:autoClose_AddPair("(", ")") call s:autoClose_AddPair("{", "}") call s:autoClose_AddPair('"', '"') endfunc " --- VIMSCRIPT STUFF --- au BufNewFile,BufRead *.vim,*vimrc :call init_vim_file() function! s:init_vim_file() setl number nnoremap :w:so % nnoremap c A" nnoremap if ofunction! m'()endfunction`'l command! -buffer Functions lex MatchingLines("^\\s*fun\\(ction\\)\\?\\>!.*$") command! -buffer Commands lex MatchingLines("^\\s*com\\(mand\\)\\?\\>!.*$") command! -buffer Autocommands lex MatchingLines("^\\s*au\\(tocmd\\)\\?\\>!\\@!.*$") endfunction " --- C / C++ Stuff --- " Insert Stuff au BufNewFile,BufRead *.c,*.cpp,*.h,*.hpp :nnoremap ii O#include <>i au BufNewFile,BufRead *.c,*.cpp,*.h,*.hpp :nnoremap ip oprintf("m'\n");`'a au BufNewFile,BufRead *.c,*.cpp,*.h,*.hpp :nnoremap im oint main(int argc, char *args[]) {}O " Other Stuff au BufNewFile,BufRead *.c,*.cpp,*.h,*.hpp :nnoremap ; m'$a;`' " --- Ruby Stuff --- au BufNewFile,BufRead *.rb :call init_ruby_file() function! s:init_ruby_file() set makeprg=ruby\ -wc\ % setl number command! -buffer Methods lex MatchingLines("^\\s*def\\>\\s\\+\\zs.*$") | lopen command! -buffer Functions Methods " Alias command! -buffer Classes lex MatchingLines("^\\s*class\\>\\s\\+\\zs.*$") | lopen command! -buffer Modules lex MatchingLines("^\\s*module\\>\\s\\+\\zs.*$") | lopen command! -buffer Members lex MatchingLines("@\\<\\i*\\>") | lopen command! -buffer Requires lex MatchingLines("^\\s*require\\(_relative\\)\\?\\>\\s\\+\\zs.*$") | lopen nnoremap ic oclass m'end`'a nnoremap id odef m'()end`'a nnoremap :w:!ruby % nnoremap :lmake:lopen nnoremap ~ :call RubyComment(0) nnoremap # :call RubyComment(1) vnoremap ~ :call RubyComment(0) vnoremap # :call RubyComment(1) endfunction function! s:RubyComment(a) if a:a==0 " silent! exec '.s/\m^\s*\zs#*//' silent! exec '.s/\v^(\s|#)*//' normal == elseif a:a==1 " silent! exec '.s/\v^(\s*#)@!/#/' silent! exec '.s/\v^(\s|#)*/# /' normal == end endfunction " augroup rbindent " autocmd! " au BufNewFile,BufRead *.rb :set noexpandtab | :retab! | " " au BufWritePre *.rb :let ts = &tabstop | set expandtab | set tabstop=2 | retab | let &tabstop=ts | :set noexpandtab " " au BufWritepost *.rb :silent! :undo | :exe "normal \" " augroup END " --- Lua Stuff --- " Matches all types of Lua string! " \v(["'])\zs.{-}\ze\\@1init_lua_file() function! s:init_lua_file() setl number command! -buffer Requires call setloclist(0, MatchingLinesDict("\\vrequire\\s*\\(?(([\"'])\\zs.{-}\\ze\\\\@1init_html_file() function! s:init_html_file() setl number command! -buffer -nargs=1 Tag normal \ i<><m'/>`' nnoremap T ""ciw<""p>m'""p>`'l nnoremap T ""diw"_cc<""p>o""p>O function! s:insert_tag(tag, newline) if !a:newline let l:text = "<".a:tag.">" else end put =l:text endfunction nnoremap :call insert_tag(input(""), 0) inoremap ""ciw<""p>m'""p>`'l inoremap ""diw"_cc<""p>o""p>O endfunction