Skip to content

deps: bump superlighttui 0.17 → 0.20 (perf + correctness fixes, plus new APIs worth adopting) #41

Closed

Description

@subinium

Status

  • Current (agf Cargo.toml): superlighttui = "0.17" → resolves to 0.17.1
  • Latest (crates.io, 2026-04-29): 0.20.1
  • Versions in between: 0.18.1 · 0.18.2 · 0.19.0 · 0.19.1 · 0.19.2 · 0.19.3 · 0.20.0 · 0.20.1 (eight releases, ~9 weeks of work)

This isn't a routine "deps are stale" bump. The 0.18 → 0.20 line includes performance, correctness, and developer-experience changes that materially affect agf — and at least one fix that agf is almost certainly hitting silently. Worth doing as a focused PR with research, not a cargo update and a prayer.

Why it matters for agf specifically

Correctness — likely silent bugs in current build

  • 0.19.1 — rgb_to_ansi256 u8 overflow at r=g=b=248. Debug builds panic; release silently maps near-white grayscale to Color::Indexed(0) (Black). agf uses slt::Color::Rgb heavily — BRIGHT_WHITE = (229, 229, 229), GRAY_400 = (163, 163, 163), agent palette colors, etc. Audit needed: any Rgb(r, g, b) where r >= 248 && g >= 248 && b >= 248 is currently rendering as black on terminals that fall back to indexed-256.
  • 0.19.1 — treemap label byte-slicing panic on multibyte input. agf doesn't use treemap, but 0.19.1 also tightened CJK char-boundary handling repo-wide. Korean session titles / project names render through SLT, so the same family of fixes applies.
  • 0.19.2 — Bordered container title overdraws the top border. ASCII titles like cargo-slt rendered as ╭─cargo-slt ╮ instead of ╭─cargo-slt──────╮. agf uses .bordered(slt::Border::Rounded) in the bulk-delete header (src/tui/mod.rs ui_bulk_delete), so any title there is potentially affected.

Performance — measurable

  • 0.18.2 — flush_buffer_diff run-length coalescing. Consecutive changed cells in a row sharing style/hyperlink/adjacency are now emitted as a single Print(run). The patch notes: "200×60 full-redraw reduces queue! calls from ~12000 to ~2000 — 3-5× flush-path speedup expected on redraw-heavy frames." agf re-renders the whole session list on every keystroke during fuzzy search; this is exactly the redraw-heavy workload that benefits.
  • 0.18.2 — Command enum size reduction. Smaller per-frame allocations, lower cache pressure — free win.

New APIs worth adopting (optional, separate PRs)

  • 0.19.0 — ui.provide(value, |ui| ...) + ui.use_context::<T>() — scoped context injection. agf currently threads &App, cwd, pinned_sessions, settings, etc. through every render_* parameter list (some functions take 5+ args). Migrating long-lived TUI state (cwd, settings, agent color palette) to context would meaningfully simplify the call sites. Not blocking — purely a refactor opportunity.
  • 0.19.3 — Anchor enum + overlay_at / modal_at — 9-cell positioning (TopLeft … BottomRight). Maps to CSS place-self. The DeleteConfirm and ResumeSelect modes are effectively modals — moving them onto modal_at(Center) would replace the current manual positioning with one-liners.
  • 0.20.0 — TestBackend::record_frames() + FrameRecord history + sequence() builder + type_string helper. agf has zero TUI snapshot tests today — every key handler is verified by reading the source and praying. With 0.20.0's recorder, we can add tests/tui_snapshot.rs that drives the TUI through fuzzy-search → action menu → resume-select with tb.sequence().type_string("hashed").press(Down).press(Enter) and asserts tb.frames().last().to_string_trimmed() matches a checked-in snapshot. This is the cleanest path to catching regressions like TUI/DeleteConfirm: Up/Down keys do nothing on the Yes/No screen (only Left/Right toggle) #38 / TUI menus: arrow keys should wrap (cycle) on short menus, matching Tab behavior #39 before they ship.

Deprecations / breaking signals

  • 0.20.1 — Context::col_gap / Context::row_gap deprecated. The two-arg shorthand collides with ContainerBuilder::col_gap / ContainerBuilder::row_gap (Tailwind gap-x / gap-y axis convention). Old form keeps compiling with a warning; preferred form is ui.container().gap(n).col(f). Audit needed: grep for ui.col_gap / ui.row_gap in src/tui/mod.rs and migrate. If we're not using either, this is a no-op.

No hard breaking changes between 0.17 and 0.20 — additive API + deprecations only. Migration cost should be small.

Suggested execution

Do this as two PRs, not one:

  1. PR 1 — version bump + correctness audit

    • Cargo.toml: superlighttui = "0.20" (or "0.20.1" for pin)
    • cargo update -p superlighttui
    • Run the existing test suite + cargo build --release
    • Manual smoke: launch TUI in a terminal that's known to fall back to 256-color (e.g. TERM=xterm-256color), verify all RGB cells render correctly (no near-white going black).
    • Verify any bordered(...) containers still draw their title bar correctly.
    • Migrate any deprecated col_gap/row_gap call sites.
    • Goal: zero behavior regression, win the 0.18.2 perf and 0.19.x correctness fixes for free.
  2. PR 2 — optional adoption of new APIs (later, if 0.20 lands cleanly)

    • Migrate cross-scope state to ui.provide / use_context.
    • Move DeleteConfirm / ResumeSelect / AgentSelect to modal_at.
    • Land first TUI snapshot test on TestBackend::sequence() covering the fuzzy-search → resume happy path. Wire it into CI.

Severity / urgency

  • Now-ish (PR 1): Medium. Silent black-grayscale on indexed-256 terminals is a real correctness bug, and 3-5x flush speedup on the search hot path is the kind of free win you don't leave on the table for long.
  • Later (PR 2): Low. Pure DX / test infra. Schedule whenever someone has time.

Out of scope

  • Major version bumps (0.21+) — none exist yet at time of writing.
  • Migrating off SLT to ratatui or similar. Not under consideration.

Activity

  1. subinium commented on May 4, 2026

    @subinium
    OwnerAuthor

    Done in v0.11.1 (PR #42, commit 3dc422f, released 2026-05-04).

    superlighttui = "0.17" → "0.20" resolves to 0.20.1. The bump turned out to be drop-in: agf doesn't touch any of v0.20's breaking surface (gauge/line_gauge/breadcrumb chainable builders, scrollable_with_gutter GutterOpts, Constraints WidthSpec/HeightSpec redesign, f32 → f64 ratio unification on SplitPane), so no migration code was needed. cargo check + clippy --all-targets -- -D warnings + cargo test (27 tests) all green on first attempt.

    Free gains shipped:

    • 3–5× flush-path speedup on redraw frames (SLT 0.18.2 bug(delete): make session deletion race-safe, exact, and complete #62 run-length coalescing)
    • ~1000× speedup on static frames via per-row hash skip in flush_buffer_diff (SLT 0.20.0 #171) — directly relevant since the agf list view is mostly static while the user reads it
    • rgb_to_ansi256 u8 overflow fix at r=g=b=248 (SLT 0.19.1 #104) — agf's palette doesn't cross the threshold, but downstream installs on color-limited terminals are now correct
    • stdout BufWriter::with_capacity(65536) so every frame batches dozens of write_all ANSI commands behind a single flush() (SLT 0.19.1 #172)

    Active adoption of the new APIs (use_context for state threading, Anchor + modal_at for DeleteConfirm/ResumeSelect simplification, TestBackend::record_frames() for snapshot tests, publish_keymap + keymap_help_overlay for Help mode) is deferred to a future release — they're additive and out of scope for the bump itself, which I wanted to keep small and reviewable. Tracking that separately when the time comes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions