I adopted tmux to my workflow recently and one of the things that I wanted on my workflow was the ability to create tmux sessions for projects that I was working on using a specific layout. Most often I found myself using the following layout:

  • Window 1 (editor)
    • nvim .
  • Window 2 (workspace vertical)
    • Server
    • Random commands workspace.

Creating this tmux session was kind of boring. My flow was something like:

  • cd to the project.
  • Start nvim on the first window.
  • Create a new panel
  • Split the window into two panels.

I thought well, I can optimize that!

First I tried tmuxinator, which is an awesome tool that you can describe a tmux session using yaml. You just need to save a yaml file under .config/tmuxinator/sample.yml, and the configuration looks something like that:

# ~/.config/tmuxinator/sample.yml

name: sample
root: ~/dev/personal/sample

windows:
  - editor:
      layout: main-vertical
      panes:
        - vim
  - server: bundle exec rails s
  - logs: tail -f log/development.log

I started to use it, and I could just execute tmuxinator start sample and everything was setup as I wanted, but one thing that bored me was creating one tmuxinator config per project, and also having to type all the tmuxinator command, needing to remember the name of the project that I wanted to work on my memory sucks!.

So, I got inspiration from tmux sessionizer and gave a try to a way to integrate my tmux workflow with fzf. So I created a base tmuxinator configuration, which is the following:

# ~/.tmuxinator/project.yml

name: project
root: <%= @settings["workspace"] %>

windows:
  - editor: nvim .
  - server:
      layout: main-vertical
      panes:
        -
        -

In this configuration, I just have my default config for every project which is one window with the editor and another with server/workspace panels. This config works for me in 90% of the projects.

Note that on the root I added an erb syntax for passing the project directory.

Using this configuration, I created a new bash command using fzf, that finds all the folders located under ~/dev/noredink (my work dev directory), and ~/dev/personal (my personal dev directory). After that, I piped it to fzf so I could select the project that I wanted to work on.

If in the folder there is a .tmuxinator.yml I use the local config for the project, if not I use the default config and then I create a new tmux session using tmuxinator.

# ~/.local/bin
#!/usr/bin/env bash

if [[ $# -eq 1 ]]; then
    selected=$1
else
    selected=$(find ~/dev/noredink ~/dev/personal -mindepth 1 -maxdepth 1 -type d | fzf)
fi

if [[ -z $selected ]]; then
    exit 0
fi

selected_name=$(basename "$selected" | tr . _)
tmux_config_file="$selected/.tmuxinator.yml"
if [[ -f "$tmux_config_file" ]]; then
  cd $selected
  tmuxinator local
  cd -
else
  tmuxinator start project -n $selected_name workspace=$selected
fi

This is flexible enough to have custom configurations when needed or just use the default one!

I also added .tmuxinator.yml to my ~/.gitignore, so it doesn’t pollute my git projects with tmux configuration files.

# ~/.gitignore
...
.tmuxinator.yml

Finally, I added a keybinding to start the tmux-sessionizer on my tmux config:

# .config/tmux/tmux.conf
...
# Start tmux session on project
bind-key -r f run-shell "tmux neww ~/.local/bin/tmux-sessionizer"

Result:

A video showing  the command being executed, creating a new tmux session