No description
  • Zig 96%
  • Makefile 2.2%
  • Roff 1.1%
  • C 0.7%
Find a file
riomoo 17bbf6a9ed
build: find kernel headers through C_INCLUDE_PATH and CPATH
On Guix, glibc's headers include <linux/errno.h> and <asm/...>, which
come from the separate linux-libre-headers package and are listed only
in C_INCLUDE_PATH. Zig doesn't read that variable, so translate-c failed
with "'linux/errno.h' not found". Pass every directory in CPATH and
C_INCLUDE_PATH to translate-c.
2026-10-17 20:43:02 -04:00
patches zst 0.1.1: build with Zig 0.15 and on Guix 2026-10-17 18:56:40 -04:00
.gitignore init commmit 2026-10-17 04:35:37 -04:00
actions.zig zig 0.1.0 minor patch 2026-10-17 18:42:22 -04:00
build.zig build: find kernel headers through C_INCLUDE_PATH and CPATH 2026-10-17 20:43:02 -04:00
c.h zig 0.1.0 minor patch 2026-10-17 18:42:22 -04:00
config.def.zig zig 0.1.0 minor patch 2026-10-17 18:42:22 -04:00
LICENSE zig 0.1.0 minor patch 2026-10-17 18:42:22 -04:00
main.zig zst 0.1.1: build with Zig 0.15 and on Guix 2026-10-17 18:56:40 -04:00
Makefile zst 0.1.1: build with Zig 0.15 and on Guix 2026-10-17 18:56:40 -04:00
pty.zig zig 0.1.0 minor patch 2026-10-17 18:42:22 -04:00
README.md zst 0.1.1: build with Zig 0.15 and on Guix 2026-10-17 18:56:40 -04:00
term.zig zig 0.1.0 minor patch 2026-10-17 18:42:22 -04:00
util.zig zst 0.1.1: build with Zig 0.15 and on Guix 2026-10-17 18:56:40 -04:00
x.zig zig 0.1.0 minor patch 2026-10-17 18:42:22 -04:00
zst.1 zig 0.1.0 minor patch 2026-10-17 18:42:22 -04:00

zst: zig simple terminal

A terminal emulator for X in the spirit of suckless st: a small base (~2.6k lines of Zig), configured by editing source, extended by patches you pick from patches/. Same libraries as st (X11, Xft, fontconfig).

base zst      175 KB   (stock st 0.9.3: 96 KB)
all patches   203 KB   + the optional zst-img image helper

Requirements

  • Zig 0.15, 0.16 or 0.17
  • libX11, libXft, libXrender, fontconfig, freetype2 headers, pkg-config

Arch: pacman -S zig libxft fontconfig pkgconf

Guix: packages zst (no patches) and zst-full (every patch) are in the PIL channel.

Build

make                 # copies config.def.zig -> config.zig on first run
sudo make install

make OPT=ReleaseFast trades some binary size for speed; make ZIGFLAGS=-Dcpu=baseline builds a binary that runs on any x86-64 CPU (the default is tuned to the build machine).

Patches

The base is deliberately plain. Everything else is a patch in patches/:

patch adds
scrollback history, Shift+PgUp/PgDn, mouse-wheel scrolling
themes pywal colors.json/colors.yml, live reload
alpha transparent background, opacity keys, -A, dim unfocused
images PNG/JPEG/GIF/WebP/AVIF/JXL/video frames, fzf previews (+ Go helper)
kbselect copy without the mouse: vim keys, search, yank
anysize fill the whole dwm tile instead of cell-sized steps
hidecursor hide the mouse pointer while typing
make patch P="scrollback themes"    # apply any set, in any order
make

Every combination of these patches applies cleanly in any order and builds. See patches/README for what each one does, how to use it, and how to remove or write patches.

Configuration

Edit config.zig and rebuild: exactly like st's config.h. Shortcuts are { modifier, keysym, function, argument }; keysyms are matched unshifted, so Ctrl+Shift+K is written TERMMOD, c.XK_k. The function can be anything in actions.zig or a function you write in config.zig:

fn hello(_: a.Arg) void { @import("pty.zig").write("echo hi\r"); }
pub const shortcuts = [_]a.Shortcut{
    .{ .mod = TERMMOD, .key = c.XK_h, .func = hello },
    ...

A function no shortcut points at is never compiled, so deleting a shortcut line removes its code from the binary too.

Default shortcuts (base)

keys action
Ctrl+Shift+K / Ctrl+Shift+J zoom in / out (also Ctrl+wheel)
Ctrl+Shift+Home reset zoom
Ctrl+Shift+C / Ctrl+Shift+V copy / paste CLIPBOARD
Shift+Insert, Ctrl+Shift+Y, middle click paste PRIMARY
Ctrl+Shift+I invert colors
Ctrl+Shift+Return new zst in the current directory
Ctrl+Shift+U pick a URL on screen with dmenu, open it
Ctrl+Shift+E open the screen contents in $EDITOR
double / triple click select word / line
Shift + mouse select even when an app grabs the mouse (htop, vim with mouse=a, tmux)

What the base does

  • xterm-compatible escape handling (TERM=xterm-256color, no terminfo to install): 16/256/truecolor, bold/italic/underline/strike/reverse, alternate screen, scroll regions, DEC line drawing, bracketed paste, focus events, SGR mouse reporting, OSC 52 clipboard, window title.
  • Colors from config.zig; applications (and pywal's wal) can still change them live with the standard OSC 4/10/11/12 escapes.
  • Xft rendering with automatic fontconfig fallback for CJK, symbols, emoji.
  • Zoom with font-size steps, CLIPBOARD and PRIMARY selections.
  • st's latency-based drawing (minlatency/maxlatency).

Layout

file job
main.zig arguments, event loop
term.zig grid, VT/xterm parser, selection
x.zig window, Xft drawing, fonts + fallback, keyboard, mouse, clipboard
pty.zig spawn the shell, read/write
actions.zig functions bindable to keys
util.zig small shared helpers
config.def.zig defaults
patches/ optional features + the patch guide

Not done

Ligatures, sixel, bidi, blinking text, the kitty keyboard protocol, and reflow on resize (st doesn't reflow either).