My Tmux and Neovim workflow.

My Tmux and Neovim workflow.

I’ve been using Tmux and Neovim lately for some of my development work and found it to be quite good.

In this post, I’ll show you how I use this system.

Tmux session scripts

I have a directory in my XDG_CONFIG_HOME called scripts. This directory is in my $PATH and contains all my scripts.

I name all my tmux scripts tmux-sessionname where sessionname is replaced with the name of the session that I’m activating.

For example, I have a script called tmux-simpledjango that will activate a session so that I can work on my simple-django project.

To run a script, I have a simple bash function in my bashrc called workon.

Here’s what it looks like:

workon () {
    tmux-$1
}

Simple enough eh? If I type workon simpledjango at the terminal, it will execute the tmux-simpledjango script.

The actual tmux script contains the following:

#!/bin/bash

SESSION_NAME=simpledjango
PROJECT_PATH='~/projects/simple-django'

tmux has-session -t $SESSION_NAME 2>/dev/null

if [ $? != 0 ]
then
    tmux new-session -s $SESSION_NAME -n editor -d
    tmux send-keys -t $SESSION_NAME "cd $PROJECT_PATH" C-m
    tmux send-keys -t $SESSION_NAME "source venv/bin/activate" C-m
    tmux send-keys -t $SESSION_NAME "$EDITOR ." C-m
    tmux split-window -v -p 30 -t $SESSION_NAME
    tmux split-pane -h -t $SESSION_NAME:1.2
    tmux send-keys -t $SESSION_NAME:1.2 "cd $PROJECT_PATH" C-m
    tmux send-keys -t $SESSION_NAME:1.2 "source venv/bin/activate" C-m
    tmux send-keys -t $SESSION_NAME:1.2 "python manage.py runserver_plus"
    tmux send-keys -t $SESSION_NAME:1.3 "cd $PROJECT_PATH" C-m
    tmux send-keys -t $SESSION_NAME:1.3 "source venv/bin/activate" C-m
    tmux send-keys -t $SESSION_NAME:1.3 "npm start"
    tmux new-window -n files -t $SESSION_NAME
    tmux new-window -n console -t $SESSION_NAME
    tmux new-window -n services -t $SESSION_NAME
    tmux send-keys -t $SESSION_NAME:2 "cd $PROJECT_PATH" C-m
    tmux send-keys -t $SESSION_NAME:2 "source venv/bin/activate" C-m
    tmux send-keys -t $SESSION_NAME:2 "ranger ." C-m
    tmux send-keys -t $SESSION_NAME:3 "cd $PROJECT_PATH" C-m
    tmux send-keys -t $SESSION_NAME:3 "source venv/bin/activate" C-m
    tmux send-keys -t $SESSION_NAME:4 "cd $PROJECT_PATH" C-m
    tmux send-keys -t $SESSION_NAME:4 "source venv/bin/activate" C-m
    tmux send-keys -t $SESSION_NAME:4 "docker-compose up -d"
    tmux select-pane -t $SESSION_NAME:1.1
fi

tmux attach -t $SESSION_NAME

Notice that I also use ranger to manage files.

Using a simple command, I can get this whole session up in seconds and start hacking right away.

Using tmux-resurrect

If you’re a heavy tmux user, then tmux-resurrect is a must have.

This plugin saves your session so that you can easily recover them even after killing your tmux server, such as after rebooting.

I also have the tmux-continuum plugin that periodically saves the session using resurrect because without it, you’ll have to manually save the session using C-prefix C-S.

Since I use Linux, I also have a systemd service that will autostart tmux whenever I login.

To do that, just place the following in a file called tmux.service inside your $XDG_CONFIG_HOME/systemd/user directory:

[Unit]
Description=Start tmux in detached session

[Service]
Type=forking
ExecStart=/usr/bin/tmux new-session -s default -d
ExecStop=/usr/bin/tmux kill-session -t default

[Install]
WantedBy=default.target

Then enable it with systemctl --user enable tmux.

With this, whenever I reboot or turn on my computer, tmux will start and all my previous sessions will be restored ready to be hacked on.

Minimalistic Neovim

When it comes to Neovim, some configurations can become really crazy.

I take a minimalistic approach myself and only use plugins that I need while relying on external Unix programs to do stuff that Vim doesn’t do out of the box.

Here’s my list of plugins:

  • Plug ’tpope/vim-projectionist'
  • Plug ’tpope/vim-commentary'
  • Plug ‘sheerun/vim-polyglot’
  • Plug ‘ap/vim-css-color’
  • Plug ‘alvan/vim-closetag’
  • Plug ‘vim-scripts/loremipsum’
  • Plug ‘psliwka/vim-smoothie’
  • Plug ‘sirver/UltiSnips’
  • Plug ‘airblade/vim-rooter’
  • Plug ’editorconfig/editorconfig-vim'
  • Plug ’tpope/vim-eunuch'

The reason why I don’t use LSP and other IDE-like plugins is because they all suck.

What do I mean?

Well, if you install Coc for example, you’ll have to configure keybindings for many of its features. Some keybindings will also conflict with default ones. You also have to configure it using json, which is another file that you have to maintain.

I can’t possible remember 1000 keybindings so I simply don’t use that stuff.

Personally, I think if you need IDE features, then go get yourself a JetBrains license because Vim is only a text editor.

Besides, most of the time you don’t actually need IDE features. These features are mostly good during large refactorings or when you need to browse complex external framework code.

For general purpose editing and reading, Vim works fine out of the box.

The most important thing is to make sure you grok vi before reaching out for plugins.

Finding files with Vim

Instead of using plugins like Fzf, I rely on wildmenu, path, find, and vimgrep.

Some people claim that this is too slow but being slow is actually better sometimes.

By using these tools, you’ll be forced to memorize the project structure, which will help you be more productive while working on this project in the long-term.

Code quality

For formatting code, I just use command line tools because I found that configuring formatprg can get too complicated. For example with Python, I want to run isort then black but I’d rather just do those at the terminal instead of messing around with formatprg.

formatprg would be more useful if you could provide it with files instead of stdout.

For linting, I use makeprg which populates the quickfix list when there are errors, which makes it easy for me to browse through and fix them.

Setting up makeprg is a simple matter of creating ftplugins for the file types and then setting makeprg to the linter you want to use. For Python it’s usually flake8 and for Javascript it’s eslint for example.

Using Vim for what it is

Like I said earlier, Vim is a text editor. Some people manage to configure it like an IDE but even then, it’s not as good as an IDE.

I don’t see the point in spending months configuring something to do something it was not meant to do. Then having to maintain that configuration so that it doesn’t break.

The reason I use Vim is so that I can code on my weak Thinkpad T450 laptop sometimes. Most of my coding is done using PyCharm on a desktop.

I also use Vim when I find myself becoming lazy or dumb. IDEs do many things for you and this might ruin your skills. By using Vim, you’ll be forced to master the basics and really memorize stuff instead on relying on software to do everything for you.

That said, I’m happy with my experience so far and will continue using this setup whenever I need a minimalistic development environment.