Skip to content

feat(tui): ship staged /uwu theme#4696

Merged
Hmbown merged 1 commit into
mainfrom
codex/v091-uwu-theme
Jul 22, 2026
Merged

feat(tui): ship staged /uwu theme#4696
Hmbown merged 1 commit into
mainfrom
codex/v091-uwu-theme

Conversation

@Hmbown

@Hmbown Hmbown commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

Ships the staged uwu theme from cw-modern/themes/ without redesign.

Behavior

  • /themeUwu, or theme = "uwu"
  • Aliases: owo, kawaiiuwu
  • When active, empty-state whale uses soft-classic mark (blush + one sparkle )
  • Color shimmer only; mark shape is not animated

Wire-up

  • palette/themes.rsUWU_UI_THEME, ThemeId::Uwu, SELECTABLE, normalize, picker labels
  • config_ui.rsUiThemeValue::Uwu + schema enum test
  • tui/underwater.rs — soft rows/bubble when ui_theme.name == "uwu"; sakura on //·

Verify

cargo test -p codewhale-tui --bin codewhale-tui --locked palette::themes
# 4 passed
python3 cw-modern/themes/check_uwu_distinct.py
# ok — uwu mode badges + semantic lanes are distinct

Out of scope

No uwu-light, no motion/fish changes, no palette redesign.

Copilot AI review requested due to automatic review settings July 22, 2026 18:06
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@claude

claude Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 3m 31s —— View job


Reviewing PR #4696 — /uwu theme

  • Gather context (diff, changed files)
  • Review palette/themes.rs changes
  • Review config_ui.rs changes
  • Review tui/underwater.rs changes
  • Check provider/model safety invariant (N/A — UI-only PR)
  • Check tests / reuse / simplification
  • Post inline comments + final review

Summary

Focused review of the diff (crates/tui/src/{palette/themes.rs, config_ui.rs, tui/underwater.rs}, +107/-7). No provider/model routing code touched, so the v0.8.65 EPIC #2608 invariant doesn't apply here.

Good

  • themes.rs / config_ui.rs wiring is exhaustive and consistent with the existing pattern: ThemeId::Uwu and UiThemeValue::Uwu are threaded through every match arm (from_str, as_str, label, description, theme()), SELECTABLE_THEMES, normalize_theme_name (with the owo/kawaii aliases), and the schema enum test.
  • Small, scoped diff that matches the PR's stated "no redesign, no motion changes" intent.

Found 2 correctness issues in underwater.rs (posted as inline comments), both stemming from the same root cause — new theme-conditional code paths that don't actually condition on the active theme:

  1. Off-center uwu whale markidle_whale_block_width() (~line 1084) returns classic_width.max(uwu_width) unconditionally, but only one variant renders per theme. Classic's widest row is 23 cols, uwu's is ~20 cols, so the block_inset centering math (line 1135) always uses 23, shifting the uwu mark ~1-2 columns off true center.
  2. Wrong cols in shimmer diagonal calcidle_whale_row_spans (~line 1044-1048) computes cols from the classic IDLE_WHALE_ROWS array even when rendering uwu rows, so the shimmer sweep is normalized against the wrong width for uwu. Cosmetic only (opacity is clamped), but same fix should cover both.

Both are minor since the base widths are close and colors still clamp safely — no panics or crashes — but they undercut the "distinct, polished" bar the PR sets for itself.

Minor style note: idle_whale_is_uwu compares app.ui_theme.name == "uwu" (a string) rather than app.theme_id == palette::ThemeId::Uwu, which is already available on App and is how the rest of the codebase dispatches on theme (ocean.rs, theme_picker.rs). The enum gives compiler-checked exhaustiveness; the string doesn't.

Tests: the new underwater.rs behavior (variant selection, block width, highlight color choice) has no unit coverage — only palette::themes (4 tests) and the python distinctness script are exercised per the PR's own verify steps.

Comment on lines 1084 to 1097
#[must_use]
fn idle_whale_block_width() -> usize {
std::iter::once(IDLE_WHALE_SPOUT_ROW)
let classic = std::iter::once(IDLE_WHALE_SPOUT_ROW)
.chain(IDLE_WHALE_ROWS.iter().copied())
.map(UnicodeWidthStr::width)
.max()
.unwrap_or(0)
.unwrap_or(0);
let uwu = std::iter::once(UWU_IDLE_WHALE_SPOUT_ROW)
.chain(UWU_IDLE_WHALE_ROWS.iter().copied())
.map(UnicodeWidthStr::width)
.max()
.unwrap_or(0);
classic.max(uwu)
}

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.

Off-center uwu whale. idle_whale_block_width() returns classic.max(uwu) unconditionally, but only one variant is ever rendered (selected via idle_whale_is_uwu at the call site). The classic block's widest row is 23 cols (" ▐██·███████████▙━━━━▞") while the uwu block's widest row is 20 cols (" ▗▄▄▄▄▄▄▄▄▄▄▄▖ ▚▞"). Since this max is always 23, the block_inset computed at line 1135 (width.saturating_sub(idle_whale_block_width()) / 2) over-indents the uwu mark by ~1-2 columns versus true center, contradicting the "one drawing, same outer inset" centering invariant described in the comment just below.

Fix: make this width theme-aware, mirroring idle_whale_rows/idle_whale_spout_row, e.g. fn idle_whale_block_width(app: &App) -> usize that only measures the active variant's rows/spout.

Fix this →

Comment on lines +1014 to +1016
fn idle_whale_is_uwu(app: &App) -> bool {
app.ui_theme.name == "uwu"
}

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.

Minor: this compares app.ui_theme.name (a &str) rather than app.theme_id (palette::ThemeId, already on App per crates/tui/src/tui/app.rs:2362). Elsewhere in the codebase theme dispatch switches on the ThemeId enum (e.g. ocean.rs:473, theme_picker.rs:167), which the compiler can exhaustively check. A string compare against "uwu" has no such guardrail against typos/renames. Consider app.theme_id == palette::ThemeId::Uwu for consistency, unless there's a reason ui_theme can diverge from theme_id that I'm missing.

for (column, ch) in text.chars().enumerate() {
let diagonal = (column as f32 + (rows - 1.0 - row as f32)) / (cols + rows);
let color = if ch == '·' {
let color = if matches!(ch, '·' | '░' | '✦') {

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.

Same root cause as the block-width issue on idle_whale_block_width below: rows/cols computed at lines 1043-1048 are always derived from IDLE_WHALE_ROWS (the classic array), even when text here is actually a UWU_IDLE_WHALE_ROWS row. cols feeds directly into the diagonal shimmer-band calc on line 1054, so the uwu whale's shimmer sweep is normalized against the wrong column count (23 vs its actual ~20). Cosmetic-only (opacity is clamped to [0,1]), but same fix would cover both spots — thread the active row set through instead of hardcoding the classic array.

Wire the pre-designed UWU_UI_THEME into ThemeId/SELECTABLE_THEMES with
aliases owo/kawaii, settings UiThemeValue parity, and the soft-classic
empty-state whale (blush + one sparkle) when theme is uwu. No palette
redesign; color shimmer only on the mark.

Signed-off-by: Hunter B <hmbown@gmail.com>
@Hmbown
Hmbown force-pushed the codex/v091-uwu-theme branch from aa2c0d4 to 20a30dd Compare July 22, 2026 18:20
@claude

claude Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 1m 11s —— View job


Re-reviewing PR #4696 — /uwu theme (new commits pushed)

  • Gather context (diff since last review)
  • Check whether prior review findings were addressed
  • Review full current diff for new issues
  • Post updated review

Summary

This trigger fired on pull request synchronize, but the branch is still at a single commit (20a30dd, unchanged since the previous review) — git diff origin/main...HEAD --stat shows the same +107/-7 across the same 3 files. No new changes landed, so the three findings from the prior review are all still present and unaddressed in crates/tui/src/tui/underwater.rs:

  1. Off-center uwu whale (idle_whale_block_width(), lines 1084–1097) — still returns classic.max(uwu) unconditionally rather than measuring only the active theme's variant, so block_inset (line 1135) over-indents the uwu mark by ~1–2 columns vs. true center.
  2. Wrong cols in shimmer diagonal calc (idle_whale_row_spans, lines 1043–1048) — still derives rows/cols from the classic IDLE_WHALE_ROWS array unconditionally, even when rendering uwu rows, so the shimmer sweep (line 1054) is normalized against the wrong width for uwu. Cosmetic only (opacity clamps to [0,1]), but same root cause as Fix cargo fmt formatting issues #1.
  3. String-based theme dispatch (idle_whale_is_uwu, lines 1014–1016) — still compares app.ui_theme.name == "uwu" instead of app.theme_id == palette::ThemeId::Uwu, which is already available on App and is how ocean.rs/theme_picker.rs dispatch on theme elsewhere. Minor, but loses compiler-checked exhaustiveness.

No new correctness, provider/model-routing, reuse, or security issues found beyond these three (the palette/themes.rs and config_ui.rs wiring remains exhaustive and correct, as previously noted). Test coverage gap also remains: no unit tests for underwater.rs's new variant-selection/width/highlight logic.

CI is currently in progress (no failures observed at time of review).

Fix this →

@Hmbown
Hmbown merged commit d27a936 into main Jul 22, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants