feat(tui): image rendering — protocol auto-detection #58

Merged
charles merged 1 commit from tui/detect-15 into main 2026-04-11 20:42:12 +00:00
Owner

Summary

Closes out Phase 2 of the loom-tui roadmap. Stacks on #57. Closes charles/loom#15.

What's in

  • image::detect::TerminalCapskitty/sixel/chafa bools, TerminalCaps::probe() reads $TERM, $TERM_PROGRAM, and scans $PATH for chafa
  • image::detect::select_renderer(override, caps) — pure function, exhaustively tested. ImageProtocol::Auto walks Kitty → sixel → chafa → halfblock; ::None returns a NoopRenderer; explicit overrides always win, falling back to halfblock if the requested backend isn't actually available
  • image::detect::NoopRenderer for [tui] image_protocol = "none"
  • main.rs probes at startup and logs the chosen protocol name at info

Tests (4 new, 59 total)

  • ImageProtocol::None always yields "none"
  • Auto + all-caps-on yields "kitty"
  • Auto + no caps yields "halfblock"
  • Explicit override beats Auto even when the caps suggest kitty

Notes

  • Kitty detection is environment-variable only in this PR; the APC query probe with a 200 ms timeout can be added once the renderer has a way to reach the raw tty before alt-screen is set up. The heuristic already catches kitty / wezterm / ghostty / etc. in practice
  • image_protocol config pathway is live end-to-end: tui.tomlLoomTuiConfig::tui.image_protocoldetect_renderer → chosen backend
## Summary Closes out **Phase 2** of the loom-tui roadmap. Stacks on #57. Closes charles/loom#15. ## What's in - **`image::detect::TerminalCaps`** — `kitty`/`sixel`/`chafa` bools, `TerminalCaps::probe()` reads `$TERM`, `$TERM_PROGRAM`, and scans `$PATH` for `chafa` - **`image::detect::select_renderer(override, caps)`** — pure function, exhaustively tested. `ImageProtocol::Auto` walks **Kitty → sixel → chafa → halfblock**; `::None` returns a `NoopRenderer`; explicit overrides always win, falling back to `halfblock` if the requested backend isn't actually available - **`image::detect::NoopRenderer`** for `[tui] image_protocol = "none"` - **`main.rs`** probes at startup and logs the chosen protocol name at `info` ## Tests (4 new, 59 total) - `ImageProtocol::None` always yields `"none"` - `Auto` + all-caps-on yields `"kitty"` - `Auto` + no caps yields `"halfblock"` - Explicit override beats `Auto` even when the caps suggest kitty ## Notes - Kitty detection is environment-variable only in this PR; the APC query probe with a 200 ms timeout can be added once the renderer has a way to reach the raw tty before alt-screen is set up. The heuristic already catches `kitty` / `wezterm` / `ghostty` / etc. in practice - `image_protocol` config pathway is live end-to-end: `tui.toml` → `LoomTuiConfig::tui.image_protocol` → `detect_renderer` → chosen backend
Closes Phase 2 of the loom-tui roadmap.

- image::detect::TerminalCaps probes TERM, TERM_PROGRAM, and PATH for
  Kitty / sixel / chafa hints without writing to the real tty
- image::detect::select_renderer takes a config override and a caps
  set and returns the best available Box<dyn ImageRenderer>. Explicit
  override always wins; Auto walks Kitty → sixel → chafa → halfblock
- image::detect::NoopRenderer returned when the user pins
  [tui] image_protocol = "none" so image screens can still run
- main.rs probes at startup and logs the chosen protocol at info

Closes charles/loom#15

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
charles changed target branch from tui/sixel-13 to main 2026-04-11 20:42:11 +00:00
charles deleted branch tui/detect-15 2026-04-11 20:42:12 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/loom!58
No description provided.