What Is Inside My Vimrc
Tags: vim, vimrc, editor, ide
Published: 2021-09-16 14:55:08

---
title: What Is Inside My Vimrc
published: true
description: What Is Inside My Vimrc
tags: vim, vimrc, editor, ide
//cover_image: https://direct_url_to_image.jpg
---

A vimrc is an important file for us Vim users.

*Edit: My Vimrc has changed since I began writing this article (it is now 7 lines long), but the principle is still the same. If you want to look at the state of the Vimrc at the time I wrote this article, check out [this link](https://github.com/iggredible/dotfiles/tree/691af3370c9914cdbb36f05af57d6c163ef5ed62).*

If you're like me, you probably have spent an ungodly amount of time tinkering with it until it grows massive. At some point, it is a good idea to split your vimrc into multiple parts for maintainability. Plus, if you want to share your vimrc to the world, splitting it into an organized structure will help clarify with other devs who are looking at your vimrc.

In this article, I will share how I organize my vimrc. Everything here is a matter of personal preference. There is no objectively right or wrong way to organize a vimrc. I hope that by sharing what's inside my vimrc, you will gain insight into how you can organize your own vimrc to meet your needs. Don't put down any line in your vimrc that you don't understand.

Lastly, this article makes the assumption that your default vimrc file and Vim files directory are in the root directory, `~/.vimrc` and `~/.vim/`, respectively.

## Source, The Secret Sauce

The secret sauce of a modular vimrc is the `source` Vimrscript command. Think of it like the `require`, `include`, or `import` command.

If you have this inside your `~/.vimrc`:

```
source '~/my-script.vim'
```

Inside `~/my-script.vim`:

```
echo "Hello from outside yo vimrc"
```

The next time you open Vim, it will output "Hello from outside yo vimrc". Great! This is how you can split your vimrc into multiple parts.

## Dotfiles

My Vim configs are stored inside my [dotfiles repository](https://github.com/iggredible/dotfiles) - this way I can access them when I'm away from my computer. So if I have to login from a foreign computer, all I need to do is symlink the Vim files from the dotfiles repository, install the dependencies (I have a script for that too, but that's for another time), and I'm set to go!

## The Structure

This is the structure for my Vim-related files:

```
dotfiles/
├─ vim/
│  ├─ custom-functions/
│  │  ├─ function1.vim
│  │  ├─ function2.vim
│  │  ├─ function-N.vim
│  ├─ custom-plugins/
│  │  ├─ ale.vim
│  │  ├─ fzf.vim
│  │  ├─ plugin-N.vim
│  ├─ main/
│  │  ├─ settings.vim
│  │  ├─ themes.vim
│  │  ├─ keymaps.vim
│  ├─ UltiSnips/
│  │  ├─ javascript.snippets
│  │  ├─ ruby.snippets
│  ├─ vimspector.json
├─ vimrc
```

The important ones are the `vimrc` file and the `vim/` directory.

Note that I name them without the dot (`vimrc` and `vim/` as opposed to `.vimrc` and `.vim/`). This is so that when I clone it, they won't be invisible. It's easier to deal with visible files than invisible ones.

Inside the `vim/` directory, I divide them into multiple sub-directories. The three important ones are:
- `custom-functions/` where I store my own custom functions
- `custom-plugins/` where I store configs specific for Vim plugins
- `main/` where I store the main Vim configurations and basic keymaps

If you notice, I also have a `vimspector.json` file and a `UltiSnips/` directory. I use the [Vimspector](https://github.com/puremourning/vimspector) plugin and it requires a config file. I also use the [ultisnips](https://github.com/SirVer/ultisnips) plugin. It uses`UltiSnips/` directory to store custom snippets. If you don't use any of these plugins, just ignore them.

## Vimrc

The vimrc file is called first whenever you launch Vim. Inside it, we have:

```
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 | source $MYVIMRC
endif

call plug#begin('~/.vim/plugged')
  Plug 'iggredible/totitle-vim'
  Plug 'tpope/vim-sensible'
  Plug 'sjl/badwolf'
  Plug 'itchyny/lightline.vim'
  Plug 'junegunn/fzf.vim'
  Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
  Plug 'ludovicchabant/vim-gutentags'
  Plug 'tomtom/tcomment_vim'
  Plug 'mattn/emmet-vim'
  Plug 'sheerun/vim-polyglot'
  Plug 'tpope/vim-fugitive'
  Plug 'Yggdroot/indentLine'
  Plug 'preservim/nerdtree'
  Plug 'luochen1990/rainbow'
  Plug 'tpope/vim-dispatch'
  Plug 'junegunn/vim-peekaboo'
  Plug 'machakann/vim-sandwich'
  Plug 'simnalamburt/vim-mundo'
  Plug 'tpope/vim-endwise'
  Plug 'tpope/vim-unimpaired'
  Plug 'godlygeek/tabular'
  Plug 'mhinz/vim-signify', { 'branch': 'legacy' }
  Plug 'ryanoasis/vim-devicons'
  Plug 'dense-analysis/ale'
  Plug 'szw/vim-maximizer'
  Plug 't9md/vim-choosewin'
  Plug 'Shougo/unite.vim'
  Plug 'puremourning/vimspector'
  Plug 'SirVer/ultisnips'
  Plug 'honza/vim-snippets'
call plug#end()

let b:fileList = split(globpath('~/.vim/main', '*.vim'), '\n')
let b:fileList += split(globpath('~/.vim/custom-functions', '*.vim'), '\n')
let b:fileList += split(globpath('~/.vim/custom-plugins', '*.vim'), '\n')

for fpath in b:fileList
  exe 'source' fpath
endfor
```

My vimrc is less than 50 lines long, including empty lines. Hey, that's pretty readable! Let's go over what they do.

### Automatically Installing Vim Plug

I use [vim-plug](https://github.com/junegunn/vim-plug) as my plugin manager. The code below checks for the existence of `~/.vim/autoload/plug.vim` when you start Vim. The plugin manager uses that file to read the plugin files. If `plug.vim` doesn't already exist, then it will download the `plug.vim` file and create the `~/.vim/autoload/plug.vim` directory.

```
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 | source $MYVIMRC
endif
```

You can also find the automatic install script above in the [vim-plug tips page](https://github.com/junegunn/vim-plug/wiki/tips#automatic-installation).

I haven't really looked at other plugin managers, but I'm confident that you can pull something similar with other plugin managers.

### Plugins

The next line lists a list of plugins I use:

```
call plug#begin('~/.vim/plugged')
  Plug 'iggredible/totitle-vim'
  Plug 'tpope/vim-sensible'
  Plug 'sjl/badwolf'
  Plug 'itchyny/lightline.vim'
  Plug 'junegunn/fzf.vim'
  Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
  Plug 'ludovicchabant/vim-gutentags'
  Plug 'tomtom/tcomment_vim'
  Plug 'mattn/emmet-vim'
  Plug 'sheerun/vim-polyglot'
  Plug 'tpope/vim-fugitive'
  Plug 'Yggdroot/indentLine'
  Plug 'preservim/nerdtree'
  Plug 'luochen1990/rainbow'
  Plug 'tpope/vim-dispatch'
  Plug 'junegunn/vim-peekaboo'
  Plug 'machakann/vim-sandwich'
  Plug 'simnalamburt/vim-mundo'
  Plug 'tpope/vim-endwise'
  Plug 'tpope/vim-unimpaired'
  Plug 'godlygeek/tabular'
  Plug 'mhinz/vim-signify', { 'branch': 'legacy' }
  Plug 'ryanoasis/vim-devicons'
  Plug 'dense-analysis/ale'
  Plug 'szw/vim-maximizer'
  Plug 't9md/vim-choosewin'
  Plug 'Shougo/unite.vim'
  " Plug 'puremourning/vimspector'
  Plug 'SirVer/ultisnips'
  Plug 'honza/vim-snippets'
call plug#end()
```

This part is totally up to you. Use whatever plugins that *you need*, not what you see other people use.

### Sourcing Stuff

Here's what the next 3 lines look like:
```
let b:fileList = split(globpath('~/.vim/main', '*.vim'), '\n')
let b:fileList += split(globpath('~/.vim/custom-functions', '*.vim'), '\n')
let b:fileList += split(globpath('~/.vim/custom-plugins', '*.vim'), '\n')
```

We are creating an array named `fileList` and appending it with the paths for all the files inside `main/`, `custom-functions/`, and `custom-plugins/`.

Finally, we have this loop. This is where the magic happens.

```
for fpath in b:fileList
  exe 'source' fpath
endfor
```

It iterates through the `fileList` array and calls `source` on each file. This keeps my vimrc to be concise and spark joy :D.

Next, let's explore some contents of my `main/`, `custom-functions/`, and `custom-plugins/`

### the Main Directory

The main directory contains the base vimrc configs that don't depend on any custom plugin.

Inside, I sub-divide them into three files: 
1. `settings.vim`
2. `keymaps.vim`
3. `themes.vim`

### Main Settings

This is what's inside the `settings.vim` file:

```
set clipboard=unnamed
set noswapfile
set relativenumber number
set tabstop=2
set shiftwidth=2
set expandtab
set ignorecase
set smartcase
set hlsearch
set confirm
set hidden
set shortmess-=S

let s:english_dict = "/usr/share/dict/words"

if filereadable(s:english_dict)
  let &dictionary=s:english_dict
endif
```

This file primarily deals with base settings (if you're curious what they do, consult `:help`). The last command with the `english_dict` adds a dictionary autocompletion (`CTRL-X CTRL-K`), if a dictionary exists.

### Main Keymaps

The `keymaps.vim` file contains key mappings independent from plugins. For plugin-specific maps, they are inside `custom-plugins/`.

Inside my `keymaps.vim`, I have:

```
let mapleader = "\<Space>"

nnoremap <Leader>vs :source ~/.vimrc<CR>
nnoremap <Leader>ve :vsplit ~/.vimrc<CR>

nnoremap <Esc><Esc> :noh<Return><Esc>
```

I like to use `Space` as the leader - but you can use whatever leader key you feel comfortable with.

I have three custom maps. The first two, `<Leader>vs` and `<Leader>ve`, are to quickly open  and source (vs mnemonic: Vimrc Source) Vimrc (mnemonics: **V**imrc **E**dit and **V**imrc **Source**). I've used this countless times.

I also have a `<Esc><Esc>` mapped to `:noh` (nohighlight). This is used to remove the highlights after searching for keywords.

### Main Themes

The `themes.vim` file contain configurations for the color schemes and various UI-related settings.

```
silent! colorscheme evening
silent! colorscheme badwolf

highlight CursorColumn guibg=#ecf0c1
highlight CursorLine guibg=#ecf0c1

set termguicolors
set background=dark
```

If you notice, I use *two* color schemes. What's up with that?

[badwolf](https://github.com/sjl/badwolf) is a custom color scheme plugin. When I launch Vim for the first time on a new machine, I won't have the plugins installed yet, using `badwolf` immediately will cause it to fail on that first Vim run. `evening` is a built-in Vim color scheme. By putting `silent! colorscheme evening` followed by `silent! colorscheme badwolf`, if `badwolf` isn't available, it will, in effect, *falls back* to `evening`. `silent!` will also omit the error message (otherwise you'll see an error message when Vim couldn't find `badwolf`)

## Custom Functions

The `custom-functions/` directory is where all the custom functions live. These are user-specific functions. What I need might be different from yours. But I'll go over some of mine anyway. Feel free to take them, modify them, and steal them (I stole two of them somewhere sometime ago :P).

I have four custom functions. Here are some of them.

### Custom Functions to Delete Buffers

```
function! DeleteAllBuffers()
  let l:current_pos = getpos('.')
  execute "%bd | e# | echo 'Buffers Deleted'"
  call setpos('.', l:current_pos)
endfunc

function! DeleteMatchingBuffers(pattern)
    let l:bufferList = filter(range(1, bufnr('$')), 'buflisted(v:val)')
    let l:matchingBuffers = filter(bufferList, 'bufname(v:val) =~ a:pattern')
    if len(l:matchingBuffers) < 1
        echo 'No buffers found matching pattern ' . a:pattern
        return
    endif
    exec 'bd ' . join(l:matchingBuffers, ' ')
endfunction

command! -nargs=1 DelBuf call DeleteMatchingBuffers('<args>')

nnoremap <silent> <Leader>bD :call DeleteAllBuffers()<CR>
nnoremap <silent> <Leader>bd :DelBuf<Space>
```

I won't go into how Vimscript works. If you want to learn Vimscript, check out [my Learn Vim book](https://github.com/iggredible/Learn-Vim) (free to read).

The main point is, I have a target-delete `<Leader>bd` to delete a specific buffer(s) and mass-delete `<Leader>bD` to delete all buffers except the current one. 

After coding for a few hours, my buffer list would usually balloon and get convoluted. I'd need to clear them up.

If you run `<Leader>bD`, it will indiscriminately delete all items in the buffer list (`:ls`).

If you run `<Leader>bd`, it will ask for a pattern. Vim will delete all buffers matching the pattern. So if you have `users_controller.rb`, `packages_controller.rb`, `user_model.rb`, and `package_model.rb` and you enter "controller" as pattern, it will delete the controller buffers and keep the model buffers. 

### Custom Functions to Open Url Under Cursor

```
function! OpenURLUnderCursor()
  let l:uri = expand('<cWORD>')
  silent exec "!open '" . l:uri . "'"
  redraw!
endfunction

nnoremap gx :call OpenURLUnderCursor()<CR>
```

This one is actually a native feature of Vim (NETRW actually - `:help netrw-gx`). By pressing `gx` while your cursor is inside a URL, Vim will open that document. However, in Mac, that behavior doesn't work.

### Custom Functions to Toggle Cursor Display

```
function! ToggleCursor()
  if(&cursorcolumn == 1)
    set nocursorcolumn
  elseif (&cursorcolumn == 0)
    set cursorcolumn
  endif

  if(&cursorline == 1)
    set nocursorline
  elseif (&cursorline == 0)
    set cursorline
  endif
endfunction

nnoremap <leader>tc :call ToggleCursor()<CR>
```

You can toggle the horizontal cursor highlight with `:set cursorline` / `:set nocursorline` and the vertical cursor highlight with `:set cursorcolumn` / `:set nocursorcolumn`. This can be useful if you need a makeshift straight edge.

### Custom Functions to Toggle Numbers

```
function! ToggleNumber()
  if(&relativenumber == 1)
    set norelativenumber
  else
    set relativenumber
  endif
endfunc

nnoremap <leader>tn :call ToggleNumber()<CR>
```

I like using `relativenumber` to see how far apart a text is from the cursor. However, there are times when I need to see the absolute line number instead. This allows me to quickly toggle the number setting.

## Custom Plugins

Finally, the `custom-plugins/` section is where the settings for each plugin is.

Since there are so many of them, I will only cover one or two in this article. If you're curious, feel free to check out my [dotfiles repository](https://github.com/iggredible/dotfiles) and see what else I have.

Inside the `custom-plugins/` directory, I have files named after the plugin itself (you can name them anything you want).

For example, inside `ale.vim` (ale is a linting engine for Vim):

```
" -------------------------
" Configs
" -------------------------

let g:ale_linters = {
      \   'javascript': ['eslint'],
      \   'ruby': ['rubocop'],
      \}

let g:ale_fixers = {
      \   'javascript': ['eslint'],
      \   'ruby': ['rubocop'],
      \}
let g:ale_linters_explicit = 1 " Only run linters named in ale_linters settings.
let g:ale_sign_column_always = 1

" -------------------------
" Keymaps
" -------------------------

nmap <silent> <C-k> <Plug>(ale_previous_wrap)
nmap <silent> <C-j> <Plug>(ale_next_wrap)

nnoremap <Leader>at :ALEToggle<CR>
```

Here, I have [ale](https://github.com/iggredible/dotfiles) configured for Javascript and Ruby (using eslint and rubocop) - because I mainly work with Ruby and Javascript. Finally, I also have some keymaps related to the ale plugin.

Many of the plugins that I use don't need any configurations, like `emmet-vim`, `tcomment_vim`, `vim-sandwich`, etc. You'll find that you don't need as many custom-plugin files as you have plugins installed.

## What Is Next?

This concludes this article. I hope that you learned a thing or two. Make your vimrc uniquely yours. Keep improving everyday.

For max usage, I strongly recommend you reading this in conjunction with my dotfiles article for a complete guide on portability.

If you're still hungry for more, I suggest looking up other people's Vimrcs. Here are a few that I can think of.

## Resources

Some great resources to learn and steal (*cough*) Vimrcs (and dotfiles):
- [amix's vimrc](https://github.com/amix/vimrc)
- [skwp's dotfiles](https://github.com/skwp/dotfiles)
- [mattjmorrison's dotfiles](https://github.com/mattjmorrison/dotfiles)
- [Thougtbot's dotfiles](https://github.com/thoughtbot/dotfiles)
- [Square's dotfiles](https://github.com/square/maximum-awesome)
- [How I increased my productivity using dotfiles [updated]](https://dev.to/mmphego/how-i-increased-my-productivity-using-dotfiles-2f4m)
- [A Good Vimrc](https://dougblack.io/words/a-good-vimrc.html)