From ac5f20dfa754cdbd4048b13d45cba8220a3a7bdb Mon Sep 17 00:00:00 2001 From: Adam Hitchcock Date: Thu, 1 Oct 2026 00:17:01 -0700 Subject: [PATCH] fix(themes): accept integer colour components in .itermcolors files (#1059) * fix(themes): accept integer colour components in .itermcolors files iTerm2 and plistlib write exact 0 and 1 as , which the loader rejected, dropping the whole theme. Co-Authored-By: Claude Opus 5.5 * docs(changelog): drop the Unreleased entry; the release notes carry it Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- src/ui/presets.rs | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/ui/presets.rs b/src/ui/presets.rs index ba917ab1..dd7b8321 100644 --- a/src/ui/presets.rs +++ b/src/ui/presets.rs @@ -1188,7 +1188,11 @@ fn load_iterm_theme(path: &std::path::Path) -> Result { let color = |key: &str| -> Option { let c = dict.get(key)?.as_dictionary()?; let comp = |k: &str| -> Option { - let f = c.get(k)?.as_real()?; + // iTerm2 and plistlib write exact 0 and 1 as ``. + let v = c.get(k)?; + let f = v + .as_real() + .or_else(|| v.as_signed_integer().map(|i| i as f64))?; Some((f.clamp(0.0, 1.0) * 255.0).round() as u32) }; Some( @@ -2584,6 +2588,35 @@ ansi: assert_eq!(img.opacity, 0.4); } + #[test] + fn iterm_theme_accepts_integer_components_and_no_alpha() { + let entry = |key: String, r: &str| { + format!( + "{key}Red Component{r}\ + Green Component0.5\ + Blue Component0" + ) + }; + let mut body: String = (0..16) + .map(|i| entry(format!("Ansi {i} Color"), "1")) + .collect(); + body += &entry("Background Color".into(), "0"); + body += &entry("Foreground Color".into(), "1.0"); + let xml = format!( + "\ + {body}" + ); + let path = + std::env::temp_dir().join(format!("tty7-int-{}.itermcolors", std::process::id())); + std::fs::write(&path, xml).unwrap(); + let theme = load_iterm_theme(&path); + let _ = std::fs::remove_file(&path); + let theme = theme.unwrap(); + assert_eq!(theme.ansi16[2], (0xff, 0x80, 0x00)); + assert_eq!(theme.background_color(), 0x008000); + assert_eq!(theme.foreground, 0xff8000); + } + #[test] fn id_and_name_titlecases_the_stem() { let (id, name) = id_and_name(std::path::Path::new("/x/solarized_dark.yaml"));