tpane 0.5.0

Configure tmux with Lua.
tpane-0.5.0 is not a library.

tpane

tpane lets you improve your tmux.conf by moving most of your configuration to Lua. It ships with widgets and a plugin system: use widgets to improve your navbar, and plugins to improve your workflow.

Quick start

Install tpane:

curl -fsSL https://raw.githubusercontent.com/phcurado/tpane/main/install.sh | sh

Add this as the last line of ~/.config/tmux/tmux.conf:

run-shell -b 'tpane'

Create ~/.config/tmux/tpane/init.lua:

tpane.use("themes")
tpane.use("vim-navigator")
tpane.use("yank")

tpane.theme("Catppuccin Mocha")

tpane.opt.mouse = true
tpane.opt.history_limit = 5000
tpane.opt.mode_keys = "vi"

tpane.bind("h", tpane.pane.select("left"))
tpane.bind("j", tpane.pane.select("down"))
tpane.bind("k", tpane.pane.select("up"))
tpane.bind("l", tpane.pane.select("right"))

local battery = tpane.widgets.battery({ every = "30s" })

tpane.statusline {
  position = "top",
  left = { tpane.widgets.session },
  right = { battery, tpane.widgets.clock },
}

Install

From crates.io:

cargo install tpane

Or install the latest GitHub release:

curl -fsSL https://raw.githubusercontent.com/phcurado/tpane/main/install.sh | sh

From source:

cargo install --path . --locked --force

Minimal tmux.conf

Only a few settings are necessary to live in tmux.conf file. These are the settings that are good to start with tmux, and tpane will have the runtime config:

set -g default-terminal "xterm-256color"
set -as terminal-features ",xterm-256color:RGB"

set -g base-index 1
set -g pane-base-index 1

set -g status-position top
set -g status-style bg=default

unbind C-b
set -g prefix C-a
bind C-a send-prefix

# Keep this last.
run-shell -b 'tpane'

Config location

tpane loads top-level Lua files from:

~/.config/tmux/tpane

Set TPANE_CONFIG_DIR to use another directory.

Replace tmux config with Lua

Use tpane.opt for tmux options:

tpane.opt.mouse = true
tpane.opt.history_limit = 5000
tpane.opt.mode_keys = "vi"
tpane.opt.renumber_windows = true
tpane.opt.escape_time = 0

tmux has options where you usually add one value without replacing the existing values. In tmux.conf that looks like:

set -ga update-environment TERM
set -ga update-environment TERM_PROGRAM

In Lua, use tpane.append for the same thing:

tpane.append("update_environment", "TERM")
tpane.append("update_environment", "TERM_PROGRAM")

Bind keys with tmux-aware actions:

tpane.bind("h", tpane.pane.select("left"))
tpane.bind("j", tpane.pane.select("down"))
tpane.bind("k", tpane.pane.select("up"))
tpane.bind("l", tpane.pane.select("right"))

tpane.bind("%", tpane.pane.split("right", { cwd = "pane" }))
tpane.bind('"', tpane.pane.split("down", { cwd = "pane" }))

tpane.bind("M-Left", tpane.pane.resize("left", 10), { prefix = false })

If some configuration is not supported by tpane, you can always write it the same way you would in tmux:

tpane.bind("R", "source-file ~/.config/tmux/tmux.conf ; display 'reloaded'")

Status bar and tabs

tpane lets you compose the statusline with widgets. It ships with common widgets, and you can add your own when you need something custom.

tpane.statusline {
  position = "top",
  left = { tpane.widgets.session },
  right = { tpane.widgets.host, tpane.widgets.clock },
}

Built-in widgets:

Widget Description
tpane.widgets.session Current tmux session.
tpane.widgets.host Hostname from tmux.
tpane.widgets.clock Current time, like 14:30.
tpane.widgets.date Current date, like Jun 25.
tpane.widgets.prefix Shows when tmux prefix is active.
tpane.widgets.battery(opts) Battery status with icons. Works on Linux and macOS.
tpane.widgets.player(opts) Current playing track. Uses playerctl, Music, or Spotify.
local battery = tpane.widgets.battery({ every = "30s" })
local player = tpane.widgets.player({ every = "5s" })

tpane.statusline {
  right = { player, battery, tpane.widgets.clock },
}

Custom widgets are just Lua functions:

local cwd = tpane.widget(function(ctx)
  return ctx.pane and ctx.pane.cwd_basename or ""
end)

For widgets that run shell commands, use job. Jobs run in the background and return a handle that widgets can render:

local uptime = tpane.job({ every = "1m", timeout = "5s", cmd = "uptime" })

tpane.statusline {
  right = { uptime },
}

Style tmux window tabs without writing the full tmux format by hand:

tpane.tabline {
  label = "cwd",
  inactive = { fg = "#777777" },
  current = { fg = "#8caaee", bold = true },
}

For lower-level styling, use nested tmux options:

tpane.options {
  status = { style = { bg = "default" } },
  pane = { border = { style = { fg = "#51576d" } } },
}

Plugins

Plugins are referenced from Lua. Built-in plugins load by name:

tpane.use("vim-navigator")
tpane.use("yank")
tpane.use("themes")

The themes plugin bundles the iTerm2 Color Schemes collection:

tpane themes
tpane.use("themes")
tpane.theme("Catppuccin Mocha")

Keep the terminal background behind the status bar:

tpane.theme("Gruvbox Dark", { transparent = true })

Git plugins install when first referenced:

tpane.use("theme", {
  repo = "https://github.com/example/tpane-theme.git",
  branch = "main",
})

You can also reference a path in case the plugin is in a monorepo:

tpane.use("tool", {
  repo = "https://github.com/example/tools.git",
  path = "plugins/tpane-tool",
})

And use the CLI to keep track of your plugins:

tpane plugin status      # show referenced, installed, dirty, and update state
tpane plugin sync        # install/update plugins referenced by Lua config
tpane plugin update      # update all installed plugins
tpane plugin update NAME # update one plugin
tpane plugin clean       # remove installed plugins not referenced by Lua config
tpane plugin list        # list installed git plugins
tpane plugin remove NAME # remove one installed plugin

Reusable panes

Register a pane once, then toggle or expand it from keybinds. Hidden panes keep their process running.

tpane.register_pane("logs", {
  side = "bottom",
  size = "25%",
  command = "tail -f logs/app.log",
})

-- Show/Hide a pane 
tpane.bind("L", function(pane)
  tpane.toggle(pane, "logs")
end)

CLI

tpane          # start or reload the daemon from inside tmux
tpane status   # show load/runtime errors
tpane reload   # reload Lua config
tpane refresh  # reload and rescan panes
tpane doctor   # inspect hidden panes/sessions
tpane update   # update tpane

Full Lua reference: docs/lua-api.md.