Skip to content

roramirez/mmterm

Repository files navigation

mmterm

mmterm icon

A cross-platform, GPU-free terminal emulator written in Rust with vim-style modal input, split panes, and multi-tab sessions.

mmterm demo

Renders entirely via a CPU pixel buffer — no GPU, no OpenGL, no Vulkan.

Features

  • Modal input — Insert, Normal, Visual, and Search modes (vim-style)
  • Split panes — binary-tree layout, horizontal and vertical splits; drag separators or use Ctrl+Shift+Arrow to resize
  • Multi-tab — independent pane trees and font metrics per tab
  • Scrollback search — live match highlighting across 10 000-line buffer; history navigable with ↑/↓, persisted to ~/.config/mmterm/search_history
  • Themes — 10 built-in themes (including ereader, a warm parchment/sepia theme for long sessions); custom themes via ~/.config/mmterm/themes/; each named scope remembers its own theme independently of the global config
  • OSC 8 hyperlinks — clickable URLs rendered in the terminal
  • OSC 52 clipboard sync — copy/paste over SSH without extra tools
  • Focus reporting?1004h/l sends \e[I/\e[O on window, tab, and pane focus changes; neovim autoread and tmux work correctly
  • DEC line drawing — box-drawing characters for ncurses TUI apps (dialog, nmtui, mutt)
  • Pane zoom — full-window focus for the active pane
  • Passthrough modeCtrl+B forwards all keystrokes directly to the PTY, bypassing mmterm shortcuts; useful when running vim, tmux, or other apps that share keybindings; status bar shows INSERT PASS; press Ctrl+B again to exit
  • Session logging — capture PTY output per-pane to ~/.mmterm/ with Ctrl+Shift+L
  • Color emoji — rendered via FreeType CBDT/CBLC
  • Visual bell — BEL (0x07) shows a dot next to the mode badge in the status bar for 150 ms; a 500 ms cooldown prevents spam from tab-completion; an optional screen flash is available via visual_bell = true in [general]
  • Session persistence — tabs, splits, and per-pane CWDs are saved on quit and restored on next launch; a centered dialog asks [s] Save and quit / [q] Quit / [Esc] Cancel; toggle with restore_session in [general]; named scopes (--scope <name>) keep isolated session files and each retain their own theme
  • Command paletteCtrl+Shift+P fuzzy-filter and run any action by name; shows the keyboard shortcut for each entry
  • TUI config editor — edit settings in-process with Ctrl+,
  • Zero-config startup — bundled JetBrains Mono fallback font (regular, bold, italic)

Requirements

  • Rust 1.85+ (edition 2024)
  • Linux (X11 or Wayland) or macOS
  • On Linux: a C toolchain and FreeType headers (libfreetype-dev)

Build

cargo build --release

The binary is at target/release/mmterm.

Install

Linux (x86_64 / aarch64)

Download the prebuilt binary into ~/.local/bin:

sh -c "$(curl -fsSL https://raw.githubusercontent.com/roramirez/mmterm/main/install.sh)"

The script verifies the download's SHA-256 checksum before installing and adds an application-menu entry. If ~/.local/bin is not already on your PATH, the installer adds it to your shell profile (~/.zshrc or ~/.bashrc).

Prefer to read before you run?

curl -fsSL https://raw.githubusercontent.com/roramirez/mmterm/main/install.sh -o install.sh
less install.sh        # inspect
sh install.sh

Environment variables:

Variable Default Effect
MMTERM_BIN_DIR ~/.local/bin Install directory
MMTERM_VERSION latest release Pin a specific tag, e.g. v0.5.0

macOS (Apple Silicon)

sh -c "$(curl -fsSL https://raw.githubusercontent.com/roramirez/mmterm/main/install.sh)"

On macOS this downloads mmterm-macos-aarch64.dmg, verifies its checksum, and opens it. Drag mmterm.app onto the Applications folder.

mmterm.app is ad-hoc signed but not notarized. The first time you launch it, right-click the app and choose Open, then confirm in the dialog. You only need to do this once. (Depending on your macOS version and how the .dmg was obtained, double-clicking the first time may be blocked by Gatekeeper — the right-click → Open path always works.)

Verify the build (optional, recommended). Inspect the installer before running it, and verify the release's build provenance with the GitHub CLI:

# Inspect the script first
curl -fsSL https://raw.githubusercontent.com/roramirez/mmterm/main/install.sh | less

# Verify provenance of the downloaded disk image
gh attestation verify mmterm-macos-aarch64.dmg --repo roramirez/mmterm

From source

Requires Rust 1.85+ (edition 2024). On Linux you also need a C toolchain and FreeType headers (libfreetype-dev).

cargo install --git https://github.com/roramirez/mmterm

Or from a local checkout:

cargo install --path .

Running

mmterm

Print version:

mmterm --version   # e.g. mmterm 0.3.0+abc1234 (local) or mmterm 0.3.0 (release)

Print help:

mmterm --help

Enable logging:

RUST_LOG=info mmterm

Enable debug logging to file:

mmterm --debug   # writes DEBUG-level logs to ~/.mmterm/debug-<timestamp>.log

Configuration

On first run, a config file is created at:

  • Linux/macOS: $XDG_CONFIG_HOME/mmterm/config.toml (defaults to ~/.config/mmterm/config.toml)
[font]
family = "Noto Sans Mono"
size   = 16.0

[window]
width           = 800
height          = 600
title           = "mmterm"
cursor_blink_ms = 500

[shell]
# program = "/bin/zsh"   # defaults to $SHELL

[terminal]
scrollback_lines = 10000  # minimum 100

[logging]
auto_log = false          # start logging automatically for every new pane
log_dir  = ""             # destination directory (empty = ~/.mmterm)

[status_bar]
right = "%pwd  %date{%H:%M}"  # format string (%pwd = OSC 7 cwd, %date{fmt} = strftime)

[theme]
name = "default"          # see ~/.config/mmterm/themes/ for available themes

[colors]
background = "#121212"
foreground = "#a0a0a0"
cursor     = "#bbbbbb"
selection  = "#3d3d3d"
palette    = [ ... ]      # 16-color ANSI palette

You can also edit settings live with Ctrl+,.

Automatic updates

mmterm checks GitHub for a newer release at most once per day (one request on startup).

  • Linux: by default, an ↑X.Y.Z badge appears in the status bar when an update is available; re-run the installer to update. You can opt in to silent background self-update (download + checksum-verify + atomically replace the binary, applied on next launch) by setting auto_update_install = true; this only applies to user-writable installs (~/.local/bin, ~/.cargo/bin), never system installs.
  • macOS: an ↑X.Y.Z badge appears in the status bar; click it to download and open the .dmg, then drag mmterm.app to Applications.

Disable via ~/.config/mmterm/config.toml:

[general]
auto_update_check = false    # turn off the daily check + badge entirely
auto_update_install = true   # Linux: opt in to silent self-replace (default: off)

HiDPI / display scaling

mmterm renders at the scale factor of the monitor the window is currently on, so text and UI chrome are crisp and correctly sized on Retina / high-DPI displays — and it adapts live when you drag the window between monitors of different DPI (no restart).

font.size (and the Ctrl+/Ctrl- font controls) are logical sizes: the perceived size stays consistent across displays of any density. If you previously increased font.size to compensate for tiny rendering on a HiDPI screen, reset it to a normal value.

Key Bindings

Global

Binding Action
Ctrl+Q Quit — when restore_session = true shows save-session dialog; otherwise confirmation overlay when multiple tabs/panes are open
Ctrl+Enter Toggle borderless fullscreen
Ctrl+, Open config panel
Ctrl+Shift+P Open command palette
Ctrl+T New tab
Ctrl+PageUp / Ctrl+PageDown Previous / next tab
Ctrl+Shift+PageUp / Ctrl+Shift+PageDown Move tab left / right
Ctrl+Shift+W Close tab
Ctrl+Shift+R Rename tab
Alt+1..Alt+9 Jump to tab by position
Ctrl++ / Ctrl+= Increase font size (current tab)
Ctrl+- Decrease font size (current tab)
Ctrl+0 Reset font size
Ctrl+Shift+K Clear scrollback
Ctrl+Shift+L Toggle session logging for active pane

Modes

Binding Action
Ctrl+. Cycle Insert → Normal → Visual → Insert
Ctrl+\ Enter Normal mode

Panes (Ctrl+W prefix)

Binding Action
Ctrl+W v Split horizontally
Ctrl+W s Split vertically
Ctrl+W a Auto-split (along longest dimension)
Ctrl+W h/j/k/l Focus left / down / up / right
Ctrl+W w Cycle focus
Ctrl+W q Close pane
Ctrl+W z Toggle pane zoom
Ctrl+W p Enter screenshot mode
Ctrl+Shift+←/→ Grow/shrink active pane horizontally
Ctrl+Shift+↑/↓ Grow/shrink active pane vertically
drag separator Drag the 1 px separator line to resize

Screenshot Mode (Ctrl+W p)

A rectangular selection overlay appears centered on the screen.

Binding Action
/ / / Move the selection
Shift+→ / Shift+← Grow / shrink the right edge
Shift+↓ / Shift+↑ Grow / shrink the bottom edge
Enter / Space Capture and save PNG
Esc Cancel

The file is saved as mmterm-YYYYMMDDTHHMMSS.png in the directory set by [general] screenshot_dir (default ~/mmterm/shot). The full path is copied to the clipboard automatically after a successful capture.

Visual Bell

BEL (0x07) — sent by the shell on tab-completion with multiple matches, by editors on invalid input, etc. — shows a yellow dot next to the mode badge in the status bar for 150 ms. A 500 ms cooldown suppresses repeated bells so rapid sequences (e.g. pressing Tab twice) only flash once.

To also flash the screen background (Terminator-style), set visual_bell = true in [general]:

[general]
visual_bell = true   # default: false

Scrollback

Binding Action
Shift+PageUp / Shift+PageDown Scroll half screen
Ctrl+Shift+Home / Ctrl+Shift+End Jump to top / bottom

Search (enter from Normal mode with /)

Binding Action
/ Open search
Enter Next match
/ Navigate search history
Ctrl+C Copy current match
n / N Next / previous match (Normal mode)
Escape Exit search

Normal Mode

Binding Action
v Enter Visual mode
i / Escape Return to Insert mode
j / k Scroll down / up
/ Open search
n / N Next / previous search match

Visual Mode

Navigate freely to position the cursor, press v to set the selection anchor, then move to the end and copy.

Binding Action
h/j/k/l or arrows Move cursor (scrolls viewport at boundaries)
w / b / e Forward word / backward word / end of word
0 / $ Start / end of line
g / G Top / bottom of viewport
v Set selection anchor at cursor (starts highlighting)
o Swap anchor and cursor
y / Ctrl+C Copy selection and exit
Y Yank (copy) the entire line at cursor
q / Escape Exit to Insert mode

Clipboard

Binding Action
Ctrl+Shift+C Copy selection
Ctrl+Shift+V Paste

Architecture

main.rs (App, event loop)
├── input/      — key → Action mapping, modal state
├── pty/        — PTY fork, shell spawn, read/write
├── terminal/   — VT/ANSI parser, cell grid, scrollback
├── ui/         — binary-tree split layout, pane struct
├── renderer/   — CPU pixel rendering, glyph cache
├── config.rs   — TOML load/save
└── tui_config/ — in-process config editor

See doc/SPEC.md for the full architecture and feature specification.

License

GPL-2.0 — see LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors