leaf
A small, no-frills terminal emulator for macOS, rendered on the GPU with wgpu. It does what vim, tmux, less and a shell need and not much else: no tabs, splits, profiles, plugins or scripting. The whole thing is ~4,000 lines of Rust meant to be read and changed.
Build and run
cargo run --release
make app # target/release/Leaf.app
make install # copies it to /Applications
The icon is the leaf from Yarndings 20
(SIL Open Font License). make icon FONT=path/to/font.ttf GLYPH=h redraws
macos/Leaf.icns from any glyph of any font.
What it supports
- 16, 256 and 24-bit color; bold, italic, dim, underline, strikethrough, inverse
- Any installed font by family name (or a font file path), with real bold/italic faces and automatic fallback for CJK, emoji and symbols
- Programming ligatures (
->,!=,>=... in fonts like Berkeley Mono, Fira Code or JetBrains Mono), via text shaping - Combining characters (accents, Vietnamese tone marks, emoji variation selectors)
- Box-drawing, block and powerline characters drawn by leaf itself, so vim splits, tmux borders and statuslines join seamlessly
- Alternate screen, scroll regions, application cursor keys, bracketed paste,
focus events, synchronized output, cursor shape changes (vim's
t_SI/t_EI) - Mouse reporting (vim
mouse=a, tmux), with Shift held to select instead - Scrollback, mouse/trackpad scrolling, click-drag / double-click (word) / triple-click (line) selection
- Text re-wraps when the window is resized
- Blinking cursor (programs like vim can switch blinking and shape)
- OSC 52 clipboard writes (e.g. vim/tmux yanking over ssh), window titles
- Multiple windows
Keys
| Key | Action |
|---|---|
| Cmd+C / Cmd+V | Copy selection / paste |
| Cmd+N / Cmd+W | New window / close window |
| Cmd+= / Cmd+- / Cmd+0 | Bigger / smaller / default font size |
| Cmd+K | Clear scrollback |
| Cmd+β / Cmd+β | Start / end of line |
| Option+β / Option+β | Back / forward a word |
| Cmd+Backspace / Option+Backspace | Delete to start of line / previous word |
| Cmd+Delete / Option+Delete | Delete to end of line / next word |
| Cmd+β / Cmd+β | Scroll back / forward a line |
| Cmd or Shift + PageUp / PageDown | Scroll back / forward a page |
| Cmd or Shift + Home / End | Top / bottom of scrollback |
| Option+key | Sent as Meta (Esc+key); see option_as_alt |
| Cmd+drag | Move the window from anywhere in it |
The line-editing keys work like iTerm's "Natural Text Editing" preset: they send the shell's (readline/zsh) bindings Ctrl-A, Ctrl-E, Ctrl-U, Ctrl-W, Ctrl-K, Esc-b, Esc-f and Esc-d, as iTerm does. In vim's insert mode only the Backspace ones (Ctrl-U, Ctrl-W) mean the same thing.
Mouse wheel scrolls the scrollback; in full-screen programs without mouse support (less, man) it sends arrow keys instead.
Configuration
~/.config/leaf/config.toml is read at startup. Everything is optional; these
are the defaults:
[font]
family = "Menlo" # family name, or a path like "~/fonts/Foo.ttf"
size = 14.0 # points
line_height = 1.0 # multiplier
fallback = [] # extra families for missing glyphs, e.g. ["Symbols Nerd Font Mono"]
builtin_box_drawing = true # draw βββ ββ etc. instead of using the font
ligatures = true
[window]
columns = 100
rows = 30
padding = 6.0 # points
option_as_alt = "both" # "both", "left", "right" or "none" (Option types special characters)
decorations = "buttonless" # "buttonless", "transparent", "none" or "full" (see below)
[colors]
foreground = "#d4d4d4"
background = "#1c1c1c"
cursor = "#d4d4d4"
# cursor_text = "#1c1c1c" # text under the block cursor; defaults to background
selection = "#3e4a5c"
palette = [
"#1c1c1c", "#e06c75", "#98c379", "#e5c07b", "#61afef", "#c678dd", "#56b6c2", "#c8c8c8",
"#5c6370", "#ff7a85", "#b5e890", "#ffd88a", "#82c4ff", "#de96f0", "#7ad4de", "#ffffff",
]
[terminal]
# shell = "/bin/zsh" # defaults to $SHELL, run as a login shell
args = []
# working_directory = "~" # defaults to $HOME
scrollback = 10000
cursor_style = "block" # "block", "beam" or "underline"
cursor_blink = true
scroll_multiplier = 3.0
copy_on_select = false
decorations picks the window frame on macOS:
buttonless: no visible title bar or buttons; drag the window by the strip along its top (double-click it to zoom)transparent: likebuttonless, with the traffic-light buttonsnone: no title bar or border at all, square corners; move the window with Cmd+dragfull: the standard title bar (dark when the background is dark)
Finding your way around
| File | What's in it |
|---|---|
src/main.rs | Windows, the event loop, keyboard shortcuts, mouse and selection |
src/term.rs | Terminal state and escape-sequence handling (the xterm subset) |
src/input.rs | Key and mouse events β bytes for the program |
src/renderer.rs | wgpu setup, glyph atlas, building each frame |
src/shader.wgsl | The one shader: instanced rects and glyphs |
src/font.rs | Font lookup, fallback, shaping and rasterizing (swash) |
src/boxdraw.rs | Procedurally drawn line and block characters |
src/pty.rs | Starting the shell on a pseudo-terminal |
src/config.rs | Config file and defaults |
Things deliberately left out: tabs and splits (use tmux), IME composition, images, hyperlinks, and the kitty keyboard protocol.
cargo test runs the terminal-emulation and key-encoding tests.