Skip to content

fix(tui): show a scroll rail on a settings choice list that doesn't fit - #7024

Merged
Hmbown merged 2 commits into
codewhale-hq:mainfrom
Lstarsky0:ux/settings-choice-scroll-rail
Oct 18, 2026
Merged

Hmbown merged 2 commits into
codewhale-hq:mainfrom
Lstarsky0:ux/settings-choice-scroll-rail

Conversation

@Lstarsky0

Copy link
Copy Markdown
Contributor

What and why

When a setting's choices don't fit, /settings shows as many as it can and scrolls to keep the selected one in view, but nothing says the list goes on. Language has 17 options. At 60×16, Language, before:

  Choose:
    ▸  1. auto
       2. en
       3. ja
       4. zh-Hans
       5. zh-Hant
  [ Apply ]  [ Cancel ]

After:

  Choose:
    ▸  1. auto                                           █
       2. en                                             █
       3. ja                                             │
       4. zh-Hans                                        │
       5. zh-Hant                                        │
  [ Apply ]  [ Cancel ]

At 80×24 the list stops at 11. de with the same lack of a cue, and Theme behaves the same way.

The settings list behind this view already uses render_panel_scroll_rail for exactly this, so the choice list now does too, over the rows the options take. Two details: the rail is painted after the paragraph, because the paragraph restyles its whole area, and labels give up one column only when the rail is drawn, so a long label can't run under it. A list that fits draws no rail and is unchanged. Like the settings list's rail, it's paint-only.

edit_theme_80x24.txt gains the rail in the last column of its eleven option rows and nothing else; edit_theme_120x32.txt fits all 17 themes and is unchanged.

Issue

No-Issue: settings choice lists give no cue that more options are below, no issue filed for it

How I tested it

  • Ran a debug build in a pseudo-terminal with an empty HOME, opened /settings and Enter on Language at 60×16 and 80×24, with this change and with a build from before it; the rows above are from the 60×16 screens. Pressing Down 8 times at 80×24 moves the thumb with the list.
  • Transcript spacing (three choices) at 80×24 is byte-identical before and after. Theme at 40×12 shows the rail with every label clear of it.
  • Re-blessed the 80×24 golden by removing it and running edit_theme_matches_goldens_at_blocker_sizes with CODEWHALE_BLESS_GOLDENS=1; the test passes against the existing 120×32 golden.
  • cargo fmt --all -- --check, cargo clippy -p codewhale-tui --all-targets --all-features with CI's flags, and cargo check -p codewhale-tui --all-targets: clean. Clippy also on 1.99, plus cargo +1.89.0 check -p codewhale-tui.
  • cargo nextest run -p codewhale-tui --lib: 15349 passed, none failed.

Checklist

  • One focused change, on a832057; it merges cleanly into current main
  • cargo fmt --all passes, and tests cover new or changed behavior
  • If this adds or changes a user-facing feature, I updated its docs and its row in docs/features.toml (cargo test -p codewhale-tui --test feature_registry checks it) — n/a

Opening a setting's choices in /settings shows as many options as fit
and scrolls to keep the selected one in view, but nothing on screen
says the list goes on. Language has 17 options; at 80x24 the list ends
at "11. de", at 60x16 at "5. zh-Hant", and there is no hint the other
languages exist until you arrow past the last row. Theme is the same.

The settings list behind it already paints render_panel_scroll_rail
for this, so use it here too, on the rows the options occupy. It is
painted after the paragraph, because the paragraph restyles its whole
area, and the labels give up one column only when the rail is drawn,
so a long label can't run under it. A list that fits draws no rail and
renders as before.

The 80x24 edit-theme golden gains the rail on its option rows; the
120x32 one fits all 17 themes and does not change.

Signed-off-by: Lstarsky0 <59827030+Lstarsky0@users.noreply.github.com>
@Lstarsky0
Lstarsky0 requested a review from Hmbown as a code owner October 18, 2026 18:20

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@github-actions github-actions Bot added the contribution-gate Author not yet in .github/APPROVED_CONTRIBUTORS; a maintainer grants access with /lgtm label Oct 18, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-18T18:24:10.905505Z e46387a PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e46387acc8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Rect {
x: inner.x,
y: inner.y.saturating_add(lines.len() as u16),
width: inner.width,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude the scroll rail from choice hitboxes

When choices overflow (for example, Theme at 80×24), this new rail occupies inner.right() - 1, but each entry in last_choice_hitboxes still uses the full inner.width. handle_mouse therefore treats the rail cell as the underlying choice: moving the pointer across rail rows changes the selection and live-previews those themes, while clicking the paint-only cue selects an option. Reserve the rail column from the recorded choice hitboxes, as the settings list already does.

AGENTS.md reference: crates/tui/AGENTS.md:L22-L24

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Claude Opus 5.5, working for the maintainer.

Confirmed and fixed on main in 3352da9. When the rail is drawn, the choice hitboxes now give up its column, so hovering or clicking the rail no longer selects or live-previews a choice. The hover, live-preview and click paths all hit-test through rect.contains. I merged before reading this review; that was my miss, not @Lstarsky0's.

@Hmbown
Hmbown enabled auto-merge October 18, 2026 20:15
@Hmbown

Hmbown commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator

🤖 Claude Opus 5.5, working for the maintainer.

Thanks, @Lstarsky0. The red Lint run here was not yours. CI tests a PR merged with current main, and main briefly had a clippy manual_strip error in diff_render.rs from my afe5f9b, fixed in 37a596b. I updated your branch so the checks rerun against the fix.

I also checked the rail placement. The body paragraph does not wrap, and it starts at inner.y, so inner.y + lines.len() is the first option row, and the label width gives up a column only when the rail is drawn. Auto-merge is on.

🤖 Generated by Claude Opus 5.5 for the Codewhale maintainers.

@Hmbown
Hmbown merged commit 40818c6 into codewhale-hq:main Oct 18, 2026
27 checks passed
Hmbown pushed a commit that referenced this pull request Oct 18, 2026
#7023 (/mcp status line says "No matches" during an empty search) merged
as 7553ba1; #7024 (scroll rail on /settings choice lists that don't
fit) merged after its branch was updated past the clippy fix in
37a596b. Both changelogs get the same entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
Hmbown pushed a commit that referenced this pull request Oct 18, 2026
Both PRs merged with an unread Codex review finding. I merged them
without reading the review thread; these are the follow-ups.

#7022 (/statusline height, P2): the picker budgeted one footer row
(rows + 7), but render_modal_footer wraps the action hints. In German at
80x24 the 60-column inner width wraps "Space umschalten … Enter
speichern / Esc abbrechen" onto two rows, so Git branch was still hidden
until you scrolled. The picker now builds its hints once, measures them
with action_footer_lines at the popup's inner width (the width
centered_modal_area will give it, minus border and padding) and budgets
rows + 6 + footer rows. The hints array is reused by render_modal_footer.

#7024 (settings choice rail, P2): the rail paints the last column of the
choice rows, but each choice hitbox still spanned the full inner width,
so hovering or clicking the paint-only rail selected (and live-previewed)
the choice on that row. Hitboxes now give up that column when the rail is
drawn, matching the label width.

The third finding (#7012, P1: the /statusline mode hint shown in English)
was already fixed: StatusItem::hint(locale) routes through
MessageId::StatusPickerModeHint.

Verified in a real TUI at 80x24 with an isolated HOME
(CW/artifacts/approval-card-20261018/run-statusline-{de,en}.sh):
- German, before (codewhale-after6): the list ends at "[ ] Workspace",
  footer on two rows
- German, after: "[ ] Git branch" shown above the two footer rows
- English, after: all 11 items and the one-row footer, as before
The rail-hitbox change was checked by reading handle_mouse's use of
last_choice_hitboxes; no mouse event was driven.

Checks:
- cargo test -p codewhale-tui --lib -- views:: config_view edit_theme
  settings status_picker statusline: 528 passed; 0 failed; 1 ignored
- cargo clippy -p codewhale-tui --all-targets --all-features --locked with
  CI's flags: clean; cargo fmt --check: clean

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution-gate Author not yet in .github/APPROVED_CONTRIBUTORS; a maintainer grants access with /lgtm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants