aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorakbash <akbash@herdr.dev>2026-09-05 19:11:19 +0300
committerGitHub <noreply@github.com>2026-09-05 18:11:19 +0200
commit6c52aad511b0fb601e6223bd6ad944f48cbdba6d (patch)
treec0e70d6ea13b40fc5d6be14e8e99e2de7e359ce9
parentaf7e189bd6749e7ecfa67d8c24f79c1bb1a498b0 (diff)
fix(ui): keep selections visible without host colors (#2710)
* fix(ui): keep selections visible without host colors refs #2708 * test(ui): strengthen selection fallback coverage refs #2708 * fix(ui): preserve selection contrast and terminal palette colors refs #2708 --------- Co-authored-by: akbash-bot <300245827+akbash-bot@users.noreply.github.com> Co-authored-by: Jonathan Liebig <jonathan.liebig@gmail.com>
-rw-r--r--src/ui/panes.rs74
1 files changed, 68 insertions, 6 deletions
diff --git a/src/ui/panes.rs b/src/ui/panes.rs
index e31ee0ad..fbd7b8eb 100644
--- a/src/ui/panes.rs
+++ b/src/ui/panes.rs
@@ -728,8 +728,16 @@ fn automatic_selection_style(
}
fn automatic_selection_bg(p: &Palette, host_theme: crate::terminal_theme::TerminalTheme) -> Color {
- let Some(background) = host_theme.background.map(terminal_theme_to_rgb) else {
- return selection_palette_background(p);
+ let fallback = selection_palette_background(p);
+ let Some(background) = host_theme
+ .background
+ .map(|color| (color.r, color.g, color.b))
+ .or(match fallback {
+ Color::Rgb(r, g, b) => Some((r, g, b)),
+ _ => None,
+ })
+ else {
+ return fallback;
};
let target = if relative_luminance(background) < 0.5 {
@@ -749,11 +757,18 @@ fn selection_palette_background(p: &Palette) -> Color {
}
}
-fn terminal_theme_to_rgb(color: crate::terminal_theme::RgbColor) -> Rgb {
- (color.r, color.g, color.b)
-}
-
fn selection_fg_for_bg(bg: Color, p: &Palette) -> Color {
+ if let Color::Rgb(r, g, b) = bg {
+ let luminance = relative_luminance((r, g, b));
+ let black_contrast = (luminance + 0.05) / 0.05;
+ let white_contrast = 1.05 / (luminance + 0.05);
+ return if black_contrast > white_contrast {
+ Color::Rgb(0, 0, 0)
+ } else {
+ Color::Rgb(255, 255, 255)
+ };
+ }
+
color_to_rgb(bg)
.map(|bg| {
if relative_luminance(bg) < 0.5 {
@@ -1416,4 +1431,51 @@ mod tests {
};
assert!(relative_luminance((r, g, b)) > relative_luminance((12, 14, 16)));
}
+
+ #[test]
+ fn automatic_selection_rgb_style_is_readable_with_or_without_host_background() {
+ for (background, selected_bg, selected_fg) in [
+ ((239, 241, 245), (172, 174, 176), (0, 0, 0)),
+ ((26, 27, 38), (90, 91, 99), (255, 255, 255)),
+ ((45, 53, 59), (104, 110, 114), (255, 255, 255)),
+ ] {
+ let mut palette = Palette::catppuccin();
+ let (r, g, b) = background;
+ palette.panel_bg = Color::Rgb(r, g, b);
+ let expected = Style::reset()
+ .bg(Color::Rgb(selected_bg.0, selected_bg.1, selected_bg.2))
+ .fg(Color::Rgb(selected_fg.0, selected_fg.1, selected_fg.2));
+
+ assert_eq!(
+ automatic_selection_style(&palette, Default::default()),
+ expected
+ );
+ assert_eq!(
+ automatic_selection_style(
+ &Palette::terminal(),
+ crate::terminal_theme::TerminalTheme {
+ background: Some(crate::terminal_theme::RgbColor { r, g, b }),
+ ..Default::default()
+ },
+ ),
+ expected
+ );
+ }
+ }
+
+ #[test]
+ fn automatic_selection_preserves_symbolic_palette_fallbacks() {
+ let mut palette = Palette::terminal();
+ assert_eq!(
+ automatic_selection_style(&palette, Default::default()),
+ Style::reset().fg(Color::White).bg(Color::DarkGray)
+ );
+ for fallback in [Color::Blue, Color::White, Color::Indexed(42), Color::Reset] {
+ palette.surface_dim = fallback;
+ assert_eq!(
+ automatic_selection_bg(&palette, Default::default()),
+ fallback
+ );
+ }
+ }
}