"----------------------------------------------------------------------------------------------------------------------- " The config is chopped up into sections. Search for these headings to quickly jump to a particular section. " " #0 GLOBALS " #1 PLUGINS " #2 BASE CONFIG " #3 CUSTOM AUTOCMDS " #4 KEY MAPPINGS " #5 PLUGIN CONFIGS " #6 VISUALS (COLORS, HIGHLIGHTING) " #7 CUSTOM FUNCTIONS & COMMANDS " " @incomplete Add setup steps (plugins, cache setup, search tool, etc). "----------------------------------------------------------------------------------------------------------------------- let g:campo_vimrc_initialized = 0 " Will be set to 1 at the end of the file. Can be used to avoid changes on subsequent vimrc reloads. scriptencoding utf-8 " @note If the file contains a BOM then vim will automatically set `bomb` for the buffer so that the BOM is written out again. set encoding=utf-8 fileencoding=utf-8 fileencodings=ucs-bom,utf8,prc set nocompatible filetype off " Store the current system name so that we can conditionally set configs for different platforms. let s:uname = system("echo -n \"$(uname)\"") let g:vim_dir = $HOME . "/.vim" let mapleader="," function! IsWindows() if s:uname =~ "mingw" || s:uname =~ "msys" return 1 endif return 0 endfunction if has('termguicolors') set termguicolors " Set Vim-specific sequences for RGB colors. let &t_8f = "\[38;2;%lu;%lu;%lum" let &t_8b = "\[48;2;%lu;%lu;%lum" endif function! PrintError(msg) abort exec 'normal! \' echohl ErrorMsg echomsg a:msg echohl None endfunction "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| " #0 GLOBALS "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "----------------------------------------------------------------------------------------------------------------------- " @note The following globals can be used to customize various functions in " this file. The easiest way to set them is in ~/.vimrc.private or an .lvimrc " file in the root folder that you want it applied to. " " Some variables cannot be customized in an .lvimrc because their value is " used by settings in this file when it's sourced. These have been flagged " with the note :unsupported-in-lvimrc. " " Also take note that an .lvimrc has precedence because it's loaded after this " and the private vimrc. "----------------------------------------------------------------------------------------------------------------------- " @note :unsupported-in-lvimrc let g:campo_max_line_length = 120 " Display a vertical bar at x=. " Set the row height of the quickfix pane, which is used to display results " from various plugins (like ctrlp, ripgrep, compilation errors, etc), in rows let g:quickfix_pane_height = 20 "################################################################################## " COLORS "################################################################################## let g:campo_light_dark_mode = 'dark' " Start vim with the dark theme. Set to 'light' for the light theme. let g:campo_dark_theme = 'campo-dark-simple' "'campo-dark-blue' let g:campo_light_theme = 'campo-light-simple' "'campo-light' let g:campo_theme_use_rainbow_parens = 1 "################################################################################## " FORMATTING "################################################################################## " When set to 1, all files will be stripped of trailing whitespace when the " file is saved. Set to 0 to disable. You can customize which files are " ignored or always stripped; see below. let g:campo_strip_trailing_whitespace = 1 " When set to 1, the whitespace stripping force/ignore file filters below will " be expected to have full paths to the files, otherwise just the filename is " required. let g:campo_use_full_paths_for_whitespace_stripping_file_filters = 1 " If g:campo_strip_trailing_whitespace is 1 then you can stop stripping in " specific directories by setting this to a list of full directory paths. " This has no effect when g:campo_strip_trailing_whitespace is 0. " " e.g. let g:campo_directories_to_ignore_when_stripping_trailing_whitespace = ['/z/modules', '/d/build'] let g:campo_directories_to_ignore_when_stripping_trailing_whitespace = [] " If g:campo_strip_trailing_whitespace is 1 then you can stop stripping in " specific files by setting this to a list of full file paths. " This has no effect when g:campo_strip_trailing_whitespace is 0. " " e.g. let g:campo_files_to_ignore_when_stripping_trailing_whitespace = ['/z/modules/test.h', '/d/build/config.h'] let g:campo_files_to_ignore_when_stripping_trailing_whitespace = [] " If g:campo_strip_trailing_whitespace is 0 then you can force whitespace " stripping in specific directories by setting this to a list of full paths. " This has no effect when g:campo_strip_trailing_whitespace is 1. " " e.g. let g:campo_directories_to_force_stripping_trailing_whitespace = ['/z/modules '/d/build'] let g:campo_directories_to_force_stripping_trailing_whitespace = [] " If g:campo_strip_trailing_whitespace is 0 then you can force whitespace " stripping in specific files by setting this to a list of full file paths. " This has no effect when g:campo_strip_trailing_whitespace is 1. " " e.g. let g:campo_files_to_force_stripping_trailing_whitespace = ['/z/modules/test.h', '/d/build/config.h'] let g:campo_files_to_force_stripping_trailing_whitespace = [] "################################################################################## " SEARCH "################################################################################## " This is included in the ripgrep args. You can use this to do things like " ignore folders in your project or limit the search to specific file types. " For example, if you want to ignore the 3rd_party dir and only search C files " (remove the backslash from the first quote as that's just here to escape it " in this comment string) " let g:campo_custom_search_args = \"-g \"!3rd_party/*\" -tc" let g:campo_custom_search_args = "" "################################################################################## " CTAGS "################################################################################## " I use the ctags executable from https://github.com/universal-ctags/ctags-win32/releases " " Be sure to check out the ctags plugin config in section #5 for additional API functions. " If != 0 then ctag generation will always happen on a file save, otherwise " it'll only be triggered if the file being saved has an extension in the " g:campo_extensions_that_run_ctags list. let g:campo_force_ctags_regardless_of_extension = 0 " If one of these file types are saved then the ctags creation function will be called. " You can append to this list in another config like so: " let g:campo_extensions_that_run_ctags = g:campo_extensions_that_run_ctags + ['foo', 'bar'] let g:campo_extensions_that_run_ctags = ['c','cpp','h','hpp','inc','cs','py','asm','ex','exs'] " Default files and directories that ctags should ignore when doing a " recursive crawl. " @note The CreateCtags function will always ignore .git and node_modules " regardless of this variable's value. let g:campo_ctags_exclude = ['*.txt', '*.config', '.cache'] " This is included in the ctags autocmd args. You can use this to customize " how ctags are built. " Examples: " * Recursive ctag generation with `let g:campo_custom_ctags_args = '-R'` " * Create tags for specific langauges: `let g:campo_custom_ctags_args = '--languages=C,C++,Elixir' " * You can see a list of languages with `ctags --list-languages` " * For C# you have to escape the ampersand like so: `--languages=C\\#` " * Exclude a directory with `let g:campo_custom_ctags_args = '--exclude=3rd_party'` let g:campo_custom_ctags_args = "" "################################################################################## " JAI "################################################################################## " Set to your Jai install path. Used for various commands, like for example " searching the modules and how_to directories with CtrlP let g:campo_jai_path = '' " Args to include when compiling a Jai file. let g:campo_jai_build_args = '' "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| " #1 PLUGINS "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| call plug#begin('~/.vim/plugged') "################################################################################## " MISC "################################################################################## Plug 'vim-airline/vim-airline' " Enhanced status/tabline. Plug 'embear/vim-localvimrc' " Add a .lvimrc to a folder to override .vimrc config. Plug 'tpope/vim-obsession' " Continuously updated session files (tracks window positions, open folds, etc). Plug 'tpope/vim-fugitive' " Git wrapper (I particularly like :Gblame, which I've wrapped as :Blame) Plug 'sir-pinecone/vim-ripgrep' " Fast grep-like search. Requires ripgrep; install Rust package: `cargo install ripgrep`. Plug 'itchyny/vim-cursorword' " Underlines all instances of the symbol under the cursor. Plug 'airblade/vim-gitgutter' " Displays a git diff in the vim gutter and allows staging/unstaging of hunks. Plug 'ctrlpvim/ctrlp.vim' " Fuzzy file, buffer, mru, tag, etc finder. Plug 'majutsushi/tagbar' " Display ctags in a window, ordered by scope. Plug 'tommcdo/vim-lion' " For text alignment, use gl= and gL= Plug 'tpope/tpope-vim-abolish' " Easily search for, substitute, and abbreviate multiple variants of a word. Add them to `vim/after/plugin/abolish.vim` Plug 'vim-scripts/AnsiEsc.vim' " Ansi escape sequences concealed, but highlighted as specified. Plug 'sir-pinecone/errormarker.vim' " Build error highlighting (requires skywind3000/asyncrun.vim). Plug 'skywind3000/asyncrun.vim' " Async commands. Plug 'nelstrom/vim-qargs' " For the GlobalReplaceIt function (i.e. search and replace). Plug 'editorconfig/editorconfig-vim' " Adds support for .editorconfig files. if IsWindows() Plug 'suxpert/vimcaps' " Disable capslock (useful if the OS isn't configured to do so). endif "################################################################################## " COLORS "################################################################################## Plug 'luochen1990/rainbow', { 'commit': '1c45e0f' } " Rainbow parens. Locked to an older commit that still works fine on my PC. Plug 'vim-airline/vim-airline-themes' if IsWindows() Plug 'godlygeek/csapprox' " Try to make gvim themes look decent on Windows. endif Plug 'dracula/vim', { 'as': 'dracula' } "///////////////////////////////////////////////// " SYNTAX HIGHLIGHTING "///////////////////////////////////////////////// Plug 'rluba/jai.vim' " Jai Plug 'bfrg/vim-cpp-modern' " C/C++ Plug 'fedorenchik/fasm.vim' " Flat Assembler Plug 'elixir-editors/vim-elixir' " Elixir Plug 'pprovost/vim-ps1' " PowerShell Plug 'tpope/vim-markdown' " Markdown "Plug 'vim-ruby/vim-ruby' " Ruby "Plug 'fatih/vim-go' " Go "Plug 'rust-lang/rust.vim' " Rust "Plug 'jdonaldson/vaxe' " Haxe " " " call plug#end() filetype plugin indent on "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| " #2 BASE CONFIG "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| set hidden set history=10000 set expandtab set tabstop=4 set shiftwidth=4 set softtabstop=4 set autoindent set laststatus=2 set showcmd " Display incomplete commands. set showmatch set incsearch " Highlight matches as you type. set hlsearch " Highlight matches. set dictionary+=/usr/share/dict/words "set clipboard=unnamed " Yank and paste with the system clipboard. set number set ignorecase smartcase " Make searches case-sensitive only if they contain upper-case characters. set visualbell " No bell sounds. set ttyfast set cmdheight=2 set switchbuf=useopen,split set numberwidth=5 set showtabline=2 set winwidth=79 " Use abbreviations. set shortmess=a " Remove gvim Menubar and Toolbar "set guioptions -=m "set guioptions -=T " @warning: This must come AFTER `set ignorecase smartcase` otherwise vim spews out a ton of errors. No idea why! if IsWindows() " Just assume we don't have a zsh shell set shell=bash else "set shell=zsh set shell=bash endif set t_ti= t_te= " Prevent Vim from clobbering the scrollback buffer. See http://www.shallowsky.com/linux/noaltscreen.html set scrolloff=3 " keep more context when scrolling off the end of a buffer set cursorline set cursorcolumn " Store swap, backup and undo files in a central spot. I have my settings in a " `vimrc.private` so that my drive paths aren't in this config. If you want to " set them here then add: " " set directory= " set backupdir= " if has('persistent_undo') " set undodir= " endif " " And make sure those directories exist before opening vim. " set backup set backupcopy=yes augroup backupCmds autocmd! autocmd BufWritePre * let &bex = '.' . strftime("%Y-%m-%d-%T") . '.bak' augroup END set writebackup " Make buckup before overwriting the current buffer. " Keep undo history across sessions by storing it in a file. The undo save " location is set in the vimrc.private file. You can also set it here with: " set undodir= " set undolevels=1000 " Allow undo when going back into a closed file set undoreload=10000 if has('persistent_undo') set undofile endif set backspace=indent,eol,start " Allow backspacing over everything in insert mode. set complete+=kspell " Spell checking autocomplete. set complete-=i " Don't scan all included files since it's really slow. set termguicolors syntax on " Enable highlighting for syntax set wildmenu set wildmode=longest,list,full set wildignore+=*/log/*,*.so,*.swp,*.zip,*/rdoc/* if executable('rg') set grepprg=rg\ --vimgrep\ --hidden " Requires ripgrep to be installed. endif set list listchars=tab:»·,trail:· " Show trailing whitespace. set timeoutlen=300 ttimeoutlen=0 " Adding this since the esc remap on the 'i' key had a long delay when pressed. " @fixme might be broken if lowered to 100 from original value of 4000. Will " first try 500 and tweak from there. " UPDATE: I lowered this to 250 and eventually started seeing some plugin " errors related to paren formatting. I think 800 might be the sweet spot. set updatetime=800 " I lowered this to make git-gutter updates faster. " Fix vim's background colour erase - http://snk.tuxfamily.org/log/vim-256color-bce.html if &term =~ '256color' " Disable Background Color Erase (BCE) so that color schemes " work properly when Vim is used inside tmux and GNU screen. " See also http://snk.tuxfamily.org/log/vim-256color-bce.html set t_ut= endif " Status line set statusline=%<%f\ (%{&ft})\ %-4(%m%)%=%-19(%3l,%02c%03V%) " Disable arrow keys. noremap noremap noremap noremap inoremap inoremap inoremap inoremap "///////////////////////////////////////////////// " LOAD PRIVATE VIMRC "///////////////////////////////////////////////// " This should be done after above base settings that don't use the global " campo variables. " " You can further customize things in a private vimrc. I use this for things " that I don't want included in my public dotfiles repo such as temp file settings. if filereadable($HOME . "/.vimrc.private") source $HOME/.vimrc.private endif " Settings that use the global campo variables: let &colorcolumn=g:campo_max_line_length "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| " #3 CUSTOM AUTOCMDS "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| augroup campoCmds " Clear all autocmds in the group. autocmd! " Automatically wrap at N characters. autocmd FileType gitcommit setlocal colorcolumn=72 " @flagged for removal. It's a bit annoying. autocmd BufRead,BufNewFile *.{md,txt,plan} exec "setlocal textwidth=".g:campo_max_line_length " Enable spell checking by default. autocmd FileType gitcommit,markdown,text setlocal spell " Jump to last cursor position unless it's invalid or in an event handler. autocmd BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g`\"" | endif " Properly indent schemes (scheme, racket, etc). autocmd BufRead,BufNewFile *.{lisp,scm,rkt} setlocal equalprg=scmindent.vim.rkt " Elixir indent autocmd FileType elixir setlocal tabstop=2 | setlocal shiftwidth=2 | setlocal softtabstop=2 " Fasm indent; uses the fedorenchik/fasm.vim plugin. autocmd BufReadPre *.asm let g:asmsyntax = "fasm" " Auto reload VIM when settings changed. " Need to use silent! now because the save commands call a custom function " and without the silent we would see an error after sourcing saying that " we can't redefine the function that initiated the save. :ReloadVimrcError " " @fixme Reload lvimrc after sourcing this file on a save. I tried calling " a function that does the source and a call to lvimrc's API but got an " error complaining that the function cannot be created while it's in use. autocmd BufWritePost .vimrc silent! source $MYVIMRC autocmd BufWritePost *.vim silent! source $MYVIMRC autocmd BufWritePost ~/.vimrc.private silent! source $MYVIMRC autocmd BufWritePost ~/.vimrc_templates.private silent! source $MYVIMRC " Remove trailing whitespace when saving any file. function! StripTrailingWhitespaces() if g:campo_strip_trailing_whitespace == 1 if len(g:campo_directories_to_ignore_when_stripping_trailing_whitespace) for path in g:campo_directories_to_ignore_when_stripping_trailing_whitespace if path == expand('%:p:h') return endif endfor endif if len(g:campo_files_to_ignore_when_stripping_trailing_whitespace) for filename in g:campo_files_to_ignore_when_stripping_trailing_whitespace if (g:campo_use_full_paths_for_whitespace_stripping_file_filters == 1 && filename == expand('%:p')) || (g:campo_use_full_paths_for_whitespace_stripping_file_filters == 0 && filename == expand('%:t')) return endif endfor endif else let l:found_match = 0 if len(g:campo_directories_to_force_stripping_trailing_whitespace) for path in g:campo_directories_to_force_stripping_trailing_whitespace if path == expand('%:p:h') let l:found_match = 1 break endif endfor endif if l:found_match == 0 && len(g:campo_files_to_force_stripping_trailing_whitespace) for filename in g:campo_files_to_force_stripping_trailing_whitespace if (g:campo_use_full_paths_for_whitespace_stripping_file_filters == 1 && filename == expand('%:p')) || (g:campo_use_full_paths_for_whitespace_stripping_file_filters == 0 && filename == expand('%:t')) let l:found_match = 1 break endif endfor endif if l:found_match == 0 return endif endif let l = line(".") let c = col(".") %s/\s\+$//e call cursor(l, c) endfun autocmd BufWritePre * call StripTrailingWhitespaces() augroup END "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| " #4 KEY MAPPINGS "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "################################################################################## " MISC "################################################################################## " Lowercase the e (have a habit of making it uppercase). :ca E e " Mapping ESC in insert mode and command mode to double i. imap jj " Suspend vim process and return to the shell. Can return to vim with `fg`. nnoremap z " edit a file nnoremap e :e " Open the vimrc file for editing / reload vimrc file. nnoremap ev :vsp $MYVIMRC nnoremap pv :vsp ~/.vimrc.private nnoremap rv :source $MYVIMRC " Type %/ in the command bar to have it replaced with the current buffer's " path if the file is on disk. One thing I noticed is that you have to type " the full %/ quickly otherwise it won't replace it. cmap %/ %:p:h/ " Open a terminal within vim. Use `exit` to close it. " DISABLING because I don't use this and I want to use the t for opening my todo file. "if exists(':terminal') " noremap t :terminal " tnoremap te " tnoremap h " tnoremap j " tnoremap k " tnoremap l " nnoremap h " nnoremap j " nnoremap k " nnoremap l "endif " Jump to other buffers. noremap noremap noremap noremap " Make it easier to jump around the command line. The default behaviour is " using the arrow keys with or without shift. :cnoremap :cnoremap " Window splitting - couldn't figure out how to remap v & n to " & noremap m :vsplit noremap mm :split " Forward delete and replace a word. noremap d ciw " Allow fast pasting by accessing the system clipboard register. noremap p "+p " Likely won't need to use this if pasting with p, but just in case here ya go. noremap pp :set paste! paste? " Toggle line numbers. noremap o :set number! number? " Show spell checking. " You can add new entries to the dict by moving the cursor over the word and pressing `zg`. noremap j :exec &spell==&spell? "se spell! spelllang=en_us" : "se spell!" noremap = z= " Clear the search buffer (highlighting) when hitting return. nnoremap :nohlsearch " Switch to the previous file. nnoremap " Replace currently selected text with default register without yanking it. vnoremap p "_dP " Switch between C++ source and header files. noremap v :e %:p:s,.h$,.X123X,:s,.cpp$,.h,:s,.X123X$,.cpp, "noremap vv :e %:p:s,.h$,.X123X,:s,.c$,.h,:s,.X123X$,.c, "noremap vvv :e %:p:s,.h$,.X123X,:s,.cc$,.h,:s,.X123X$,.cc, " Replace all instances of the highlighted text with whatever you enter. nnoremap :%s///g "################################################################################## " SAVING AND QUITING "################################################################################## " I used to have a BufWritePost autocommand that ran the ctags generator but " it ends up running multiple times when saving multiple buffers at once. In " order to only call it once for a group of saves I've had to remap the " various save commands to a function call. function! CreateCtags() " Only allow one instance of ctags to run in this directory at any given time. let l:lock_file = "ctags.lock" if filereadable(l:lock_file) || filereadable("newtags") " Don't print a warning because this will always show when saving multiple files at the same time with a :wa or :xa return endif let l:extension = tolower(expand('%:e')) if (g:campo_force_ctags_regardless_of_extension == 0) && (index(g:campo_extensions_that_run_ctags, l:extension) < 0) "echo "Skipping ctags generation" return endif " Abort if we're editing a text file. This won't be an exhaustive " filter. We can restrict what goes into the tag file " First determine if we're in a root drive directory. If we are then " we bail because we don't want to recurse across the entire drive! let l:path = expand('%:p:h') let l:path_without_slashes = substitute(l:path, "/", "", "g") if (strchars(l:path) - strchars(l:path_without_slashes)) <= 1 call PrintError("Not going to run ctags because the file is in a root drive directory") return endif " Always ignore .git and node_modules let g:campo_ctags_exclude = g:campo_ctags_exclude + ['.git', 'node_modules'] let l:exclude_list = "" for name in g:campo_ctags_exclude let l:exclude_list .= "--exclude=" . name . " " endfor " Include local variables for C-like languages. let l:ctags_cmd = 'ctags '.l:exclude_list.' '.g:campo_custom_ctags_args.' --c-types=+l --c++-types=+l -o newtags' " Add the filename to the ctags command if not running in recursive mode. let l:recursive = matchstr(g:campo_custom_ctags_args, '\(-R\s\)\|\(-R$\)\|\(--recurse=yes\)\|\(--recurse\s\)\|\(--recurse$\)') if l:recursive == '' let l:ctags_cmd .= ' ' . expand('%:t') echo "Creating non-recursive ctags" else echo "Creating recursive ctags" endif " The ampersand at the end is to make this run in the background. I had to group the " commands in parens to make the chained commands run in the background. let l:cmd = '!(touch '.l:lock_file.'; '.l:ctags_cmd.'; mv newtags tags &>/dev/null; rm '.l:lock_file.') &' silent! exec l:cmd endfun " @note We have an autocmd that reloads the vimrc files after they're saved. " These write functions below will not be reloaded because they initiate the " save. So if you make changes to them then you need to manually reload this " file using rv or whatever. :ReloadVimrcError function! WriteCurrentFileAndCreateCtags() write! call CreateCtags() endfunction function! WriteCurrentFileAndCreateCtagsThenQuit() write! call CreateCtags() quit endfunction " @fixme Sometimes a :wa that saves multiple files causes vim to hang and use a lot of CPU. function! WriteAllModifiedFilesAndCreateCtags() wall! call CreateCtags() endfunction cnoreabbrev w :call WriteCurrentFileAndCreateCtags() cnoreabbrev W :call WriteCurrentFileAndCreateCtags() cnoreabbrev wa :call WriteAllModifiedFilesAndCreateCtags() cnoreabbrev Wa :call WriteAllModifiedFilesAndCreateCtags() cnoreabbrev WA :call WriteAllModifiedFilesAndCreateCtags() cnoreabbrev wq :call WriteCurrentFileAndCreateCtagsThenQuit() cnoreabbrev Wq :call WriteCurrentFileAndCreateCtagsThenQuit() cnoreabbrev WQ :call WriteCurrentFileAndCreateCtagsThenQuit() nnoremap w :call WriteCurrentFileAndCreateCtags() nnoremap x :call WriteCurrentFileAndCreateCtagsThenQuit() nnoremap q :q cnoreabbrev Q q cnoreabbrev Qa qa command! Qa qall " Disable Ex mode. noremap Q "################################################################################## " MULTIPURPOSE TAB KEY "################################################################################## function! InsertTabWrapper() let l:col = col('.') - 1 if !l:col || getline('.')[l:col - 1] !~ '\k' return "\" else return "\" endif endfunction inoremap =InsertTabWrapper() inoremap "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| " #5 PLUGIN CONFIGS "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "################################################################################## " LOCAL VIMRC "################################################################################## let g:localvimrc_sandbox = 0 let g:localvimrc_ask = 0 "################################################################################## " EDITOR CONFIG "################################################################################## let g:EditorConfig_exclude_patterns = ['fugitive://.*'] "################################################################################## " LION (TEXT ALIGNMENT) "################################################################################## let b:lion_squeeze_spaces = 1 "################################################################################## " TAGBAR "################################################################################## noremap :TagbarToggle " Sort tags by their order in the source file. Press 's' to sort them alphabetically. let g:tagbar_sort = 0 "################################################################################## " GITGUTTER "################################################################################## let g:gitgutter_enabled = 1 let g:gitgutter_highlight_lines = 0 nnoremap hh :GitGutterToggle nmap ha (GitGutterStageHunk) nmap [h (GitGutterNextHunk) nmap ]h GitGutterPrevHunk augroup gitGutterPluginCmds autocmd! " Update marks on save autocmd BufWritePost * GitGutter augroup END "################################################################################## " SYNTASTIC "################################################################################## " NOTE: there is a status line config in the status line section let g:syntastic_always_populate_loc_list = 1 let g:syntastic_auto_loc_list = 1 let g:syntastic_check_on_open = 0 let g:syntastic_check_on_wq = 0 " Customize Rust " https://github.com/rust-lang/rust.vim/issues/130 " Can remove once this Syntastic PR is merged https://github.com/rust-lang/rust.vim/pull/132 "let g:syntastic_rust_rustc_exe = 'cargo check' "let g:syntastic_rust_rustc_fname = '' "let g:syntastic_rust_checkers = ['rustc'] "################################################################################## " RIPGREP "################################################################################## let g:rg_highlight = 1 let g:rg_window_height = g:quickfix_pane_height "################################################################################## " C-TAGS "################################################################################## " Set extra paths to use when searching for ctags files. By default the current " directory is always checked. You can use this to combine tag lookups from " different projects, e.g. set it to the Jai directory and you can look up " current project tags and Jai module tags (of course this isn't needed if you " have Jai module tags in your local file). " " This destructively overwrites the tags option value. " " Call this from a .vimrc.private or .lvimrc file, e.g. " call g:SetExtraCtagsPaths([g:campo_jai_path.'/tags']) " function! g:SetExtraCtagsPaths(paths_array) let l:list = './tags,tags' " This is the default tags list set by vim. for path in a:paths_array let l:list .= ',' . path endfor let &tags=l:list endfunction "################################################################################## " CTRL-P "################################################################################## " keybindings: " " leader-f = open CtrlP in tag searching mode. " leader-g = open CtrlP in file searching mode. " ctrl-f = toggle search mode " enter = open result in a current buffer or in an already open buffer for that file. " ctrl-v = open result in a vertically-split buffer. " ctrl-h = open result in a horizontally-split buffer. " ctrl-t = open result in a new tab. " ctrl-j | ctrl-k = move up and down the search results. " ctrl-y = create file and open it. " ctrl-z = mark multiple file search results to open (I think you can only use ctrl-v or ctrl-x and not enter). " ctrl-o = ask how to open a file search result. " ctrl-o = ask how to open a file search result. " ctrl-p | ctrl-n = traverse search history. " CtrlP finds the tags file by using vim's 'tags' option value. I initially " tried changing the tags value to the working_path if one is provided. I made " a copy of the current tags value and attempted to restore it when CtrlP was " exited without an action or a tag action took place. I wasn't able to get " the tags restored because there's no vim event that gets triggered when a " tag is opened using the :tag comment. I tried a bunch of autocmds on buffer, " window and cmdline events but wasn't able to find anything that fired AFTER " the tag command. So we're instead just setting the tags list once for the " session and not bothering with changing it on the fly. See g:SetExtraCtagsPaths function! CtrlP_Search(search_path) " If a:search_path is empty then ctrlp will use g:ctrlp_working_path_mode to determine the cwd to search in. execute 'CtrlP ' . a:search_path endfunction function! CtrlP_JaiSearch(jai_rel_search_path) if g:campo_jai_path == '' call PrintError("g:campo_jai_path isn't set!") return endif let l:path = g:campo_jai_path if a:jai_rel_search_path != '' let l:path .= '/' . a:jai_rel_search_path endif if !isdirectory(l:path) call PrintError("Directory ".l:path." doesn't exist.") return endif call CtrlP_Search(l:path) endfunction " CtrlP File Searching noremap g :call CtrlP_Search('') " Search in current directory noremap gg :call CtrlP_JaiSearch('') " Search in Jai directory noremap gm :call CtrlP_JaiSearch('modules') " Search in Jai modules noremap gh :call CtrlP_JaiSearch('how_to') " Search in Jai how_to noremap ge :call CtrlP_JaiSearch('examples') " Search in Jai examples let g:ctrlp_map = 'f' let g:ctrlp_cmd = 'CtrlPTag' " Search tags by default. let g:ctrlp_by_filename = 1 " File search by filename as opposed to full path. let g:ctrlp_match_window = 'bottom,order:ttb,min:10,max:'.g:quickfix_pane_height.',results:'.g:quickfix_pane_height let g:ctrlp_use_caching = 1 let g:ctrlp_clear_cache_on_exit = 1 " No need to keep cache for now since I mostly work in git repos. Press F5 inside CtrlP to rebuild the cache. let g:ctrlp_working_path_mode = 'ra' " Search from nearest ancestor of the current file that contains .git OR directory of the current file unless it's a subdirectory of the cwd let g:ctrlp_switch_buffer = 'et' " If a file is already open, open it again in a new pane instead of switching to the existing pane let g:ctrlp_custom_ignore = '\v[\/]\.(git|hg|svn)$' let g:ctrlp_user_command = ['.git', 'cd %s && git ls-files -co --exclude-standard'] " If a git repo, use checked in files (ignore things in .gitignore); fallback to globpath() "################################################################################## " GIT "################################################################################## noremap gb :Git blame -w " Ignore whitespace changes; follow renames and copies. command! -bar -bang -nargs=* Blame :Git blame -wCM command! -bar -bang -nargs=* Gblame :Git blame -wCM "################################################################################## " GIST VIM "################################################################################## let g:gist_detect_filetype = 1 let g:gist_open_browser_after_post = 1 let g:gist_show_privates = 1 let g:gist_post_private = 1 "################################################################################## " VIM-CLOJURE-STATIC "################################################################################## " Default let g:clojure_fuzzy_indent = 1 let g:clojure_align_multiline_strings = 1 let g:clojure_fuzzy_indent_patterns = ['^match', '^with', '^def', '^let'] let g:clojure_fuzzy_indent_blacklist = ['-fn$', '\v^with-%(meta|out-str|loading-context)$'] "################################################################################## " RUST.VIM "################################################################################## "let g:rustfmt_autosave = 1 " auto run rust formatter when saving "################################################################################## " RAINBOW "################################################################################## let g:rainbow_active = 1 " Always on let s:light_rainbow = ['red', 'green', 'magenta', 'cyan', 'yellow', 'white', 'gray', 'blue'] let s:dark_rainbow = ['darkblue', 'red', 'black', 'darkgreen', 'darkyellow', 'darkred', 'darkgray'] let s:rainbow_theme = g:campo_light_dark_mode function! UpdateRainbowConf() let g:rainbow_conf = { \ 'ctermfgs': (s:rainbow_theme == "light"? s:dark_rainbow : s:light_rainbow) \} "\ 'separately': { "\ '*': 0, " Disable all "\ 'c++': {} " Only enable c++ "\ } endfunction call UpdateRainbowConf() function! ReloadRainbow() if g:campo_theme_use_rainbow_parens if exists(':RainbowToggle') call UpdateRainbowConf() call rainbow#clear() | call rainbow#hook() endif else let g:rainbow_active = 0 if exists(':RainbowToggle') call UpdateRainbowConf() call rainbow#clear() endif endif endfunction "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| " #6 VISUALS (COLORS, HIGHLIGHTING) "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "########################################################################### " COLORS "########################################################################### exec "autocmd ColorScheme " . g:campo_dark_theme . " call ReloadRainbow()" exec "autocmd ColorScheme " . g:campo_light_theme . " call ReloadRainbow()" " Toggle between light and dark themes. noremap l :call ToggleLightDarkTheme() let s:current_light_dark_mode = g:campo_light_dark_mode function! ToggleLightDarkTheme() if s:current_light_dark_mode == 'light' call ChangeLightDarkMode('dark', 0) else call ChangeLightDarkMode('light', 0) endif endfunction function! ChangeLightDarkMode(mode, onlySetTheme) if a:mode == 'light' let s:rainbow_theme = 'light' let s:theme = g:campo_light_theme exe 'colorscheme ' . s:theme set background=light else let s:rainbow_theme = 'dark' let s:theme = g:campo_dark_theme " We have to set the theme twice in order to get its correct dark-theme colors. " Weird stuff. exe 'colorscheme ' . s:theme set background=dark exe 'colorscheme ' . s:theme endif let s:current_light_dark_mode = a:mode if !a:onlySetTheme exec 'AirlineTheme' a:mode endif endfunction " Set the intial light/dark mode. if g:campo_light_dark_mode =~ 'light' call ChangeLightDarkMode('light', 1) else call ChangeLightDarkMode('dark', 1) endif " Open the current color scheme for editing. function! EditColorScheme() let l:path = g:vim_dir . '/colors/' . s:theme . '.vim' if filereadable(l:path) execute 'vsplit ' . l:path else call PrintError("Failed to open " . l:path . " for editing.") endif endfunction command -nargs=0 EditColorScheme call EditColorScheme() "################################################################################## " HIGHLIGHTS - TODO, NOTE, FIXME, etc "################################################################################## " NOTE: These depend on custom color names (Bugs, Notes and Notices) defined " in the campo color themes. Since most themes won't define these, you can " use WildMenu as substitution. " " FIXME: the custom Bugs, Notes and Notices highlighting for campo-light isn't " working... augroup vimrc_bugs autocmd! autocmd Syntax * syn match MyBugs /\v<(FIXME|BUG|DEPRECATED):/ \ containedin=.*Comment,vimCommentTitle augroup END hi def link MyBugs Bugs augroup vimrc_notes autocmd! autocmd Syntax * syn match MyNotes /\v<(IDEA|NOTE|QUESTION|WARNING|IMPORTANT):/ \ containedin=.*Comment,vimCommentTitle augroup END hi def link MyNotes Notes augroup vimrc_notices autocmd! autocmd Syntax * syn match MyNotices /\v<(WARNING|IMPORTANT):/ \ containedin=.*Comment,vimCommentTitle augroup END hi def link MyNotices Notices augroup vimrc_annotated_todo autocmd! " This was a major pain in the ass to get working... autocmd Syntax * syn match cTodo /@\S\+/ \ containedin=.*Comment,vimCommentTitle augroup END augroup vimrc_annotated_notes autocmd! autocmd Syntax * syn match cTodo /#\+ .\+$/ \ containedin=.*Comment,vimCommentTitle augroup END "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| " #7 CUSTOM FUNCTIONS & COMMANDS "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "################################################################################## " COMPILING CODE "################################################################################## " AsyncRun status line let g:airline_section_error = airline#section#create_right(['%{g:asyncrun_status}']) " "make" value is needed for asyncrun to work with the errormarker plugin " https://github.com/skywind3000/asyncrun.vim/wiki/FAQ#can-asyncrunvim-trigger-an-autocommand-quickfixcmdpost-to-get-some-plugin-like-errormaker-processing-the-content-in-quickfix- let g:asyncrun_auto = "make" " Error and warning gutter characters. let errormarker_errortext = "E" let errormarker_warningtext = "W" let errormarker_infotext = "I" " Gutter character colors. See color file for the group definition. let errormarker_errortextgroup = "BuildError" let errormarker_warningtextgroup = "BuildWarn" let errormarker_infotextgroup = "BuildInfo" " Colors for the marked lines. See color file for the group definition. let errormarker_errorgroup = "BuildError" let errormarker_warninggroup = "BuildWarn" let errormarker_infogroup = "BuildInfo" " I don't know how to map to a plugin command, so I'm wrapping it with a function...ugh. function! ShowErrorAtCursor() " This is defined in errormarker.vim ErrorAtCursor endfunction nnoremap ce :call ShowErrorAtCursor() "///////////////////////////////////////////////// " CUSTOM ERROR FORMATS "///////////////////////////////////////////////// " @note: You can debug the error parsing by running :ShowErrorEntries " This will print the valid entries. You'll know parsing is correct when the " entries have a type, line num, error message, etc. function! ShowErrorEntries() " Prints out valid quickfix errors. redraw! for l:d in getqflist() if l:d.valid == 1 echomsg l:d endif endfor endfunction command -nargs=0 ShowErrorEntries call ShowErrorEntries() " Jai " " Z:\path\main.jai:100,10: Error: Undeclared identifier 's1'. set errorformat=\\\ %#%f:%l\\,%c:\ %t%[A-z]%#:\ %m " Microsoft compiler: cl.exe " " Z:\path\main.cpp(2808): error C2220: the following warning is treated as an error set errorformat+=\\\ %#%f(%l):\ %#%t%[A-z]%#\ %[A-z]%#%n:\ %m " Microsoft MSBuild errors " " @note I got this off the Internet and haven't tested it yet. " " Z:\path\main.cpp(2808): error C2220: the following warning is treated as an error set errorformat+=\\\ %#%f(%l\\,%c):\ %m " Microsoft HLSL compiler: fxc.exe " " @note I got this off the Internet and haven't tested it yet. " @todo Add an example set errorformat+=\\\ %#%f(%l\\\,%c-%*[0-9]):\ %#%t%[A-z]%#\ %m "///////////////////////////////////////////////// " BUILD FUNCTIONS "///////////////////////////////////////////////// function! HideBuildResultsAndClearErrors() RemoveErrorMarkers call asyncrun#quickfix_toggle(g:quickfix_pane_height, 0) endfunction function! HideAsyncResults() call asyncrun#quickfix_toggle(g:quickfix_pane_height, 0) endfunction function! ToggleBuildResults() call asyncrun#quickfix_toggle(g:quickfix_pane_height) endfunction function! StopRunTask() AsyncStop call HideAsyncResults() endfunction function! Build(optimized=0, silent=0) let l:async_cmd = "AsyncRun! " if a:silent let l:async_cmd .= "-post=call\\ HideAsyncResults() " endif let l:is_jai = 0 let l:cmd = "" let l:ext = tolower(expand('%:e')) let l:current_dir = expand('%:h') let l:parent_dir = expand('%:p:h') " Check if this is a jai module with a build.jai one directory back. This " only works when the file is directly inside the modules folder. let l:jai_module_with_build = (tolower(l:current_dir) == "modules") && filereadable(l:current_dir . "/../build.jai") if (l:jai_module_with_build == 1) || filereadable(l:parent_dir . "/build.jai") " Jai build file let l:is_jai = 1 let l:cmd = "jai " . l:parent_dir . "/" if l:jai_module_with_build == 1 let l:cmd .= "../build.jai" else let l:cmd .= "build.jai" endif if a:optimized == 1 echo "Compiling release build.jai" " @note We pass 'release' as a user command arg for the build file " to parse. -release is a compiler arg and we don't want to use " that. Ideally the build script would ignore that completely. let l:cmd .= " - release" else echo "Compiling debug build.jai" endif " @note We aren't importing the local modules because the build file " should manage that sort of thing for us. elseif l:ext == "jai" let l:is_jai = 1 let l:cmd = "jai % " if a:optimized == 1 echo "Compiling release " . expand('%:t') let l:cmd .= " -release" else echo "Compiling debug " . expand('%:t') endif " If there's a local modules/ directory then we'll import it. if isdirectory(l:parent_dir . "/modules") let l:cmd .= " -import_dir modules" endif else let l:cmd .= './build* ' if a:optimized == 1 let l:cmd .= ' -o' endif endif if l:is_jai let l:cmd .= ' '.g:campo_jai_build_args endif " I was originally passing -save=2 to AsyncRun! in order to save all " modified files (it just does a `silent! wall` call), but I want ctags to " be generated so we're handling the save ourselves. call WriteAllModifiedFilesAndCreateCtags() exec l:async_cmd . l:cmd endfunction function! RunProgram() if filereadable("run") exec "AsyncRun! -post=call\\ StopRunTask() ./run %" else let l:ext = tolower(expand('%:e')) if l:ext == "jai" if filereadable(expand('%:p:r') . '.exe') exec "AsyncRun! " . expand('%:p:r') . ".exe" else if tolower(expand('%:h')) == "modules" " This is likely a jai module inside a project. Check for an " exe one directory back. let l:files = systemlist('ls ' . expand('%:p:h') . '/../*.exe 2>/dev/null') else let l:files = systemlist('ls ' . expand('%:p:h') . '/*.exe 2>/dev/null') endif if len(l:files) > 0 exec "AsyncRun! " . l:files[0] else call PrintError("No exe found. Compile first?") endif endif elseif l:ext == "py" exec "AsyncRun! python %" endif endif endfunction " Show results window the moment the async job starts augroup asyncPluginCmds autocmd! autocmd User AsyncRunStart call asyncrun#quickfix_toggle(g:quickfix_pane_height, 1) augroup END " Toggle build results nnoremap bc :call ToggleBuildResults() noremap :call ToggleBuildResults() " Hide build results and clear errors noremap :call HideBuildResultsAndClearErrors() " Execute build script and keep results. nnoremap b :call Build(0) " Execute build and hide results. nnoremap :call Build(0, 1) " Execute optimized build script nnoremap bb :call Build(1) " Execute run script nnoremap br :call RunProgram() nnoremap :call RunProgram() nnoremap bs :AsyncStop "Go to next build error nnoremap :cn nnoremap :cn "Go to previous build error nnoremap :cp nnoremap :cp "################################################################################## " TEXT SEARCH "################################################################################## " Search using ripgrep (first install with Rust: cargo install ripgrep). function! Search(path, search_args, case_insensitive=0) let l:helper = "Search '" . a:path . "' (" . (len(a:search_args) > 0 ? a:search_args . " | " : '') . (a:case_insensitive ? "INSENSITIVE" : "SENSITIVE") . "): " let l:term = input(l:helper) if empty(l:term) return endif " @note --pretty (i.e. colors) is not enabled in vim-ripgrep because the " quickfix window doesn't seem to parse the ansi color codes. let l:rg_args = "--column --line-number --no-heading --fixed-strings --no-ignore --hidden --follow --trim -g \"!tags\" -g \"!.git/\" -g \"!AppData/\" " . a:search_args if a:case_insensitive let l:rg_args .= " --ignore-case" endif " Some characters need to be escaped. let l:escaped_term = substitute(l:term, '[#%]', '\\\\\\&', 'g') let l:format = 'Rg ' . l:rg_args . ' ' . a:path . ' -e %s' let l:cmd = printf(l:format, shellescape(l:escaped_term)) exec l:cmd endfunction "///////////////////////////////////////////////// " SEARCH IN CURRENT DIRECTORY "///////////////////////////////////////////////// " Case insensitive: noremap s :call Search('.', g:campo_custom_search_args, 1) " Case sensitive: noremap ss :call Search('.', g:campo_custom_search_args) "///////////////////////////////////////////////// " SEARCH IN DIRECTORY CONTAINING THE ACTIVE FILE "///////////////////////////////////////////////// " Case insensitive: noremap sf :call Search(expand('%:p:h'), g:campo_custom_search_args, 1) " Case sensitive: noremap ssf :call Search(expand('%:p:h'), g:campo_custom_search_args) "///////////////////////////////////////////////// " SEARCH IN JAI FOLDERS "///////////////////////////////////////////////// " Case insensitive: noremap sg :call Search(g:campo_jai_path, g:campo_custom_search_args, 1) noremap sm :call Search(g:campo_jai_path . '/modules', g:campo_custom_search_args, 1) noremap sh :call Search(g:campo_jai_path . '/how_to', g:campo_custom_search_args, 1) noremap se :call Search(g:campo_jai_path . '/examples', g:campo_custom_search_args, 1) " Case sensitive: noremap ssg :call Search(g:campo_jai_path, g:campo_custom_search_args) noremap ssm :call Search(g:campo_jai_path . '/modules', g:campo_custom_search_args) noremap ssh :call Search(g:campo_jai_path . '/how_to', g:campo_custom_search_args) noremap sse :call Search(g:campo_jai_path . '/examples', g:campo_custom_search_args) " Navigation for the vim-ripgrep search results. " Hit o on a result line to open the file at that line. " Hit p on a result line to open the file at that line and return to the results pane. nnoremap o (&buftype is# "quickfix" ? "\|:lopen" : "o") nnoremap p (&buftype is# "quickfix" ? "\|:copen" : "p") "################################################################################## " TEXT SEARCH & REPLACE "################################################################################## " @warning I've stopped using this because it sometimes locks up vim and I " have to force exit the process then clean up the swap files. " @improve Figure out what's causing vim to freeze and fix it. Seems to happen " when it quickly changes and saves a handful of buffers. " Replace text in a git repo's committed files. " The range identifier allows us to run this once when multiple lines are selected in a file. function! GlobalReplaceIt(confirm_replacement) range if exists(':Ggrep') call inputsave() if a:confirm_replacement let l:term = input('Enter search term (w/ confirmation): ') else let l:term = input('Enter search term (no confirmation): ') endif call inputrestore() if empty(l:term) return endif call inputsave() let l:replacement = input('Enter replacement: ') call inputrestore() if empty(l:replacement) return endif if a:confirm_replacement let l:confirm = 'c' else let l:confirm = 'e' endif " Capture opened buffers and windows so that we can restore everything after running cdo. exec 'mksession! _replace_session.vim' " Search all committed files in the current directory " Ignoring binary files (-I) " Only including a matching filename once (--name-only) exec 'Ggrep --threads 4 -I --name-only' l:term '.' " cdo will run the command foreach file in the grep results. It opens " the file in a window so we immediately write the changes and then " wipe the buffer (closing the window). If we don't close it then vim " will run out of space when modifying a lot of files. This will " likely close buffers that were open before running the replace, but " we will restore them below from the saved session file. " Note that we don't run autocommands for optimization purposes! :noautocmd exec 'cdo' '%s/'.l:term.'/'.l:replacement.'/g'.l:confirm '| write | bwipe' " Restore the session. if filereadable('_replace_session.vim') silent! exec 'source _replace_session.vim | !rm _replace_session.vim &>/dev/null' endif call CreateCtags() else call PrintError("Unable to search since you're not in a git repo!") endif endfunction noremap r :call GlobalReplaceIt(0) noremap rr :call GlobalReplaceIt(1) "################################################################################## " RENAME CURRENT FILE "################################################################################## function! RenameFile() let l:old_name = expand('%') let l:new_name = input('New file name: ', expand('%'), 'file') if l:new_name != '' && l:new_name != l:old_name let l:confirm = confirm("Rename ".l:old_name." to ".l:new_name."?", "&Yes\n&No") if l:confirm == 1 exec 'saveas' l:new_name exec 'silent! !rm' l:old_name redraw! endif endif endfunction noremap n :call RenameFile() "################################################################################## " CENTER THE BUFFER "################################################################################## function! CenterPane() " Centers the current pane as the middle 2 of 4 imaginary columns should " be called in a window with a single pane. " Taken from https://dev.to/vinneycavallo/easily-center-content-in-vim lefta vnew wincmd w exec 'vertical resize' string(&columns * 0.65) endfunction function! RemoveCenterPane() wincmd w close endfunction nnoremap cc :call CenterPane() nnoremap cd :call RemoveCenterPane() "################################################################################## " SIMPLE VIEW "################################################################################## " Applies a clean view of the current buffer by turning off line " numbers, trailing spaces, tabs and git diff markers in the gutter. function! ToggleSimpleView() " I wasn't able to get this to apply to every copy of the same buffer, " e.g. you have a split view showing the same file; only the active one " will be affected, but they will share the same state! I tried many " different approaches (bufdo, looping over windows and buffers) and " nothing worked. I looked at the gitgutter plugin since it supports " toggling a buffer and it correctly modifies all instances, but the code " is complex and there's so much just to do a simple thing. Fuck it. It's " not worth the hassle and the inevitable hair pulling that I always " experience when trying to do non-trivial things with this garbage " scripting language. if ! exists("b:simple_view_enabled") let b:simple_view_enabled = 0 endif if b:simple_view_enabled == 0 let b:simple_view_enabled = 1 setlocal nonumber setlocal nolist exec 'GitGutterBufferDisable' else let b:simple_view_enabled = 0 setlocal number setlocal list exec 'GitGutterBufferEnable' endif endfunction nnoremap c :call ToggleSimpleView() "----------------------------------------------------------------------------------------------------------------------- let g:campo_vimrc_initialized = 1