Tmux is an awesome terminal multiplexer. Fvwm is a great window manager. Combined they form the general user interface through which I'm working with computers. My "Desktop" basically looks like this: There are a number of virtual desktops, which all feature a set of status applications on the left side of the screen, which give detailed information about what is going on on the system. And then there is usually a terminal, that fills (almost) all of the remaining screen real estate. Typically, each of those terminals contains an instance of tmux.

For me that makes a lot of sense, because a large part of the programs I'm using on a daily basis are terminal-based. And running them in tmux allows for a number of useful things: You can attach to the programs from multiple places; copy data from application to application; don't care if X11 decides to flake out... and more.

With tmux, I've started to organise my terminal sessions way more than I did when I was using GNU screen (basically because with tmux, the sessions are related to each other, because they run within the same server). You might say, what's there to organise? You open a terminal, run the multiplexer and then start a bunch of programs and let the multiplexer... well... multiplex, right?

Wrong. When your system is running for weeks, you tend to accumulate a lot of programs. I know I did when I was running screen. I had one session I did most of my work in. I was working on multiple projects in that session and my windows got seriously mixed up, when I ran into ranges of - say - 20 of them or more. There was no way to remember which window did what.

With tmux that changes.

There is one Server, that runs all sessions (unless you deliberately start a second server - which most people don't do). That has many many advantages: You get to switch from session to session with a simple keystroke. You can share data among all sessions. You can move windows from one session to another. You can... well, let's just say, that there's a lot you can do. There's one downside to all this, though: If the tmux server dies, it dies with all its sessions. That may sound scary, but in all the time I've used tmux, it didn't crash on me. Not even once. I'm feeling quite save, even with a dozen sessions.

Anyway. The workflow I've started to use is to start one session for one job. And let me tell you: that's SO much better, it isn't even funny. On top of that I've got three sessions that get started by default when the tmux server starts. That's one session for email/music/usenet/calendar; one for web-browsing in text-based browsers like w3m; and one for miscellaneous applications, which are a set of free shells by default.

Now, if I want to work on a project, I don't do that in my miscellaneous session. Nope, I'm giving that task its own separate session. No mixing up anymore. To actually handle a lot of sessions, I have done some integration of tmux within fvwm's dynamic menus (even though tmux has quite a decent completion for zsh). I got a "tmux sessions" sub-menu in my main fvwm menu (which I can open by pressing ‘F12’). It's available via a short-cut, namely ‘x’. That means I can quickly get to that menu by hitting "F12 x".

That menu shows the three default sessions, a command to add new sessions and yet another sub-menu which lists other existing sessions (again available via ‘x’ so, "F12 x x" gets me to a list of existing sessions quickly).

All of that looks like this:

fvwm tmux menu

...the existing-sessions sub-menu:

fvwm tmux existing menu

...and finally the new-session dialog:

fvwm tmux new session dialog

Also note the "(attached)" markers, so I can quickly see which session is already attached to by a client from somewhere. The "existing sessions" sub-menu is sorted alphabetically and each session automatically gets its own shortcut, for immediate selection. The whole tmux menu (with its sub-menu) is generated by a fairly simple Perl script, that parses the output of "tmux list-sessions".

Pressing enter when any sessions name is selected (or directly hitting the sessions shortcut-key), fvwm spawns a new terminal, which will then attach to said session. When the new-session dialog is envoked, I'm prompted for a session name. Then a new terminal is started which runs a trivial script, which either attaches to the session (if a session of the given name already exists), or creates a new session by the name and then attaches to it. In short: If I need a new tmux session, I'm hitting "F12 x a" give the name and hit RET.

While this is already quite cool, there is one thing that's annoying: All shells, which tmux starts start out in the directory the tmux server was started in. Which in most cases will be my home-directory. But when I'm working on a project, that project usually resides in a certain directory somewhere on the computer. And it'd be awesome if tmux could spawn all shells (or other programs) in that directory.

As you've guessed, I would not be writing about that if it wasn't possible. I wrote this little shell function I called ‘cdm’ (I actually forgot what I meant by the ‘m’ after the Change-Dir - oh well):

# change to a directory and set up a running tmux session accordingly.

emulate -L zsh
setopt extendedglob
local tmp

if [ -z "${TMUX}" ]; then
    printf 'Not inside of `tmux'\''. Giving up.\n'
    return 1
fi

if [ -n "$1" ]; then
    [ "$1" = . ] && tmp="${PWD}" || tmp="$1"
else
    tmp="${HOME}"
fi

cd "${tmp}"
tmp="${PWD}"
tmux "set-option" "default-path" "${tmp}"
[ -n "${DISPLAY}" ] && tmp=on || tmp=off
tmux "set-option" "set-titles" "${tmp}"
return 0

That function probably works for most bourne-like shells (the ‘emulate’ and ‘setopt’ lines are there to get a predictable zsh environment - for other shells you will need to remove/replace them; also, your shell needs to have support for locally scoped variables). Now after I have started a new session I can do the following to have all new windows in that session start in the directory I gave to ‘cdm’ as its argument:

% cdm ~/src/sys/zsh.git

Need a new shell for project xyz? Hit "C-a c" in the appropriate sessions and be done with it. That's incredibly useful. Trust me. ;)

This is pretty much all about how I'm using tmux with fvwm. But there might still be a few things worth noting about how my tmux setup works. So here goes.

Tmux reads its configuration from ‘~/.tmux.conf’ when the server starts. Not each time you run a client. This is important to remember when you're changing that configuration.

And now here is another important thing: Don't open windows or start sessions from ‘~/.tmux.conf’. Why? Well, two reasons: a) when the server is not running, you couldn't just start tmux with a simple empty session by just calling ‘tmux’. And b) you couldn't re-source ‘~/.tmux.conf’ after you made changes to it, because each time tmux sees a ‘new-session’ command, it runs that command.

"But automatically starting stuff in sessions is awesome!1!!" you scream. Yes, it is. And there is a way out. Here is what I do: I keep all my tmux setup files in ‘~/etc/tmux’. For each session I want to start automatically, I keep a file "session-\.conf" (yes, there's a reason for that - just wait). Then there is a file "\.conf" which is the configuration that puts it all together:

  • it reads the basic configuration from ‘~/.tmux.conf’.
  • it loads all the automatic-session configuration files.

Now, when I want a full-blown tmux server running on a system called ‘bones’, I'm doing this:

tmux -f ~/etc/tmux/bones.conf start-server

I'm doing that in my ‘~/.xinitrc’ file so when I'm starting X11 (and therefore fvwm), I can be sure tmux is there. The cool thing about ‘start-server’ is, that it is a no-operation, when the tmux server is already running.

Now for the separate session configuration files: Say I've closed all applications from a default session. ...the session vanishes. If that happened on purpose, that's quite alright, but if it was an accident: Bummer. With these per-session configs, I can just restart the session again using a script I hacked up: ‘spawn-session.sh’. For example, I can say the following to get the "web" session back running if it got closed accidentially:

% spawn-session.sh web

That's all for now, I guess. I hope, this gave you some ideas of how to integrate tmux into your working environment.

Oh, yeah. If you're interested in my respective setups, try the following links:

Posted Sun 10 Jul 2011 11:44:20 CEST Tags: