Replacing Tmux with Neovim

Posted on Mon 27 March 2017 in Neovim

While I have tried to use my window manager i3 for creating workspaces for development workflow, I just have not been able to find a completely comfortable solution. There is something about switching between terminals and vim through i3 that I did not find as convenient as my tmux setup so I have stuck with tmux for a long time.

I've been a big fan of tmux in my development workflow for years, it's been great for moving between the editor and terminal. While I understand there are many other features of tmux, my typical use case was only to use the windows and panes and take advantage of the numbered windows to switch between tasks. Usually my tmux workflow will involve three windows:

  1. Vim.
  2. Terminal sessions for running development servers and other necessary services. Usually this window was used for any service that I will be switching to frequently for debugging info or logs, occasionally on big projects with a lot of services running this will be expanded into another window if I am on my laptop and run out of room to be able to view everything I need.
  3. One more terminal session for adding and committing code via git. For some reason I just really liked having a separate window for this and the tmux hotkeys make it easy to switch between windows.

When I switched to neovim recently my use of tmux changed. First, there was an annoying little bug with neovim and tmux which caused changing between splits very annoying. Then I started using neovim's terminal emulator which really changed the way tmux was integrated with my workflow. Opening a terminal as a buffer in neovim became the new standard. While the setup was not perfect tmux was being used less as I used neovim more.

My current neovim setup looks like this: Neovim

On the bottom right is an example of how the terminal integrates seemlessly into neovim splits.

Optimizations

Change the hotkey to get out of insert mode. By default the hotkey to enter normal mode is Ctr+\ Ctr+n. I changed that to 'jj' with the following code in my .config/nvim/init.vim. Note: I used jj as opposed to escape to not create issues when opening a nvim window inside of a neovim terminal, such as doing a git commit.

tnoremap jj <C-\><C-n>

Automatically enter insert mode when a terminal is selected

:au BufEnter * if &buftype == 'terminal' | :startinsert | endif

Use fzf to search buffers for easy file and terminal switching

function! s:buflist()
  redir => ls
  silent ls
  redir END
  return split(ls, '\n')
endfunction

function! s:bufopen(e)
  execute 'buffer' matchstr(a:e, '^[ 0-9]*')
endfunction

nnoremap <silent> <Leader>b :call fzf#run({
\   'source':  reverse(<sid>buflist()),
\   'sink':    function('<sid>bufopen'),
\   'options': '+m',
\   'down':    len(<sid>buflist()) + 2
\ })<CR>

Rename buffers for easier searching. By default the terminal buffer titles will be named in a way that does not easily allow you to search for them by name (example: term://.//15645:/usr/bin/zsh). There are a couple ways to get over this, you can invoke the terminal command with a comment to create a logical name:

:term zsh \# PythonDevServer
:terminal zsh \# PythonDevServer

Alternatively you can rename the buffer with the :file command

:file PythonDevServer

I prefer using the :term zsh \# foo option as it allows me to easily see the buffer is a terminal as the name will read term://.//15645:/zsh # PythonDevServer

This allows me to open the fzf search with b and just search for anything in the name of the terminal to switch to that buffer.