Log in
README.md 135 lines · 5.5 KB

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

KeyAction
Cmd+C / Cmd+VCopy selection / paste
Cmd+N / Cmd+WNew window / close window
Cmd+= / Cmd+- / Cmd+0Bigger / smaller / default font size
Cmd+KClear scrollback
Cmd+← / Cmd+β†’Start / end of line
Option+← / Option+β†’Back / forward a word
Cmd+Backspace / Option+BackspaceDelete to start of line / previous word
Cmd+Delete / Option+DeleteDelete to end of line / next word
Cmd+↑ / Cmd+↓Scroll back / forward a line
Cmd or Shift + PageUp / PageDownScroll back / forward a page
Cmd or Shift + Home / EndTop / bottom of scrollback
Option+keySent as Meta (Esc+key); see option_as_alt
Cmd+dragMove 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: like buttonless, with the traffic-light buttons
  • none: no title bar or border at all, square corners; move the window with Cmd+drag
  • full: the standard title bar (dark when the background is dark)

Finding your way around

FileWhat's in it
src/main.rsWindows, the event loop, keyboard shortcuts, mouse and selection
src/term.rsTerminal state and escape-sequence handling (the xterm subset)
src/input.rsKey and mouse events β†’ bytes for the program
src/renderer.rswgpu setup, glyph atlas, building each frame
src/shader.wgslThe one shader: instanced rects and glyphs
src/font.rsFont lookup, fallback, shaping and rasterizing (swash)
src/boxdraw.rsProcedurally drawn line and block characters
src/pty.rsStarting the shell on a pseudo-terminal
src/config.rsConfig 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.