When it comes to my developer toolset, I like solutions that I can easily understand and tweak. I guess I’m not the only one. I believe that for a lot of people one of the (many) reasons to join the Ruby bandwagon was that you could do virtually everything without a big, fat IDE, that I never know what it’s doing and how. Just your editor and console. First class citizens.

Struggling with finding Senior Ruby developers? - Show your job post here and reach thousands of developers quickly.

Boring introduction

And I still like this kind of workflows. But, let’s be honest, sometimes there are moments, that you wish your tools did a little better when it comes to helping you with tedious tasks.

You can often find an editor plugin that does what you need. And it’s fine. But sometimes you’re like: do I really need to pull another plugin to do this simple thing?. After all, we’re programmers. We can program basically anything, why not our developer environments.

It seems to me, that often what we need are just the proper building blocks.

tmux is one of such building blocks, that can really help you a lot when it comes to automating your developer workflows. Generally one could say it’s a screen on steroids. It let’s you manage terminal sessions and interact with them programmatically.

On Mac OS you can install it with brew install tmux.

It’s a powerful and versatile tool - a lot of people us it for a lot of different things. I’m neither a heavy, nor a longtime tmux user, but let me present a couple problems where it paid off for me. I’m not encouraging you to adopt “full tmux workflow”, whathever that means, but maybe it’ll show how you can easily solve a specific problem yourself.

Solution 1 - launching gazzillion servers locally

Sometimes you work on a project with one rails server and probably a background worker. Not a big deal to launch when you start your work in the morning. But what when you have 10 microservices? You don’t want to do it by hand.

Of course, there are so many tools that can help you with that, pow, puma-dev, docker, whatever. But you don’t always wanna learn and employ a new tool to do a dead simple thing like launching a server. You wanna keep it simple, and not spend a day on configuring a specific solution.

How did tmux help me with that? I simply wanted something that will just “prepare” terminal windows for me, so that I can later interact with them in a “typical” way, like ^C to kill the process, then press up and enter to start it again, rather that running the processes in the background, etc. I often want to tweak my workflow step by step, rather than by revolution.

So tmux has this nice command “send-keys”. What does it do? Yup, it sends a particular key sequence to the terminal session. As simple as that. Let’s have a look at this sample tmux invocation:

tmux \
  new-session -s your_session_name                                       \; \
  send-keys -t :0 "cd ~/app_1" Enter "bundle exec rails s -p 5000" Enter \; \
  new-window                                                             \; \
  send-keys -t :1 "cd ~/app_2" Enter "bundle exec rails s -p 6000" Enter \; \
  new-window                                                             \; \
  send-keys -t :2 "cd ~/app_3" Enter "bundle exec rails s -p 7000" Enter 

One tmux binary invocation let’s you specify multiple tmux-commands:

  • new-session starts a new session with given name, that you can later identify it with in -t options
  • new-window opens another window within a session. They’re identified with numbers like this: -t :1
  • send-keys - tmux tries to make it easy for you and guess whether you meant a key or literal sequence: Enter does what you’d (not) expect

Basic usage

Once you launch your script, you can:

  • press ctrl+b followed by window number to switch window
  • press ctrl+b followed by d to detach from the session - now everything is in the background (ctrl+b prefixes all tmux hotkeys; people often sometimes it to ctrl+a)
  • run tmux a to attach to it again. Add -t your_session_name if you have more of them
  • run tmux kill-session -t your_session_name to quit everything. Same as exiting every terminal window one by one.
  • run tmux ls to see all the sessions

Tweaking the config

You’ll find your tmux config in ~/.tmux.conf:

  • remap alt+left & alt+right to easily switch to the left/right window:
bind -n M-Left select-window -p
bind -n M-Right select-window -n
  • start window numbers from 1 to match keyboard ordering
set -g base-index 1
set-window-option -g pane-base-index 1

More goodies

  • give your windows specific names to show up on the status bar: just do this new-window -n app_1_bg_worker in the launching snippet
  • start the session initially detached: new-session -d
  • put it all in a handy script in you PATH - so that you can later just type myproject start|quit from any directory
  • if you use iterm on Mac OS, you can enable tmux integration and attach to the session like this: tmux -CC a - this way your tmux session will appear as a normal iterm session and you can use all your hotkeys as you normally do

Working with multiple repos?

By the way, if you sometimes happen to work with multiple repos, you might wanna have a look at this shell-one-liner: multigit - it lets you run (git) commands on all “sibling” repos.

Solution 2 - spinning off builds/tests in a terminal session

…to come in another blogpost - but the building blocks are the same, no additional magic needed :)