Tmux and productivity
The tmux is a terminal multiplexer. It lets you switch easily between several programs in one terminal, detach them (they keep running in the background) and reattach them to a different terminal. So it can gives more flexibility within a terminal, like keep more tabs are open and switch among them quickly.
From my productivity workflow, tmux has a key role. I use it when I login to a server to perform some maintenance action, but I also when I start a Neovim and start to work. Until now, when I open a project, I manually started tmux windows and tabs and started commands there, like:
- Open Neovim and restore previous session
- Start backend
- Start frontend
- Start database
Once, I started tinkering and I wondered that I could automate it or not. Does tmux can be controlled from script? How should I do it? In this article I cover these questions.
Why do I automate things?
It is a solid question, specially in this case when to bring up this environment does not takes too much time. Like creating a new user or grant authorization for a product. But why in IT do we automate things?
Does it worth to put more hours of efforts to automate something that can be done under minutes? My answer is: YES! Why? Let’s talk about what do we win with automation:
- Process is more consistent: a script always do that it is programmed. It never forget or miss any action that is there.
- Documentation: a good automation is a very good documentation. How many times I was in situation that an old guy were doing the process manually for decades, without writing it down. Then the old guys gone and well, it is a really “fucked up” situation because the “show must go on”.
To automate things, let it be in a development environment, or be it on a server, is a key motivation, at least to myself. If anybody wants to have a sustainable IT, then automating things must have a priority.
Scripting with tmux
Tmux is basically a command link interface. Before any script, let’s see how would I do that by commands on a simple example.
# Start a new tmux session in the background with "blog" name
tmux new-session -d -t blog
# Create a new window with "editor" name
tmux new-window -t blog -n editor
# Open Neovim in that window
# 1. Go to work directory
# 2. Open Neovim
# 3. Restore session (command "s" in Neovim)
tmux send-keys -t blog:1 "cd /home/ati/blog_content/" C-m
tmux send-keys -t blog:1 "nvim" C-m
tmux send-keys -t blog:1 "s" C-m
# Split the window and start hugo server
tmux split-window -h -t blog:1
tmux send-keys -t blog:1 "hugo -D --bind=0.0.0.0 --baseURL=http://atihome.lan"
# Attach into the session
tmux a -t blog
But I want to avoid to write script for every single project that I have, so
instead I wrote a script that read a YAML (using yq) file from the project
root directory and create environment based on that.
The full script can be found in this gist: tmux-profile.sh
How is this working?
The script can be started on two different way:
- If parameter is passed, which must be a directory, it goes there and
looking for
.tmux-profile.yamlfile. - If called without parameter, then
fdutility listing all directories and display it infzfwindow. So project directory can be searched.
And from this moment the script goes further on one way:
- Read the YAML file. To parse YAML file, it uses the
yqutility. - Create proper windows and execute commands in the window.
- Note: a change directory command are executed in every window, so the commands can assume that they are in the project’s directory.
And basically that’s all, it is not that overcomplicated.
I show and example YAML file from one of my project:
session_name: athena
windows:
- name: editor
splits:
- commands:
- nvim
- s
- name: db
splits:
- commands:
- podman volume inspect dev-db-vol || podman volume create dev-db-vol
- |
podman run --rm --name dev-db \
-p 5432:5432 \
-e POSTGRES_PASSWORD=abcd \
-e POSTGRES_USER=utest \
-e POSTGRES_DB=test_db \
-e PGDATA=/var/lib/postgresql/data/pgdata \
-v dev-db-vol:/var/lib/postgresql/data \
--userns=keep-id \
docker.io/library/postgres
- commands:
- sleep 10
- podman exec -it dev-db bash
- export PGPASSWORD=abcd
- psql -U utest -d test_db
type: h
- name: server
splits:
- commands:
- sleep 10
- |
go run . \
serve \
--config \
configs/onlyati-athena.yaml \
--log-level debug \
--server-hostname 0.0.0.0 \
--cors-origins '*'
- commands:
- cd website
- npx vite --port 3000 --host 0.0.0.0
type: h
The commands in windows are executed parallel using pipeline. So the sleep commands are put there to wait the database are up and initialized.
See it in action
🎬 Play me!
Final words
I find tmux a very useful program, and it just makes it more grate that it can be easily scripted in bash script. Advantage of bash that it is really on every machine, thus the dependency for this script is really low.
