Personal Vim configuration designed in a modular way.
A warn note. I tested it on my local machine only so far. Most likely it depends on my own environment (terminal, OS, installed apps) in some unforeseen ways. With that said, I cannot guarantee the smooth experience on your machine. Be prepared to fix issues on your own.
Tested under:
Table of Contents
<C-u>
, <C-d>
,<C-f>
, <C-b>
page movements. Recenter screen after most motions. Includes a bunch of useful text objects: line, url, entire buffer, matchit %
region, lines with same indentation, current fold, function/class, etc. Improved f
and t
movements via clever-f plugin.IntelliSense
) provided by coc.nvim and language servers.git status
files and make a commit. Undo, stage or preview diff hunks while working with a buffer.<C-arrow>
and <S-arrow>
keys work smoothly. FocusGained
and FocusLost
events are properly captured by Vim (via tmux-plugins/vim-tmux-focus-events). <S-CR>
and <C-CR>
keys are added by configuring iTerm to send custom escape sequence. Different cursor shape is applied depending on the current mode.git clone https://github.com/samoshkin/dotvim ~/.vim
cd ~/.vim
./install.sh
Required external dependencies. Make sure they are installed and are available on PATH
:
grep
replacement.Most native Vim mappings work as you expect. This config follows and builds upon the ideology and spirit of the Vim, rather than fighting against it.
leader
and localleader
are mapped as:
nnoremap <Space> <Nop>
let mapleader=" " "<Space>
let maplocalleader=","
Toggle various settings/feature ON and OFF with a uniform mapping that starts with <leader>t
, for example:
nmap <leader>ts :ToggleSyntax<CR>
nmap <leader>th :set hlsearch!<CR>
nmap <leader>tl <Plug>(qf_loc_toggle_stay)
nmap <leader>tq <Plug>(qf_qf_toggle_stay)
nmap <leader>tt :GutentagsToggle<CR>
nmap <leader>t{} :DelimitMateSwitch<CR>
nmap <leader>tp :set paste!<CR>
nmap <leader>td :GitGutterBufferToggle<CR>
nmap <leader>tw :setl wrap!<CR>
nmap <leader>tz :setlocal foldenable!<CR>
nmap <leader>te :call CocAction("diagnosticToggle")<CR>
<C-C>
is mapped to <Esc>
. Use it to exit from any non-Normal mode, plus it works to exit insert completion menu, coc.nvim
lists, various fzf
popups. IMO, <C-c>
is easier to type that <ESC>
or other alternatives like jk
. Most likely you already get used to it after working in a shell.
inoremap <C-C> <ESC>
noremap <C-C> <ESC>
vnoremap <C-C> <ESC>
By default terminal Vim does not distinguish <S-CR>
and <C-CR>
from regular <CR>
. However, you can tell the terminal to send specific escape sequence (\e[13;2u
, \e[13;5u
) and instruct Vim to recognize them.
" See https://stackoverflow.com/questions/16359878/how-to-map-shift-enter
" See https://vim.fandom.com/wiki/Mapping_fast_keycodes_in_terminal_Vim
execute "set <F20>=\e[13;2u"
execute "set <F21>=\e[13;5u"
The solution is not portable, but these keys are quite useful, especially in the Insert mode:
" Shift-Enter(remapped as <F20>) to start editing new line below without splitting the current one
" Ctrl-Enter(remapped as <F21>) to start editing new line above
inoremap <F20> <C-o>o
inoremap <F21> <C-o>O
When Vim is running inside tmux, <S-arrow>
and <C-arrow>
keys are not delegated by tmux downwards to the Vim. To enable it, you need to change your tmux.conf
:
set -wg xterm-keys on
Even despite that, Vim's still not able to automatically recognize <S-arrow>
and <C-arrow>
keys when tmux
reports itself as a screen-256color
. This is due to the lack of data in a terminfo
database for that terminal type. To fix it manually tell Vim about right escape sequences:
if &term =~ '^screen'
" tmux will send xterm-style keys when its xterm-keys option is on
execute "set <xUp>=\e[1;*A"
execute "set <xDown>=\e[1;*B"
execute "set <xRight>=\e[1;*C"
execute "set <xLeft>=\e[1;*D"
endif
There're a bunch of custom text objects installed. The "Zen" of vim is that you're speaking a language. Grammar consists of basic vocabulary: verbs, modifiers, nouns. The text objects extend the vocabulary of available {nouns}
.
iW aW, WORD
iw aw, word
is as, sentence
ip ap, paragraph
i' a', single quotes
i" a", double quotes
i` a`, back ticks
iq/aq, between any quote
i( a(, parenthesis
i[ a[, brackets
i{ a{, bracnes
i> a>, angle brackets
ib/ab, between any paretheses and braces
if/af, function (when supported by the language server)
ic/ac, class (when supported by the language server)
ia/aa, function arguments
ie/ae, entire file
il/al, current line
ii/ai, block of lines with same indentation
iy/ay, syntax highlights
iu/au, URIs
iv/av, variable segement of lower_case or camelCase
iz/az, block of folded lines
ih/ah, vim-gitgutter diff hunks
im/am, to select matchit % pairs
ib/ab, text between parentheses and braces ( [ { <
gc, commented text
Language server integration brings highly important features that are usually found only in IDEs. To enumerate most prominent ones:
IntelliSense
in the Microsoft realm)Prettier
, the language server is capable enough to properly format the region of the text without reformatting the whole file. For example, format function body or the text range you just altered in the Insert mode.coc.nvim is the Vim plugin that represent the client-side of the LSP protocol, whereas language server itself should be installed separately. Each language server usually takes care of a particular file type or a language. To mention some of them: tsserver, vim-lsp, vscode-json-languageservice, bash-language-service
coc-extensions file is just a normal package.json
file that declares installed language servers. Extensions should be installed in a special folder, and install.sh
script takes care of it:
mkdir -p "~/.config/coc/extensions"
ln -sf "~/.vim/coc-extensions.json" "~/.config/coc/extensions/package.json"
pushd ~/.config/coc/extensions
yarn install
popd
coc-settings.json is the main configuration file for coc.nvim
itself plus any language server you installed before. To open it from inside the Vim, use :CocConfig
command.
Code linting is done through the coc-diagnostic language server. It's a special one because it's not limited to support single file type, but allows you to plug any linter program and lint any file. Checkout [coc-settings.json]() for the configuration:
"diagnostic-languageserver.filetypes": {
"vim": "vint",
"email": "languagetool",
"markdown": [ "write-good", "markdownlint" ],
"sh": "shellcheck",
"javascript": ["eslint"],
"javascriptreact": ["eslint"],
"scss": ["stylelint"],
"sass": ["stylelint"],
"less": ["stylelint"],
"css": ["stylelint"]
}
Note, that dense-analysis/ale is not used in this config.
Unlike most .vim
configuration on the internet, this one does not keep hundreds of settings kept in a single giant vimrc
file. On the contrary, settings and functions are broken down into the individual files, with a respect to Vim guidelines.
vimrc
, the main entry point of Vim configuration. Is executed first. Keeps only few settings and lists installed plugins.plugin/
, any file in this directory is automatically sourced by Vim, however don't rely on the execution order. Most configuration is kept here, with each file limited to a specific aspect or a single plugin.after/
, files in this directory are guaranteed to run after vimrc
and plugin/*
files.after/ftplugin
, keeps settings that are unique only for the particular file type.after/syntax
, defines regular expressions to match various syntax groups in a file of a given file type. Syntax highlighting relies on the extracted syntax groupsafter/colors
, syntax highlight and color customization for a particular colorschemeautoload/_
, custom functions are defined here. Functions are lazy loaded when used by a command or a mapping. Weird _
directory name is used as a private namespace for my own functions, so they don't conflict with functions defined in other plugins.coc-extensions.json
and coc-settings.json
are files related to coc.nvim
plugin and language server configuraton.filetype.vim
, associate the file with a file type by looking at file extension. Once file type is set, ftplugin/{filetype}.vim
files are sourced.Ultisnips/
, user-defined snippets.Here is the .vim
directory outline:
├── after
│ ├── colors
│ │ └── gruvbox.vim
│ ├── ftplugin
│ │ ├── git.vim
│ │ ├── gitcommit.vim
│ │ ├── markdown.vim
│ │ ├── scss.vim
│ ├── plugin
│ │ └── colorscheme.vim
│ └── syntax
│ ├── gitcommit.vim
│ ├── json.vim
│ └── nerdtree.vim
├── autoload
│ ├── _
│ │ ├── buffer.vim
│ │ ├── diff.vim
│ │ ├── fugitive.vim
│ │ ├── mixedwhitespace.vim
│ │ ├── qfloc.vim
│ │ ├── search.vim
│ │ ├── session.vim
│ │ ├── util.vim
│ │ └── window.vim
│ └── plug.vim
├── coc-extensions.json
├── coc-settings.json
├── deprecated
│ ├── plug_ale.vim
│ └── plug_findfiles.vim
├── filetype.vim
├── install.sh
├── nerdtree_plugin
│ ├── copy_path_to_clipboard.vim
│ └── gitignore_filter.vim
├── plugin
│ ├── buffer.vim
│ ├── colors.vim
│ ├── command.vim
│ ├── diagnostic.vim
│ ├── diff.vim
│ ├── motion.vim
| | ...........
│ ├── plug_cleverf.vim
│ ├── plug_coc.vim
│ ├── plug_commentary.vim
│ ├── plug_delimitmate.vim
│ ├── plug_editorconfig.vim
│ ├── plug_exchange.vim
├── UltiSnips
└── vimrc
vim-plug is used as a plugin manager. All plugin dependencies are pinned to a specific commit for repeatable and stable installations.
Plug 'junegunn/fzf', { 'do': { -> fzf#install() }, 'commit': '8c533e3' }
Plug 'junegunn/fzf.vim', { 'commit': '811b860' }
Plug 'pbogut/fzf-mru.vim', { 'commit': 'c0a6bda' }
For the full list of plugins, checkout main vimrc file or use :PlugStatus
command.