Learn-Vim/ch21_vimrc.md

388 lines
14 KiB
Markdown
Raw Normal View History

# Ch21. Vimrc
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
In the previous chapters, you learned how to use Vim. In this chapter, you will learn how to orgnize and configure vimrc.
2020-11-13 15:20:23 +00:00
## How Vim Finds Vimrc
2021-01-12 15:13:41 +00:00
The conventional wisdom for vimrc is to add a `.vimrc` dotfile in the root directory (`~/.vimrc`).
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
Behind the scene, Vim looks at multiple places for a vimrc file. Here are the places that Vim checks:
2020-11-13 15:20:23 +00:00
- `$VIMINIT`
- `$HOME/.vimrc`
- `$HOME/.vim/vimrc`
2020-11-13 17:36:22 +00:00
- `$EXINIT`
2020-11-13 15:20:23 +00:00
- `$HOME/.exrc`
- `$HOME/.vim/exrc`
- `$VIMRUNTIME/default.vim`
2021-01-12 15:13:41 +00:00
When you start Vim, it will check the above seven locations in that order for a vimrc file. The first vimrc file found will be used and the rest is ignored. First Vim will look for a `$VIMINIT`. If there is nothing there, Vim will check for `$HOME/.vimrc`. If there is nothing there, Vim will check for `$HOME/.vim/vimrc`. If Vim finds it, it will stop looking and use `$HOME/.vim/vimrc`. Let's break down what each path means.
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
The first, `$VIMINIT`, is an environment variable. By default it is undefined. If you want to use `~/dotfiles/hellovim` as your `$VIMINIT` value, you can create an environment variable containing the path of that vimrc. After you run `export VIMINIT='let $MYVIMRC="$HOME/dotfiles/hellovim" | source $MYVIMRC'`, Vim will now use `~/.dotfiles/hellovim` as your vimrc file.
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
The second, `$HOME/.vimrc`, is the conventional path for many Vim users. `$HOME` in most cases is your root directory (`~`). If you have a `~/.vimrc` file, Vim will use this as your vimrc file.
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
The third, `$HOME/.vim/vimrc`, is located inside the `~/.vim` directory. You might have the `~/.vim` directory already for your plugins, custom scripts, or View files. Note that there is no dot in vimrc file name (`$HOME/.vim/.vimrc` won't work, but `$HOME/.vim/vimrc` will).
The fourth, `$EXINIT` works similar to `$VIMINIT`.
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
The fifth and sixth, `$HOME/.exrc` and `$HOME/.vim/exrc` work also similar to `$HOME/.vimrc` and `$HOME/.vim/vimrc`.
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
The seventh, `$VIMRUNTIME/defaults.vim` is the default vimrc that comes with your Vim build. In my case, I have Vim 8.2 installed using Homebrew, so my path is (`/usr/local/share/vim/vim82`). If Vim does not find any of the previous six vimrc files, it will use this file.
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
For the remaining of this chapter, I am assuming that the vimrc uses the `~/.vimrc` path.
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
## What To Put In My Vimrc?
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
A question I asked when I started to use Vim seriously was, "What should I put in my vimrc?"
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
The answer is, "anything you want". The temptation to copy-paste other people's vimrc is real, but you should resist it. If you insist to use someone else's vimrc, make sure that you know what it does, why and how s/he uses it, and most importantly, if it is relevant to you. Everyone has a different coding style. The person you copy it from might have a different workflow from you.
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
## Basic Vimrc Content
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
In the nutshell, a vimrc is a collection of:
- Plugins
- Settings
- Custom Functions
- Custom Commands
- Mappings
There are other things not mentioned above,but in general, this covers most use cases.
### Plugins
2020-11-13 15:20:23 +00:00
In the previous chapters, I have ocassionally mentioned different plugins, like [fzf.vim](https://github.com/junegunn/fzf.vim), [vim-mundo](https://github.com/simnalamburt/vim-mundo), and [vim-fugitive](https://github.com/tpope/vim-fugitive).
2021-01-12 15:13:41 +00:00
Ten years ago, managing plugins was a nightmare. However, with the rise of modern plugin managers, installing plugins can now be done in seconds. I am currently using [vim-plug](https://github.com/junegunn/vim-plug) as my plugin manager, so I will use it in this section. The concept should be similar with other popular plugin managers. I would strongly recommend you to check out different ones, such as:
2020-11-13 15:20:23 +00:00
- [vundle.vim](https://github.com/VundleVim/Vundle.vim)
- [vim-pathogen](https://github.com/tpope/vim-pathogen)
- [dein.vim](https://github.com/Shougo/dein.vim)
2021-01-12 15:13:41 +00:00
There are more plugin managers than the ones listed above, feel free to look around. To install vim-plug, if you have a Unix machine, run:
2020-11-13 15:20:23 +00:00
```
curl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
```
To add new plugins, drop your plugin names (`Plug 'github-username/repository-name'`) between the `call plug#begin()` and the `call plug#end()` lines. So if you want to install `emmet-vim` and `nerdtree`, put the following snippet down in your vimrc:
```
call plug#begin('~/.vim/plugged')
Plug 'mattn/emmet-vim'
Plug 'preservim/nerdtree'
call plug#end()
```
Save the changes, source it (`:source %`), and run `:PlugInstall` to install them.
In the future if you need to remove unused plugins, you just need to remove the plugin names from the `call` block, save and source, and run the `:PlugClean` command to remove it from your machine.
2021-01-12 15:13:41 +00:00
Vim 8 has its own built-in package managers. You can check out `:h packages` for more information. In the next chapter, I will show you how to use it.
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
### Settings
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
It is common to see a lot of `set` options in any vimrc. If you run the set command from the Command-line mode, it is not permanent. You will lose it when you close Vim. For example, instead of running `:set relativenumber number` from the Command-line mode each time you run Vim, you could just put these inside vimrc:
2020-11-13 15:20:23 +00:00
```
set relativenumber
set number
```
2021-01-12 15:13:41 +00:00
You can also put them as a one-liner:
2020-11-13 15:20:23 +00:00
```
set relativenumber number
```
2021-01-12 15:13:41 +00:00
Some settings require you to pass it a value, like `set tabstop=2`.
You can also use a `let` instead of `set` (make sure to prepend it with `&`). With `let`, you can use an expression as a value. For example, to set the `dictionary` option to a path only if the path exists:
```
let s:english_dict = "/usr/share/dict/words"
if filereadable(s:english_dict)
let &dictionary=s:english_dict
endif
```
You will learn about Vimscript assignments and conditionals in later chapters.
For a list of all possible options in Vim, check out `:h E355`.
### Custom Functions
Vimrc is a good place for custom functions. You will learn how to write your own Vimscript functions in a later chapter.
### Custom Commands
You can create a custom Command-line command with `command`.
To create a basic command `GimmeDate` to display today's date:
```
:command! GimmeDate echo call("strftime", ["%F"])
```
When you run `:GimmeDate`, Vim will display a date like "2021-01-1".
To create a basic command with an input, you can use `<args>`. If you want to pass to `GimmeDate` a specific time/date format:
```
:command! GimmeDate echo call("strftime", [<args>])
:GimmeDate "%F"
" 2020-01-01
:GimmeDate "%H:%M"
" 11:30
```
If you want to restrict the number of arguments, you can pass it `-nargs` flag. Use `-nargs=0` to pass no argument, `-nargs=1` to pass one argument, `-nargs=+` to pass at least one argument, `-nargs=*` to pass any number of arguments, and `-nargs=?` to pass 0 or one arguments. If you want to pass nth argument, use `-nargs=n` (where `n` is any integer).
`<args>` has two variants: `<f-args>` and `<q-args>`. The former is used to pass arguments to Vimscript functions. The latter is used to automatically convert user input to strings.
Using `args`:
```
:command! -nargs=1 Hello echo "Hello " . <args>
:Hello "Iggy"
" returns 'Hello Iggy'
:Hello Iggy
" Undefined variable error
```
Using `q-args`:
```
:command! -nargs=1 Hello echo "Hello " . <q-args>
:Hello Iggy
" returns 'Hello Iggy'
```
Using `f-args`:
```
:function! PrintHello(person1, person2)
: echo "Hello " . a:person1 . " and " . a:person2
:endfunction
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
:command! -nargs=* Hello call PrintHello(<f-args>)
:Hello Iggy1 Iggy2
" returns "Hello Iggy1 and Iggy2"
```
To learn more, check out `:h command` and `:args`.
### Mappings
If you find yourself repeatedly performing the same complex task, it is a good indicator that you should create a mapping for that task.
For example, I have these two mappings in my vimrc:
```
nnoremap <silent> <C-f> :GFiles<CR>
nnoremap <Leader>tn :call ToggleNumber()<CR>
```
On the first one, I map `Ctrl-F` to [fzf.vim](https://github.com/junegunn/fzf.vim) plugin's `:Gfiles` command (quickly search for Git files). On the second one, I map `<Leader>tn` to call a custom function `ToggleNumber` (toggles `norelativenumber` and `relativenumber` options). The `Ctrl-F` mapping overwrites Vim's native page scroll. Your mapping will overwrite Vim controls if they collide. Because I almost never used that feature, I decided that it is safe to overwrite it.
By the way, I personally like to use `<space>` as the leader key instead of Vim's default. To change your leader key, add this in your vimrc:
2020-11-13 15:20:23 +00:00
```
let mapleader = "\<space>"
```
2021-01-12 15:13:41 +00:00
The `nnoremap` command indicates three things:
- `map` is the map command.
- `n` represents the Normal mode.
- `nore` means non-recursive.
You could have used `nmap` instead of `nnoremap`. However, it is a good practice to use the non-recursive variant to avoid inifinite loop. Here's what could happen if you don't map non-recursively. Suppose you want to add a mapping to `B` to add a semi-colon at the end of the line, then go back one WORD (recall that `B` n Vim is a Normal-mode navigation key to go backward one WORD).
```
nmap B A;<esc>B
```
When you press `B`... oh no! Vim adds `;` uncontrollably (interrupt it with `Ctrl-C`). Why did that happen? Because in the mapping `A;<esc>B`, the `B` does not refer to Vim's native `B` function (go back one WORD), but it refers to the mapped function. What you have is actually this:
```
A;<esc>A;<esc>A;<esc>A;esc>...
```
To solve this problem, you need to add a non-recursive map:
```
nnoremap B A;<esc>B
```
Now try calling `B` again. This time it successfully adds a `;` at the end of the line and go back one WORD. The `B` in this mapping represents Vim's original `B` functionality.
2020-11-13 15:20:23 +00:00
I find myself opening, editing, and sourcing vimrc quite often in the middle of a programming session. Having to manually find vimrc can take a lot of effort, so I add this in my vimrc:
```
nnoremap <Leader>ve :vsplit $MYVIMRC<CR>
nnoremap <Leader>vs :source $MYVIMRC<CR>
```
2021-01-12 15:13:41 +00:00
Vim has the environment variable `$MYVIMRC` to store the path of your vimrc. I can quickly open my vimrc file with `<Leader>ve` ("vimrc edit" mnemonic) and source it with `<leader>vs` ("vimrc source" mnemonic).
Vim has different maps for different modes. If you want to create a map for Insert mode to exit Insert mode when you press `jk`:
```
inoremap jk <esc>
```
The other map modes are: `map` (Normal, Visual, Select, and Operator-pending), `vmap` (Visual and Select), `smap` (Select), `xmap` (Visual), `omap` (Operator-pending), `map!` (Insert and Command-line), `lmap` (Insert, Command-line, Lang-arg), `cmap` (Command-line), and `tmap` (terminal-job). I won't cover them in detail here. To learn more, check out `:h map.txt`.
Create a mapping that's most intuitive, consistent, and easy-to-remember.
2020-11-13 15:20:23 +00:00
## Organizing Vimrc
2021-01-12 15:13:41 +00:00
Over time, your vimrc will grow large and become convoluted. There are two ways to keep your vimrc to look clean:
2020-11-13 15:20:23 +00:00
- Split your vimrc into several files.
2021-01-12 15:13:41 +00:00
- Fold your vimrc file.
2020-11-13 15:20:23 +00:00
### Splitting Your Vimrc
You can split your vimrc to multiple files using Vim's `source` command. This command reads command-line commands from the given file argument.
Let's create a file inside the `~/.vim` directory and name it `/settings` (`~/.vim/settings`). The name itself is arbitrary and you can name it whatever you like.
You are going to split it into three components:
- Third-party plugins (`~/.vim/settings/plugins.vim`).
- General settings (`~/.vim/settings/configs.vim`).
- Key mappings (`~/.vim/settings/mappings.vim`) .
Inside `~/.vimrc`:
```
source $HOME/.vim/settings/plugins.vim
source $HOME/.vim/settings/configs.vim
source $HOME/.vim/settings/mapppings.vim
```
Inside `~/.vim/settings/plugins.vim`:
```
call plug#begin('~/.vim/plugged')
Plug 'mattn/emmet-vim'
Plug 'preservim/nerdtree'
call plug#end()
2021-01-12 15:13:41 +00:00
2020-11-13 15:20:23 +00:00
```
Inside `~/.vim/settings/configs.vim`:
```
2021-01-12 15:13:41 +00:00
set nocompatible
2020-11-13 15:20:23 +00:00
set relativenumber
set number
```
Inside `~/.vim/mappings.vim`:
```
nnoremap <Leader>vs :source $MYVIMRC<CR>
nnoremap <Leader>ve :vsplit $MYVIMRC<CR>
2021-01-12 15:13:41 +00:00
nnoremap <silent> <C-f> :GFiles<CR>
2020-11-13 15:20:23 +00:00
```
Your vimrc should works as usual, but now it is only three lines long!
2021-01-12 15:13:41 +00:00
With this setup, you easily know where to go. If you need to add more mappings, add them to the `/mappings.vim` file. In the future, you can always add more directories as your vimrc grows. For example, to store custom functions like `ToggleNumber`, you can store them inside `/functions.vim`.
2020-11-13 15:20:23 +00:00
### Keeping One Vimrc File
2021-01-12 15:13:41 +00:00
If you prefer to keep one vimrc file to keep it portable, you can use the marker folds to keep it organized. Add this at the top of your vimrc:
2020-11-13 15:20:23 +00:00
```
" setup folds {{{
augroup filetype_vim
autocmd!
autocmd FileType vim setlocal foldmethod=marker
augroup END
" }}}
```
Vim can detect what kind of filetype the current buffer has (`:set filetype?`). If it is a `vim` filetype, you can use a marker fold method. Recall that a marker fold uses `{{{` and `}}}` to indicate the starting and ending folds.
Add `{{{` and `}}}` folds to the rest of your vimrc (don't forget to comment them with `"`):
```
" setup folds {{{
augroup filetype_vim
autocmd!
autocmd FileType vim setlocal foldmethod=marker
augroup END
" }}}
" plugins {{{
call plug#begin('~/.vim/plugged')
Plug 'mattn/emmet-vim'
Plug 'preservim/nerdtree'
call plug#end()
" }}}
" configs {{{
set nocompatible
set relativenumber
set number
" }}}
" mappings {{{
nnoremap <Leader>vs :source $MYVIMRC<CR>
nnoremap <Leader>ve :vsplit $MYVIMRC<CR>
2021-01-12 15:13:41 +00:00
nnoremap <silent> <C-f> :GFiles<CR>
2020-11-13 15:20:23 +00:00
" }}}
```
Your vimrc should look like this:
```
+-- 6 lines: setup folds -----
+-- 6 lines: plugins ---------
+-- 5 lines: configs ---------
2021-01-12 15:13:41 +00:00
+-- 5 lines: mappings --------
2020-11-13 15:20:23 +00:00
```
2020-11-14 20:28:13 +00:00
## Running Vim With Or Without Vimrc And Plugins
2020-11-13 15:20:23 +00:00
2020-11-14 20:28:13 +00:00
If you need to run Vim without both vimrc and plugins, run:
2020-11-13 15:20:23 +00:00
```
vim -u NONE
```
2020-11-14 20:28:13 +00:00
If you need to launch Vim without vimrc but with plugins, run:
2020-11-13 15:20:23 +00:00
```
2020-11-14 20:28:13 +00:00
vim -u NORC
```
If you need to run Vim with vimrc but without plugins, run:
```
vim --noplugin
2020-11-13 15:20:23 +00:00
```
2021-01-12 15:13:41 +00:00
If you need to run Vim with a *different* vimrc, say `~/.vimrc-backup`, run:
2020-11-14 20:28:13 +00:00
```
2021-01-12 15:13:41 +00:00
vim -u ~/.vimrc-backup
2020-11-14 20:28:13 +00:00
```
2020-11-13 15:20:23 +00:00
2020-11-13 15:26:44 +00:00
## Configure Vimrc The Smart Way
2020-11-13 15:20:23 +00:00
2021-01-12 15:13:41 +00:00
Vimrc is an important component of Vim customization. A good way to start building your vimrc is by reading other people's vimrcs and gradually build it over time. The best vimrc is not the one that developer X uses, but the one that is tailored exactly to fit your thinking framework and editing style.