Attyx – 用 Zig 编写的微小且快速的 GPU 加速终端模拟器
Attyx – tiny and fast GPU-accelerated terminal emulator written in Zig

原始链接: https://github.com/semos-labs/attyx

## Attyx:用Zig语言编写的确定性终端模拟器 Attyx是一个用Zig编程语言从头开始构建的终端模拟器,优先考虑正确性和清晰性。其核心是一个确定性的状态机——这意味着相同的输入*始终*产生相同的输出——这无需依赖传统的终端组件,如PTY或窗口系统来实现。 其架构清晰地分离了解析、状态管理和渲染。输入通过解析器处理,触发修改终端状态并更新网格显示的动作。Attyx支持广泛的VT功能,包括SGR颜色、超链接、鼠标报告和带括号的粘贴。 目前,Attyx具有GPU加速渲染(macOS上的Metal,Linux上的OpenGL)和一个功能性的PTY桥接,用于shell交互。配置通过TOML文件和CLI参数处理,并具有强大的测试套件,利用黄金快照比较。开发遵循基于里程碑的方法,许多核心功能已经实现并积极维护。Attyx的设计具有可扩展性,并正在为通过会话事件日志进行AI集成做准备。

Hacker News新 | 过去 | 评论 | 提问 | 展示 | 工作 | 提交登录Attyx – 用Zig编写的微小且快速的GPU加速终端模拟器 (github.com/semos-labs)7 points by nicholasrq 1 小时前 | 隐藏 | 过去 | 收藏 | 2 评论 帮助 varispeed 24 分钟前 [–] GPU加速有什么好处?我最讨厌的是输入时从按键到屏幕显示之间的延迟。例如,当我打字时,我能清楚地看到滞后。如果有人能想办法直接实时地访问键盘,以确保零可察觉的延迟(一些去抖动开关的芯片甚至会给按键增加50毫秒的延迟!),那我会非常喜欢。回复bigwheels 9 分钟前 | 父评论 [–] > GPU加速有什么好处?是的,我也不是很清楚这与PTY有什么不同。 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请YC | 联系 搜索:
相关文章

原文

Epist

Deterministic VT-compatible terminal emulator in Zig

Tests Zig 0.15 MIT License

ArchitectureBuildingTestingRoadmapDocs


Attyx is a terminal emulator built from scratch in Zig. The core is a pure, deterministic state machine — no PTY, no windowing, no platform APIs required. Given the same input bytes, it always produces the same grid state.

The project prioritizes correctness over features and clarity over cleverness. Every feature is testable in headless mode.


The core follows a strict pipeline — parsing never touches state, state never influences parsing:

Raw bytes ─▸ Parser ─▸ Action ─▸ State.apply() ─▸ Grid
Layer Directory Purpose
Terminal engine src/term/ Pure, deterministic core — parser, state, grid, hash
Headless runner src/headless/ Test harness and golden snapshot tests
Config src/config/ TOML config loading, CLI parsing, AppConfig struct
App src/app/ PTY bridge + OS integration
Renderer src/render/ GPU + font rendering (Metal on macOS, OpenGL on Linux)
  • Action — tagged union (20 variants including print, control, sgr, enter_alt_screen, hyperlink_start, dec_private_mode, ...) — the vocabulary between parser and state.
  • Parser — incremental 5-state machine (ground → escape → CSI / OSC). Zero allocations in hot path, handles partial sequences across chunk boundaries. Recognizes DEC private modes and OSC sequences.
  • TerminalState — dual-buffer (main + alt) with per-buffer cursor, pen, scroll region, saved cursor, and hyperlink state. Global hyperlink table, title, and terminal mode flags (mouse tracking, bracketed paste). Mutates only via apply(action).
  • Engine — glue that connects parser and state with a simple feed(bytes) API.
  • input — allocation-free input encoder: bracketed paste wrapping and SGR mouse event encoding.
  • hash — pure FNV-1a hash of visible terminal state (cursor + grid + attrs). Used to detect screen changes.
  • Pty — POSIX PTY bridge: spawn a child shell, non-blocking reads, write bytes, resize via ioctl.
  • SessionLog — bounded ring buffer of session events (PTY input/output chunks + frame snapshots). Preparation for AI integration.
  • AttyxView — MTKView subclass handling keyboard input: special keys, Ctrl+key, Alt+ESC prefix, paste, DECCKM-aware arrow keys, IME composition (CJK), mouse selection (single/double/triple click).
  • platform_linux.c — Linux platform layer: GLFW window, OpenGL 3.3 renderer, FreeType glyph rasterization, Fontconfig font discovery, same bridge.h shared-state interface.

See docs/architecture.md for the full breakdown.


Requires Zig 0.15.2+.

zig build              # build
zig build run          # launch terminal

GPU-accelerated terminal rendered in a native window. PTY output drives the engine; the renderer draws the grid at 60 fps.

  • macOS: Metal + Cocoa + Core Text
  • Linux: OpenGL 3.3 + GLFW + FreeType + Fontconfig
zig build run                                # default: bash 24x80
zig build run -- --rows 30 --cols 100        # custom size
zig build run -- --cmd /bin/zsh              # custom shell
zig build run -- --cell-width 110%           # wider cells (percentage)
zig build run -- --cell-height 18            # fixed cell height (pixels)
sudo apt install libglfw3-dev libfreetype-dev libfontconfig-dev libgl-dev

Set ATTYX_FONT to override the default monospace font (e.g., ATTYX_FONT="JetBrains Mono").


Attyx reads configuration from a TOML file and CLI flags. Precedence: defaults < config file < CLI flags.

Config file location:

  • Linux/macOS: $XDG_CONFIG_HOME/attyx/attyx.toml (default: ~/.config/attyx/attyx.toml)

See config/attyx.toml.example for a full example with defaults.

[font]
family = "JetBrains Mono"
size = 14
cell_width = "100%"       # percentage of font-derived width (default)
cell_height = 20           # absolute pixels
fallback = ["Symbols Nerd Font Mono", "Noto Color Emoji"]

[theme]
name = "default"

[scrollback]
lines = 20000

[reflow]
enabled = true

[cursor]
shape = "block"           # "block" | "beam" | "underline"
blink = true

[background]
opacity = 1.0             # 0.0 (transparent) – 1.0 (opaque)
blur = 30                 # blur radius; only applies when opacity < 1.0

[logging]
level = "info"            # "err" | "warn" | "info" | "debug" | "trace"
# file = "/tmp/attyx.log" # append logs to file in addition to stderr

cell_width and cell_height control the grid cell dimensions. Each accepts either:

  • Percentage (string): "110%" — scale relative to the font-derived default. "100%" is the default.
  • Pixels (integer): 10 — absolute pixel value, overrides font metrics.
cell_width = "120%"    # 20% wider than default
cell_height = 18       # exactly 18 pixels tall
attyx --cell-width 120% --cell-height 18
--rows N                   Terminal rows (default: 24)
--cols N                   Terminal cols (default: 80)
--cmd <command...>         Override shell command
--shell <path>             Shell program (default: $SHELL or /bin/sh)
--font-family <string>     Font family (default: "JetBrains Mono")
--font-size <int>          Font size in points (default: 14)
--cell-width <value>       Cell width: pixels (e.g. 10) or percent (e.g. "110%")
--cell-height <value>      Cell height: pixels (e.g. 20) or percent (e.g. "110%")
--theme <string>           Theme name (default: "default")
--scrollback-lines <int>   Scrollback buffer lines (default: 20000)
--reflow / --no-reflow     Enable/disable reflow on resize
--cursor-shape <shape>     Cursor shape: block, beam, underline
--cursor-blink / --no-cursor-blink
--background-opacity <f>   Window opacity 0.0–1.0 (default: 1.0)
--background-blur <int>    Blur radius when opacity < 1 (default: 30)
--log-level <level>        Log level: err, warn, info, debug, trace (default: info)
--log-file <path>          Append logs to file (default: stderr only)
--config <path>            Load config from a specific file
--no-config                Skip reading config from disk
--print-config             Print merged config and exit
--help, -h                 Show this help

Reloading config at runtime

Send SIGUSR1 or press Ctrl+Shift+R inside the terminal to apply config changes without restarting:

Setting On reload
cursor.shape, cursor.blink Applied immediately
scrollback.lines Applied immediately
font.family, font.size, cell_width, cell_height Applied immediately — rebuilds glyph cache and snaps window size
background.opacity, background.blur Requires restart (window transparency is set at startup)
logging.level, logging.file Requires restart

All tests run in headless mode — no PTY, no window, no OS interaction.

zig build test                # run all tests
zig build test --summary all  # run with detailed summary

The test suite uses golden snapshot testing: feed known bytes into a terminal of known size, serialize the grid to a plain-text string, and compare against an exact expected value.

What's tested Count
Grid operations (get/set, scroll, clear, region scroll, style) 7
Parser state machine (ESC, CSI, DEC private mode, OSC dispatch) 39
State mutations (apply actions, scroll regions, alt screen, hyperlinks, title) 16
Snapshot serialization 2
Input encoder (paste wrapper, SGR mouse encoding) 15
Engine + runner integration 3
State hashing (identity, content, cursor) 3
Golden + attribute tests (text, cursor, erase, SGR, 256/truecolor, alt, OSC, modes, DECCKM) 112
Total 197

See docs/testing.md for the full testing strategy.


Attyx is built milestone by milestone. Each milestone is stable and tested before the next begins.

# Milestone Status
1 Grid + cursor + printable text + control chars ✅ Done
2 Action stream + parser skeleton (ESC/CSI framing) ✅ Done
3 Minimal CSI support (cursor movement, erase, SGR 16 colors) ✅ Done
4 Scroll regions (DECSTBM) + Index/Reverse Index ✅ Done
5 Alternate screen + save/restore cursor + mode handling ✅ Done
6 SGR extended colors (256-color + truecolor) ✅ Done
7 OSC support (hyperlinks + title) ✅ Done
8 Mouse reporting + bracketed paste + input encoder ✅ Done
UI-0 Rendering spike (Metal window, demo grid) ✅ Done
UI-1 PTY bridge (headless app loop — spawn shell, read/write PTY, snapshot) ✅ Done
S-0 Minimal session event log (ring buffer, no AI yet) ✅ Done
UI-2 Window + GPU renderer (live grid rendering, Metal on macOS) ✅ Done
UI-3 Keyboard input + interactive shell (PTY write + key encoding) ✅ Done
UI-4 Mouse selection + copy/paste (single/double/triple click) ✅ Done
UI-5 Scrollback viewport (Shift+PgUp/PgDn, mouse wheel) ✅ Done
UI-6 Window resize + grid snap ✅ Done
UI-7 IME composition input (CJK, macOS) ✅ Done
UI-8 Linux platform parity (GLFW + OpenGL + FreeType) ✅ Done
UI-9 In-terminal search (Ctrl+F incremental search bar) ✅ Done
CFG-1 Config reload at runtime (SIGUSR1 + Ctrl+Shift+R) ✅ Done
INF-1 Logging + diagnostics (structured log, 5 levels, file output) ✅ Done
VIS-1 Background transparency + blur (opacity + NSVisualEffectView) ✅ Done

See docs/milestones.md for detailed write-ups.


src/
  term/
    actions.zig      Action union + control/CSI/mode types
    parser.zig       Incremental VT parser (ground/escape/CSI/OSC)
    state.zig        TerminalState — grid + cursor + pen + modes + apply()
    grid.zig         Cell + Grid + Color + Style
    snapshot.zig     Grid → plain text serialization
    engine.zig       Glue: Parser + TerminalState
    input.zig        Input encoder: paste wrapping + mouse SGR
    hash.zig         State hashing for change detection
  headless/
    runner.zig       Test convenience functions
    tests.zig        Golden snapshot + attribute tests
  config/
    config.zig       AppConfig struct, TOML parsing, CellSize type
    cli.zig          CLI argument parser + usage text
    reload.zig       Config reload helper (loadReloadedConfig)
  logging/
    log.zig          Structured logger (5 levels, file output, C bridge hook)
    diag.zig         PTY throughput diagnostics window
  app/
    pty.zig          POSIX PTY bridge (spawn, read, write, resize)
    ui2.zig          Terminal runner (PTY thread + GPU window, macOS/Linux)
    session_log.zig  Session event log (ring buffer, byte tracking)
    bridge.h         C bridge types (AttyxCell, cursor, quit signaling)
    platform_macos.m Metal renderer + Cocoa window (macOS)
    platform_linux.c OpenGL renderer + GLFW window (Linux)
    main.zig         UI-0 demo (standalone test executable)
  render/
    color.zig        Color resolution (ANSI → RGB lookup)
  root.zig           Library root
  main.zig           CLI entry point
config/
  attyx.toml.example Example config with all defaults
docs/
  architecture.md    System design and data flow
  milestones.md      Milestone details and history
  terminal-basics.md How terminals work (learning reference)
  testing.md         Test strategy and snapshot format

MIT


Built byte by byte • escape sequence by escape sequence

联系我们 contact @ memedata.com