rs-mrxvt/README.md

16 KiB
Executable File

rs-mrxvt — The Modernized Power-User Terminal

rs-mrxvt is a modernized, distro-agnostic terminal emulator inspired by the classic mrxvt. It is written in Rust and pairs 2008-era "tabbed power" with 2020s reliability.

The MVP ships with four rendering backends and an auto-detect chain that falls back gracefully:

  1. wgpu (Vulkan) — full GPU acceleration on modern hardware
  2. wgpu (GL) — older GPUs that lack Vulkan drivers
  3. softbuffer + tiny-skia — CPU rasterizer, the modern VESA mode
  4. TUI (ratatui + crossterm) — always available, even over SSH

The default build uses the TUI backend (zero system graphics deps). Build with --features gpu to enable the wgpu and softbuffer backends.

Three opt-in feature flags extend the terminal in orthogonal directions:

  • --features lua — dynamic, programmable configuration via config.lua
  • --features images — Sixel + iTerm2 inline image protocol support
  • --features gpu — wgpu + softbuffer rendering backends

✨ Features (implemented)

Core (always available)

  • Multi-tab PTY — each tab runs an independent shell via portable-pty, with VT emulation by alacritty_terminal. Tabs are managed by a single TerminalManager; one tab's heavy output never blocks the others.
  • Copy & paste — click-drag select (line-based, like xterm/Ghostty), double-click word, triple-click line. Ctrl+Shift+C/Ctrl+Shift+V, classic Ctrl+Ins/Shift+Ins, middle-click pastes the primary selection, right-click pastes the clipboard, and copy-on-select follows the classic mrxvt/xterm behavior. Copies are also mirrored to the host terminal via OSC 52, so copy works over SSH.
  • Scrollback navigation — mouse wheel, Shift+PageUp/PageDown, Shift+Home/End, and palette commands. The wheel does the right thing on the alternate screen (sends arrows to less/vim); typing snaps the viewport back to the live bottom.
  • Mouse reporting — DECSET 9/1000/1002/1003/1006 tracked from the child program; SGR-1006 and legacy X11 encodings both supported. Shift+click always bypasses reporting so you can select text in vim/htop.
  • OSC 52 in and out — programs (tmux, nvim) can set the clipboard; reads are off by default for security (clipboard.osc52_read = true to enable).
  • Dynamic tab titles — OSC 0/2 title sequences from the child rename the tab (e.g. vim shows the filename, ssh shows the host).
  • Login shells by default — default-shell tabs run as login shells (classic mrxvt loginShell: True), so /etc/profile and its distro GUI-session exports (D-Bus, flatpak/snap paths) reach every app you launch — including GUI apps.
  • Input Broadcasting — the classic mrxvt killer feature. Toggle broadcast-to-all with Ctrl+Shift+I, or broadcast only to tagged groups via --tag on the CLI or the ToggleBroadcastGroup command in the palette.
  • Command Palette — Ctrl+Shift+P opens a fuzzy-search overlay over every command. Inspired by Warp / VS Code.
  • Backend auto-detect — --backend auto (default) probes wgpu → soft → TUI. Override with --backend {tui,wgpu,soft} if needed.
  • Classic mrxvt CLI flags — -e CMD, -t TITLE, -n N, -j (broadcast), -g TAG (group tag), -c PATH (config), -d DIR (cwd), -b {auto,tui,wgpu,soft} (backend).
  • TOML config — ~/.config/rs-mrxvt/config.toml with profiles, macros, keybindings, and transparency settings.
  • Per-tab fading — inactive tabs dim smoothly via a lerp animation.
  • Stress-tested — 200+ unit + integration tests, plus a 50-instance Python stress harness that broadcasts a marker to 50 shells in ~30ms.

With --features lua

  • Dynamic Lua config — config.lua with full logic: conditionals, env vars, time-of-day themes, programmable macros. Auto-detected by file extension; force with --config-format lua.
  • Backward-compatible — TOML config still works; pick per file.

With --features gpu

  • wgpu renderer — Vulkan/GL accelerated. Instanced quad pipeline with a glyph atlas texture and WGSL shaders. Renders the full terminal grid (text + colors + tab bar + status bar).
  • softbuffer renderer — CPU rasterizer via tiny-skia + ab_glyph. The modern VESA mode: works on any display server, no GPU driver required.
  • Pseudo-transparency + tinting — classic mrxvt -tint and -sh flags, implemented as a WGSL shader uniform. Configurable via [transparency] in config.
  • Shared glyph cache — ab_glyph rasterizes glyphs on demand; both backends use the same cache.

With --features images

  • iTerm2 inline images — ESC ] 1337 ; File = ... protocol. Display PNG/JPEG/GIF/WebP/BMP inline. Compatible with ranger, neofetch, chafa, viu.
  • Thread-safe image store — images keyed by ID, mutex-protected for concurrent PTY reader + renderer access.

🗺️ Roadmap

Feature Status Notes
Multi-tab PTY ✅ shipped 200+ tests covering routing, broadcasting, EOF
Input broadcasting ✅ shipped Active / All / Group(tag)
Command palette ✅ shipped fuzzy-matcher, Ctrl+Shift+P
Backend auto-detect ✅ shipped wgpu → soft → tui chain
TUI renderer ✅ shipped ratatui + crossterm, distro-agnostic
wgpu renderer ✅ shipped instanced pipeline, glyph atlas, WGSL shaders
softbuffer renderer ✅ shipped tiny-skia + ab_glyph, the VESA mode
Pseudo-transparency ✅ shipped WGSL shader, tint + opacity uniforms
Per-tab fading ✅ shipped lerp animation, configurable speed/amount
Lua config ✅ shipped mlua, dynamic themes, programmable macros
Config hot-reload ✅ shipped Polling watcher, survives bad configs
iTerm2 image protocol ✅ shipped PNG/JPEG/GIF/WebP/BMP inline
Sixel image protocol ✅ shipped Pure-Rust parser, color registers, repeats
Mouse + SGR-1006 ✅ shipped X10/X11/SGR encoders, shift-bypass selection
OSC 8 hyperlinks ✅ shipped Parser + scanner + cell-indexed store
Alt+N / Alt+Arrows ✅ shipped New tab, shuffle forward/back
Alt+Shift+X close ✅ shipped Closes focused tab
Alt+Z zsh tab ✅ shipped Secondary shell on a hotkey
True-color themes ✅ shipped Tokyo Night, Gruvbox, Dracula, Solarized
Multi-distro sysprep ✅ shipped pacman/apt/dnf/zypper/xbps/apk/cast/emerge
Clipboard ✅ shipped Select/copy/paste, OSC 52 mirror, tools+mock
Scrollback navigation ✅ shipped Wheel, Shift+PgUp/PgDn/Home/End, palette cmds
Selection modes ✅ shipped Drag/word/line, copy-on-select, highlight
Tab title sync ✅ shipped OSC 0/2 from child renames the tab
Login shells ✅ shipped GUI-session env reaches apps (mrxvt default)
GUI backend polish 🚧 planned Selection/cursor highlight in wgpu+soft UIs

🚀 Quick start

Build from source (TUI only — default)

# Dependencies: Rust 1.75+ (rustup recommended), and a POSIX shell.
# No system graphics libs required for the TUI backend.

cargo build --release
./target/release/rs-mrxvt

Build with everything

# Install system dev headers first:
#   Debian/Ubuntu: sudo apt install libvulkan-dev libwayland-dev libxkbcommon-dev
#   Arch:          sudo pacman -S vulkan-headers wayland-protocols libxkbcommon
#   Fedora:        sudo dnf install vulkan-headers wayland-devel libxkbcommon-devel
#   SourceMage:    cast vulkan-loader wayland-protocols libxkbcommon

cargo build --release --features gpu,lua,images
./target/release/rs-mrxvt                    # auto-detects best backend
./target/release/rs-mrxvt --backend wgpu     # force wgpu
./target/release/rs-mrxvt --backend soft     # force CPU rasterizer (VESA mode)
./target/release/rs-mrxvt --backend tui      # force TUI
./target/release/rs-mrxvt --config-format lua  # force Lua config

Distro-agnostic install

sudo make install              # installs to /usr/local by default
sudo PREFIX=/usr make install  # installs to /usr

Try it without installing

# 3 tabs, broadcasting on, all tagged "cluster"
./target/release/rs-mrxvt -n 3 -j -g cluster

# With a Lua config that picks theme by time of day
./target/release/rs-mrxvt --features lua -c ~/.config/rs-mrxvt/config.lua

🎹 Keybindings (default)

Shortcut Action
Ctrl+Shift+T / Alt+N New tab (login shell)
Alt+Z New tab running zsh (secondary shell)
Alt+Shift+X Close the currently focused tab
Ctrl+Shift+W Close tab (classic mrxvt binding)
Ctrl+Shift+C / Ctrl+Insert Copy selection to clipboard
Ctrl+Shift+V / Shift+Insert Paste from clipboard
Ctrl+Shift+I Toggle broadcast (all tabs)
Ctrl+Shift+P Open command palette
Ctrl+Tab / Alt+Right Next tab (wraps)
Ctrl+Shift+Tab / Alt+Left Previous tab (wraps)
Alt+1 … Alt+0 Go to tab N (1..10)
Shift+PageUp / Shift+PageDown Scroll scrollback a page
Shift+Home / Shift+End Jump to top / bottom of scrollback

Mouse: drag selects, double-click selects a word, triple-click selects a line, release copies (copy-on-select), middle-click pastes the primary selection, right-click pastes the clipboard, and the wheel scrolls the scrollback (or the alternate-screen program). Shift+click bypasses application mouse reporting so you can always select text.

All bindings are rebindable in config.toml or config.lua.

⚙️ Configuration

Default location: ~/.config/rs-mrxvt/config.toml (or .lua with the lua feature). Override with --config or $MRXVT_CONFIG. See examples/config.toml and examples/config.lua for fully-commented references.

Transparency example (TOML)

[transparency]
enabled = true
tint = "#004080"      # blue tint
opacity = 0.85         # 1.0 = opaque, 0.0 = fully transparent
# background_image = "/path/to/wallpaper.png"

Clipboard

[clipboard]
copy_on_select = true   # selecting text copies it (classic mrxvt/xterm)
osc52 = true            # mirror copies to the host terminal — works over SSH
osc52_read = false      # let programs read the clipboard via OSC 52 (security)
# tool = "xclip"        # force a tool; otherwise auto-detected

rs-mrxvt talks to the system clipboard through the standard tools (xclip/xsel on X11, wl-clipboard on Wayland, pbcopy/pbpaste on macOS, termux-clipboard-* on Android) — no clipboard library is linked. Every copy is additionally emitted as an OSC 52 escape sequence, so the host terminal performs the clipboard write too; over SSH with no local clipboard tool, that mirror is what makes copy work.

Paste sanitation matches mainstream terminals: control characters that could inject escape sequences are stripped, CRLF is normalized to LF, and a single trailing newline is dropped so a paste doesn't auto-submit your command. When the child enabled bracketed paste (DECSET 2004), pastes are wrapped in ESC[200~ … ESC[201~.

Time-based theme (Lua)

local hour = tonumber(os.date("%H"))
local theme = "mrxvt"
if hour >= 20 or hour < 6 then
  theme = "tokyo-night"
end

return {
  ui = { theme = theme },
  terminal = { cols = 120, rows = 40 },
}

🎨 Themes

Built-in true-color themes (set ui.theme in your config):

Theme Style
mrxvt Classic green-on-black (default)
tokyo-night Dark blue, popularized by VS Code
gruvbox Warm retro palette
dracula Dark purple
solarized-dark Solarized Dark
solarized-light Solarized Light

Custom themes can be defined in TOML — see examples/config.toml for the full color list (16 ANSI colors + bg/fg/cursor).

🛠 Troubleshooting

GUI apps refuse to start from a tab (cannot open display, D-Bus errors): default-shell tabs run login shells, which source /etc/profile — that's where distros export the GUI session environment (DBUS_SESSION_BUS_ADDRESS, flatpak/snap paths). If tabs still can't launch GUI apps, rs-mrxvt itself was probably started from a non-graphical context (plain TTY, sudo, a stripped service): the child environment is inherited, so there is no DISPLAY/WAYLAND_DISPLAY to inherit. Start rs-mrxvt from your graphical session, or set the variables yourself. rs-mrxvt logs a warning at spawn when this is the case. If your ~/.bash_profile is noisy, per-profile login_shell = false restores plain non-login shells.

Copy works but paste doesn't (over SSH): paste reads the local system clipboard, which needs a local tool (xclip, xsel, wl-paste). OSC 52 can only write the client's clipboard, not read it synchronously — that's a protocol limit, not a bug.

🧪 Testing

cargo test                            # default suite (~10s, 150+ tests)
cargo test --features lua             # + Lua config tests
cargo test --features images          # + image + Sixel tests
cargo test --features gpu             # + GPU backend tests
cargo test --features lua,images      # everything, 200+ tests
python3 scripts/stress_test.py        # 50-instance broadcast harness

📦 Distribution-agnostic packaging

Three helper scripts make the build pipeline distro-agnostic:

./scripts/sysprep.sh              # install build deps (auto-detects distro)
./scripts/build.sh                # cargo build with feature flags
./install.sh                      # build + install to $PREFIX
./install.sh --sysprep            # sysprep + build + install in one go

sysprep.sh

Detects your distro via /etc/os-release and installs the right packages:

Distro family Package manager
Arch, Manjaro, EndeavourOS, Garuda pacman
Debian, Ubuntu, Pop!_OS, Mint, Kali apt
Fedora, RHEL, Rocky, Alma, CentOS dnf
openSUSE, SLES zypper
Void xbps-install
Alpine apk
NixOS prints shell.nix recipe
SourceMage cast
Gentoo, Funtoo emerge

Flags: --no-rust (skip rustup), --no-gpu (skip GPU headers), --dry-run.

build.sh

Wraps cargo build with feature-flag presets:

./scripts/build.sh                          # release, all features
./scripts/build.sh --debug                  # debug build
./scripts/build.sh --features lua,images    # specific features
./scripts/build.sh --no-features            # bare TUI
./scripts/build.sh --test                   # cargo test
./scripts/build.sh --check                  # cargo check only

install.sh

Builds + copies binary, examples, and (optional) man page / .desktop file into $PREFIX (default /usr/local).

sudo ./install.sh                  # /usr/local
sudo ./install.sh /usr             # /usr
sudo ./install.sh --sysprep        # full pipeline: deps + build + install
sudo ./install.sh --no-features    # TUI-only build (no GPU headers needed)

The Makefile still works for the common cases (make install, make dist, make deb, make rpm).

📜 License

GPL v2 (or later). See LICENSE.

🤝 Contributing

See CONTRIBUTING.md. The wgpu and softbuffer backends are functional but always benefit from optimization work — glyph atlas packing, sub-pixel positioning, and shader effects are good first PRs.