Files
viexp/docs/research/rust-preview-stack.md
T

76 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
type: research
status: analyzed
confidence: high
created: 2026-10-17
question: Which Rust crates should render previews (images, PDF, DJVU, EPUB, markdown, media) in a terminal, with what licenses and fallbacks?
tags: [research, rust, crates, preview, ratatui]
---
# Rust preview stack (October 2026)
Versions verified against crates.io metadata on 2026-10-17.
## Recommended stack
| Concern | Crate | Why | Notes / license |
|---|---|---|---|
| TUI | **ratatui 0.30** + **crossterm 0.29** | De-facto standard; 0.30 split into `ratatui-core`/`-widgets` facade; yazi & felix use it | MIT; MSRV 1.88 |
| Images in TUI | **ratatui-image 11.1** | kitty, sixel, iTerm2, halfblocks + `Picker` protocol/font detection; lives in the ratatui org | MIT |
| Image decode | **image 0.25** | yazi's choice; jpeg/png/gif/webp/bmp/tiff (+avif feature) | MIT/Apache |
| Resize | **fast_image_resize 6.1** (SIMD) or `image::thumbnail` (triangle filter, yazi-style) | hot loop | MIT/Apache |
| Sixel encode | **quantette 0.6** (+ moxcms, palette) | yazi's actual sixel pipeline | MIT |
| PDF | **pdfium-render 0.9** + pdfium binary | only mature page→image in-process option | pdfium is **Apache-2.0** (b redistribute, ~5 MB); spawn `pdftoppm` as fallback |
| DJVU | **djvu-rs 0.43** (pure Rust, render→image) | first usable pure-Rust DjVu decoder | **6 months old** — keep `ddjvu` fallback |
| EPUB | hand-rolled: **zip** + quick-xml/html-to-text | the `epub` crate is **GPL-3.0 — viral** if statically linked | avoid the trap |
| Markdown | **comrak 0.56** → styled ratatui lines, or **termimad** (ready-made renderer) | termimad = fastest integration (broot uses it) | MIT |
| Syntax highlight | **syntect 5.3** | yazi's choice; regex Sublime syntaxes, no C deps | tree-sitter = heavier, per-language grammars |
| Media metadata | **spawn `ffprobe -print_format json`** | no linking pain; what yazi does | ffmpeg-next ties you to system FFmpeg — avoid |
| Video thumbnail | **spawn `ffmpeg -ss … -vframes 1 -vf scale…`** (+ `attached_pic` cover-art fallback) | yazi's proven recipe | — |
| Audio (optional in-process) | **symphonia 0.6** | pure-Rust metadata/album art | MPL-2.0 |
| MIME | **infer 0.22** (magic bytes) + **xdg-mime 0.4** (extension DB) | fast sniffing + correct `text/*` | `new_mime_guess` unmaintained — avoid |
| FS events | **notify 8.2** | yazi's watcher | CC0 |
| Fuzzy | **nucleo 0.5** | Helix's matcher, library-first | MPL-2.0 |
| Config | **serde + toml 1.1** | yazi's set | solid |
| Errors/logs | **anyhow + thiserror 2.x + tracing** | boring and correct | — |
| Async | **tokio 1.x** with results marshalled to a single-threaded UI actor | yazi's exact architecture; ecosystem is tokio-first | start threads-only, adopt tokio in Sprint 8 |
## Image protocol fallback chain (first match wins)
1. **kitty graphics** (unicode-placeholder mode) — kitty ≥0.28, Ghostty ← *our primary target*
2. **iTerm2 inline** — WezTerm, iTerm2, Warp, VSCode terminal
3. **sixel** — foot, Konsole 22.04+, Windows Terminal ≥1.22, WezTerm, rio
4. **ueberzug++ subprocess** — X11 + Wayland (wlroots compositors: sway/hyprland/niri/wayfire);
the only option for alacritty; not GNOME/KDE compositors
5. **chafa / halfblocks** — works everywhere incl. SSH and tmux
6. text: filename + size + mime
Terminal facts (Oct 2026): kitty has **no sixel by design**; alacritty rejected both protocols;
tmux needs `allow-passthrough on` and never passes kitty-old. The daily terminal here is
**kitty without a multiplexer** → tier 1 covers the primary user; tiers 3–5 cover everyone else.
## Thumbnail caching (yazi-proven)
Decode once at preview size (max ~600×900, triangle filter) → persist rendered pages/frames to
a disk cache dir → keep decoded previews in an in-process LRU → preload neighbors in background.
Re-encoding for a protocol is cheap; re-decoding is not.
## Risk notes
- GPL traps: `epub` crate (static link), ueberzug++ (fine — spawned), pdftoppm (fine — spawned).
- pdfium must be shipped as a binary (~5 MB/platform) or static-linked via pdfium-render `static`.
- djvu-rs is young; config-selectable `ddjvu` fallback required.
- ratatui 0.30 subcrate split may cause ecosystem churn in 2026 — pin carefully.
## Outcome
Feeds ADR-001, ADR-004 and Sprints 5–8 crate choices.
## Sources
- https://github.com/sxyazi/yazi (adapter/Cargo.tomls, preset plugins pdf.lua/video.lua)
- https://yazi-rs.github.io/docs/image-preview, /blog/why-is-yazi-fast/
- crates.io version metadata (ratatui, ratatui-image, image, fast_image_resize, quantette,
pdfium-render, djvu-rs, epub, comrak, termimad, syntect, symphonia, notify, nucleo, infer, xdg-mime)
- https://github.com/ajrcarey/pdfium-render; pdfium LICENSE (Apache-2.0)
- https://www.arewesixelyet.com; https://sw.kovidgoyal.net/kitty/graphics-protocol
- https://github.com/jstkdng/ueberzugpp; https://github.com/matyushkin/djvu-rs