/rmuxinator

tmux session configuration utility

Primary LanguageRustMIT LicenseMIT

rmuxinator

Screenshot

What is this?

This project aims to be a successor to tmuxinator, which allows users to define tmux project profiles (e.g. open two windows, split each into three panes and run a series of commands in each). It is written in Rust and will be more dependable (config is typechecked where possible) and simpler to install. It's also a great excuse for me to learn more about Rust, its ecosystem and compiling/distributing binaries for various platforms.

How does it work?

  • install tmux (>= 2.8), rust and cargo
  • build and run with: cargo build && ./target/debug/rmuxinator start Example.toml

Documentation

Project Config

Projects are defined using toml.

For example:

layout = "main-horizontal"
name = "example"
pane_name_user_option = "custom_pane_title"
start_directory = "/home/peter/projects/vim"

[[hooks]]
  command = "run-shell \"tmux display-message 'Hi from pane-focus-in hook!'\""
  name = "pane-focus-in"

[[windows]]
  layout = "tiled"
  name = "one"
  start_directory = "/home/peter/projects/sample-project"

  [[windows.panes]]
  commands = ["echo pane-one"]
  name = "Work"

  [[windows.panes]]
  commands = ["echo pane-two"]
  name = "Music"
  start_directory = "/home/peter/projects/rmuxinator/src"

  [[windows.panes]]
  commands = ["echo pane-three"]
  name = "RSS"

  [[windows.panes]]
  commands = ["echo hi one", "echo intermediate one", "echo bye one"]

[[windows]]
  name = "two"
  start_directory = "/home/peter/projects/sample-project"

  [[windows.panes]]
  commands = ["echo pane-one"]

  [[windows.panes]]
  commands = ["echo pane-two"]
  start_directory = "/home/peter/projects/rmuxinator/src"

  [[windows.panes]]
  commands = ["echo pane-three"]

  [[windows.panes]]
  commands = ["echo hi one", "echo intermediate one", "echo bye one"]

Configuration Options

Optional attributes will be noted below.

Project
  • name (string)
  • windows (array; see dedicated entry)
Optional
  • hooks (array; see dedicated entry)
  • layout (string; preset tmux layouts: "even-horizontal", "even-vertical", "main-horizontal", "main-vertical", "tiled")
  • pane_name_user_option (string; must have matching entry in .tmux.conf (e.g. set -g pane-border-format "#{@custom_pane_title}")
  • start_directory (string)
Hooks
  • command (string; must use tmux's run_shell; see tmux docs)
  • name (string; must match existing tmux hook (e.g. after-select-pane); see tmux docs)
Windows
  • panes (array; see dedicated entry)
Optional
  • layout (string; preset tmux layouts: "even-horizontal", "even-vertical", "main-horizontal", "main-vertical", "tiled")
  • name (string)
  • start_directory (string)
Panes
  • commands (array of strings)
Optional
  • name (string)
  • start_directory (string)

Commands

debug

Print the tmux commands that would be used to start and configure a tmux session using a path to a project config file: rmuxinator debug Example.toml

start

Start a tmux session using a path to a project config file: rmuxinator start Example.toml

Known Issues and Workarounds

Indexes

rmuxinator currently assumes that both base-index and pane-base-index are 0. This will be handled programatically in a future release, but for the time being, it can be worked around by either removing overrides from .tmux.conf or by adding the following:

set -g base-index 0
set -g pane-base-index 0

Status

This project is currently a proof of concept and I'll be duplicating tmuxinator features and adding additional improvements as I can find time. Right now, it's capable of:

  • parsing a TOML project config file
  • starting a named tmux session
  • setting a default layout for project windows
  • setting the default working directory
  • creating windows
  • setting cwd for windows
  • setting window layout
  • creating panes
  • setting cwd for panes
  • setting a pane title using a "user option" (requires >= tmux 3.0a and related pane-border-format config option)
  • running pane commands
  • wiring up optional tmux event hooks/callbacks

Still TODO:

  • Consider building up and executing a single script (a la tmuxinator) instead of shelling out many times
  • Support custom layouts?
  • Break lib into component files (Config, CliArgs, etc.)
  • Do we need custom hooks, like tmuxinator uses for pre_window, project_start, etc.? I was hoping to leverage tmux's hooks and save the trouble, but the mapping is not 1:1 and users could have to result to hacks like having hooks remove themselves in order to prevent duplicate events.
  • CliArgs.project_name should change to reflect that it's a file path
  • Looks like format doesn't consume values, so refs aren't (always?) necessary
  • Use feature detection to conditionally apply/opt out of certain features (user options)
  • Integration tests which verify compound/derived values (e.g. start_directory)
  • Integration tests which verify calls to tmux?
  • Handle shell failures -- tmux kill-window was failing silently
  • Can commands can all be moved into structs and computed up front? This might require writing a custom Serde deserializer for the Config type.
  • Select window on attach (can this be handled by a pre-existing hook?)
  • Attach if session exists instead of creating sesssion
  • Search for project config file on disk (XDG_CONFIG?) instead of parsing config (I'm not convinced this is necessary)
  • Other CLI commands? (stop session, create/edit/delete project)
  • Use named args in calls to format! where possible
  • Cut v0.0.1 release and publish binaries

Platforms

Here are the platforms rmuxinator is known to work on:

  • x86_64 GNU/Linux
  • x86_64 GNU/Linux (Windows Subshell)
  • armv6l GNU/Linux (RPi Zero; I was able to successfully cross-compile from Debian x86_64 => armv6l using the arm-linux-gnueabihf linker provided in the raspberrypi/tools repository. The Debian package did not work; I was able to compile successfully, but the program segfaulted immediately when executed.)

Resources