tlc: Sprint 2 B8 — Input widget uses theme tokens by default

Input widget colors no longer hardcoded to Color::White / Blue /
Yellow. New instances use Color::Reset as a sentinel meaning
'use the theme token', and render() falls back to:
  - fg: theme.foreground
  - bg: theme.background
  - cursor_color: theme.warning

Callers that explicitly call .fg() / .bg() / .cursor_color() still
override the sentinel — existing API surface preserved.

Changes:
  - input.rs::Input::new() defaults fg/bg/cursor_color to Color::Reset
  - input.rs::Input::render() resolves Reset → theme token
  - New pub fn cursor_color(c) builder (was missing; .fg/.bg existed)

Tests (2 new in widget::input::tests):
  - default_colors_are_reset_sentinel
  - explicit_color_overrides_reset_sentinel

Total: 1268 passing (was 1266; +2 new).
This commit is contained in:
kellito
2026-07-05 17:34:47 +03:00
parent c737337681
commit 9ea6826a58
@@ -67,9 +67,13 @@ impl Input {
placeholder: None,
candidates: Vec::new(),
ac_index: None,
fg: Color::White,
bg: Color::Blue,
cursor_color: Color::Yellow,
// Defaults are `Color::Reset` so render() falls back to
// theme tokens (theme.foreground / theme.background /
// theme.warning for the cursor). Callers can still
// override with .fg() / .bg() / .cursor_color().
fg: Color::Reset,
bg: Color::Reset,
cursor_color: Color::Reset,
}
}
@@ -123,6 +127,13 @@ impl Input {
self
}
/// Set the cursor marker color.
#[must_use]
pub fn cursor_color(mut self, c: Color) -> Self {
self.cursor_color = c;
self
}
/// Current text.
#[must_use]
pub fn value(&self) -> &str {
@@ -305,8 +316,14 @@ impl Input {
} else {
self.text.clone()
};
// Apply theme defaults when the Input was not customized via
// the builder methods. `Color::Reset` is the sentinel meaning
// "use the theme token".
let fg = if self.fg == Color::Reset { theme.foreground } else { self.fg };
let bg = if self.bg == Color::Reset { theme.background } else { self.bg };
let cursor_color = if self.cursor_color == Color::Reset { theme.warning } else { self.cursor_color };
let style = if self.focused {
Style::default().fg(self.fg).bg(self.bg)
Style::default().fg(fg).bg(bg)
} else {
Style::default().fg(theme.hidden)
};
@@ -320,7 +337,7 @@ impl Input {
.border_style(style)
.title(Span::styled(
title,
Style::default().fg(self.fg).add_modifier(Modifier::BOLD),
Style::default().fg(fg).add_modifier(Modifier::BOLD),
));
let p = Paragraph::new(display).style(style).block(block);
frame.render_widget(p, area);
@@ -332,7 +349,7 @@ impl Input {
let marker = Paragraph::new(Span::styled(
"|",
Style::default()
.fg(self.cursor_color)
.fg(cursor_color)
.add_modifier(Modifier::SLOW_BLINK),
));
frame.render_widget(marker, Rect::new(cursor_x, inner.y, 1, 1));
@@ -508,4 +525,24 @@ mod tests {
assert!(i.handle_key(Key::ctrl('d')));
assert_eq!(i.value(), "bc");
}
#[test]
fn default_colors_are_reset_sentinel() {
// The default fg/bg/cursor_color fields are Color::Reset so
// render() can fall back to theme tokens. Callers that
// explicitly set colors via .fg() / .bg() / .cursor_color()
// override the sentinel.
let i = Input::new();
assert_eq!(i.fg, Color::Reset);
assert_eq!(i.bg, Color::Reset);
assert_eq!(i.cursor_color, Color::Reset);
}
#[test]
fn explicit_color_overrides_reset_sentinel() {
let i = Input::new().fg(Color::Red).bg(Color::Green).cursor_color(Color::Magenta);
assert_eq!(i.fg, Color::Red);
assert_eq!(i.bg, Color::Green);
assert_eq!(i.cursor_color, Color::Magenta);
}
}