color-to-tui-0.3.0/.cargo_vcs_info.json0000644000000001360000000000100133710ustar { "git": { "sha1": "844395d6877c4af5adbd614973a88a40d6514dde" }, "path_in_vcs": "" }color-to-tui-0.3.0/.gitignore000064400000000000000000000001411046102023000141450ustar 00000000000000/target # Added by cargo # # already existing elements were commented out #/target Cargo.lock color-to-tui-0.3.0/Cargo.toml0000644000000021270000000000100113710ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "color-to-tui" version = "0.3.0" authors = ["Uttarayan Mondal "] exclude = [ ".drone.yml", ".github/*", ] description = "Parse colors and convert them to ratatui::style::Colors" homepage = "https://git.uttarayan.me/uttarayan/color-to-tui" readme = "README.md" license = "MIT" repository = "https://git.uttarayan.me/uttarayan/color-to-tui" [dependencies.serde] version = "1.0" features = ["derive"] [dependencies.tui] version = "0.*" default-features = false package = "ratatui" [dev-dependencies.serde_json] version = "1.0.68" [features] default = ["optional"] optional = [] color-to-tui-0.3.0/Cargo.toml.orig000064400000000000000000000012731046102023000150530ustar 00000000000000[package] name = "color-to-tui" version = "0.3.0" authors = ["Uttarayan Mondal "] edition = "2021" description = "Parse colors and convert them to ratatui::style::Colors" homepage = "https://git.uttarayan.me/uttarayan/color-to-tui" repository = "https://git.uttarayan.me/uttarayan/color-to-tui" license = "MIT" exclude = [".drone.yml", ".github/*"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] serde = { version = "1.0", features = ["derive"] } tui = { package="ratatui", version = "0.*", default-features = false } [dev-dependencies] serde_json = "1.0.68" [features] default = ["optional"] optional = [] color-to-tui-0.3.0/README.md000064400000000000000000000022401046102023000134360ustar 00000000000000# Color -> TUI [![build](https://img.shields.io/drone/build/uttarayan/color-to-tui?server=https%3A%2F%2Fdrone.uttarayan.me)][color-to-tui] [![build](https://github.com/uttarayan21/color-to-tui/actions/workflows/build.yaml/badge.svg)][mirror] Parse HEX colors to [ratatui](https://github.com/tui-rs-revival/ratatui)'s [Rgb](https://docs.rs/ratatui/latest/ratatui/style/enum.Color.html) colors. ## Example - `#C3F111` -> `Color::Rgb(195,241,17)` - `#CFB` -> `Color::Rgb(204,255,187)` - `142` -> `Color::Indexed(142)` ## Usage ```rust #[derive(Serialize, Deserialize, PartialEq)] sruct ColorStruct { #[serde(with = "color_to_tui"] color: ratatui::style::Color, #[serde(with = "color_to_tui::optional"] optional_color: Option, } let color_text = r###"{ "color" : "#12FC1C", "optional_color" : "123" }"### let t: ColorStruct = serde_json::from_str::(color_text).unwrap(); let c = ColorStruct { color: Color::Rgb(18, 252, 28), optional_color: Option, }; assert_eq!(t, c); ``` [color-to-tui]: https://git.uttarayan.me/uttarayan/color-to-tui [mirror]: https://github.com/uttarayan21/color-to-tui color-to-tui-0.3.0/src/lib.rs000064400000000000000000000140631046102023000140700ustar 00000000000000#[cfg(feature = "optional")] pub mod optional; use serde::{Deserialize, Deserializer, Serializer}; use tui::style::Color; pub fn serialize(color: &Color, serializer: S) -> Result { serializer.serialize_str(&match color { Color::Reset => "Reset".to_string(), Color::Red => "Red".to_string(), Color::Green => "Green".to_string(), Color::Black => "Black".to_string(), Color::Yellow => "Yellow".to_string(), Color::Blue => "Blue".to_string(), Color::Magenta => "Magenta".to_string(), Color::Cyan => "Cyan".to_string(), Color::Gray => "Gray".to_string(), Color::White => "White".to_string(), Color::DarkGray => "DarkGray".to_string(), Color::LightBlue => "LightBlue".to_string(), Color::LightCyan => "LightCyan".to_string(), Color::LightGreen => "LightGreen".to_string(), Color::LightMagenta => "LightMagenta".to_string(), Color::LightRed => "LightRed".to_string(), Color::LightYellow => "LightYellow".to_string(), Color::Indexed(index) => format!("{:03}", index), Color::Rgb(r, g, b) => format!("#{:02X}{:02X}{:02X}", r, g, b), }) } pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result { use serde::de::{Error, Unexpected}; let color_string = String::deserialize(deserializer)?; Ok(match color_string.to_lowercase().as_str() { "reset" => Color::Reset, "red" => Color::Red, "green" => Color::Green, "black" => Color::Black, "yellow" => Color::Yellow, "blue" => Color::Blue, "magenta" => Color::Magenta, "cyan" => Color::Cyan, "gray" => Color::Gray, "white" => Color::White, "darkgray" => Color::DarkGray, "lightblue" => Color::LightBlue, "lightcyan" => Color::LightCyan, "lightgreen" => Color::LightGreen, "lightmagenta" => Color::LightMagenta, "lightred" => Color::LightRed, "lightyellow" => Color::LightYellow, _ => match color_string.len() { 3 => { let index = color_string.parse::(); if let Ok(index) = index { Color::Indexed(index) } else { return Err(Error::invalid_type( Unexpected::Bytes(color_string.as_bytes()), &"u8 index color", )); } } 4 | 7 => { if !color_string.starts_with('#') { return Err(Error::invalid_value( Unexpected::Char(color_string.chars().next().unwrap()), &"# at the start", )); } let color_string = color_string.trim_start_matches('#'); let (r, g, b); match color_string.len() { 6 => { r = u8::from_str_radix(&color_string[0..2], 16); g = u8::from_str_radix(&color_string[2..4], 16); b = u8::from_str_radix(&color_string[4..6], 16); } 3 => { r = u8::from_str_radix(&color_string[0..1], 16).map(|r| r * 17); g = u8::from_str_radix(&color_string[1..2], 16).map(|g| g * 17); b = u8::from_str_radix(&color_string[2..3], 16).map(|b| b * 17); } _ => unreachable!("Can't be reached since already checked"), } match (r, g, b) { (Ok(r), Ok(g), Ok(b)) => Color::Rgb(r, g, b), (_, _, _) => { return Err(Error::invalid_value( Unexpected::Bytes(color_string.as_bytes()), &"hex color string", )); } } } _ => { return Err(serde::de::Error::invalid_length( color_string.len(), &"color string with length 4 or 7", )) } }, }) } #[cfg(test)] mod tests { use serde::{Deserialize, Serialize}; use tui::style::Color; #[derive(Debug, PartialEq, Serialize, Deserialize)] struct Test { #[serde(with = "super")] pub c: Color, } #[test] fn serialize_index() { let color: Color = Color::Indexed(123); let t = Test { c: color }; let color_string = serde_json::to_string(&t).unwrap(); assert_eq!(color_string, r###"{"c":"123"}"###); } #[test] fn serialize_hex() { let color: Color = Color::Rgb(18, 252, 28); let t = Test { c: color }; let color_string = serde_json::to_string(&t).unwrap(); assert_eq!(color_string, r###"{"c":"#12FC1C"}"###); } #[test] fn deserialize_hex() { let color: Color = Color::Rgb(18, 252, 28); let color_text = r###"{ "c": "#12fc1c" }"###; let t: Test = serde_json::from_str::(color_text).unwrap(); assert_eq!(t, Test { c: color }); } #[test] fn deserialize_short_hex() { let color: Color = Color::Rgb(255, 255, 170); let color_text = r###"{ "c": "#FFA" }"###; let t: Test = serde_json::from_str::(color_text).unwrap(); assert_eq!(t, Test { c: color }); } #[test] fn deserialize_hex_and_short_hex() { let color_text_hex = r###"{ "c": "#FF99CC" }"###; let color_text_short_hex = r###"{ "c": "#F9C" }"###; let t_h: Test = serde_json::from_str::(color_text_hex).unwrap(); let t_sh: Test = serde_json::from_str::(color_text_short_hex).unwrap(); assert_eq!(t_h, t_sh); } #[test] fn deserialize_index() { let color: Color = Color::Indexed(123); let color_text = r###"{ "c": "123" }"###; let t: Test = serde_json::from_str::(color_text).unwrap(); assert_eq!(t, Test { c: color }); } } color-to-tui-0.3.0/src/optional.rs000064400000000000000000000143151046102023000151470ustar 00000000000000use serde::{Deserialize, Deserializer, Serializer}; use tui::style::Color; pub fn serialize(color: &Option, serializer: S) -> Result { use serde::ser::Error; if color.is_none() { return Err(Error::custom("color is none")); } let color = color.unwrap(); serializer.serialize_str(&match color { Color::Reset => "Reset".to_string(), Color::Red => "Red".to_string(), Color::Green => "Green".to_string(), Color::Black => "Black".to_string(), Color::Yellow => "Yellow".to_string(), Color::Blue => "Blue".to_string(), Color::Magenta => "Magenta".to_string(), Color::Cyan => "Cyan".to_string(), Color::Gray => "Gray".to_string(), Color::White => "White".to_string(), Color::DarkGray => "DarkGray".to_string(), Color::LightBlue => "LightBlue".to_string(), Color::LightCyan => "LightCyan".to_string(), Color::LightGreen => "LightGreen".to_string(), Color::LightMagenta => "LightMagenta".to_string(), Color::LightRed => "LightRed".to_string(), Color::LightYellow => "LightYellow".to_string(), Color::Indexed(index) => format!("{:03}", index), Color::Rgb(r, g, b) => format!("#{:02X}{:02X}{:02X}", r, g, b), }) } pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result, D::Error> { use serde::de::{Error, Unexpected}; let color_string = String::deserialize(deserializer)?; Ok(Some(match color_string.to_lowercase().as_str() { "reset" => Color::Reset, "red" => Color::Red, "green" => Color::Green, "black" => Color::Black, "yellow" => Color::Yellow, "blue" => Color::Blue, "magenta" => Color::Magenta, "cyan" => Color::Cyan, "gray" => Color::Gray, "white" => Color::White, "darkgray" => Color::DarkGray, "lightblue" => Color::LightBlue, "lightcyan" => Color::LightCyan, "lightgreen" => Color::LightGreen, "lightmagenta" => Color::LightMagenta, "lightred" => Color::LightRed, "lightyellow" => Color::LightYellow, _ => match color_string.len() { 3 => { let index = color_string.parse::(); if let Ok(index) = index { Color::Indexed(index) } else { return Err(Error::invalid_type( Unexpected::Bytes(color_string.as_bytes()), &"u8 index color", )); } } 4 | 7 => { if !color_string.starts_with('#') { return Err(Error::invalid_value( Unexpected::Char(color_string.chars().next().unwrap()), &"# at the start", )); } let color_string = color_string.trim_start_matches('#'); let (r, g, b); match color_string.len() { 6 => { r = u8::from_str_radix(&color_string[0..2], 16); g = u8::from_str_radix(&color_string[2..4], 16); b = u8::from_str_radix(&color_string[4..6], 16); } 3 => { r = u8::from_str_radix(&color_string[0..1], 16).map(|r| r * 17); g = u8::from_str_radix(&color_string[1..2], 16).map(|g| g * 17); b = u8::from_str_radix(&color_string[2..3], 16).map(|b| b * 17); } _ => unreachable!("Can't be reached since already checked"), } match (r, g, b) { (Ok(r), Ok(g), Ok(b)) => Color::Rgb(r, g, b), (_, _, _) => { return Err(Error::invalid_value( Unexpected::Bytes(color_string.as_bytes()), &"hex color string", )); } } } _ => { return Err(serde::de::Error::invalid_length( color_string.len(), &"color string with length 4 or 7", )) } }, })) } #[cfg(test)] mod tests { use serde::{Deserialize, Serialize}; use tui::style::Color; #[derive(Debug, PartialEq, Serialize, Deserialize)] struct Test { #[serde(with = "super")] pub c: Option, } #[test] fn serialize_index() { let color: Color = Color::Indexed(123); let t = Test { c: Some(color) }; let color_string = serde_json::to_string(&t).unwrap(); assert_eq!(color_string, r###"{"c":"123"}"###); } #[test] fn serialize_hex() { let color: Color = Color::Rgb(18, 252, 28); let t = Test { c: Some(color) }; let color_string = serde_json::to_string(&t).unwrap(); assert_eq!(color_string, r###"{"c":"#12FC1C"}"###); } #[test] fn deserialize_hex() { let color: Color = Color::Rgb(18, 252, 28); let color_text = r###"{ "c": "#12fc1c" }"###; let t: Test = serde_json::from_str::(color_text).unwrap(); assert_eq!(t, Test { c: Some(color) }); } #[test] fn deserialize_short_hex() { let color: Color = Color::Rgb(255, 255, 170); let color_text = r###"{ "c": "#FFA" }"###; let t: Test = serde_json::from_str::(color_text).unwrap(); assert_eq!(t, Test { c: Some(color) }); } #[test] fn deserialize_hex_and_short_hex() { let color_text_hex = r###"{ "c": "#FF99CC" }"###; let color_text_short_hex = r###"{ "c": "#F9C" }"###; let t_h: Test = serde_json::from_str::(color_text_hex).unwrap(); let t_sh: Test = serde_json::from_str::(color_text_short_hex).unwrap(); assert_eq!(t_h, t_sh); } #[test] fn deserialize_index() { let color: Color = Color::Indexed(123); let color_text = r###"{ "c": "123" }"###; let t: Test = serde_json::from_str::(color_text).unwrap(); assert_eq!(t, Test { c: Some(color) }); } }