" Inspired by Amir Salihefendic's Awesome version of the Ultimate Vim configuration
" https://github.com/amix/vimrc
" see also https://realpython.com/vim-and-python-a-match-made-in-heaven
if &compatible
" Vim defaults to `compatible` when selecting a vimrc with the command-line
" `-u` argument. Override this.
set nocompatible
endif
filetype off " Will be set after the plugins are loaded
" Setting here because it's used in the Plugins section
let mapleader = ","
let g:mapleader = ","
" Plugins {{{
" Vim-plug {{{
" If vim-plug is not here, install it and install all the plugins
if has('nvim')
if empty(glob('~/.local/share/nvim/site/autoload/plug.vim'))
silent !curl -fLo ~/.local/share/nvim/site/autoload/plug.vim --create-dirs
\ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif
else
if empty(glob('~/.vim/autoload/plug.vim'))
silent !curl -fLo ~/.vim/autoload/plug.vim --create-dirs
\ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif
endif
if has('nvim')
call plug#begin(stdpath('data') . '/plugged')
else
call plug#begin('~/.vim/plugged')
endif
" Add vim-plug to get its vim help
Plug 'junegunn/vim-plug'
" General
Plug 'scrooloose/nerdtree' " View of the file system
Plug 'morhetz/gruvbox' " Color scheme
Plug 'ctrlpvim/ctrlp.vim' " Fuzzy search for files
Plug 'vim-airline/vim-airline' " Status line at the bottom
Plug 'mileszs/ack.vim' " ack/ag in vim
Plug 'embear/vim-localvimrc' " Local vimrc files for project-specific settings
" General programming
Plug 'vim-syntastic/syntastic' " Syntax checker
Plug 'tpope/vim-surround' " Act on surrounding things like quotes and HTML tags
Plug 'tpope/vim-repeat' " Repeat certain commands such as surround
Plug 'tpope/vim-commentary' " Comment/uncomment code
Plug 'janko/vim-test' " Run tests
Plug 'tpope/vim-fugitive' " git integration
Plug 'airblade/vim-gitgutter' " Shows git diff in the 'gutter' (sign column)
Plug 'neoclide/coc.nvim', {'branch': 'release'} " Intellisense engine
Plug 'ludovicchabant/vim-gutentags' " Keep tags files up to date
Plug 'AndrewRadev/sideways.vim' " Move function arguments left and right
" Python
" Better syntax highlighting
if has('nvim')
Plug 'numirias/semshi', {'do': ':UpdateRemotePlugins'}
else
Plug 'vim-python/python-syntax'
endif
Plug 'nvie/vim-flake8' " Python style checker
" Ruby on Rails
Plug 'vim-ruby/vim-ruby'
Plug 'tpope/vim-rails'
" Some plugins to consider
" Plugin 'easymotion/vim-easymotion' " Vim motion on speed!
" Plugin 'slj/gundo.vim' " Display undo tree in graphical form
" Plugin 'garbas/vim-snipmate' " Code snippets
" Plugin 'jiangmiao/auto-pairs' " Insert/delete parens/quotes in pairs
" Plugin 'skywind3000/asyncrun.vim' " Kick off builds/tests asynchronously
" PLugin 'Xuyuanp/nerdtree-git-plugin' " NERDTree git integration
" Plugin 'terryma/vim-multiple-cursors' " Sublime's multiple selection feature
" Plugin 'tmhedberg/SimpylFold'
" Plugin 'vim-scripts/indentpython.vim'
" All plugins must be added before the following line
call plug#end()
" }}}
" Ack.vim {{{
nnoremap <leader>aa :Ack!<space>
" Search for word under cursor (overwrites p registry)
nnoremap <leader>aw "pyiw:Ack!<space><C-R>p<cr>
" Search for selection (overwrites p registry)
vnoremap <leader>as "py:Ack!<space><C-R>p<cr>
if executable('ag')
let g:ackprg = 'ag --vimgrep --path-to-ignore ~/.ignore --follow'
endif
" }}}
" coc.nvim {{{
" Disable integration with airline
let g:airline#extensions#coc#enabled = 0
" Use tab for trigger completion with characters ahead and navigate.
inoremap <silent><expr> <TAB>
\ pumvisible() ? "\<C-n>" :
\ <SID>check_back_space() ? "\<TAB>" :
\ coc#refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"
function! s:check_back_space() abort
let col = col('.') - 1
return !col || getline('.')[col - 1] =~# '\s'
endfunction
" Enter confirms completion
inoremap <expr> <cr> pumvisible() ? "\<C-y>" : "\<CR>"
" Code navigation
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gr <Plug>(coc-references)
" Use K to show documentation in preview window.
nnoremap <silent> K :call <SID>show_documentation()<CR>
function! s:show_documentation()
if (index(['vim','help'], &filetype) >= 0)
execute 'h '.expand('<cword>')
else
call CocAction('doHover')
endif
endfunction
" }}}
" Gutentags {{{
let g:gutentags_ctags_exclude = ['.tox', '*.json']
" }}}
" NERDTree {{{
" Open NERDTree by default
autocmd StdinReadPre * let s:std_in=1
autocmd VimEnter * if argc() == 0 && !exists("s:std_in") | NERDTree | endif
" Shortcut to open NERDTree
nnoremap <leader>ne :NERDTreeToggle<Enter>
" Ignore some files
let NERDTreeIgnore=['\.pyc$', '\~$']
" Automatically close NERDTree when you open a file
let NERDTreeQuitOnOpen = 1
" Automatically close a tab if the only remaining window is NERDTree
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif
" Automatically delete the buffer of the file you just deleted with NerdTree:
let NERDTreeAutoDeleteBuffer = 1
" Making it prettier
let NERDTreeMinimalUI = 1
let NERDTreeDirArrows = 1
" }}}
" Semshi {{{
if has('nvim')
nnoremap <leader>rr :Semshi rename
endif
" }}}
" Sideways {{{
nnoremap <leader>sh :SidewaysLeft<Enter>
nnoremap <leader>sl :SidewaysRight<Enter>
" }}}
" Syntastic {{{
let g:syntastic_always_populate_loc_list = 1
let g:syntastic_auto_loc_list = 1
let g:syntastic_check_on_open = 1
let g:syntastic_check_on_wq = 0
let g:syntastic_python_checkers = ['pylint', 'flake8']
" Show all levels of pylint messages
let g:syntastic_quiet_messages = { "level": [] }
let g:syntastic_python_pylint_quiet_messages = { "level" : [] }
" }}}
" vim-test {{{
" Run tests in a split window
if has('nvim')
let g:test#strategy = 'neovim'
else
let g:test#strategy = 'vimterminal'
endif
" }}}
" vim-surround {{{
" Don't select extra space when working around quotes
" https://github.com/tpope/vim-surround/issues/276
nmap ysa' ys2i'
nmap ysa" ys2i"
nmap ysa` ys2i`
" }}}
" }}}
" General {{{
" Sets how many lines of history VIM has to remember
set history=500
" Set to auto read when a file is changed from the outside
set autoread
" Last 5 lines can be used as modelines
set modelines=5
" Leader namespaces - for related actions
" b: Buffers
" e: Edit file (vimrc, etc)
" g: Go (code completion)
" h: Hunks (gitgutter)
" r: Refactor
" s: Spell checker, Source file (vimrc, etc), Sideways plugin
" t: Tabs, Tests
" Fast saving
nmap <leader>w :w!<cr>
" Allow saving of files as sudo when I forgot to start vim using sudo.
cmap w!! w !sudo tee > /dev/null %
" Access the system clipboard (should work at least on OS X)
set clipboard=unnamed
" Quickly edit/reload the vimrc file
nmap <silent> <leader>ev :e ~/.vimrc<CR>
nmap <silent> <leader>sv :so ~/.vimrc<CR>
" }}}
" User interface {{{
" Show the number of the current line and the relative number of the others
set number
set relativenumber
" Show absolute numbers when in insert mode or losing focus
:augroup numbertoggle
: autocmd!
: autocmd BufEnter,FocusGained,InsertLeave * set relativenumber
: autocmd BufLeave,FocusLost,InsertEnter * set norelativenumber
:augroup END
" Set 7 lines/columns to the cursor
set scrolloff=7
set sidescrolloff=7
" Avoid garbled characters in Chinese language windows OS
let $LANG='en'
set langmenu=en
source $VIMRUNTIME/delmenu.vim
source $VIMRUNTIME/menu.vim
" Turn on the WiLd menu (shows possible matches when pressing tab in command mode)
set wildmenu
" First tab completes the longest common string; next tab completes the first alternative
set wildmode=longest:full,full
" Ignore compiled files
set wildignore=*.o,*~,*.pyc
if has("win16") || has("win32")
set wildignore+=.git\*,.hg\*,.svn\*
else
set wildignore+=*/.git/*,*/.hg/*,*/.svn/*,*/.DS_Store
endif
"Always show current position
set ruler
" Height of the command bar
set cmdheight=2
" A buffer becomes hidden when it is abandoned
set hidden
" Configure backspace so it acts as it should act
set backspace=eol,start,indent
set whichwrap+=<,>,h,l
" Search
set ignorecase " Ignore case when searching
set smartcase " When searching try to be smart about cases
set hlsearch " Highlight search results
set incsearch " Makes search act like search in modern browsers
" Stop highlighting last search pattern
map <silent> <leader><cr> :noh<cr>
" Don't redraw while executing macros
set lazyredraw
" For regular expressions turn magic on
set magic
" Show matching brackets when text indicator is over them
set showmatch
" How many tenths of a second to blink when matching brackets
set matchtime=2
" No annoying sound on errors
set noerrorbells
set novisualbell
set t_vb=
set timeoutlen=500
" Properly disable sound on errors on MacVim
if has("gui_macvim")
autocmd GUIEnter * set vb t_vb=
endif
" Add a bit extra margin to the left
set foldcolumn=1
" }}}
" Colors and Fonts {{{
" Enable syntax highlighting
syntax enable
" Highlight current line
set cursorline
set t_Co=256
colorscheme gruvbox
" Fix semshi highlighting after setting the colorscheme
" TODO Only set colorscheme if none has been defined before
" Changing colorschemes (even to the same one) messes up semshi in nvim
if has('nvim')
function SetSemshiColors()
" https://vim.fandom.com/wiki/Xterm256_color_names_for_console_Vim
hi semshiLocal ctermfg=209 guifg=#ff875f
hi semshiGlobal ctermfg=214 guifg=#ffaf00
hi semshiImported ctermfg=214 guifg=#ffaf00 cterm=bold gui=bold
hi semshiParameter ctermfg=75 guifg=#5fafff
hi semshiParameterUnused ctermfg=117 guifg=#87d7ff cterm=underline gui=underline
hi semshiFree ctermfg=218 guifg=#ffafd7
hi semshiBuiltin ctermfg=96 guifg=#ff5fff
hi semshiAttribute ctermfg=44 guifg=#00ffaf
hi semshiSelf ctermfg=249 guifg=#b2b2b2
hi semshiUnresolved ctermfg=226 guifg=#ffff00 cterm=underline gui=underline
hi semshiSelected ctermfg=231 guifg=#ffffff ctermbg=103 guibg=#d7005f
hi semshiErrorSign ctermfg=231 guifg=#ffffff ctermbg=160 guibg=#d70000
hi semshiErrorChar ctermfg=231 guifg=#ffffff ctermbg=160 guibg=#d70000
endfunction
autocmd ColorScheme * call SetSemshiColors()
endif
set background=dark
" Set extra options when running in GUI mode
if has('gui_running')
set guioptions-=T
set guioptions-=e
set t_Co=256
set guitablabel=%M\ %t
endif
" Set utf8 as standard encoding and en_US as the standard language
set encoding=utf8
" Use Unix as the standard file type
set fileformats=unix,dos,mac
" Highlight one-line comments in JSON files (useful for jsonc files such as coc-settings.json)
autocmd FileType json syntax match Comment +\/\/.\+$+
" }}}
" Files, backups and undo {{{
" Turn backup off and rely on version control instead
set nobackup
set nowritebackup
set noswapfile
" }}}
" Text, tab and indent {{{
" Use spaces instead of tabs
set expandtab
" Be smart when using tabs ;)
set smarttab
" 1 tab == 2 spaces
set shiftwidth=2
set tabstop=2 " Number of visual spaces per TAB
set softtabstop=2 " Number of spaces per TAB when editing
set shiftround " Indenting rounds to a multiple of 2 (instead of just changing by 2)
" Wrap long lines
set linebreak
set colorcolumn=80 " Vertical bar
set textwidth=80 " Wrap automatically
set autoindent
set smartindent
set wrap " Wrap lines
" }}}
" Visual mode {{{
" Visual mode pressing * or # searches for the current selection
vnoremap <silent> * :<C-u>call VisualSelection('', '')<CR>/<C-R>=@/<CR><CR>
vnoremap <silent> # :<C-u>call VisualSelection('', '')<CR>?<C-R>=@/<CR><CR>
" }}}
" Terminal mode {{{
if has('nvim')
" Better command to switch from insert to normal mode
tmap <C-o> <C-\><C-n>
endif
" }}}
" Moving around, tabs, windows and buffers {{{
" Map j to gj so vim behaves as expected with wrapped lines
" But keep normal behaviour if doing something like 4j
nnoremap <expr> j v:count ? 'j' : 'gj'
nnoremap <expr> k v:count ? 'k' : 'gk'
" Specify where splits should occur
set splitbelow
set splitright
" Smart way to move between windows
map <C-j> <C-W>j
map <C-k> <C-W>k
map <C-h> <C-W>h
map <C-l> <C-W>l
" Close the current buffer
map <leader>bd :Bclose<cr>
" Close all the buffers
map <leader>ba :bufdo bd<cr>
map <leader>l :bnext<cr>
map <leader>h :bprevious<cr>
" Useful mappings for managing tabs
map <leader>tn :tabnew<cr>
map <leader>to :tabonly<cr>
map <leader>tc :tabclose<cr>
map <leader>tm :tabmove
map <leader>t<leader> :tabnext
" Let 'bl' toggle between this and the last accessed tab
let g:lasttab = 1
nmap <leader>bl :exe "tabn ".g:lasttab<CR>
au TabLeave * let g:lasttab = tabpagenr()
" Opens a new tab with the current buffer's path
map <leader>te :tabedit <c-r>=expand("%:p:h")<cr>/
" Switch CWD to the directory of the open buffer
map <leader>cd :cd %:p:h<cr>:pwd<cr>
" Specify the behavior when switching between buffers
try
set switchbuf=useopen,usetab,newtab
set showtabline=1
catch
endtry
" Return to last edit position when opening files
au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
" Shortcut for 'go to buffer'
nnoremap gb :ls<cr>:b<space>
" }}}
" Editing mappings {{{
" Map Y to act like D and C, i.e. to yank until EOL, rather than act as yy,
" which is the default
map Y y$
" Don't write to yank buffer when deleting a single character
noremap x "_x
noremap X "_X
" Map Command key shortcuts to use the Alt key
if has("mac") || has("macunix")
nmap <D-j> <M-j>
nmap <D-k> <M-k>
vmap <D-j> <M-j>
vmap <D-k> <M-k>
endif
" Move a line of text using ALT+[jk] or Command+[jk] on mac
" TODO not working, at least on mac
nmap <M-j> mz:m+<cr>`z
nmap <M-k> mz:m-2<cr>`z
vmap <M-j> :m'>+<cr>`<my`>mzgv`yo`z
vmap <M-k> :m'<-2<cr>`>my`<mzgv`yo`z
" Delete trailing white space on save
fun! CleanExtraSpaces()
let save_cursor = getpos(".")
let old_query = getreg('/')
silent! %s/\s\+$//e
call setpos('.', save_cursor)
call setreg('/', old_query)
endfun
if has("autocmd")
autocmd BufWritePre *.txt,*.js,*.py,*.wiki,*.sh,*.coffee :call CleanExtraSpaces()
endif
" }}}
" Code {{{
" Enable code folding
set foldenable
set foldmethod=indent
set foldlevel=99
" Enable folding with the spacebar
nnoremap <space> za
" Show list of tags if there are multiples matches
" https://stackoverflow.com/a/42078499/
nnoremap <C-]> g<C-]>
" Search the tags file in the directory of the current file, then in the current
" directory
set tags=./tags,tags
" python with virtualenv support
" Neovim seems to be doing this automatically
if !has('nvim')
py3 << EOF
import os
import sys
if 'VIRTUAL_ENV' in os.environ:
project_base_dir = os.environ['VIRTUAL_ENV']
# TODO stop relying on actuvate_this.py
# Python 3.6 deprecated usage of the pyvenv script in favor of `python3 -m venv`
# https://docs.python.org/3/whatsnew/3.6.html
# But venv doesn't have activate_this.py https://bugs.python.org/issue21496
activate_this = os.path.join(project_base_dir, 'bin/activate_this.py')
with open(activate_this) as f:
exec(open(activate_this).read(), {'__file__': activate_this})
EOF
endif
" Pretty code
let python_highlight_all=1
" Ruby autocomplete
autocmd FileType ruby,eruby let g:rubycomplete_buffer_loading = 1
autocmd FileType ruby,eruby let g:rubycomplete_classes_in_global = 1
autocmd FileType ruby,eruby let g:rubycomplete_rails = 1
" Run tests
" Using ,tj because ,tn is used by tabs
nmap <silent> <leader>tj :TestNearest<CR>
nmap <silent> <leader>tf :TestFile<CR>
nmap <silent> <leader>ts :TestSuite<CR>
nmap <silent> <leader>tl :TestLast<CR>
nmap <silent> <leader>tg :TestVisit<CR>
" }}}
" Spell checking {{{
" Toggle and untoggle spell checking
map <leader>ss :setlocal spell!<cr>
" Next misspelled word
map <leader>sn ]s
" Previous misspelled word
map <leader>sp [s
" Add to dictionary
map <leader>sa zg
" Suggest corrections
map <leader>s? z=
" Replace with first correction
map <leader>s1 z=1<CR><CR>
map <leader>se :setlocal spelllang=en_en<CR>
map <leader>sf :setlocal spelllang=fr<CR>
" }}}
" Misc {{{
" Remove the Windows ^M - when the encodings gets messed up
noremap <leader>m mmHmt:%s/<C-V><cr>//ge<cr>'tzt'm
" Quickly open a scratchpad for scribble
map <leader>q :e ~/scratchpad<cr>
" Toggle paste mode on and off
map <leader>pp :setlocal paste!<cr>
" }}}
" Helper functions {{{
" Returns true if paste mode is enabled
function! HasPaste()
if &paste
return 'PASTE MODE '
endif
return ''
endfunction
" Don't close window, when deleting a buffer
command! Bclose call <SID>BufcloseCloseIt()
function! <SID>BufcloseCloseIt()
let l:currentBufNum = bufnr("%")
let l:alternateBufNum = bufnr("#")
if buflisted(l:alternateBufNum)
buffer #
else
bnext
endif
if bufnr("%") == l:currentBufNum
new
endif
if buflisted(l:currentBufNum)
execute("bdelete! ".l:currentBufNum)
endif
endfunction
function! CmdLine(str)
exe "menu Foo.Bar :" . a:str
emenu Foo.Bar
unmenu Foo
endfunction
function! VisualSelection(direction, extra_filter) range
let l:saved_reg = @"
execute "normal! vgvy"
let l:pattern = escape(@", "\\/.*'$^~[]")
let l:pattern = substitute(l:pattern, "\n$", "", "")
if a:direction == 'gv'
call CmdLine("Ack '" . l:pattern . "' " )
elseif a:direction == 'replace'
call CmdLine("%s" . '/'. l:pattern . '/')
endif
let @/ = l:pattern
let @" = l:saved_reg
endfunction
" }}}
" Local configuration {{{
if filereadable(glob("~/.vimrc.local"))
source ~/.vimrc.local
endif
" }}}
" vim: foldmethod=marker:foldlevel=0