Sunday, September 25, 2011

tmux: awesome yet frustrating

So tmux is pretty awesome. You can split a terminal into several windows, and then you can subdivide each window into panes. (A terminology that I rather like.) Here's my config file (~/.tmux.conf):

bind k kill-session

new -s theusual -n tehusual
split-window htop
split-window
clock-mode
setw main-pane-width 55
select-layout -t 0 main-vertical
selectp -t 0

And yeah, that didn't work the first time. There are some things about tmux configuration that are... non-obvious. Let's run through the config, and then I'll detail my issues and what I did to fix them. In the following, I'll be using Emacs notation (i.e. C-x means Ctrl+x, M-x means Alt+x, et cetera.)

bind k kill-session

This one's easy. This binds the tmux kill-session command to C-b k, so that I can exit tmux easily without having to close each pane individually.

new -s theusual -n tehusual

This creates a new session, which is the parent object of windows. That is, one session can have several windows which can in turn have several panes. This session is called "theusual," and it creates a window inside the new session called "tehusual." It was unclear from the documentation whether sessions and windows share a namespace, so I thought it best to differentiate the two.

This is also where I ran into my first problem. Try as I might, tmux would not launch into my new session. Instead, it would create a default session first and put theusual in the background, thus squeezing a couple extra keystrokes out of me in the process.

After an hour of frantic googling, the solution turned out to be to not run "tmux" but instead run "tmux attach". The latter instructs tmux to not create a default session, and instead attach itself to an already running session, the one that had just been created by running .tmux.conf. (Fun fact! You can detach tmux instead of quitting entirely with C-b d.)

split-window htop
split-window
clock-mode

The next three instructions cause tehusual to be split twice so that it now contains three panes: the original pane which is split in twain and then split again. Note that panes are zero-indexed. So pane 0 contains a bash prompt (the default command,) pane 1 contains htop (a rather nice top replacement,) and pane 2 is placed into clock mode.

Here's where I ran into the second and third problems. At first, no panes were being created at all! I was stuck with just one big pane. After a while, I discovered that I did not actually have htop installed. A quick visit to SlackBuilds.org fixed that, but it leads us to an important point. tmux fails silently if the command passed to split-window fails. Silent failure is always a bad design choice, but here again it rears its ugly head.

The last two lines had originally been one: "split-window 'tmux clock-mode'". Well, tmux didn't like that. The solution seemed to be to run split-window on a line by itself, and then switch the newly created pane, which apparently has focus, into clock-mode.

setw main-pane-width 55
select-layout -t 0 main-vertical
selectp -t 0

The last three lines ended up being the least trouble.

Let's do the second line first. A window can be given various layouts which automatically reposition panes. I chose "main-vertical," which rearranges panes into one main pane and one or more baby panes. The "-t 0" option simply specifies window 0 (aka tehusual).

Going backwards, the first line sets a window option that specifies the main pane in the main-vertical layout should be 55 in width; a number I arrived at after experimentation.

Finally, the last line selects pane 0 as the pane having focus. Fun facts! You can switch pane focus with C-b o and rotate panes with C-b C-o. That is, the contents of pane 1 go to pane 0, the contents of pane 2 go to pane 1, and the contents of pane 0 go to pane 2. It's a nice quick way to give htop more real estate when I need to fiddle with it.

And there you have it. The icing on the cake was to add " [[ $TERM != "screen" ]] && tmux attach && exit" to my .bashrc file. This checks to see if my current terminal is already tmux (tmux terminals identify themselves as screen, presumably for interoperability with GNU screen.) Then it executes "tmux attach" and then exits.

And yes, I know it's silly to run konsole now, but I haven't gotten around to configuring xterm.