1778 lines
71 KiB
VimL
1778 lines
71 KiB
VimL
"-----------------------------------------------------------------------------------------------------------------------
|
|
" 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).
|
|
"-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
if !exists("g:campo_vimrc_initialized")
|
|
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.
|
|
endif
|
|
|
|
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=","
|
|
|
|
fu! IsWindows()
|
|
if s:uname =~? "mingw" || s:uname =~? "msys"
|
|
return 1
|
|
endif
|
|
if has("win64") || has("win32") || has("win16")
|
|
return 1
|
|
endif
|
|
return 0
|
|
endfu
|
|
|
|
if has('termguicolors')
|
|
set termguicolors
|
|
" Set Vim-specific sequences for RGB colors.
|
|
let &t_8f = "\<Esc>[38;2;%lu;%lu;%lum"
|
|
let &t_8b = "\<Esc>[48;2;%lu;%lu;%lum"
|
|
endif
|
|
|
|
fu! PrintError(msg) abort
|
|
exec 'normal! \<Esc>'
|
|
echohl ErrorMsg
|
|
echomsg a:msg
|
|
echohl None
|
|
endfu
|
|
|
|
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
" #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=<n>.
|
|
|
|
" 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'
|
|
|
|
|
|
"##################################################################################
|
|
" 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', 'run_tree']
|
|
|
|
" 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 directories using g:campo_ctags_exclude
|
|
let g:campo_custom_ctags_args = ""
|
|
|
|
|
|
" 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 (the latter isn't needed if you
|
|
" have Jai module tags in your local file, which can be generated using the
|
|
" ctags module at compile time). Related, if you're generating jai ctags and
|
|
" the editor isn't finding module references then check if the current
|
|
" directory is set to where the tags file exists. I've been caught up by this
|
|
" because I have a build.jai in the root and my code in a src/ folder, so the
|
|
" tags file gets created in the root and won't be seen if I've cd'd into src/
|
|
" when editing code.
|
|
"
|
|
" 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'])
|
|
"
|
|
" You can see what your ctags search list is set to in the editor with :echo &tags
|
|
fu! 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
|
|
endfu
|
|
|
|
|
|
"##################################################################################
|
|
" 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_compiler_args = ''
|
|
let g:campo_jai_metaprogram_args = ''
|
|
|
|
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
" #1 PLUGINS
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
call plug#begin('~/.vim/plugged')
|
|
|
|
" I've locked the plugins to stable commits. No need to upgrade them unless there are bug fixes.
|
|
|
|
"""""""""""""""""""
|
|
" # MISC
|
|
"""""""""""""""""""
|
|
Plug 'sir-pinecone/errormarker.vim' " Build error highlighting (requires skywind3000/asyncrun.vim).
|
|
Plug 'sir-pinecone/vim-ripgrep' " Fast grep-like search. Requires ripgrep; install Rust package: `cargo install ripgrep`.
|
|
Plug 'sir-pinecone/vim-qargs', " For the GlobalReplaceIt function (i.e. search and replace).
|
|
Plug 'sir-pinecone/AnsiEsc.vim' " Ansi escape sequences concealed, but highlighted as specified.
|
|
Plug 'sir-pinecone/ctrlp.vim', " Fuzzy file, buffer, mru, tag, etc finder.
|
|
Plug 'sir-pinecone/ctrlp-py-matcher' " Significantly speed up ctrlp's fuzzy matcher.
|
|
Plug 'vim-airline/vim-airline', { 'commit': 'c7460aa' } " Enhanced status/tabline.
|
|
Plug 'embear/vim-localvimrc', { 'commit': '0206f5f' } " Add a .lvimrc to a folder to override .vimrc config.
|
|
Plug 'tpope/vim-fugitive', { 'commit': '46eaf89' } " Git wrapper (I particularly like :Gblame, which I've wrapped as :Blame)
|
|
Plug 'tpope/tpope-vim-abolish', { 'commit': 'dcbfe06' } " Search for, substitute, and abbreviate multiple variants of a word. Add to `after/plugin/abolish.vim`
|
|
Plug 'tpope/vim-obsession', { 'commit': 'fe9d3e1' } " @flagged for removal. Continuously updated session files (tracks window positions, open folds, etc).
|
|
Plug 'itchyny/vim-cursorword', { 'commit': '74a97c4' } " Underlines all instances of the symbol under the cursor. Requires a ctags file.
|
|
Plug 'skywind3000/asyncrun.vim', { 'commit': '61cc308' } " (prev stable: 58d23e7) Async commands.
|
|
Plug 'airblade/vim-gitgutter', { 'commit': 'fe0e8a2' } " Displays a git diff in the vim gutter and allows staging/unstaging of hunks.
|
|
Plug 'majutsushi/tagbar', { 'commit': '5d6990e' } " Generates ctags on-demand and shows the current file's symbols. Doesn't support existing ctag files, so no Jai support.
|
|
Plug 'tommcdo/vim-lion', { 'commit': 'ce46593' } " For text alignment, use gl= and gL=
|
|
Plug 'editorconfig/editorconfig-vim', { 'commit': '95cb75e' } " Adds support for .editorconfig files.
|
|
|
|
"""""""""""""""""""
|
|
" # SYNTAX
|
|
"""""""""""""""""""
|
|
Plug 'sir-pinecone/jai.vim' " Jai
|
|
Plug 'sir-pinecone/fasm.vim' " Flat Assembler
|
|
Plug 'bfrg/vim-cpp-modern', { 'commit': 'cc7019b' } " C/C++
|
|
Plug 'elixir-editors/vim-elixir', { 'commit': '6dd03f8' } " Elixir
|
|
Plug 'pprovost/vim-ps1', { 'commit': '308aac5' } " PowerShell
|
|
Plug 'tpope/vim-markdown', { 'commit': 'f2b82b7' } " Markdown
|
|
"Plug 'vim-ruby/vim-ruby' { 'commit': 'f06f069' } " Ruby
|
|
|
|
"""""""""""""""""""
|
|
" # THEMES
|
|
"""""""""""""""""""
|
|
Plug 'vim-airline/vim-airline-themes', { 'commit': '04fa4fc' }
|
|
Plug 'dracula/vim', { 'commit': '6495b4f', 'as': 'dracula' }
|
|
|
|
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=<dir path for swap files>
|
|
" set backupdir=<dir path for backup files>
|
|
" if has('persistent_undo')
|
|
" set undodir=<dir path for undo files>
|
|
" 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=<path>
|
|
"
|
|
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
|
|
|
|
" Disabled this because it clears my custom syntax highlights (see campoSyntax augroup)
|
|
" when the vimrc file is resourced. I guess I don't need to set this to have
|
|
" syntax highlighting. It's probably being enabled by a plugin.
|
|
"set syntax on
|
|
|
|
set wildmenu
|
|
set wildmode=longest,list,full
|
|
set wildignore+=*/log/*,*.so,*.swp,*.zip,*/rdoc/*
|
|
|
|
" Allow <tab> inserts in the command bar to autocomplete, e.g. see <leader>e
|
|
set wildcharm=<tab>
|
|
|
|
if executable('rg')
|
|
set grepprg=rg\ --vimgrep\ --hidden " Requires ripgrep to be installed.
|
|
endif
|
|
|
|
" Show trailing tabs and whitespace.
|
|
set listchars=tab:»\ ,trail:·,extends:>,precedes:<,nbsp:+
|
|
|
|
set timeoutlen=250 ttimeoutlen=0 " Don't set it too low otherwise you won't be able to type use multi-key sequences.
|
|
|
|
" Keeping this a bit low to make git-gutter updates faster. The original value
|
|
" was 4000. I tried 250 and eventually started seeing some plugin errors
|
|
" related to paren formatting. 800 seems to be the sweet spot.
|
|
set updatetime=800
|
|
|
|
" 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 <up> <nop>
|
|
noremap <down> <nop>
|
|
noremap <left> <nop>
|
|
noremap <right> <nop>
|
|
inoremap <up> <nop>
|
|
inoremap <down> <nop>
|
|
inoremap <left> <nop>
|
|
inoremap <right> <nop>
|
|
|
|
|
|
"/////////////////////////////////////////////////
|
|
" 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 $MYVIMRC 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.
|
|
fu! 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
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
" Note: if there are two+ mappings that start with the same sequence then vim
|
|
" will introduce a delay before the mapping is handled in order to wait for
|
|
" the entire sequence to be typed. e.g. <leader>s and <leader>sg will
|
|
" introduce a timeout delay, which will be noticed when you're trying to use
|
|
" <leader>s. If you type <leader>sg then it'll be handled immediately, unless
|
|
" there is a third mapping with that initial sequence, e.g. <leader>sgn.
|
|
"
|
|
" You can adjust the timeout duration by modidying the timeoutlen option.
|
|
"
|
|
" You can see when a keysequence is mapped to by entering :map <sequence>
|
|
" e.g. :map ,s
|
|
" This is helpful when you are experiencing a timeout but you only have one
|
|
" mapping defined in your vimrc. It's likely that a plugin added a similar
|
|
" mapping sequence.
|
|
"
|
|
" The difference between map and noremap is that the former does recursive
|
|
" expansion and the latter doesn't. The expansion means that if the mapped key
|
|
" sequence contains any mappings then those mappings will be expanded as well.
|
|
" This can lead to issues and confusion, so it's best to use noremap unless
|
|
" you really have a reason not to.
|
|
|
|
"##################################################################################
|
|
" MISC
|
|
"##################################################################################
|
|
|
|
" Lowercase the e (have a habit of making it uppercase).
|
|
:ca E e
|
|
|
|
" Bail out of insert mode by double-pressing 'j'.
|
|
" Disabling because it's annoying and I now have a keyboard that I can use
|
|
" through the Steam Link that lets me map caps to ctrl, so I no longer need
|
|
" this.
|
|
" imap jj <Esc>
|
|
|
|
" Suspend vim process and return to the shell. Can return to vim with `fg`.
|
|
nnoremap <leader>z <c-z>
|
|
|
|
" Open the vimrc file for editing / reload vimrc file.
|
|
nnoremap <silent> <leader>ev :vsp $MYVIMRC<cr>
|
|
nnoremap <silent> <leader>pv :vsp ~/.vimrc.private<cr>
|
|
nnoremap <silent> <leader>rv :source $MYVIMRC<cr>
|
|
|
|
" 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 <leader>t for opening my todo file.
|
|
"if exists(':terminal')
|
|
" noremap <leader>t :terminal<cr>
|
|
" tnoremap <leader>te <C-\><C-n>
|
|
" tnoremap <A-h> <C-\><C-n><C-w>h
|
|
" tnoremap <A-j> <C-\><C-n><C-w>j
|
|
" tnoremap <A-k> <C-\><C-n><C-w>k
|
|
" tnoremap <A-l> <C-\><C-n><C-w>l
|
|
" nnoremap <A-h> <C-w>h
|
|
" nnoremap <A-j> <C-w>j
|
|
" nnoremap <A-k> <C-w>k
|
|
" nnoremap <A-l> <C-w>l
|
|
"endif
|
|
|
|
" Jump to other buffers.
|
|
noremap <c-k> <c-w><Up>
|
|
noremap <c-j> <c-w><Down>
|
|
noremap <c-l> <c-w><Right>
|
|
noremap <c-h> <c-w><Left>
|
|
|
|
" Make it easier to jump around the command line. The default behaviour is
|
|
" using the arrow keys with or without shift.
|
|
:cnoremap <C-J> <S-Left>
|
|
:cnoremap <C-K> <S-Right>
|
|
|
|
" Window splitting - couldn't figure out how to remap <c-w>v & <c-w>n to <c-m>
|
|
" & <c-n>
|
|
noremap <leader>m :vsplit<cr>
|
|
noremap <leader>mm :split<cr>
|
|
|
|
" Disable treating special characters as regex when doing searches as it's so
|
|
" fucking annoying having to escape them, particularly periods and asterisk.
|
|
" This is done by setting the 'very nomagic' setting \V.
|
|
nnoremap / /\V
|
|
|
|
"-----------------------------------------------------
|
|
" 'a' register helpers
|
|
"
|
|
" Faster way to activate the 'a' named register. These registers can be used
|
|
" for various operations like yanking (copying), deleting, and pasting text.
|
|
" Each register is identified by a single character. For example, there are
|
|
" named registers 'a' to 'z', where text yanked or deleted can be specifically
|
|
" stored and later retrieved.
|
|
"
|
|
" First activate the register with <leader>a and then do your yank, delete or
|
|
" paste. Subsequent yanks into <leader>a will overwrite existing data. You can
|
|
" append to the register by using <leader>aa
|
|
"
|
|
|
|
" This overwrites the contents of a.
|
|
noremap <leader>a "a
|
|
|
|
" This appends to a.
|
|
noremap <leader>aa "A
|
|
"-----------------------------------------------------
|
|
|
|
" Backward replace word including cursor character.
|
|
noremap <leader>d cvb
|
|
|
|
" Allow fast pasting by accessing the system clipboard register.
|
|
noremap <leader>p "+p
|
|
" Likely won't need to use this if pasting with <leader>p, but just in case here ya go.
|
|
noremap <leader>pp :set paste! paste?<cr>
|
|
|
|
" Toggle line numbers.
|
|
nnoremap <leader>o :set number! number?<cr>
|
|
|
|
" Show spell checking.
|
|
" You can add new entries to the dict by moving the cursor over the word and pressing `zg`.
|
|
noremap <leader>j :exec &spell==&spell? "se spell! spelllang=en_us" : "se spell!"<cr>
|
|
noremap <leader>= z=
|
|
|
|
" Clear the search buffer (highlighting) when hitting return.
|
|
nnoremap <cr> :nohlsearch<cr>
|
|
|
|
" Switch to the previous file.
|
|
nnoremap <leader><leader> <c-^>
|
|
|
|
" Replace currently selected text with default register without yanking it.
|
|
vnoremap p "_dP
|
|
|
|
" Switch between C++ source and header files.
|
|
noremap <leader>v :e %:p:s,.h$,.X123X,:s,.cpp$,.h,:s,.X123X$,.cpp,<CR>
|
|
noremap <leader>vv :e %:p:s,.h$,.X123X,:s,.c$,.h,:s,.X123X$,.c,<CR>
|
|
"noremap <leader>vvv :e %:p:s,.h$,.X123X,:s,.cc$,.h,:s,.X123X$,.cc,<CR>
|
|
|
|
" Replace all instances of the highlighted text with whatever you enter.
|
|
nnoremap <c-g> :%s///g<left><left>
|
|
|
|
|
|
"##################################################################################
|
|
" 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.
|
|
|
|
fu! 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')
|
|
if IsRootDrive(l:path)
|
|
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 <leader>rv or whatever. :ReloadVimrcError
|
|
fu! WriteCurrentFileAndCreateCtags()
|
|
write!
|
|
call CreateCtags()
|
|
endfu
|
|
|
|
fu! WriteCurrentFileAndCreateCtagsThenQuit()
|
|
write!
|
|
call CreateCtags()
|
|
quit
|
|
endfu
|
|
|
|
" @fixme Sometimes a :wa that saves multiple files causes vim to hang and use a lot of CPU.
|
|
fu! WriteAllModifiedFilesAndCreateCtags()
|
|
wall!
|
|
call CreateCtags()
|
|
endfu
|
|
|
|
" Create a command abbreviation that only applies when it's at the beginning
|
|
" of a ex command. If you were to do a normal cnoreabbrev or cabbrev then the
|
|
" subsitution can happen anywhere in the command line. It was mostly affecting
|
|
" my text search; I'd type '/w' and it would be replaced with the call to save
|
|
" and create ctags.
|
|
fu! Cabbrev(key, value)
|
|
exe printf('cabbrev <expr> %s (getcmdtype() == ":" && getcmdpos() <= %d) ? %s : %s',
|
|
\ a:key, len(a:key)+1, string(a:value), string(a:key))
|
|
endfu
|
|
|
|
call Cabbrev('w', 'call WriteCurrentFileAndCreateCtags()')
|
|
call Cabbrev('W', 'call WriteCurrentFileAndCreateCtags()')
|
|
call Cabbrev('wa', 'call WriteAllModifiedFilesAndCreateCtags()')
|
|
call Cabbrev('Wa', 'call WriteAllModifiedFilesAndCreateCtags()')
|
|
call Cabbrev('WA', 'call WriteAllModifiedFilesAndCreateCtags()')
|
|
call Cabbrev('wq', 'call WriteCurrentFileAndCreateCtagsThenQuit()')
|
|
call Cabbrev('Wq', 'call WriteCurrentFileAndCreateCtagsThenQuit()')
|
|
call Cabbrev('WQ', 'call WriteCurrentFileAndCreateCtagsThenQuit()')
|
|
|
|
" Faster way to open a file in the same directory.
|
|
" <tab> will autocomplete the expansion here because we set wildcharm to <tab>.
|
|
nnoremap <leader>e :e %:p:h/<tab>
|
|
" Jai folders
|
|
nnoremap <leader>ee :e <C-r>=g:campo_jai_path<CR>/<tab>
|
|
nnoremap <leader>em :e <C-r>=g:campo_jai_path<CR>/modules/<tab>
|
|
nnoremap <leader>eh :e <C-r>=g:campo_jai_path<CR>/how_to/<tab>
|
|
|
|
nnoremap <leader>w :call WriteCurrentFileAndCreateCtags()<cr>
|
|
nnoremap <leader>x :call WriteCurrentFileAndCreateCtagsThenQuit()<cr>
|
|
nnoremap <leader>q :q<cr>
|
|
|
|
call Cabbrev('Q', 'q')
|
|
call Cabbrev('Qa', 'qa')
|
|
command! Qa qall
|
|
" Disable Ex mode.
|
|
noremap Q <Nop>
|
|
|
|
"##################################################################################
|
|
" MULTIPURPOSE TAB KEY
|
|
"##################################################################################
|
|
|
|
fu! InsertTabWrapper()
|
|
let l:col = col('.') - 1
|
|
if !l:col || getline('.')[l:col - 1] !~ '\k'
|
|
return "\<tab>"
|
|
else
|
|
return "\<c-p>"
|
|
endif
|
|
endfu
|
|
inoremap <tab> <c-r>=InsertTabWrapper()<cr>
|
|
inoremap <s-tab> <c-n>
|
|
|
|
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
" #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 <F12> :TagbarToggle<cr>
|
|
" 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 <leader>hh :GitGutterToggle<cr>
|
|
nmap <leader>ha <Plug>(GitGutterStageHunk)
|
|
nmap [h <Plug>(GitGutterNextHunk)
|
|
nmap ]h <Plug>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
|
|
|
|
"##################################################################################
|
|
" 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
|
|
fu! 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
|
|
endfu
|
|
|
|
fu! 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)
|
|
endfu
|
|
|
|
" CtrlP File Searching
|
|
noremap <leader>g :call CtrlP_Search('')<cr> " Search in current directory
|
|
noremap <leader>gg :call CtrlP_JaiSearch('')<cr> " Search in Jai directory
|
|
noremap <leader>gm :call CtrlP_JaiSearch('modules')<cr> " Search in Jai modules
|
|
noremap <leader>gh :call CtrlP_JaiSearch('how_to')<cr> " Search in Jai how_to
|
|
noremap <leader>ge :call CtrlP_JaiSearch('examples')<cr> " Search in Jai examples
|
|
|
|
let g:ctrlp_map = '<leader>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()
|
|
let g:ctrlp_match_func = { 'match': 'pymatcher#PyMatch' }
|
|
|
|
"##################################################################################
|
|
" GIT
|
|
"##################################################################################
|
|
noremap <leader>gb :Git blame -w<cr>
|
|
" Ignore whitespace changes; follow renames and copies.
|
|
command! -bar -bang -nargs=* Blame :Git blame<bang> -wCM <args>
|
|
command! -bar -bang -nargs=* Gblame :Git blame<bang> -wCM <args>
|
|
|
|
"##################################################################################
|
|
" 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
|
|
|
|
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
" #6 VISUALS (COLORS, HIGHLIGHTING)
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
|
|
"###########################################################################
|
|
" COLORS
|
|
"###########################################################################
|
|
|
|
" Custom notes highlights. These are used in my color schemes.
|
|
"
|
|
" @incomplete I can't get these to only match in comments. Not a big deal but
|
|
" would be nice to fix.
|
|
augroup campoSyntax
|
|
autocmd!
|
|
|
|
autocmd Syntax * syntax match MyAnnotatedNote /@\S\+/ containedin=.*Comment,vimCommentTitle display
|
|
autocmd Syntax * syntax match MyTitle /#\+ .\+$/ containedin=.*Comment,vimCommentTitle display
|
|
autocmd Syntax * syntax match MyNote /\v<(NOTE|IDEA|TODO):/ containedin=.*Comment,vimCommentTitle display
|
|
autocmd Syntax * syntax match MyEmphasis /\v<(WARNING|IMPORTANT):/ containedin=.*Comment,vimCommentTitle display
|
|
autocmd Syntax * syntax match MyBug /\v<(FIXME|BUG|DEPRECATED):/ containedin=.*Comment,vimCommentTitle display
|
|
|
|
highlight link MyAnnotatedNote CampoAnnotatedNote
|
|
highlight link MyTitle CampoTitle
|
|
highlight link MyNote CampoNote
|
|
highlight link MyEmphasis CampoEmphasis
|
|
highlight link MyBug CampoBug
|
|
augroup END
|
|
|
|
" Toggle between light and dark themes.
|
|
noremap <leader>l :call ToggleLightDarkTheme()<cr>
|
|
|
|
let s:current_light_dark_mode = g:campo_light_dark_mode
|
|
|
|
fu! ToggleLightDarkTheme()
|
|
if s:current_light_dark_mode == 'light'
|
|
call ChangeLightDarkMode('dark', 0)
|
|
else
|
|
call ChangeLightDarkMode('light', 0)
|
|
endif
|
|
endfu
|
|
|
|
fu! ChangeLightDarkMode(mode, onlySetTheme)
|
|
if a:mode == 'light'
|
|
let s:theme = g:campo_light_theme
|
|
exe 'colorscheme ' . s:theme
|
|
set background=light
|
|
else
|
|
let s:theme = g:campo_dark_theme
|
|
exe 'colorscheme ' . s:theme
|
|
set background=dark
|
|
endif
|
|
|
|
let s:current_light_dark_mode = a:mode
|
|
|
|
if !a:onlySetTheme
|
|
exec 'AirlineTheme' a:mode
|
|
endif
|
|
endfu
|
|
|
|
" 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.
|
|
fu! 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
|
|
endfu
|
|
|
|
command -nargs=0 EditColorScheme call EditColorScheme()
|
|
|
|
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
" #7 CUSTOM FUNCTIONS & COMMANDS
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
"|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
fu! IsRootDrive(path) abort
|
|
let l:path_without_slashes = substitute(a:path, "/", "", "g")
|
|
return strchars(l:path_without_slashes) <= 1
|
|
endfu
|
|
|
|
fu! IsPathContained(path1, path2) abort
|
|
let l:normalized_path1 = substitute(fnamemodify(a:path1, ':p'), '\', '/', 'g')
|
|
let l:normalized_path2 = substitute(fnamemodify(a:path2, ':p'), '\', '/', 'g')
|
|
|
|
" Ensure paths end with a directory separator
|
|
if l:normalized_path1[-1:] != '/'
|
|
let l:normalized_path1 .= '/'
|
|
endif
|
|
if l:normalized_path2[-1:] != '/'
|
|
let l:normalized_path2 .= '/'
|
|
endif
|
|
|
|
echo l:normalized_path1
|
|
echo l:normalized_path2
|
|
|
|
return match(l:normalized_path1, '^' . escape(l:normalized_path2, '\')) != -1
|
|
endfu
|
|
|
|
fu! CountChar(str, char) abort
|
|
" Remove all characters that are not the target character.
|
|
let l:filtered = substitute(a:str, '[^' . a:char . ']', '', 'g')
|
|
return strlen(l:filtered)
|
|
endfu
|
|
|
|
fu! WindowsToUnixPath(str) abort
|
|
let l:result = substitute(a:str, '\\', '/', 'g')
|
|
return l:result
|
|
endfu
|
|
|
|
fu! ConvertQuickfixPathsToUnixSlashes()
|
|
let l:qflist = getqflist()
|
|
for i in range(len(l:qflist))
|
|
let l:bufnr = l:qflist[i]['bufnr']
|
|
if l:bufnr != -1 && bufexists(l:bufnr)
|
|
let l:filename = bufname(l:bufnr)
|
|
let l:filename = substitute(l:filename, '\\', '/', 'g')
|
|
let l:qflist[i]['module'] = l:filename
|
|
endif
|
|
endfor
|
|
call setqflist(l:qflist)
|
|
endfu
|
|
|
|
"##################################################################################
|
|
" 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.
|
|
fu! ShowErrorAtCursor()
|
|
" This is defined in errormarker.vim
|
|
ErrorAtCursor
|
|
endfu
|
|
nnoremap <leader>ce :call ShowErrorAtCursor()<cr>
|
|
|
|
"/////////////////////////////////////////////////
|
|
" 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.
|
|
|
|
fu! ShowErrorEntries()
|
|
" Prints out valid quickfix errors.
|
|
redraw!
|
|
for l:d in getqflist()
|
|
if l:d.valid == 1
|
|
echomsg l:d
|
|
endif
|
|
endfor
|
|
endfu
|
|
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
|
|
"/////////////////////////////////////////////////
|
|
|
|
fu! HideBuildResultsAndClearErrors()
|
|
RemoveErrorMarkers
|
|
call asyncrun#quickfix_toggle(g:quickfix_pane_height, 0)
|
|
endfu
|
|
|
|
fu! HideAsyncResults()
|
|
call asyncrun#quickfix_toggle(g:quickfix_pane_height, 0)
|
|
endfu
|
|
|
|
fu! ToggleBuildResults()
|
|
call asyncrun#quickfix_toggle(g:quickfix_pane_height)
|
|
endfu
|
|
|
|
fu! StopRunTask()
|
|
AsyncStop
|
|
call HideAsyncResults()
|
|
endfu
|
|
|
|
" @incomplete use the same path searching from RunProgram
|
|
" @incomplete use the same path searching from RunProgram
|
|
" @incomplete use the same path searching from RunProgram
|
|
" @incomplete use the same path searching from RunProgram
|
|
" @incomplete use the same path searching from RunProgram
|
|
" @incomplete use the same path searching from RunProgram
|
|
" @incomplete use the same path searching from RunProgram
|
|
fu! Build(optimized=0, silent=0) abort
|
|
let l:async_cmd = "AsyncRun! "
|
|
if a:silent
|
|
let l:async_cmd .= "-post=call\\ HideAsyncResults() "
|
|
endif
|
|
|
|
let l:is_jai = 0
|
|
let l:has_jai_build_file = 0
|
|
let l:has_jai_first_file = 0
|
|
|
|
let l:ext = tolower(expand('%:e'))
|
|
let l:current_dir = expand('%:p:h')
|
|
let l:one_dir_back = expand('%:p:h:h')
|
|
|
|
let l:cmd = ""
|
|
|
|
if l:ext == "jai"
|
|
let l:is_jai = 1
|
|
|
|
" Check for a build file in the current directory or one directory back when one directory back isn't the root of a drive.
|
|
" (e.g. we're in modules/ or src/, code/, etc)
|
|
if filereadable(l:current_dir . "/build.jai") || filereadable(l:current_dir . "/first.jai") || ((l:one_dir_back != "/") && (filereadable(l:one_dir_back . "/build.jai") || filereadable(l:one_dir_back . "/first.jai")))
|
|
let l:has_jai_build_file = 1
|
|
|
|
if filereadable(l:current_dir . "/build.jai")
|
|
let l:cmd = "jai ". l:current_dir . "/build.jai"
|
|
elseif filereadable(l:current_dir . "/first.jai")
|
|
let l:cmd = "jai ". l:current_dir . "/first.jai"
|
|
let l:has_jai_first_file = 1
|
|
else
|
|
" It's one directory back. We don't want to include '../' in
|
|
" the cmd because then our reported paths in the program get
|
|
" botched, e.g. path shown in an assert error.
|
|
if filereadable(l:one_dir_back . "/build.jai")
|
|
let l:cmd = "jai " . l:one_dir_back . "/build.jai"
|
|
else
|
|
let l:cmd = "jai " . l:one_dir_back . "/first.jai"
|
|
let l:has_jai_first_file = 1
|
|
endif
|
|
endif
|
|
else
|
|
let l:cmd = "jai % "
|
|
endif
|
|
else
|
|
if filereadable("build") && !isdirectory("build")
|
|
let l:cmd .= './build '
|
|
elseif filereadable("build.sh")
|
|
let l:cmd .= './build.sh '
|
|
elseif filereadable("build.bat")
|
|
let l:cmd .= './build.bat '
|
|
else
|
|
let l:cmd .= './build* '
|
|
endif
|
|
|
|
if a:optimized == 1
|
|
let l:cmd .= ' -o'
|
|
endif
|
|
endif
|
|
|
|
if l:is_jai
|
|
let l:cmd .= ' '.g:campo_jai_compiler_args
|
|
let l:set_metaprogram_args = 0
|
|
|
|
if l:has_jai_build_file
|
|
let l:filename = "build.jai"
|
|
if l:has_jai_first_file
|
|
let l:filename = "first.jai"
|
|
endif
|
|
|
|
if a:optimized == 1
|
|
echo "Compiling release " . l:filename
|
|
" @note We pass 'release' as a user metaprogram arg for the
|
|
" build file to parse in case it cares about that. -release is
|
|
" a compiler arg that we also include because some build
|
|
" scripts won't be looking at the user metaprogram args.
|
|
" We also don't bother adding an import directory for local modules
|
|
" because the build file should manage that sort of thing for us.
|
|
let l:cmd .= " -release - -release"
|
|
let l:set_metaprogram_args = 1
|
|
else
|
|
echo "Compiling debug " . l:filename
|
|
endif
|
|
else
|
|
if a:optimized == 1
|
|
echo "Compiling release " . expand('%:t')
|
|
let l:cmd .= " -release"
|
|
else
|
|
echo "Compiling debug " . expand('%:t')
|
|
endif
|
|
endif
|
|
|
|
if g:campo_jai_metaprogram_args != ""
|
|
if l:set_metaprogram_args == 1
|
|
let l:cmd .= ' '.g:campo_jai_metaprogram_args
|
|
else
|
|
let l:cmd .= ' - '.g:campo_jai_metaprogram_args
|
|
endif
|
|
endif
|
|
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
|
|
endfu
|
|
|
|
fu! RunProgram() abort
|
|
if tolower(expand('%:e')) == "py"
|
|
exec "AsyncRun! python %"
|
|
return
|
|
endif
|
|
|
|
" Sometimes vim mixes unix and windows slashes so we need to normalize and
|
|
" use this in future fnamemodify calls (can't use expand with a string
|
|
" that doesn't contain wildcards).
|
|
let l:full_path = WindowsToUnixPath(expand('%'))
|
|
|
|
let l:file_exe_name = fnamemodify(l:full_path, ':t:r').'.exe' " Just the filename without the path
|
|
|
|
" Easy case is the current file has an exe with the same name in the
|
|
" same directory. We run that if found.
|
|
if filereadable(fnamemodify(l:full_path, ':p:h') . '/' . l:file_exe_name)
|
|
exec 'AsyncRun! ' . fnamemodify(l:full_path, ':p:h') . '/' . l:file_exe_name
|
|
return
|
|
endif
|
|
|
|
" We start by looking for something to run relative to the current file's
|
|
" path. If nothing is found then we start over looking in the current
|
|
" working directory (the directory vim was opened in).
|
|
let l:current_path = fnamemodify(l:full_path, ':p:h')
|
|
|
|
if !RunProgramInDirectory(l:current_path, l:file_exe_name)
|
|
let l:cwd = getcwd()
|
|
if !RunProgramInDirectory(l:cwd, l:file_exe_name)
|
|
call PrintError("No exe or run script found in current file path '" . l:current_path . "' or working directory '". l:cwd ."'")
|
|
endif
|
|
endif
|
|
endfu
|
|
|
|
|
|
fu! RunProgramInDirectory(starting_path, file_exe_name) abort
|
|
let l:search_path = a:starting_path
|
|
let l:ext = tolower(expand('%:e'))
|
|
let l:also_search_for_cpp_run_script = 0 " Covers the case of having a run-cpp file in a jai project.
|
|
|
|
if l:ext == "jai"
|
|
" Check if we're editing inside a modules file and if so then get a
|
|
" path that takes us outside of it. We'll use that path for finding an
|
|
" exe or run script.
|
|
let l:pos = match(l:search_path, "modules")
|
|
if l:pos != -1
|
|
" e.g. if the current path is
|
|
" /z/jai/examples/wasm/modules/Blah/blah.jai then this is /z/jai/examples/wasm/
|
|
let l:module_root_path = l:search_path[:l:pos-1]
|
|
|
|
" We don't want to proceed if the path is in the jai compiler's modules folder.
|
|
let l:jai_path = tolower(g:campo_jai_path)
|
|
if l:jai_path[-1:] != '/'
|
|
let l:jai_path .= '/'
|
|
endif
|
|
|
|
"echo 'modules root path: ' . l:module_root_path . ' | jai path: ' . l:jai_path
|
|
if tolower(l:module_root_path) == l:jai_path
|
|
"echo 'inside jai modules. Aborting run'
|
|
return 0
|
|
endif
|
|
|
|
let l:search_path = l:module_root_path
|
|
endif
|
|
elseif l:ext == "cpp" || l:ext == "c" || l:ext == "h" || l:ext == "inc"
|
|
let l:also_search_for_cpp_run_script = 1
|
|
endif
|
|
|
|
let l:search_path = fnamemodify(l:search_path, ':p') " Normalize the path just in case.
|
|
|
|
" Search the current path for a run script, an exe with the current
|
|
" filename, a bin/filename exe, a run_tree/filename exe - if nothing is
|
|
" found then repeat one directory back when the current folder doesn't
|
|
" contain a .git/ or it's not a root directory, e.g. /z/.
|
|
"
|
|
" If nothing is found after exhausting the search then we start over and
|
|
" find the first exe with any name.
|
|
|
|
fu! TryRun(path) abort
|
|
if filereadable(a:path)
|
|
exec "AsyncRun! " . a:path
|
|
return 1
|
|
endif
|
|
return 0
|
|
endfu
|
|
|
|
let l:current_path = l:search_path
|
|
while 1
|
|
" run script
|
|
if l:also_search_for_cpp_run_script
|
|
if TryRun(l:current_path . 'run-cpp') | return 1 | endif
|
|
endif
|
|
if TryRun(l:current_path . 'run') | return 1 | endif
|
|
|
|
" run_tree/run script
|
|
if l:also_search_for_cpp_run_script
|
|
if TryRun(l:current_path . 'run_tree/run-cpp') | return 1 | endif
|
|
endif
|
|
if TryRun(l:current_path . 'run_tree/run') | return 1 | endif
|
|
|
|
" filename exe
|
|
if TryRun(l:current_path . a:file_exe_name) | return 1 | endif
|
|
|
|
" bin/filename exe
|
|
if TryRun(l:current_path. 'bin/' . a:file_exe_name) | return 1 | endif
|
|
|
|
" run_tree/filename exe
|
|
if TryRun(l:current_path. 'run_tree/' . a:file_exe_name) | return 1 | endif
|
|
|
|
" Only go back a directory if the current path doesn't have a .git folder or we're not in a root drive path.
|
|
if isdirectory(l:current_path . '.git') || IsRootDrive(l:current_path)
|
|
break
|
|
endif
|
|
|
|
let l:current_path = fnamemodify(l:current_path."../", ':p')
|
|
endwhile
|
|
|
|
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
" Start over but look for the first exe. The user will confirm if they
|
|
" want to run it.
|
|
"
|
|
" @improve maybe provide the first 4 or 5 exes found and let them input
|
|
" which one they want?
|
|
|
|
fu! GetFirstExePath(path)
|
|
let l:files = systemlist('ls '.a:path.'*.exe 2>/dev/null')
|
|
if len(l:files) > 0
|
|
return l:files[0]
|
|
endif
|
|
return ""
|
|
endfu
|
|
|
|
let l:current_path = l:search_path
|
|
let l:exe_to_confirm = ""
|
|
|
|
while 1
|
|
let l:exe = GetFirstExePath(l:current_path)
|
|
if l:exe != ""
|
|
let l:exe_to_confirm = l:exe
|
|
break
|
|
endif
|
|
|
|
" bin/filename exe
|
|
let l:exe = GetFirstExePath(l:current_path."bin/")
|
|
if l:exe != ""
|
|
let l:exe_to_confirm = l:exe
|
|
break
|
|
endif
|
|
|
|
" run_tree/filename exe
|
|
let l:exe = GetFirstExePath(l:current_path."run_tree/")
|
|
if l:exe != ""
|
|
let l:exe_to_confirm = l:exe
|
|
break
|
|
endif
|
|
|
|
" Only go back a directory if the current path doesn't have a .git folder or we're not in a root drive path.
|
|
if isdirectory(l:current_path . '.git') || IsRootDrive(l:current_path)
|
|
break
|
|
endif
|
|
|
|
let l:current_path = fnamemodify(l:current_path."../", ':p')
|
|
endwhile
|
|
|
|
if l:exe_to_confirm != ""
|
|
let l:confirm = confirm("Found exe ".l:exe_to_confirm." - run this?", "&Yes\n&No")
|
|
if l:confirm == 1
|
|
exec "AsyncRun! " . l:exe_to_confirm
|
|
return 1
|
|
endif
|
|
redraw!
|
|
endif
|
|
|
|
return 0
|
|
endfu
|
|
|
|
" 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 <leader>bc :call ToggleBuildResults()<cr>
|
|
noremap <F11> :call ToggleBuildResults()<cr>
|
|
" Hide build results and clear errors
|
|
noremap <F10> :call HideBuildResultsAndClearErrors()<cr>
|
|
|
|
" Execute build script and display results.
|
|
nnoremap <silent><leader>b :call Build(0)<cr>
|
|
nnoremap <silent><F8> :call Build(0)<cr>
|
|
|
|
" Execute optimized build script
|
|
nnoremap <leader>bb :call Build(1)<cr>
|
|
|
|
" Execute run script
|
|
nnoremap <silent><leader>br :call RunProgram()<cr>
|
|
nnoremap <silent><F9> :call RunProgram()<cr>
|
|
|
|
nnoremap <leader>bs :AsyncStop<cr>
|
|
|
|
"Go to next build error
|
|
nnoremap <F7> :cn<CR>
|
|
nnoremap <C-n> :cn<CR>
|
|
|
|
"Go to previous build error
|
|
nnoremap <F6> :cp<CR>
|
|
nnoremap <C-p> :cp<CR>
|
|
|
|
|
|
"##################################################################################
|
|
" TEXT SEARCH
|
|
"##################################################################################
|
|
|
|
" Search using ripgrep (first install with Rust: cargo install ripgrep).
|
|
fu! 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
|
|
|
|
call ConvertQuickfixPathsToUnixSlashes()
|
|
endfu
|
|
|
|
fu! SearchExt(path, search_args, case_insensitive=0)
|
|
call inputsave()
|
|
let l:ext = input('Enter extension to search on (leave blank for files with no ext): ')
|
|
call inputrestore()
|
|
redraw!
|
|
|
|
if empty(l:ext)
|
|
let l:ext = "!*.*"
|
|
else
|
|
let l:ext = "*.".l:ext
|
|
endif
|
|
|
|
let l:args = a:search_args." -g \"".l:ext."\""
|
|
|
|
call Search(a:path, l:args, a:case_insensitive)
|
|
endfu
|
|
|
|
"/////////////////////////////////////////////////
|
|
" SEARCH IN CURRENT WORKING DIRECTORY
|
|
"/////////////////////////////////////////////////
|
|
|
|
" Case insensitive:
|
|
nnoremap <leader>s :call Search( '.', g:campo_custom_search_args, 1)<cr>
|
|
nnoremap <leader>sd :call SearchExt('.', g:campo_custom_search_args, 1)<cr>
|
|
" Case sensitive:
|
|
nnoremap <leader>ss :call Search( '.', g:campo_custom_search_args, 0)<cr>
|
|
nnoremap <leader>ssd :call SearchExt('.', g:campo_custom_search_args, 0)<cr>
|
|
|
|
"/////////////////////////////////////////////////
|
|
" SEARCH IN DIRECTORY CONTAINING THE ACTIVE FILE
|
|
"/////////////////////////////////////////////////
|
|
|
|
" Case insensitive:
|
|
nnoremap <leader>sf :call Search( expand('%:p:h'), g:campo_custom_search_args, 1)<cr>
|
|
nnoremap <leader>sdf :call SearchExt(expand('%:p:h'), g:campo_custom_search_args, 1)<cr>
|
|
" Case sensitive:
|
|
nnoremap <leader>ssf :call Search( expand('%:p:h'), g:campo_custom_search_args, 0)<cr>
|
|
nnoremap <leader>ssdf :call SearchExt(expand('%:p:h'), g:campo_custom_search_args, 0)<cr>
|
|
|
|
"/////////////////////////////////////////////////
|
|
" SEARCH IN JAI FOLDERS
|
|
"/////////////////////////////////////////////////
|
|
|
|
" Case insensitive:
|
|
"
|
|
" ROOT
|
|
nnoremap <leader>sg :call Search( g:campo_jai_path, g:campo_custom_search_args, 1)<cr>
|
|
nnoremap <leader>sdg :call SearchExt(g:campo_jai_path, g:campo_custom_search_args, 1)<cr>
|
|
" MODULES
|
|
nnoremap <leader>sm :call Search( g:campo_jai_path.'/modules', g:campo_custom_search_args, 1)<cr>
|
|
nnoremap <leader>sdm :call SearchExt(g:campo_jai_path.'/modules', g:campo_custom_search_args, 1)<cr>
|
|
" HOW TO
|
|
nnoremap <leader>sh :call Search( g:campo_jai_path.'/how_to', g:campo_custom_search_args, 1)<cr>
|
|
nnoremap <leader>sdh :call SearchExt(g:campo_jai_path.'/how_to', g:campo_custom_search_args, 1)<cr>
|
|
" EXAMPLES
|
|
nnoremap <leader>se :call Search( g:campo_jai_path.'/examples', g:campo_custom_search_args, 1)<cr>
|
|
nnoremap <leader>sde :call SearchExt(g:campo_jai_path.'/examples', g:campo_custom_search_args, 1)<cr>
|
|
|
|
" Case sensitive:
|
|
"
|
|
" ROOT
|
|
nnoremap <leader>ssg :call Search( g:campo_jai_path, g:campo_custom_search_args, 0)<cr>
|
|
nnoremap <leader>ssdg :call SearchExt(g:campo_jai_path, g:campo_custom_search_args, 0)<cr>
|
|
" MODULES
|
|
nnoremap <leader>ssm :call Search( g:campo_jai_path.'/modules', g:campo_custom_search_args, 0)<cr>
|
|
nnoremap <leader>ssdm :call SearchExt(g:campo_jai_path.'/modules', g:campo_custom_search_args, 0)<cr>
|
|
" HOW TO
|
|
nnoremap <leader>ssh :call Search( g:campo_jai_path.'/how_to', g:campo_custom_search_args, 0)<cr>
|
|
nnoremap <leader>ssdh :call SearchExt(g:campo_jai_path.'/how_to', g:campo_custom_search_args, 0)<cr>
|
|
" EXAMPLES
|
|
nnoremap <leader>sse :call Search( g:campo_jai_path.'/examples', g:campo_custom_search_args, 0)<cr>
|
|
nnoremap <leader>ssde :call SearchExt(g:campo_jai_path.'/examples', g:campo_custom_search_args, 0)<cr>
|
|
|
|
" 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 <expr> o (&buftype is# "quickfix" ? "<CR>\|:lopen<CR>" : "o")
|
|
nnoremap <expr> p (&buftype is# "quickfix" ? "<CR>\|:copen<CR>" : "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.
|
|
fu! 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
|
|
endfu
|
|
noremap <leader>r :call GlobalReplaceIt(0)<cr>
|
|
noremap <leader>rr :call GlobalReplaceIt(1)<cr>
|
|
|
|
|
|
"##################################################################################
|
|
" RENAME CURRENT FILE
|
|
"##################################################################################
|
|
|
|
fu! 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
|
|
endif
|
|
endif
|
|
redraw!
|
|
endfu
|
|
noremap <leader>n :call RenameFile()<cr>
|
|
|
|
|
|
"##################################################################################
|
|
" CENTER THE BUFFER
|
|
"##################################################################################
|
|
|
|
fu! 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)
|
|
endfu
|
|
|
|
fu! RemoveCenterPane()
|
|
wincmd w
|
|
close
|
|
endfu
|
|
|
|
nnoremap <leader>cc :call CenterPane()<cr>
|
|
nnoremap <leader>cd :call RemoveCenterPane()<cr>
|
|
|
|
|
|
"##################################################################################
|
|
" 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.
|
|
|
|
fu! 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
|
|
endfu
|
|
|
|
nnoremap <leader>c :call ToggleSimpleView()<cr>
|
|
|
|
"-----------------------------------------------------------------------------------------------------------------------
|
|
|
|
let g:campo_vimrc_initialized = 1
|
|
|