Alex Selimov


My nvim/tmux workflow

Published: Mar 04, 2024

At my previous employment I was forced to use a windows system. Although not ideal, I was able to continue using my Linux terminal workflows by heavily utilizing Windows Subsystem for Linux. As part of this I had to get comfortable with integrating tmux into my workflow as I didn’t care to learn the Windows Terminal options for terminal multiplexing. I don’t need tmux quite as much anymore since my current employer allows me run Linux on my development machine, but I still use it when remoting into my work desktop via ssh. Hopefully this can be of use in improving the efficiency of others that depend on terminal based workflows.

tmux setup

As a note, all of the below settings should be added to your ~/.tmux.conf if you are interested in using them.

Some nice settings

I wanted to start out with some nice settings for tmux that I generally like. First and foremost I remap the send-prefix key.

unbind C-b
set -g prefix C-p
bind C-p send-prefix

I also rebind the pane splitting commands:

bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
unbind '"'
unbind %

And finally, I enable vim key binds in scrolling mode

set-window-option -g mode-keys vi
bind-key -T copy-mode-vi v send -X begin-selection
bind-key -T copy-mode-vi V send -X select-line
bind-key -T copy-mode-vi y send -X copy-pipe-and-cancel 'xclip -in -selection clipboard'

Integration with neovim

Here by integration, I mean seamlessly transitioning between tmux and neovim splits. To do this we want tmux to figure out if the current tmux split contains a vim process (and potential vim splits). We then can then bind the same motion keys in tmux and nvim so that we can seamlessly move from a tmux split into a vim split and back all using the same keys! We can do this with the following code snippet in our ~/.tmux.conf.

is_vim="ps -o state= -o comm= -t '#{pane_tty}' \
    | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|n?vim?x?)(diff)?$'"

bind-key -n C-h  if-shell  "$is_vim"  "send-keys C-h"  "select-pane -L"
bind-key -n C-j   if-shell  "$is_vim"  "send-keys C-j"   "select-pane -D"
bind-key -n C-k  if-shell  "$is_vim"  "send-keys C-k"  "select-pane -U"
bind-key -n C-l   if-shell  "$is_vim"  "send-keys C-l"   "select-pane -R"
bind-key -n C-\   if-shell  "$is_vim"  "send-keys C-\\"  "select-pane -l"

is_vim defines a command to determine whether the current pane is running vim. If so, we send the key codes directly to vim, otherwise process the key binding with tmux. For this case we utilize <C-{vim_keys}> for motion to make things easy.

Neovim setup

Now we need to make sure we can go from a neovim split smoothly to a tmux split. To do this we utilize the christoomey/vim-tmux-navigator plugin. First add it to your plugin manager,

Lazy.nvim:

require("lazy").setup({
    "christoomey/vim-tmux-navigator"
})

or Vim-plug:

call plug#begin('~/.vim/plugged')
    Plug 'christoomey/vim-tmux-navigator'
call plug#end()

and that’s it! It should automatically add the <C-{vim_keys}> for motion and handle moving out of vim splits to tmux panes. Hopefully this is useful to someone else!

Bonus

Gruvbox is everywhere even tmux gets a nice theme.