" personal vimrc " Author: Jon Smithers " URL: https://github.com/jonsmithers/dotfiles/blob/master/vim/vimrc " Last Updated: 2023-06-02 :scriptencoding utf8 if !exists('s:os') if has('win64') || has('win32') || has('win16') let s:os = 'Windows' elseif has('mac') let s:os = 'MacOS' else let s:os = 'Linux' endif endif if (s:os ==# 'Windows') set encoding=utf-8 endif :let g:mapleader = ' ' " ┌───────────────────┐ " │ download vim-plug │ " └───────────────────┘ " {{{ if (s:os !=# 'Windows') if empty(glob('~/.vim/autoload/plug.vim')) silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim augroup vimplug au! autocmd VimEnter * PlugInstall --sync | exec 'source ' . expand('') augroup END endif else if empty(glob('~\vimfiles\autoload\plug.vim')) set shell=C:\\WINDOWS\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe !md ~\vimfiles\autoload !(New-Object Net.WebClient).DownloadFile('https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim', $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('~\vimfiles\autoload\plug.vim')) augroup vimplug au! autocmd VimEnter * PlugInstall --sync | source $MYVIMRC augroup END endif endif " }}} " ┌─────────────────────────┐ " │ install missing plugins │ " └─────────────────────────┘ autocmd VimEnter * \ if len(filter(values(g:plugs), '!isdirectory(v:val.dir)')) \| PlugInstall --sync | q | echom "Installed new plugins" \| endif " {{{ Personal vim-plug utils let s:config_queue = [] com! -nargs=+ PlugIfNeovim call s:plugIfNeovim() com! -nargs=+ PlugIfNotNeovim call s:plugIfNotNeovim() com! -nargs=+ PlugDevelop call s:plugDev() fun! s:plugIfNeovim(repo, opts = {}, f = 'none') if a:0 != 0 return s:err('Extraneous arguments') endif if (has('nvim')) call plug#(a:repo, a:opts) if (a:f != 'none') let s:config_queue = add(s:config_queue, a:f) endif endif endfun fun! s:plugIfNotNeovim(repo, opts = {}, f = 'none') if a:0 != 0 return s:err('Extraneous arguments') endif if (!has('nvim')) call plug#(a:repo, a:opts) if (a:f != 'none') let s:config_queue = add(s:config_queue, a:f) endif endif endfun fun! s:plugDev(repo, ...) if a:0 > 1 return s:err('Invalid number of arguments (1..2)') endif let l:devPath = '~/git/' . split(a:repo, '/')[1] let l:opts = a:0 == 1 ? a:1 : { } if (!empty(glob(l:devPath))) call extend(l:opts, { 'dir': l:devPath }) call plug#(a:repo, l:opts) else call plug#(a:repo, l:opts) endif endfun fun! s:err(msg) echohl ErrorMsg echom '[vimrc] '.a:msg echohl None endfun let s:nerdtree_triggers = ['NERDTreeFind', 'NERDTreeClose', 'NERDTreeToggle', 'NERDTreeRefreshRoot'] " }}} " ┌─────────┐ " │ plugins │ " └─────────┘ call plug#begin('~/.vim/plugged') Plug 'AndrewRadev/splitjoin.vim' " gJ on first line to join object literal into one line " gS to split one-line object into multiple lines Plug 'airblade/vim-gitgutter', { 'on': 'GitGutterEnable'} " {{{ " I use vim-signify in lieu of gitgutter because it's faster. However, " gitgutter has a killer feature to stage the hunk under cursor. So I " disable every aspect of gitgutter, and temporarily enable it just when I " want to use this feature. let g:gitgutter_enabled = 0 let g:gitgutter_signs = 0 let g:gitgutter_async = 0 let g:gitgutter_map_keys = 0 :nmap ga :GitGutterEnable:GitGutterStageHunk:GitGutterDisable:SignifyRefresh:echo 'staged hunk' " }}} " {{{ security patch if !has('nvim') && !has('patch-8.1.1365') " mitigate modeline security vulnerability in older vims https://github.com/numirias/security/blob/master/doc/2019-06-04_ace-vim-neovim.md set nomodeline Plug 'ciaranm/securemodelines' let g:secure_modelines_verbose = 1 endif " }}} Plug 'airblade/vim-rooter' " {{{ let g:rooter_silent_chdir = 1 let g:rooter_patterns = ['.git', '_darcs', '.hg', '.bzr', '.svn', 'Makefile'] " }}} Plug 'chrisbra/Colorizer' " Show hex colors by running :ColorHighlight or :ColorToggle " {{{ let g:colorizer_fgcontrast = 0 let g:colorizer_hex_pattern = ['#\?', '\%(\x\{6}\)', ''] " }}} PlugIfNeovim 'folke/trouble.nvim' nnoremap xx TroubleToggle nnoremap xw TroubleToggle workspace_diagnostics nnoremap xd TroubleToggle document_diagnostics nnoremap xq TroubleToggle quickfix " Open LSP issues and Telescope results in a fany pane " {{{ " TroubleToggle quickfix " TroubleToggle workspace_diagnostic " }}} " Plug 'Houl/ExplainPattern-vim' " Use :ExplainPattern to explain a vim-flavored regex " {{{ lightline fun! s:ConfigLightline() " Some inspiration for this configuration is taken from https://statico.github.io/vim3.html#lightline-powerline-airline-and-status-bars set laststatus=2 "always show status bar (even when there are no splits) set noshowmode "lightline will show mode for me set showcmd "shows size of visual selection BELOW lightline let g:lightline = { \ 'active': { \ 'left': [ \ ['mode', 'paste'], \ ['filename', 'modified'], \ ['git_changes'], \ ], \ 'right': [ \ ['lineinfo'], \ ['percent'], \ ['readonly', 'linter_warnings', 'linter_errors', 'linter_ok'], \ ] \ }, \ 'component_function': { \ 'git_changes': 'LightLineChanges', \ }, \ 'component_expand': { \ 'linter_warnings': 'LightlineLinterWarnings', \ 'linter_errors': 'LightlineLinterErrors', \ 'linter_ok': 'LightlineLinterOK', \ }, \ 'component_type': { \ 'readonly': 'error', \ 'linter_warnings': 'warning', \ 'linter_errors': 'error' \ }, \ 'separator': { \ 'left': '', \ 'right': '' \ }, \ 'enable': { \ 'statusline': 1, \ 'tabline': 0 \ } \ } " let g:lightline.separator.right = '' " let g:lightline.separator.left = '' fun! LightLineChanges() let l:hunkSummary = v:null if exists('g:loaded_signify') && sy#buffer_is_active() let l:hunkSummary = sy#repo#get_stats() elseif exists('*GitGutterGetHunkSummary') let l:hunkSummary = GitGutterGetHunkSummary() endif if (empty(l:hunkSummary)) return '' else let [ l:added, l:modified, l:removed ] = l:hunkSummary let l:total = (l:added + l:modified + l:removed) let l:output = '' if (l:added != 0) let l:output .= printf('+%d ', l:added) endif if (l:modified != 0) let l:output .= printf('~%d ', l:modified) endif if (l:removed != 0) let l:output .= printf('-%d ', l:removed) endif return '(' . l:output . ')' endif endfun fun! LightlineLinterWarnings() abort if (&readonly) return '' endif let l:counts = ale#statusline#Count(bufnr('')) let l:all_errors = l:counts.error + l:counts.style_error let l:all_non_errors = l:counts.total - l:all_errors return l:all_non_errors == 0 ? '' : printf('%d ▲', l:all_non_errors) endfun fun! LightlineLinterErrors() abort if (&readonly) return '' endif let l:counts = ale#statusline#Count(bufnr('')) let l:all_errors = l:counts.error + l:counts.style_error let l:all_non_errors = l:counts.total - l:all_errors return l:all_errors == 0 ? '' : printf('%d ✗', l:all_errors) endfun fun! LightlineLinterOK() abort if (&readonly) return '' endif let l:counts = ale#statusline#Count(bufnr('')) let l:all_errors = l:counts.error + l:counts.style_error let l:all_non_errors = l:counts.total - l:all_errors return l:counts.total == 0 ? '✓' : '' endfun augroup vimrc_LightlineColorscheme autocmd! autocmd ColorScheme * call s:matchLightlineColorscheme() autocmd User ALELint call s:maybeUpdateLightline() augroup END fun! s:maybeUpdateLightline() " Update and show lightline but only if it's visible (e.g., not in Goyo) if exists('#lightline') call lightline#update() end endfun fun! s:removeDashes(s) return substitute(a:s, '-', '', '') endfunc fun! s:matchLightlineColorscheme() abort let s:vim_colorscheme = g:colors_name let s:vim_colorscheme = s:removeDashes(s:vim_colorscheme) " For example, rose-pine > rosepine func! s:MatchesColorscheme(idx, val) abort let l:lightlineScheme = a:val let l:lightlineScheme = substitute(l:lightlineScheme, '_.*', '', '') let l:result = (-1 != match(s:vim_colorscheme, l:lightlineScheme)) return l:result endfunc let l:colorschemes = s:getLightlineColorschemes() call filter(l:colorschemes, function('s:MatchesColorscheme')) if (len(l:colorschemes) > 0) " echom l:colorschemes[0] . ' matches ' . g:colors_name . '. ' . string(len(l:colorschemes)) let g:lightline.colorscheme = l:colorschemes[0] else " echom 'no lightline colorscheme for ' . g:colors_name if (exists('g:lightline.colorscheme')) unlet g:lightline.colorscheme endif endif if (exists('g:loaded_lightline') && exists('#lightline')) " ^ lightline is not disabled (e.g. by Goyo) call lightline#init() call lightline#colorscheme() call lightline#update() endif endfun fun! s:getLightlineColorschemes() return map(globpath(&runtimepath,'autoload/lightline/colorscheme/*.vim',1,1), "fnamemodify(v:val,':t:r')") endfun command! -nargs=1 -complete=custom,s:lightlineColorschemeCompletion LightlineColorscheme call s:setLightlineColorscheme() function! s:lightlineColorschemeCompletion(...) abort return join(s:getLightlineColorschemes(), "\n") endfunction function! s:setLightlineColorscheme(name) abort let g:lightline.colorscheme = a:name call lightline#init() call lightline#colorscheme() call lightline#update() endfunction endfun PlugIfNotNeovim 'itchyny/lightline.vim', {}, function('s:ConfigLightline') " }}} Plug 'jonsmithers/apprentice-lightline-experimental' " A custom theme I made to go with the apprentice theme PlugDevelop 'jonsmithers/pivotal-tracker-fzf.vim', { 'for': 'gitcommit' } Plug 'junegunn/fzf' Plug 'junegunn/fzf.vim' " Incredible fuzzy search for all sorts of things. " {{{ let g:fzf_command_prefix = 'Fzf' " or to toggle preview window " customize fzf colors to match color scheme let g:fzf_colors = \ { 'fg': ['fg', 'Normal'], \ 'bg': ['bg', 'Normal'], \ 'hl': ['fg', 'Comment'], \ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'], \ 'bg+': ['bg', 'CursorLine', 'CursorColumn'], \ 'hl+': ['fg', 'Statement'], \ 'info': ['fg', 'PreProc'], \ 'border': ['fg', 'Ignore'], \ 'prompt': ['fg', 'Conditional'], \ 'pointer': ['fg', 'Exception'], \ 'marker': ['fg', 'Keyword'], \ 'spinner': ['fg', 'Label'], \ 'header': ['fg', 'Comment'] } function! RipgrepFzf(query, fullscreen, preview) " let command_fmt = 'rg --column --line-number --no-heading --color=always --smart-case %s | awk --field-separator=: ''{ x=$1; sub("/.*/", "/.../", x); print (x":"$2":"$3":"$4); }'' || true' let command_fmt = 'rg --column --line-number --no-heading --color=always --smart-case %s || true' let initial_command = printf(command_fmt, shellescape(a:query)) let reload_command = printf(command_fmt, '{q}') let l:history_file = '/var/tmp/' . substitute(getcwd(), '/', '%', 'g') . '.ripgrep.fzf-history' let spec = {'options': ['--disabled', '--query', a:query, '--bind', 'change:reload:'.reload_command, '--history='.l:history_file ]} let spec = a:preview ? fzf#vim#with_preview(spec) : spec call fzf#vim#grep(initial_command, 1, spec, a:fullscreen) endfunction command! -nargs=* -bang Rg call RipgrepFzf(, 0, 1) command! -nargs=* -bang RgNoPreview call RipgrepFzf(, 0, 0) :nnoremap F :Rg! :nnoremap :Rg "search for word in working directory :nnoremap sw :FzfRg  :vnoremap s y:FzfRg " com! -bang FzfBuffersCustom call fzf#vim#buffers " command! -bar -bang -nargs=? -complete=buffer FzfBuffers call fzf#vim#buffers(, fzf#vim#with_preview({ "placeholder": "{1}" }), 0) command! -bar -bang -nargs=? -complete=buffer FzfBuffersCustom call fzf#vim#buffers(, fzf#vim#with_preview({ "placeholder": "{1}", "options": ['--bind', 'ctrl-k:up', '--bind', 'ctrl-y:preview-up'] }), 0) :nnoremap :FzfBuffersCustom :nnoremap :FzfFiles :nnoremap or :FzfHistory! :nnoremap ft :FzfFiletypes :nnoremap f/ :FzfHistory/ :nnoremap f: :FzfHistory: " (note - you can call histdel("cmd", "regexp") to delete mistaken history items) " fuzzy relative filepath completion! inoremap fzf#vim#complete#path( \ "find . -path '*/\.*' -prune -o -print \| sed '1d;s:^..::'", \ fzf#wrap({'dir': expand('%:p:h')})) inoremap F " Ctrl-X Shift-F will provide native c-x c-f functionality if (!executable('fzf') && !empty(glob("~/.fzf/bin"))) " Save fzf from downloading a redundant binary (it's common for GUI vims " to not see fzf in the PATH) let $PATH=$PATH..":"..expand("~/.fzf/bin") endif " }}} Plug 'junegunn/goyo.vim', { 'on': 'Goyo' } " Distraction free mode. Good for coding and as well as prose writing. " {{{ nnoremap [og :Goyo nnoremap ]og :Goyo! nnoremap yog :Goyo let g:goyo_width = 81 " make vim close the First time you do :quit " https://github.com/junegunn/goyo.vim/wiki/Customization function! s:goyo_enter() lua require('lualine').hide() let b:quitting = 0 let b:quitting_bang = 0 Limelight SoftPencil if (exists(':LspDisableCompletion')) LspDisableCompletion silent! CloseFloatingWindows endif augroup goyo_buffer au! autocmd QuitPre let b:quitting = 1 augroup END cabbrev q! let b:quitting_bang = 1 q! endfunction function! s:goyo_leave() Limelight! NoPencil if (exists(':LspEnableCompletion')) LspEnableCompletion silent! CloseFloatingWindows endif " Quit Vim if this is the only remaining buffer if b:quitting && len(filter(range(1, bufnr('$')), 'buflisted(v:val)')) == 1 if b:quitting_bang qa! else qa endif endif lua require('lualine').hide({unhide = true}) endfunction augroup goyo_stuff au! autocmd User GoyoEnter call goyo_enter() autocmd User GoyoLeave call goyo_leave() augroup END " }}} Plug 'junegunn/limelight.vim' " :Limelight for distraction-free fanciness Plug 'junegunn/rainbow_parentheses.vim' " :RainbowParentheses to color matching parens/brackets " {{{ let g:rainbow#pairs = [['(', ')'], ['[', ']'], ['{', '}']] " }}} Plug 'junegunn/gv.vim', { 'on': 'GV' } " :GV to open git view (commit browser) Plug 'junegunn/vader.vim', { 'on': 'Vader', 'for': 'vader' } " Testing framework for vim plugins Plug 'junegunn/vim-easy-align' " Vertically align code " {{{ " | toggle "live" interactive " | cycle "ignore groups" :xmap ga (EasyAlign) :nmap ga (EasyAlign) " }}} Plug 'justinmk/vim-dirvish' " Directory viewer " {{{ " [range]:Shdo cp {} {}.bakZ! " sort folders at top let g:dirvish_mode = ':sort ,^.*[\/],' augroup dirvish_stuff au! autocmd FileType dirvish setlocal relativenumber autocmd FileType dirvish silent! unmap augroup END " }}} Plug 'mbbill/undotree' Plug 'markonm/traces.vim' " Show a live preview of :substitute Plug 'mg979/vim-visual-multi' " Multiple cursors. Seems to be faster than 'terryma/vim-multiple-cursors'. " {{{ " | MODE | KEY | DESCRIPTION " | normal | | start selection by word under cursor (or visual selection) " | normal | \\/ | start selection by regex " | normal | \\A | select ALL of word " | normal | \\gS | restore VM selection " | VM-selecting | | skip " | VM-selecting | n | find next occurence " | VM-selecting | N | find prev occurence " | VM-selecting | q | skip occurence " | VM-selecting | Q | remove occurence " | VM-selecting | [ | go to prev selected " | VM-selecting | ] | go to next selected " | VM-selecting | [ | go to prev selected " | VM | \\a | align regions " | VM | \\C | Case conversion " | VM | \\@ | Run Macro let g:VM_mouse_mappings = 1 let g:VM_no_meta_mappings = 1 let g:VM_maps = {} let g:VM_maps["Add Cursor Up"] = '\k' let g:VM_maps["Add Cursor Down"] = '\j' " }}} Plug 'mhinz/vim-signify' " Git info in gutter " {{{ " [c,]c jump to prev/next change " [C,]C jump to last/first change " }}} Plug 'mzlogin/vim-markdown-toc' " {{{ " :GenTocGFM " :GenTocGitLab " :UpdateToc let g:vmt_auto_update_on_save = 1 " }}} Plug 'nelstrom/vim-visual-star-search' " Bring "*" key behavior into visual mode. Extremely useful. (see ":help *"). PlugIfNeovim 'nvim-treesitter/nvim-treesitter-textobjects' PlugIfNeovim 'nvim-treesitter/nvim-treesitter' PlugIfNeovim 'nvim-treesitter/playground' PlugIfNeovim 'nvim-treesitter/nvim-treesitter-context' PlugIfNeovim 'nvim-treesitter/nvim-treesitter-refactor' PlugIfNeovim 'windwp/nvim-ts-autotag' Plug 'prettier/vim-prettier', { \ 'do': 'yarn install', \ 'for': ['javascript', 'typescript', 'css', \ 'javascriptreact', 'typescriptreact', \ 'less', 'scss', 'json', 'graphql', \ 'markdown', 'vue', 'svelte', 'yaml', \ 'html', 'prisma'] } nnoremap lp Prettier Plug 'psliwka/vim-smoothie' " {{{ File tree plugin - 'scrooloose/nerdtree' or 'kyazdani42/nvim-tree.lua' fun! s:ConfigNerdtree() let g:NERDTreeHijackNetrw=0 " let dirvish replace netrw let g:NERDTreeMinimalUI=1 :nnoremap tt :NERDTreeTogglep :nnoremap tf :NERDTreeFind :nnoremap tF :NERDTreeFindp :nnoremap tr :NERDTreeRefreshRoot endfun PlugIfNotNeovim 'scrooloose/nerdtree', { 'on': s:nerdtree_triggers }, function('s:ConfigNerdtree') " }}} Plug 'reedes/vim-pencil' Plug 'rbong/vim-flog' " GV.vim with more features " {{{ " a - toggle --all " / - next/preview next commit " ]r, [r - next/prev ref " y - yank commit hash " }}} " if ((has('python') || has('python3')) && !empty(glob($HOME.'/.vim/UltiSnips'))) " Plug 'SirVer/ultisnips' " " Code snippets " " {{{ " let g:UltiSnipsSnippetDirectories = [$HOME.'/.vim/UltiSnips', $HOME.'/.config/smithers/UltiSnips'] " " ^ workaround bug https://github.com/SirVer/ultisnips/issues/711 " let g:UltiSnipsExpandTrigger = '' " let g:UltiSnipsJumpForwardTrigger = '' " let g:UltiSnipsJumpBackwardTrigger = '' " " augroup ultisnip " au! " autocmd Filetype typescript :UltiSnipsAddFiletypes javascript " augroup END " " }}} " endif Plug 'tomtom/tcomment_vim' " Toggle code comments. Mapped to Ctrl-// " {{{ " NOTE: ctrl-// doesn't work in gvim. Instead use ctrl-__ let g:tcomment#replacements_xml = {} " don't substitute weird characters when commenting html lines " }}} Plug 'tpope/vim-abolish' " crs | coerce word to camelCase " crs | coerce word to mixedCase " crs | coerce word to snake_case " cru | coerce word to SNAKE_UPPERCASE " crk | coerce word to kabob-case " cr. | coerce word to dot.case augroup abolish_vimrc au! autocmd VimEnter * :Abolish anomol{y,ies} anomal{} augroup END Plug 'tpope/vim-dadbod' Plug 'kristijanhusak/vim-dadbod-ui' augroup vimrc_dbui au! autocmd FileType dbui set cmdheight=1 augroup END Plug 'tpope/vim-dispatch' Plug 'tpope/vim-eunuch' ":Delete, :Chmod, :SudoWrite, :Rename, :Mkdir Plug 'tpope/vim-endwise' " Automatically insert endif/endfunction/end/fi/esac Plug 'tpope/vim-fugitive' Plug 'tpope/vim-rhubarb' Plug 'shumphrey/fugitive-gitlab.vim' " Various integrated git tools. I use this a lot. " {{{ " Git difftool -y open quickfix list of changes, open diff of each file as tab " Git mergetool open quickfix list of merge conflicts nnoremap gb :Git blame -w " ~ reblame at hovered commit " A resize to author column " D resize to date column " p preview commit " o open commit in split " O open commit in tab nnoremap gs :0Git:normal gU " ri - Rebase Interactive " rw - Rebase reWord " rm - Rebase Modify " rd - Rebase Drop " r - :Git rebase " c? - help " cF - Commit Fixup (rebase immediately) " cS - Commit Squash (rebase immediately) " cc - Commit Create " cvc - Commit Verbose Create " ca - Commit Amend " cva - Command Verbose Amend " cw - Commit reWord " c - :Git commit " http://vimcasts.org/episodes/fugitive-vim-working-with-the-git-index/ " c-n, c-p jumps to files " - stages/unstages nnoremap gd :Gvdiffsplit " (left is index (staged), right is working) " dp diffput " do diffget (think "obtain") " :w write to index/working copy " [c,]c jump to prev/next change " c-w c-o nice way to exit " c-w c-w goes between columns augroup vimrc_fugitive au! autocmd FileType fugitive setlocal relativenumber augroup END " }}} Plug 'tpope/vim-projectionist' Plug 'tpope/vim-repeat' " Improve the versatility of the "." repeat command Plug 'tpope/vim-rsi' " Add readline keybindings http://readline.kablamo.org/emacs.html Plug 'tpope/vim-speeddating' Plug 'tpope/vim-surround' " {{{ " mappings to quickly modify surrounding chars like ",],),},', " NORMAL MODE: " ds to delete surround " cs to change surround from/to " ys to surround text object " yS to surround text object on new line " " cstt to change tag name! " VISUAL MODE: " S " INSERT MODE: " s let b:surround_{char2nr('b')} = "**\r**" augroup vimrc_surround autocmd! autocmd FileType markdown let b:surround_{char2nr('b')} = "**\r**" " use 'b' to surround something with double asterisks augroup END " }}} Plug 'tpope/vim-unimpaired' " Add lots of very useful pair-related keybindings. See :help unimpaired Plug 'tpope/vim-sleuth' " Support editorconfig and auto indent detection command! -bang -nargs=? -complete=dir FilesWithPreview \ call fzf#vim#files(, fzf#vim#with_preview(), 0) if (!empty(glob('~/Dropbox/obsidian'))) nnoremap of :FilesWithPreview ~/Dropbox/obsidian/ nnoremap oF :call VimWikiLines('$HOME/Dropbox/obsidian/**/*') endif if (!empty(glob('~/Dropbox/vimwiki'))) " {{{ " I don't use the vimwiki plugin because it borks markdown &comments, even " after I set ft=markdown. nnoremap wf :FilesWithPreview ~/Dropbox/vimwiki/md nnoremap wF :call VimWikiLines('$HOME/Dropbox/vimwiki/md/*') augroup vimrc_vimwiki autocmd! autocmd BufEnter $HOME/Dropbox/vimwiki/md/*.md command! -buffer ArchiveNote :Move %:h/archive/%:t autocmd BufEnter $HOME/Dropbox/vimwiki/md/archive/*.md delcommand ArchiveNote " disable binding that conflicts with dirvish autocmd Filetype markdown nmap zxcv VimwikiRemoveHeaderLevel augroup end command! -nargs=+ WriteWikiNote call s:writeWikiNote() func! s:writeWikiNote(filename) let l:writePath = '$HOME/Dropbox/vimwiki/md/' . a:filename . '.md' exec ':save ' . expand(l:writePath) endfunc func! VimWikiLines(path) " load all vimwiki notes for l:filename in split(expand(a:path), '\n') exec 'badd '.l:filename endfor Lines endfunc " }}} endif PlugIfNotNeovim 'Xuyuanp/nerdtree-git-plugin', { 'on': s:nerdtree_triggers } " Show git indicators in nerdtree " {{{ let g:NERDTreeIndicatorMapCustom = { \ "Modified" : '*', \ "Staged" : '+', \ "Untracked" : '✭', \ "Renamed" : '➜', \ "Unmerged" : '═', \ "Deleted" : '✖', \ "Dirty" : '*', \ "Clean" : '✔︎', \ 'Ignored' : '☒', \ "Unknown" : '?' \ } " }}} " w0rp/ale: Awesome asynchronous linting of all kinds " {{{ fun! s:ConfigAleIfNotNeovim() let g:ale_linters = { \ 'html': ['eslint'], \ 'javascript': ['tsserver', 'eslint'], \ 'javascriptreact': ['tsserver', 'eslint'], \ 'java': [], \ 'typescript': ['tsserver', 'eslint'], \ 'typescriptreact': ['tsserver', 'eslint'], \ 'rust': ['rustc', 'cargo'] \} let g:ale_linter_aliases = { 'html': ['html', 'javascript'] } let g:ale_echo_msg_format = '%linter%: %s (%code%)' let g:ale_fixers = { \ 'javascript': ['eslint'], \ 'javascriptreact': ['eslint'], \ 'typescript': ['eslint'], \ 'typescriptreact': ['eslint'], \ 'html': ['eslint'], \} let g:ale_completion_enabled = 1 let g:ale_completion_autoimport = 1 :nnoremap an :ALENextWrap :nnoremap ]g :ALENextWrap :nnoremap [g :ALEPreviousWrap :nnoremap ah :ALEHover :nnoremap lh :ALEHover :nnoremap lr :ALERename :nnoremap le :ALEFix eslint :nnoremap af :ALEFix :nnoremap ld :ALEDetail :nnoremap li :ALEImport :nnoremap lx :ALEIgnoreEslint command! ALEIgnoreEslint call AleIgnoreEslint() function! AleIgnoreEslint() " https://stackoverflow.com/questions/54961318/vim-ale-shortcut-to-add-eslint-ignore-hint let l:codes = [] if (!exists('b:ale_highlight_items')) echo 'cannot ignore eslint rule without b:ale_highlight_items' return endif for l:item in b:ale_highlight_items if (l:item['lnum']==line('.') && l:item['linter_name']=='eslint') let l:code = l:item['code'] call add(l:codes, l:code) endif endfor if len(l:codes) exec 'normal O/* eslint-disable-next-line ' . join(l:codes, ', ') . ' */' endif endfunction endfun PlugIfNotNeovim 'w0rp/ale', { }, function('s:ConfigAleIfNotNeovim') " }}} " Plug 'wellle/targets.vim' " Advanced vim text objects. Sometimes this is slow. Plug 'whiteinge/diffconflicts' " {{{ " git config --global merge.tool diffconflicts " git config --global mergetool.diffconflicts.cmd 'vim -c DiffConflicts "$MERGED" "$BASE" "$LOCAL" "$REMOTE"' " git config --global mergetool.diffconflicts.trustExitCode true " git config --global mergetool.keepBackup false " git mergetool " }}} Plug 'Yggdroot/indentLine' " {{{ " more obvious visual depiction of indentation " let g:indentLine_char_list = ['|', '¦', '┆', '┊'] let g:indentLine_enabled = 0 nnoremap [o :IndentLinesEnable nnoremap ]o :IndentLinesDisable nnoremap yo :IndentLinesToggle let g:indentLine_char = '┊' augroup vimrc_indentline au! autocmd ColorScheme * call s:matchIndentLine() augroup END fun! s:matchIndentLine() let g:indentLine_color_gui = synIDattr(synIDtrans(hlID('Comment')), "fg#") endfun " }}} " {{{ language syntax plugins Plug 'dag/vim-fish' Plug 'fatih/vim-go' Plug 'fladson/vim-kitty' Plug 'Glench/Vim-Jinja2-Syntax' Plug 'jonsmithers/vim-html-template-literals' Plug 'MaxMEllon/vim-jsx-pretty' Plug 'posva/vim-vue' Plug 'rust-lang/rust.vim' Plug 'tfnico/vim-gradle' Plug 'tpope/vim-markdown' Plug 'vim-scripts/groovyindent-unix' let g:html_indent_script1 = 'inc' let g:html_indent_style1 = 'inc' let g:markdown_fenced_languages = ['rust', 'typescript', 'typescriptreact', 'javascript', 'bash', 'json'] let g:vim_jsx_pretty_colorful_config = 1 " }}} " {{{ colorscheme/theme plugins if &term == 'alacritty' let &term='xterm-256color' endif if (has('termguicolors')) set termguicolors else set t_Co=256 endif Plug 'arcticicestudio/nord-vim' Plug 'ayu-theme/ayu-vim' PlugIfNotNeovim 'cormacrelf/vim-colors-github' PlugIfNeovim 'projekt0n/github-nvim-theme' Plug 'dracula/vim', { 'as': 'dracula' } Plug 'junegunn/seoul256.vim' Plug 'kjssad/quantum.vim' Plug 'KKPMW/sacredforest-vim' Plug 'mhartington/oceanic-next' Plug 'morhetz/gruvbox' Plug 'nanotech/jellybeans.vim' Plug 'NLKNguyen/papercolor-theme' Plug 'rakr/vim-one' " old Plug 'joshdick/onedark.vim' Plug 'romainl/Apprentice' let g:onedark_hide_endofbuffer=1 let g:onedark_terminal_italics=1 let g:gruvbox_contrast_dark='hard' let g:gruvbox_contrast_light='hard' " }}} if !empty(glob('~/.profile.vim')) source ~/.profile.vim endif call plug#end() for F in s:config_queue call F() endfor let s:config_queue = [] " ┌──────────────┐ " │ Key Mappings │ " └──────────────┘ " {{{ nnoremap ; : vnoremap ; : " search and replace (works well with Traces.vim) vnoremap A y:call ReplaceAppend() vnoremap c y:call ReplaceChange() vnoremap I y:call ReplaceInsert() fun! ReplaceAppend() let l:selection = escape(@0, '/\') call feedkeys(":%substitute/\\V\\C" . l:selection . '/' . l:selection . "/gc\\\") return '' endfun fun! ReplaceChange() let l:selection = escape(@0, '/\') call feedkeys(":%substitute/\\V\\C" . l:selection . '/' . "/gc\\\") return '' endfun fun! ReplaceInsert() let l:selection = escape(@0, '/\') call feedkeys(":%substitute/\\V\\C" . l:selection . '/' . l:selection . "/gc\\\" . repeat("\", len(l:selection))) return '' endfun " insert ISO date in : menu cnoremap =strftime('%Y-%m-%d') inoremap =strftime('%Y-%m-%d') inoremap jk inoremap jl : " https://castel.dev/post/lecture-notes-1/ inoremap u[s1z=`]au " reformat current paragraph without leaving insert mode inoremap gwip " clear search nnoremap sdf :let @/ = '' " horizontal scroll nnoremap 5zh nnoremap 5zl " disable confusing and near-obsolete ex mode nnoremap Q nnoremap x :call CloseBufferWithNerdTree(v:false) nnoremap X :call CloseBufferWithNerdTree(v:true) fun! CloseBufferWithNerdTree(force) let l:nerdtreeopen = exists("g:NERDTree") && g:NERDTree.IsOpen() if (l:nerdtreeopen) :NERDTreeClose endif if (a:force) bd! else bd end if (l:nerdtreeopen) :NERDTreeToggle :wincmd p endif endfun " quick save nnoremap :w " switch with most recent buffer nnoremap :b# " refresh syntax if it gets out of whack (sometimes useful for large files of deeply-nested syntaxes (e.g.