diff --git a/crates/gpui/src/color.rs b/crates/gpui/src/color.rs index 7246af46a8fcdf81bae9e683d14398afba479e59..7a466d2e79fc72c9bf60bd9dba01259e96646474 100644 --- a/crates/gpui/src/color.rs +++ b/crates/gpui/src/color.rs @@ -1,4 +1,4 @@ -use anyhow::bail; +use anyhow::{bail, Context}; use serde::de::{self, Deserialize, Deserializer, Visitor}; use std::fmt; @@ -126,6 +126,7 @@ impl TryFrom<&'_ str> for Rgba { const RRGGBBAA: usize = "rrggbbaa".len(); const EXPECTED_FORMATS: &str = "Expected #rgb, #rgba, #rrggbb, or #rrggbbaa"; + const INVALID_UNICODE: &str = "invalid unicode characters in color"; let Some(("", hex)) = value.trim().split_once('#') else { bail!("invalid RGBA hex color: '{value}'. {EXPECTED_FORMATS}"); @@ -133,11 +134,31 @@ impl TryFrom<&'_ str> for Rgba { let (r, g, b, a) = match hex.len() { RGB | RGBA => { - let r = u8::from_str_radix(&hex[0..1], 16)?; - let g = u8::from_str_radix(&hex[1..2], 16)?; - let b = u8::from_str_radix(&hex[2..3], 16)?; + let r = u8::from_str_radix( + hex.get(0..1).with_context(|| { + format!("{INVALID_UNICODE}: r component of #rgb/#rgba for value: '{value}'") + })?, + 16, + )?; + let g = u8::from_str_radix( + hex.get(1..2).with_context(|| { + format!("{INVALID_UNICODE}: g component of #rgb/#rgba for value: '{value}'") + })?, + 16, + )?; + let b = u8::from_str_radix( + hex.get(2..3).with_context(|| { + format!("{INVALID_UNICODE}: b component of #rgb/#rgba for value: '{value}'") + })?, + 16, + )?; let a = if hex.len() == RGBA { - u8::from_str_radix(&hex[3..4], 16)? + u8::from_str_radix( + hex.get(3..4).with_context(|| { + format!("{INVALID_UNICODE}: a component of #rgba for value: '{value}'") + })?, + 16, + )? } else { 0xf }; @@ -151,11 +172,40 @@ impl TryFrom<&'_ str> for Rgba { (duplicate(r), duplicate(g), duplicate(b), duplicate(a)) } RRGGBB | RRGGBBAA => { - let r = u8::from_str_radix(&hex[0..2], 16)?; - let g = u8::from_str_radix(&hex[2..4], 16)?; - let b = u8::from_str_radix(&hex[4..6], 16)?; + let r = u8::from_str_radix( + hex.get(0..2).with_context(|| { + format!( + "{}: r component of #rrggbb/#rrggbbaa for value: '{}'", + INVALID_UNICODE, value + ) + })?, + 16, + )?; + let g = u8::from_str_radix( + hex.get(2..4).with_context(|| { + format!( + "{INVALID_UNICODE}: g component of #rrggbb/#rrggbbaa for value: '{value}'" + ) + })?, + 16, + )?; + let b = u8::from_str_radix( + hex.get(4..6).with_context(|| { + format!( + "{INVALID_UNICODE}: b component of #rrggbb/#rrggbbaa for value: '{value}'" + ) + })?, + 16, + )?; let a = if hex.len() == RRGGBBAA { - u8::from_str_radix(&hex[6..8], 16)? + u8::from_str_radix( + hex.get(6..8).with_context(|| { + format!( + "{INVALID_UNICODE}: a component of #rrggbbaa for value: '{value}'" + ) + })?, + 16, + )? } else { 0xff };