style.rs
1 use std::fmt; 2 3 use derive_more::{ 4 Deref, 5 DerefMut, 6 }; 7 use enumflags2::{ 8 BitFlags, 9 bitflags, 10 }; 11 12 use crate::{ 13 Display, 14 Write, 15 with, 16 }; 17 18 #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] 19 pub enum Color { 20 #[default] 21 Primary, 22 Fixed(u8), 23 Rgb(u8, u8, u8), 24 Black, 25 Red, 26 Green, 27 Yellow, 28 Blue, 29 Magenta, 30 Cyan, 31 White, 32 BrightBlack, 33 BrightRed, 34 BrightGreen, 35 BrightYellow, 36 BrightBlue, 37 BrightMagenta, 38 BrightCyan, 39 BrightWhite, 40 } 41 42 impl Color { 43 #[must_use] 44 pub const fn fg(self) -> Style { 45 Style::new().fg(self) 46 } 47 48 #[must_use] 49 pub const fn bg(self) -> Style { 50 Style::new().bg(self) 51 } 52 } 53 54 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 55 #[bitflags] 56 #[repr(u16)] 57 pub enum Attr { 58 Bold = 1 << 0, 59 Dim = 1 << 1, 60 Italic = 1 << 2, 61 Underline = 1 << 3, 62 Blink = 1 << 4, 63 RapidBlink = 1 << 5, 64 Invert = 1 << 6, 65 Conceal = 1 << 7, 66 Strike = 1 << 8, 67 } 68 69 impl Attr { 70 #[must_use] 71 pub const fn style(self) -> Style { 72 Style::new().attr(self) 73 } 74 } 75 76 #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] 77 pub struct Style { 78 pub fg: Color, 79 pub bg: Color, 80 pub attrs: BitFlags<Attr>, 81 } 82 83 macro_rules! set { 84 ($($name:ident : $field:ident $symbol:tt $value:expr;)*) => { 85 $( 86 #[must_use] 87 pub const fn $name(mut self) -> Style { 88 self.$field $symbol $value; 89 self 90 } 91 )* 92 }; 93 } 94 95 macro_rules! set_attr { 96 ($($name:ident : $attr:expr;)*) => { 97 $( 98 #[must_use] 99 pub const fn $name(mut self) -> Style { 100 self.attrs = self.attrs.union_c(BitFlags::<Attr>::from_bits_truncate_c( 101 $attr as u16, 102 BitFlags::CONST_TOKEN, 103 )); 104 self 105 } 106 )* 107 }; 108 } 109 110 impl Style { 111 #[must_use] 112 pub const fn new() -> Self { 113 Self { 114 fg: Color::Primary, 115 bg: Color::Primary, 116 attrs: BitFlags::EMPTY, 117 } 118 } 119 120 #[must_use] 121 pub const fn fg(mut self, color: Color) -> Self { 122 self.fg = color; 123 self 124 } 125 126 #[must_use] 127 pub const fn unfg(mut self) -> Self { 128 self.fg = Color::Primary; 129 self 130 } 131 132 #[must_use] 133 pub const fn bg(mut self, color: Color) -> Self { 134 self.bg = color; 135 self 136 } 137 138 #[must_use] 139 pub const fn unbg(mut self) -> Self { 140 self.bg = Color::Primary; 141 self 142 } 143 144 #[must_use] 145 pub const fn attr(mut self, attr: Attr) -> Self { 146 self.attrs = self.attrs.union_c(BitFlags::<Attr>::from_bits_truncate_c( 147 attr as u16, 148 BitFlags::CONST_TOKEN, 149 )); 150 self 151 } 152 153 #[must_use] 154 pub const fn unattr(mut self, attr: Attr) -> Self { 155 self.attrs = self.attrs.intersection_c( 156 BitFlags::<Attr>::from_bits_truncate_c(attr as u16, BitFlags::CONST_TOKEN) 157 .not_c(BitFlags::CONST_TOKEN), 158 ); 159 self 160 } 161 162 #[must_use] 163 pub const fn fixed(mut self, color: u8) -> Self { 164 self.fg = Color::Fixed(color); 165 self 166 } 167 168 #[must_use] 169 pub const fn on_fixed(mut self, color: u8) -> Self { 170 self.bg = Color::Fixed(color); 171 self 172 } 173 174 #[must_use] 175 pub const fn rgb(mut self, r: u8, g: u8, b: u8) -> Self { 176 self.fg = Color::Rgb(r, g, b); 177 self 178 } 179 180 #[must_use] 181 pub const fn on_rgb(mut self, r: u8, g: u8, b: u8) -> Self { 182 self.bg = Color::Rgb(r, g, b); 183 self 184 } 185 186 set! { 187 black: fg = Color::Black; 188 red: fg = Color::Red; 189 green: fg = Color::Green; 190 yellow: fg = Color::Yellow; 191 blue: fg = Color::Blue; 192 magenta: fg = Color::Magenta; 193 cyan: fg = Color::Cyan; 194 white: fg = Color::White; 195 196 on_black: bg = Color::Black; 197 on_red: bg = Color::Red; 198 on_green: bg = Color::Green; 199 on_yellow: bg = Color::Yellow; 200 on_blue: bg = Color::Blue; 201 on_magenta: bg = Color::Magenta; 202 on_cyan: bg = Color::Cyan; 203 on_white: bg = Color::White; 204 205 bright_black: fg = Color::BrightBlack; 206 bright_red: fg = Color::BrightRed; 207 bright_green: fg = Color::BrightGreen; 208 bright_yellow: fg = Color::BrightYellow; 209 bright_blue: fg = Color::BrightBlue; 210 bright_magenta: fg = Color::BrightMagenta; 211 bright_cyan: fg = Color::BrightCyan; 212 bright_white: fg = Color::BrightWhite; 213 214 on_bright_black: bg = Color::BrightBlack; 215 on_bright_red: bg = Color::BrightRed; 216 on_bright_green: bg = Color::BrightGreen; 217 on_bright_yellow: bg = Color::BrightYellow; 218 on_bright_blue: bg = Color::BrightBlue; 219 on_bright_magenta: bg = Color::BrightMagenta; 220 on_bright_cyan: bg = Color::BrightCyan; 221 on_bright_white: bg = Color::BrightWhite; 222 } 223 224 set_attr! { 225 bold: Attr::Bold; 226 dim: Attr::Dim; 227 italic: Attr::Italic; 228 underline: Attr::Underline; 229 blink: Attr::Blink; 230 rapid_blink: Attr::RapidBlink; 231 invert: Attr::Invert; 232 conceal: Attr::Conceal; 233 strike: Attr::Strike; 234 } 235 } 236 237 #[derive(Deref, DerefMut, Debug, Clone, PartialEq, Eq)] 238 pub struct Styled<T> { 239 #[deref] 240 #[deref_mut] 241 pub value: T, 242 pub style: Style, 243 } 244 245 macro_rules! styled { 246 ($($method:ident),* $(,)?) => { 247 $( 248 #[must_use] 249 pub const fn $method(mut self) -> Self { 250 self.style = self.style.$method(); 251 self 252 } 253 )* 254 }; 255 } 256 257 impl<T> Styled<T> { 258 pub const fn new(value: T) -> Self { 259 Self { 260 value, 261 style: Style::new(), 262 } 263 } 264 265 #[must_use] 266 pub const fn fg(mut self, color: Color) -> Self { 267 self.style = self.style.fg(color); 268 self 269 } 270 271 #[must_use] 272 pub const fn bg(mut self, color: Color) -> Self { 273 self.style = self.style.bg(color); 274 self 275 } 276 277 #[must_use] 278 pub const fn attr(mut self, attr: Attr) -> Self { 279 self.style = self.style.attr(attr); 280 self 281 } 282 283 #[must_use] 284 pub const fn fixed(mut self, color: u8) -> Self { 285 self.style = self.style.fixed(color); 286 self 287 } 288 289 #[must_use] 290 pub const fn on_fixed(mut self, color: u8) -> Self { 291 self.style = self.style.on_fixed(color); 292 self 293 } 294 295 #[must_use] 296 pub const fn rgb(mut self, r: u8, g: u8, b: u8) -> Self { 297 self.style = self.style.rgb(r, g, b); 298 self 299 } 300 301 #[must_use] 302 pub const fn on_rgb(mut self, r: u8, g: u8, b: u8) -> Self { 303 self.style = self.style.on_rgb(r, g, b); 304 self 305 } 306 307 styled! { 308 black, 309 red, 310 green, 311 yellow, 312 blue, 313 magenta, 314 cyan, 315 white, 316 317 on_black, 318 on_red, 319 on_green, 320 on_yellow, 321 on_blue, 322 on_magenta, 323 on_cyan, 324 on_white, 325 326 bright_black, 327 bright_red, 328 bright_green, 329 bright_yellow, 330 bright_blue, 331 bright_magenta, 332 bright_cyan, 333 bright_white, 334 335 on_bright_black, 336 on_bright_red, 337 on_bright_green, 338 on_bright_yellow, 339 on_bright_blue, 340 on_bright_magenta, 341 on_bright_cyan, 342 on_bright_white, 343 344 bold, 345 dim, 346 italic, 347 underline, 348 blink, 349 rapid_blink, 350 invert, 351 conceal, 352 strike, 353 } 354 } 355 356 macro_rules! wrap_styled { 357 ($($method:ident),* $(,)?) => { 358 $( 359 #[must_use] 360 fn $method(self) -> Styled<Self> { 361 let mut styled = self.styled(); 362 styled.style = styled.style.$method(); 363 styled 364 } 365 )* 366 }; 367 } 368 369 impl<D: fmt::Display> Display for Styled<D> { 370 fn display_styled(&self, writer: &mut dyn Write) -> fmt::Result { 371 with(writer, self.style, |writer| { 372 write!(writer, "{value}", value = **self) 373 }) 374 } 375 } 376 377 pub trait StyledExt 378 where 379 Self: Sized, 380 { 381 fn styled(self) -> Styled<Self> { 382 Styled::new(self) 383 } 384 385 fn style(self, style: Style) -> Styled<Self> { 386 let mut styled = self.styled(); 387 styled.style = style; 388 styled 389 } 390 391 #[must_use] 392 fn fg(self, color: Color) -> Styled<Self> { 393 let mut styled = self.styled(); 394 styled.style = styled.style.fg(color); 395 styled 396 } 397 398 #[must_use] 399 fn bg(self, color: Color) -> Styled<Self> { 400 let mut styled = self.styled(); 401 styled.style = styled.style.bg(color); 402 styled 403 } 404 405 #[must_use] 406 fn attr(self, attr: Attr) -> Styled<Self> { 407 let mut styled = self.styled(); 408 styled.style = styled.style.attr(attr); 409 styled 410 } 411 412 #[must_use] 413 fn fixed(self, color: u8) -> Styled<Self> { 414 let mut styled = self.styled(); 415 styled.style = styled.style.fixed(color); 416 styled 417 } 418 419 #[must_use] 420 fn on_fixed(self, color: u8) -> Styled<Self> { 421 let mut styled = self.styled(); 422 styled.style = styled.style.on_fixed(color); 423 styled 424 } 425 426 #[must_use] 427 fn rgb(self, r: u8, g: u8, b: u8) -> Styled<Self> { 428 let mut styled = self.styled(); 429 styled.style = styled.style.rgb(r, g, b); 430 styled 431 } 432 433 #[must_use] 434 fn on_rgb(self, r: u8, g: u8, b: u8) -> Styled<Self> { 435 let mut styled = self.styled(); 436 styled.style = styled.style.on_rgb(r, g, b); 437 styled 438 } 439 440 wrap_styled! { 441 black, 442 red, 443 green, 444 yellow, 445 blue, 446 magenta, 447 cyan, 448 white, 449 450 on_black, 451 on_red, 452 on_green, 453 on_yellow, 454 on_blue, 455 on_magenta, 456 on_cyan, 457 on_white, 458 459 bright_black, 460 bright_red, 461 bright_green, 462 bright_yellow, 463 bright_blue, 464 bright_magenta, 465 bright_cyan, 466 bright_white, 467 468 on_bright_black, 469 on_bright_red, 470 on_bright_green, 471 on_bright_yellow, 472 on_bright_blue, 473 on_bright_magenta, 474 on_bright_cyan, 475 on_bright_white, 476 477 bold, 478 dim, 479 italic, 480 underline, 481 blink, 482 rapid_blink, 483 invert, 484 conceal, 485 strike, 486 } 487 } 488 489 impl<T> StyledExt for T {}