Ditch VSCode for neovim
Tags: vim, vscode, rust, python
Published: 2020-09-19 18:03:20

I found myself in the past always reaching for VSCode when I start working on a new project, or a code base I am not really familiar with.  Simply because of the intellisense that is built into it!  I am always frustrated with how slow it is, and how inflexible the terminal is with my work flow.  So here is what I have done to ditch VSCode completely.

![Image](https://dev-to-uploads.s3.amazonaws.com/i/5r1io48zt902dy8bwonq.png)

## Setup neovim
First lets setup neovim to use a very similar LSP engine.  In this post we are going to use [coc](https://github.com/neoclide/coc.nvim)

### Requirements
#### All of these should be installed with your OS package manager
1. [neovim](https://neovim.io/)
2. [git](https://git-scm.com/download/)
3. [tmux](https://github.com/tmux/tmux)
4. [alacritty](https://github.com/alacritty/alacritty)

#### Tools
1. [vim-plug](https://github.com/junegunn/vim-plug)
2. [gitmux](https://github.com/arl/gitmux) (save to PATH `/usr/local/bin`)

#### Font
1. [JetBrains Mono](https://www.jetbrains.com/lp/mono/)

### init.vim
Lets create an `init.vim` file.  For linux and OSX this file is should be saved here `~/.config/nvim/init.vim`

Add this snippet to `init.vim`
```vim
"------------------------------------------------
" Plugins START
call plug#begin()
  Plug 'airblade/vim-gitgutter'
  Plug 'cespare/vim-toml'
  Plug 'editorconfig/editorconfig-vim'
  Plug 'itchyny/lightline.vim'
  Plug 'junegunn/vim-easy-align'
  Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
  Plug 'junegunn/fzf.vim'
  Plug 'mengelbrecht/lightline-bufferline'
  Plug 'lifepillar/vim-gruvbox8'
  Plug 'neoclide/coc.nvim', {'branch': 'release'}
  Plug 'tpope/vim-commentary'
call plug#end()
" Plugins END
"------------------------------------------------

"------------------------------------------------
" Settings START
let mapleader = "\<Space>"
filetype plugin on
set completeopt=menuone
set mouse=a
set nobackup
set nocompatible
set noswapfile
set nowritebackup
set number
set signcolumn=yes
set title
set wrap
setlocal wrap
" Settings END
"------------------------------------------------

"------------------------------------------------
" persist START
set undofile " Maintain undo history between sessions
set undodir=~/.vim/undodir

" Persist cursor
autocmd BufReadPost *
  \ if line("'\"") >= 1 && line("'\"") <= line("$") && &ft !~# 'commit'
  \ |   exe "normal! g`\""
  \ | endif
" persist END
"------------------------------------------------

"------------------------------------------------
" Theme START
syntax on
set termguicolors
colorscheme gruvbox8
set background=dark
set cursorline
set hidden
set cmdheight=1
set laststatus=2

let g:gruvbox_transp_bg = 1
let g:gruvbox_italicize_strings = 0

set list
set listchars=tab:»·,trail:·

" let buffers be clickable
let g:lightline#bufferline#clickable=1
let g:lightline#bufferline#shorten_path=1
let g:lightline#bufferline#min_buffer_count=1

let g:lightline = {
\  'colorscheme': 'jellybeans',
\  'active': {
\    'left': [ [], [], [ 'relativepath' ] ],
\    'right': [ [], [], [ 'lineinfo', 'percent' ] ]
\  },
\  'inactive': {
\    'left': [ [], [], [ 'relativepath' ] ],
\    'right': [ [], [], [ 'lineinfo', 'percent' ] ]
\  },
\  'subseparator': {
\    'left': '', 'right': ''
\  },
\  'tabline': {
\    'left': [ ['buffers'] ],
\    'right': [ [] ]
\  },
\  'tabline_separator': {
\    'left': "", 'right': ""
\  },
\  'tabline_subseparator': {
\    'left': "", 'right': ""
\  },
\  'component_expand': {
\    'buffers': 'lightline#bufferline#buffers'
\  },
\  'component_raw': {
\    'buffers': 1
\  },
\  'component_type': {
\    'buffers': 'tabsel'
\  }
\}

" Theme END
"------------------------------------------------

"------------------------------------------------
" Remaps START
" Align GitHub-flavored Markdown tables
au FileType markdown vmap <Leader><Bslash> :EasyAlign*<Bar><Enter>

" Toggle between buffers
nmap <Leader>bn :bn<CR>
nmap <Leader>bp :bp<CR>
nnoremap <C-p> :Rg<Cr>
nnoremap <C-e> :Files<Cr>
nmap <Leader>bl :Buffers<CR>
nmap <Leader>g :GFiles<CR>
nmap <Leader>e :Files<CR>
nmap <Leader>p :Rg<CR>
nmap <Leader>g? :GFiles?<CR>
nmap <Leader>h :History<CR>
" Remaps END
"------------------------------------------------

"------------------------------------------------
" Coc START
" Having longer updatetime (default is 4000 ms = 4 s) leads to noticeable
" delays and poor user experience.
set updatetime=300

" Don't pass messages to |ins-completion-menu|.
set shortmess+=c

" Use tab for trigger completion with characters ahead and navigate.
" NOTE: Use command ':verbose imap <tab>' to make sure tab is not mapped by
" other plugin before putting this into your config.
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

" Use <c-space> to trigger completion.
if has('nvim')
  inoremap <silent><expr> <c-space> coc#refresh()
else
  inoremap <silent><expr> <c-@> coc#refresh()
endif

" Use <cr> to confirm completion, `<C-g>u` means break undo chain at current
" position. Coc only does snippet and additional edit on confirm.
" <cr> could be remapped by other vim plugin, try `:verbose imap <CR>`.
if exists('*complete_info')
  inoremap <expr> <cr> complete_info()["selected"] != "-1" ? "\<C-y>" : "\<C-g>u\<CR>"
else
  inoremap <expr> <cr> pumvisible() ? "\<C-y>" : "\<C-g>u\<CR>"
endif

" Use `[g` and `]g` to navigate diagnostics
" Use `:CocDiagnostics` to get all diagnostics of current buffer in location list.
nmap <silent> [g <Plug>(coc-diagnostic-prev)
nmap <silent> ]g <Plug>(coc-diagnostic-next)

" GoTo code navigation.
nmap <silent> gd <Plug>(coc-definition)
nmap <silent> gy <Plug>(coc-type-definition)
nmap <silent> gi <Plug>(coc-implementation)
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 CocActionAsync('doHover')
  endif
endfunction

" Highlight the symbol and its references when holding the cursor.
autocmd CursorHold * silent call CocActionAsync('highlight')

" Symbol renaming.
nmap <leader>rn <Plug>(coc-rename)

" Formatting selected code.
xmap <leader>f  <Plug>(coc-format-selected)
nmap <leader>f  <Plug>(coc-format-selected)

augroup mygroup
  autocmd!
  " Setup formatexpr specified filetype(s).
  autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected')
  " Update signature help on jump placeholder.
  autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp')
augroup end

" Remap keys for applying codeAction to the current buffer.
nmap <leader>ga  <Plug>(coc-codeaction)
" Apply AutoFix to problem on the current line.
nmap <leader>qf  <Plug>(coc-fix-current)

" Add `:Format` command to format current buffer.
command! -nargs=0 Format :call CocAction('format')

" Add `:Fold` command to fold current buffer.
command! -nargs=? Fold :call     CocAction('fold', <f-args>)

" Add `:OR` command for organize imports of the current buffer.
command! -nargs=0 OR   :call     CocAction('runCommand', 'editor.action.organizeImport')

" Mappings for CoCList
" Show all diagnostics.
nnoremap <silent><nowait> <space>a  :<C-u>CocList diagnostics<cr>
" Show commands.
nnoremap <silent><nowait> <space>c  :<C-u>CocList commands<cr>
" Find symbol of current document.
nnoremap <silent><nowait> <space>o  :<C-u>CocList outline<cr>
" Search workspace symbols.
nnoremap <silent><nowait> <space>s  :<C-u>CocList -I symbols<cr>
" Do default action for next item.
nnoremap <silent><nowait> <space>j  :<C-u>CocNext<CR>
" Do default action for previous item.
nnoremap <silent><nowait> <space>k  :<C-u>CocPrev<CR>
```
I know there is a lot here but this gets everything we need to be like vscode.

### tmux.conf
For linux and OSX create `~/.tmux.conf`

```conf
# Scroll up with mouse
set-option -g mouse on
set -g set-clipboard on

# Scrollback buffer
set -g history-limit 1000

# tmux display things in 256 colors
set-option -g default-terminal "xterm-256color"
set-option -g terminal-overrides "xterm-256color"

# allow for navigating between words with option
set-window-option -g xterm-keys on

# command delay? We don't want that, make it short
set -g escape-time 10

# Allow the arrow key to be used immediately after changing windows
set-option -g repeat-time 0

# Set window notifications
set -g monitor-activity on
set -g visual-activity on

# Update files on focus (using for vim)
set -g focus-events on

# Status update interval
set -g status-interval 1

# Reduce time to wait for Escape key. You'll want this for neovim.
set-option escape-time 40

# Option to clear histroy
bind -n C-k clear-history
bind-key -n C-l send-keys 'C-l'
bind-key R switch-client -r

######### DISPLAY ##########
set -g renumber-windows on    # renumber windows when a window is closed

######### THEME  ##########
set -g status-bg colour237
set -g status-fg colour246
set-option -g pane-active-border-style fg=colour239
set-option -g pane-border-style fg=colour237
set -g mode-style fg=colour235,bg=colour66
set-option -g message-style bg=colour66,fg=colour235

set-option -g status-justify "left"
set-option -g status-left-style none
set-option -g status-left-length "80"
set-option -g status-right-style none
set-option -g status-right-length "80"

set-option -g status-right '#(gitmux -cfg ~/.gitmux.conf "#{pane_current_path}") %H:%M:%S '
set-window-option -g window-status-separator " "
set-window-option -g window-status-current-format "#[fg=colour66]#W"
set-window-option -g window-status-format "#W"

# Allow us to reload our Tmux configuration while
# using Tmux
bind r source-file ~/.tmux.conf \; display "Reloaded!"

if "test ! -d ~/.tmux/plugins/tpm" \
   "run 'git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm && ~/.tmux/plugins/tpm/bin/install_plugins'"

set -g @plugin 'casonadams/tmux-vi-navigation'
set -g @yank_selection 'clipboard'
set -g @yank_selection_mouse 'clipboard'

run -b '~/.tmux/plugins/tpm/tpm'
```
To install plugins while in `tmux` session `ctrl+b I`

### alacritty.yml
Linux and OSX save this file to `~/.config/alacritty/alacritty.yml`

```yml
env:
  TERM: xterm-256color

window:
  dimensions:
    columns: 0
    lines: 0
  padding:
    x: 0
    y: 0

  # Spread additional padding evenly around the terminal content.
  dynamic_padding: true
  decorations: full
  startup_mode: Windowed

scrolling:
  history: 10000
  multiplier: 3

# Font configuration (changes require restart)
font:
  # Normal (roman) font face
  normal:
    family: "JetBrains Mono"
    style: Regular
  size: 10.0
  offset:
    x: 0
    y: 0
  glyph_offset:
    x: 0
    y: 0

# If `true`, bold text is drawn using the bright color variants.
draw_bold_text_with_bright_colors: true

# Colors (Gruvbox dark)
colors:
  primary:
    hard contrast: background = '0x1d2021'
    background: "0x282828"
    soft contrast: background = '0x32302f'
    foreground: "0xebdbb2"

  # Normal colors
  normal:
    black: "0x282828"
    red: "0xcc241d"
    green: "0x98971a"
    yellow: "0xd79921"
    blue: "0x458588"
    magenta: "0xb16286"
    cyan: "0x689d6a"
    white: "0xa89984"

  # Bright colors
  bright:
    black: "0x928374"
    red: "0xfb4934"
    green: "0xb8bb26"
    yellow: "0xfabd2f"
    blue: "0x83a598"
    magenta: "0xd3869b"
    cyan: "0x8ec07c"
    white: "0xebdbb2"

mouse:
  hide_when_typing: false

selection:
  semantic_escape_chars: ',│`|:"'' ()[]{}<>'
  save_to_clipboard: false

cursor:
  style: Block
  unfocused_hollow: true

# Live config reload (changes require restart)
live_config_reload: true
```

### gitmux.conf
Linux and OSX save to ~/.gitmux.conf

```conf
tmux:
  symbols:
    branch: ''
    hashprefix: ':'
    ahead: ↑·
    behind: ↓·
    staged: '● '
    conflict: '✖ '
    modified: '✚ '
    untracked: '… '
    stashed: '⚑ '
    clean: ✔
  styles:
    state: '#[fg=red]'
    branch: '#[fg=colour246]'
    remote: '#[fg=cyan]'
    staged: '#[fg=green]'
    conflict: '#[fg=red]'
    modified: '#[fg=red]'
    untracked: '#[fg=magenta]'
    stashed: '#[fg=cyan]'
    clean: '#[fg=green]'
  layout: [branch, '']
  options:
    branch_max_len: 0
```

## Install
run this command in the terminal to install plugins `nvim +'PlugInstall' +qa --headless`

## Using
Change Dir to project. Open a file to edit `nvim file`
`coc-vim` will prompt to install pugins for the lanugage of choice.

## Some Navigation tips
| cmd              | Description         |
| :--------------- | :------------------ |
|  `gd`            | Go to Definition    |
|  `gy`            | Type Definition     |
|  `gi`            | Implentation        |
|  `gr`            | Show References     |
|  `rn`            | Rename              |
|  `Space qf`      | Quick fix           |
|  `Shift K`       | Show Hover          |
|  `Space bl`      | Show Buffers        |
|  `Space e`       | Show Files          |
|  `Space p`       | Fuzzy find          |
|  `ctrl+b \`      | Split pane horz 25% |
|  `ctrl+b h`      | Jump to pane left   |
|  `ctrl+b j`      | Jump to pane down   |
|  `ctrl+b k`      | Jump to pane up     |
|  `ctrl+b l`      | Jump to pane right  |