Hazard

Putting the Space in Workspace April 15, 2018

I use my terminal as an IDE, largely thanks to Tmux. I spin up sessions for the API, the client front-end, and any other codebases I happen to be working in, as well as a session for tracking to do’s and ideas.

I launch a session using a script I call zmux. If given a session name, zmux attaches to the session. If given a directory, zmux launches a new session and looks for a .tmuxrc file in the directory that it can source to set up the session, allowing me to easily spin up a workspace and daemon processes for a project. This is especially useful for projects I haven’t touched in years. My typical .tmuxrc file looks like this:

rename-session api

rename-window main
send "vim" C-m
split-window -h
resize-pane -x 80

new-window -t 8 -n tools
send "vim +'tab all' .vimlocal .snippets" C-m

new-window -t 9 -n daemons
send "./server.sh" C-m

I created a Tmux binding to switch between sessions on partial session name matches:

unbind t; bind t command-prompt -p "session" "run-shell \"find-tmux-session %%\""

Each Tmux session has its own arrangement of windows and panes that varies by project, but I tend to arrange processes by the frequency with which I use them. Window 1 has Vim and a shell. Window 9 has server daemons. I name windows deliberately, rather than letting them auto-name based on the running process, which makes it easier to refer to them in scripts. If I spend much time in a pane that shares a window with other panes, I’ll maximize it with prefix z. I have one window of tools that’s useful in several different projects, so I link it to multiple sessions with Tmux’s link-window.

Tmux’s hierarchy of panes, windows, and sessions evokes a sense of moving in three dimensions. Changing sessions feels like moving up and down, while windows orient left and right. Zooming panes adds another dimension.

Within a Tmux pane, I spend more time in Vim than anywhere else, and Vim adds two more navigable dimensions: splits and tabs. I use splits rarely, usually only to see code side-by-side, and then only briefly. I don’t use splits for organizing open buffers. For that, I use tabs. I often arrange tabs such that code higher in the stack is further left. Sometimes that means having multiple tabs open to different places in a single file. With tabs arranged this way, moving up and down in the stack is as easy as gt and gT, which can supply a small bit of sanity in tricky legacy code.

In all, I count five dimensions or degrees of freedom for organizing my view of all the code I work in on a daily basis:

Architecting my workspace this way gives me a very kinesthetic sense of navigating code and processes. I have at least twenty different terminals going at any given moment, and it could easily feel like a confusing maze, but a few specific keystrokes take me anywhere I want, up or down, left or right, in any of the five dimensions listed above. I’ve never felt lost in what could easily be a fun-house of terminal windows that all look alike. (I’ve seen developers working solely in iTerm tabs who suddenly realize they just restarted the wrong server.) Once, a coworker told me he marveled to watch me work so quickly in so many different windows. I’d never thought about it. It felt natural.

I haven’t used IDEs or other GUI editors much, and while I’m missing some terrific features, I always feel claustrophobic having no more than splits and tabs, or having to close the current workspace to open a new one. I’ll use an IDE for a specific problem, but Tmux and Vim have become by all-purpose tools of choice.

Appendix

My zmux script:

#!/bin/bash

if [ -n "$1" ] && [ -n "$(tmux list-session | cut -d':' -f1 | grep "^$1\$")" ]; then
  tmux -2 attach -t $1
elif cd $1; then
  if [ -e ".tmuxrc" ]; then
    tmux -2 new \; source-file `pwd`/.tmuxrc \; attach
  else
    tmux -2 new \; attach
  fi
else
  echo "'$1' directory or session does not exist"
  exit 1
fi

A simple find-tmux-session script:

#!/bin/bash

session=$(tmux list-sessions | cut -d':' -f1 | grep "^$1" | head -1)
tmux switch-client -t $session