(
json: &OpencodeThemeJson,
defs: &HashMap<String, ColorValueJson>,
s: &str,
mode: &str,
seen: &mut HashSet<String>,
)
| 927 | } |
| 928 | |
| 929 | fn resolve_color_string( |
| 930 | json: &OpencodeThemeJson, |
| 931 | defs: &HashMap<String, ColorValueJson>, |
| 932 | s: &str, |
| 933 | mode: &str, |
| 934 | seen: &mut HashSet<String>, |
| 935 | ) -> anyhow::Result<Color> { |
| 936 | let t = s.trim(); |
| 937 | if t.eq_ignore_ascii_case("none") || t.eq_ignore_ascii_case("transparent") { |
| 938 | return Ok(Color::Reset); |
| 939 | } |
| 940 | |
| 941 | if let Some(hex) = t.strip_prefix('#') { |
| 942 | if hex.len() == 6 { |
| 943 | let r = u8::from_str_radix(&hex[0..2], 16)?; |
| 944 | let g = u8::from_str_radix(&hex[2..4], 16)?; |
| 945 | let b = u8::from_str_radix(&hex[4..6], 16)?; |
| 946 | return Ok(Color::Rgb(r, g, b)); |
| 947 | } else if hex.len() == 8 { |
| 948 | let r = u8::from_str_radix(&hex[0..2], 16)?; |
| 949 | let g = u8::from_str_radix(&hex[2..4], 16)?; |
| 950 | let b = u8::from_str_radix(&hex[4..6], 16)?; |
| 951 | let a = u8::from_str_radix(&hex[6..8], 16)?; |
| 952 | let base = if mode == "light" { 255 } else { 0 }; |
| 953 | return Ok(Color::Rgb( |
| 954 | blend_alpha_channel(r, a, base), |
| 955 | blend_alpha_channel(g, a, base), |
| 956 | blend_alpha_channel(b, a, base), |
| 957 | )); |
| 958 | } |
| 959 | } |
| 960 | |
| 961 | // Reference resolution: defs first, then theme keys. |
| 962 | if !seen.insert(t.to_string()) { |
| 963 | anyhow::bail!("Theme color reference cycle detected at \"{}\"", t); |
| 964 | } |
| 965 | |
| 966 | if let Some(v) = defs.get(t) { |
| 967 | return resolve_color_value(json, defs, v, mode, seen); |
| 968 | } |
| 969 | if let Some(v) = json.theme.get(t) { |
| 970 | return resolve_color_value(json, defs, v, mode, seen); |
| 971 | } |
| 972 | |
| 973 | anyhow::bail!("Theme color reference \"{}\" not found", t) |
| 974 | } |
| 975 | |
| 976 | fn blend_alpha_channel(fg: u8, alpha: u8, bg: u8) -> u8 { |
| 977 | let fg = fg as u16; |
no test coverage detected