Skip to content

Cheap wins from the register audit: 5 small, independent fixes #561

Description

@emal-avala

Five independently-shippable items surfaced by the 2026-07-28 register audit. Each was verified against origin/main with file:line evidence; each is small and self-contained. Listed together for tracking — they should land as separate PRs, not one.

Ordered by value-per-line.


1. D3-43 — diff rendering has no perf guardrails (TRIVIAL)

render_unified_diff (ui/modern/diffview.rs:206) has no byte cap, no line cap and no per-line length cap. Its only guard is display truncation applied after all the work: if !expanded && out.len() > cap { out.truncate(cap) } (:305). Every line has already been syntect-highlighted, and paired runs word-diffed via TextDiff::from_words (:49), before anything is thrown away.

The single call site passes a hard-coded cap of 24 (layout.rs:511) with no size test beforehand. So a multi-megabyte edit result is fully highlighted on every cache miss — and again on every width change, since LayoutCache::sync clears all blocks when the width changes (layout.rs:80).

Fix: byte/line/line-length thresholds at the top of render_unified_diff that fall back to plain tinted lines, and short-circuit before rendering rather than after.


2. D5-30 — mouse capture cannot be relinquished (TRIVIAL, and a prerequisite)

EnableMouseCapture is unconditional at run.rs:649 and again at :711; DisableMouseCapture appears only on teardown. There is no toggle, no slash command, no config key. Native click-drag copy is therefore unavailable for the whole session, and the UI advertises a line-granular substitute instead (render.rs:170).

Fix: an App flag, a chord plus a slash command that execute Disable/EnableMouseCapture against the backend, and a sticky hint. All four call sites already exist.

Do this before #558 — adding hover means capturing motion events, which makes native selection worse. Ship the escape hatch first.


3. D6-13 — the status-line template engine is built, tested, and never called (SMALL)

StatusLineConfig (config/schema.rs:558) and render_statusline_template (:597) implement {model} {turn} {tokens} {cost} {cwd} {session_id} substitution with {{/}} escaping, backed by ~8 unit tests. git grep finds zero call sites outside schema.rs. Nothing reads cfg.ui.statusline; there is no /statusline command and no preview.

Fix: wire it into the modern status bar, add the command, render the candidate template against live vars as the user types.

This is the fifth instance of built-but-never-wired found in this codebase (after notifications, hyperlinks, keybindings.rs, /vim, and the theme picker) — worth noting as a pattern, not just a bug.


4. D3-26 — streaming re-highlights the whole block on every flush (SMALL)

emit_code_block (markdown.rs:418) constructs HighlightLines::new fresh on every invocation, and render_markdown re-parses the entire accumulated block. The layout cache re-renders a block whenever its content hash changes, and the streaming tail's hash changes on every flush (~10/s). So each flush re-runs pulldown-cmark plus syntect over the whole block including every previously-seen line — quadratic in block length.

Fix: cache per-block (ParseState, HighlightState, lines_consumed) and highlight only newly-appended lines, resetting when the fence closes or the prefix changes.


5. D8-12 — an unknown theme id in config fails silently (TRIVIAL)

/color <name> rejects properly with a list (commands/mod.rs:1949), but a bad id in the config file does not: resolve_theme returns unknown strings unchanged (theme_runtime.rs:241) and Theme::from_name has _ => DEFAULT_DARK with no log (theme.rs:790). Startup calls init_with_options without checking. /doctor has no theme check.

Fix: a catalog_ids().contains() check in resolve_theme (or a diagnostics.rs check) emitting unknown theme 'x'; using one-dark. Run /color to list.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions