@akiojin/gwt 9.0.4 → 9.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.ja.md +106 -146
  2. package/README.md +103 -143
  3. package/bin/gwt.cjs +1 -1
  4. package/package.json +5 -5
  5. package/rustfmt.toml +0 -2
  6. package/scripts/check-release-flow.sh +2 -8
  7. package/scripts/postinstall.js +17 -7
  8. package/scripts/run-local-backend-tests-on-commit.sh +6 -12
  9. package/scripts/test-all.sh +1 -5
  10. package/scripts/check-e2e-coverage-threshold.mjs +0 -238
  11. package/scripts/run-local-e2e-coverage-on-commit.sh +0 -69
  12. package/scripts/run-local-e2e-on-commit.sh +0 -60
  13. package/scripts/verify-ci-node-toolchain.sh +0 -76
  14. package/scripts/voice-eval.sh +0 -48
  15. package/vendor/ratatui-core/src/backend/test.rs +0 -1077
  16. package/vendor/ratatui-core/src/backend.rs +0 -405
  17. package/vendor/ratatui-core/src/buffer/assert.rs +0 -71
  18. package/vendor/ratatui-core/src/buffer/buffer.rs +0 -1388
  19. package/vendor/ratatui-core/src/buffer/cell.rs +0 -377
  20. package/vendor/ratatui-core/src/buffer.rs +0 -9
  21. package/vendor/ratatui-core/src/layout/alignment.rs +0 -89
  22. package/vendor/ratatui-core/src/layout/constraint.rs +0 -526
  23. package/vendor/ratatui-core/src/layout/direction.rs +0 -63
  24. package/vendor/ratatui-core/src/layout/flex.rs +0 -212
  25. package/vendor/ratatui-core/src/layout/layout.rs +0 -2838
  26. package/vendor/ratatui-core/src/layout/margin.rs +0 -79
  27. package/vendor/ratatui-core/src/layout/offset.rs +0 -66
  28. package/vendor/ratatui-core/src/layout/position.rs +0 -253
  29. package/vendor/ratatui-core/src/layout/rect/iter.rs +0 -356
  30. package/vendor/ratatui-core/src/layout/rect/ops.rs +0 -136
  31. package/vendor/ratatui-core/src/layout/rect.rs +0 -1114
  32. package/vendor/ratatui-core/src/layout/size.rs +0 -147
  33. package/vendor/ratatui-core/src/layout.rs +0 -333
  34. package/vendor/ratatui-core/src/lib.rs +0 -82
  35. package/vendor/ratatui-core/src/style/anstyle.rs +0 -348
  36. package/vendor/ratatui-core/src/style/color.rs +0 -788
  37. package/vendor/ratatui-core/src/style/palette/material.rs +0 -608
  38. package/vendor/ratatui-core/src/style/palette/tailwind.rs +0 -653
  39. package/vendor/ratatui-core/src/style/palette.rs +0 -6
  40. package/vendor/ratatui-core/src/style/palette_conversion.rs +0 -82
  41. package/vendor/ratatui-core/src/style/stylize.rs +0 -668
  42. package/vendor/ratatui-core/src/style.rs +0 -1069
  43. package/vendor/ratatui-core/src/symbols/bar.rs +0 -51
  44. package/vendor/ratatui-core/src/symbols/block.rs +0 -51
  45. package/vendor/ratatui-core/src/symbols/border.rs +0 -709
  46. package/vendor/ratatui-core/src/symbols/braille.rs +0 -21
  47. package/vendor/ratatui-core/src/symbols/half_block.rs +0 -3
  48. package/vendor/ratatui-core/src/symbols/line.rs +0 -259
  49. package/vendor/ratatui-core/src/symbols/marker.rs +0 -82
  50. package/vendor/ratatui-core/src/symbols/merge.rs +0 -748
  51. package/vendor/ratatui-core/src/symbols/pixel.rs +0 -30
  52. package/vendor/ratatui-core/src/symbols/scrollbar.rs +0 -46
  53. package/vendor/ratatui-core/src/symbols/shade.rs +0 -5
  54. package/vendor/ratatui-core/src/symbols.rs +0 -15
  55. package/vendor/ratatui-core/src/terminal/frame.rs +0 -192
  56. package/vendor/ratatui-core/src/terminal/terminal.rs +0 -926
  57. package/vendor/ratatui-core/src/terminal/viewport.rs +0 -58
  58. package/vendor/ratatui-core/src/terminal.rs +0 -40
  59. package/vendor/ratatui-core/src/text/grapheme.rs +0 -84
  60. package/vendor/ratatui-core/src/text/line.rs +0 -1678
  61. package/vendor/ratatui-core/src/text/masked.rs +0 -149
  62. package/vendor/ratatui-core/src/text/span.rs +0 -904
  63. package/vendor/ratatui-core/src/text/text.rs +0 -1434
  64. package/vendor/ratatui-core/src/text.rs +0 -64
  65. package/vendor/ratatui-core/src/widgets/stateful_widget.rs +0 -193
  66. package/vendor/ratatui-core/src/widgets/widget.rs +0 -174
  67. package/vendor/ratatui-core/src/widgets.rs +0 -9
@@ -1,788 +0,0 @@
1
- #![allow(clippy::unreadable_literal)]
2
-
3
- use core::fmt;
4
- use core::str::FromStr;
5
-
6
- use crate::style::stylize::{ColorDebug, ColorDebugKind};
7
-
8
- /// ANSI Color
9
- ///
10
- /// All colors from the [ANSI color table] are supported (though some names are not exactly the
11
- /// same).
12
- ///
13
- /// | Color Name | Color | Foreground | Background |
14
- /// |----------------|-------------------------|------------|------------|
15
- /// | `black` | [`Color::Black`] | 30 | 40 |
16
- /// | `red` | [`Color::Red`] | 31 | 41 |
17
- /// | `green` | [`Color::Green`] | 32 | 42 |
18
- /// | `yellow` | [`Color::Yellow`] | 33 | 43 |
19
- /// | `blue` | [`Color::Blue`] | 34 | 44 |
20
- /// | `magenta` | [`Color::Magenta`] | 35 | 45 |
21
- /// | `cyan` | [`Color::Cyan`] | 36 | 46 |
22
- /// | `gray`* | [`Color::Gray`] | 37 | 47 |
23
- /// | `darkgray`* | [`Color::DarkGray`] | 90 | 100 |
24
- /// | `lightred` | [`Color::LightRed`] | 91 | 101 |
25
- /// | `lightgreen` | [`Color::LightGreen`] | 92 | 102 |
26
- /// | `lightyellow` | [`Color::LightYellow`] | 93 | 103 |
27
- /// | `lightblue` | [`Color::LightBlue`] | 94 | 104 |
28
- /// | `lightmagenta` | [`Color::LightMagenta`] | 95 | 105 |
29
- /// | `lightcyan` | [`Color::LightCyan`] | 96 | 106 |
30
- /// | `white`* | [`Color::White`] | 97 | 107 |
31
- ///
32
- /// - `gray` is sometimes called `white` - this is not supported as we use `white` for bright white
33
- /// - `gray` is sometimes called `silver` - this is supported
34
- /// - `darkgray` is sometimes called `light black` or `bright black` (both are supported)
35
- /// - `white` is sometimes called `light white` or `bright white` (both are supported)
36
- /// - we support `bright` and `light` prefixes for all colors
37
- /// - we support `-` and `_` and ` ` as separators for all colors
38
- /// - we support both `gray` and `grey` spellings
39
- ///
40
- /// `From<Color> for Style` is implemented by creating a style with the foreground color set to the
41
- /// given color. This allows you to use colors anywhere that accepts `Into<Style>`.
42
- ///
43
- /// # Example
44
- ///
45
- /// ```
46
- /// use std::str::FromStr;
47
- ///
48
- /// use ratatui_core::style::Color;
49
- ///
50
- /// assert_eq!(Color::from_str("red"), Ok(Color::Red));
51
- /// assert_eq!("red".parse(), Ok(Color::Red));
52
- /// assert_eq!("lightred".parse(), Ok(Color::LightRed));
53
- /// assert_eq!("light red".parse(), Ok(Color::LightRed));
54
- /// assert_eq!("light-red".parse(), Ok(Color::LightRed));
55
- /// assert_eq!("light_red".parse(), Ok(Color::LightRed));
56
- /// assert_eq!("lightRed".parse(), Ok(Color::LightRed));
57
- /// assert_eq!("bright red".parse(), Ok(Color::LightRed));
58
- /// assert_eq!("bright-red".parse(), Ok(Color::LightRed));
59
- /// assert_eq!("silver".parse(), Ok(Color::Gray));
60
- /// assert_eq!("dark-grey".parse(), Ok(Color::DarkGray));
61
- /// assert_eq!("dark gray".parse(), Ok(Color::DarkGray));
62
- /// assert_eq!("light-black".parse(), Ok(Color::DarkGray));
63
- /// assert_eq!("white".parse(), Ok(Color::White));
64
- /// assert_eq!("bright white".parse(), Ok(Color::White));
65
- /// ```
66
- ///
67
- /// [ANSI color table]: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
68
- #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
69
- pub enum Color {
70
- /// Resets the foreground or background color
71
- #[default]
72
- Reset,
73
- /// ANSI Color: Black. Foreground: 30, Background: 40
74
- Black,
75
- /// ANSI Color: Red. Foreground: 31, Background: 41
76
- Red,
77
- /// ANSI Color: Green. Foreground: 32, Background: 42
78
- Green,
79
- /// ANSI Color: Yellow. Foreground: 33, Background: 43
80
- Yellow,
81
- /// ANSI Color: Blue. Foreground: 34, Background: 44
82
- Blue,
83
- /// ANSI Color: Magenta. Foreground: 35, Background: 45
84
- Magenta,
85
- /// ANSI Color: Cyan. Foreground: 36, Background: 46
86
- Cyan,
87
- /// ANSI Color: White. Foreground: 37, Background: 47
88
- ///
89
- /// Note that this is sometimes called `silver` or `white` but we use `white` for bright white
90
- Gray,
91
- /// ANSI Color: Bright Black. Foreground: 90, Background: 100
92
- ///
93
- /// Note that this is sometimes called `light black` or `bright black` but we use `dark gray`
94
- DarkGray,
95
- /// ANSI Color: Bright Red. Foreground: 91, Background: 101
96
- LightRed,
97
- /// ANSI Color: Bright Green. Foreground: 92, Background: 102
98
- LightGreen,
99
- /// ANSI Color: Bright Yellow. Foreground: 93, Background: 103
100
- LightYellow,
101
- /// ANSI Color: Bright Blue. Foreground: 94, Background: 104
102
- LightBlue,
103
- /// ANSI Color: Bright Magenta. Foreground: 95, Background: 105
104
- LightMagenta,
105
- /// ANSI Color: Bright Cyan. Foreground: 96, Background: 106
106
- LightCyan,
107
- /// ANSI Color: Bright White. Foreground: 97, Background: 107
108
- /// Sometimes called `bright white` or `light white` in some terminals
109
- White,
110
- /// An RGB color.
111
- ///
112
- /// Note that only terminals that support 24-bit true color will display this correctly.
113
- /// Notably versions of Windows Terminal prior to Windows 10 and macOS Terminal.app do not
114
- /// support this.
115
- ///
116
- /// If the terminal does not support true color, code using the `TermwizBackend` will
117
- /// fallback to the default text color. Crossterm and Termion do not have this capability and
118
- /// the display will be unpredictable (e.g. Terminal.app may display glitched blinking text).
119
- /// See <https://github.com/ratatui/ratatui/issues/475> for an example of this problem.
120
- ///
121
- /// See also: <https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit>
122
- Rgb(u8, u8, u8),
123
- /// An 8-bit 256 color.
124
- ///
125
- /// See also <https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit>
126
- Indexed(u8),
127
- }
128
-
129
- impl Color {
130
- /// Convert a u32 to a Color
131
- ///
132
- /// The u32 should be in the format 0x00RRGGBB.
133
- pub const fn from_u32(u: u32) -> Self {
134
- let r = (u >> 16) as u8;
135
- let g = (u >> 8) as u8;
136
- let b = u as u8;
137
- Self::Rgb(r, g, b)
138
- }
139
- }
140
-
141
- #[cfg(feature = "serde")]
142
- impl serde::Serialize for Color {
143
- /// This utilises the [`fmt::Display`] implementation for serialization.
144
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
145
- where
146
- S: serde::Serializer,
147
- {
148
- use alloc::string::ToString;
149
-
150
- serializer.serialize_str(&self.to_string())
151
- }
152
- }
153
-
154
- #[cfg(feature = "serde")]
155
- impl<'de> serde::Deserialize<'de> for Color {
156
- /// This is used to deserialize a value into Color via serde.
157
- ///
158
- /// This implementation uses the `FromStr` trait to deserialize strings, so named colours, RGB,
159
- /// and indexed values are able to be deserialized. In addition, values that were produced by
160
- /// the the older serialization implementation of Color are also able to be deserialized.
161
- ///
162
- /// Prior to v0.26.0, Ratatui would be serialized using a map for indexed and RGB values, for
163
- /// examples in json `{"Indexed": 10}` and `{"Rgb": [255, 0, 255]}` respectively. Now they are
164
- /// serialized using the string representation of the index and the RGB hex value, for example
165
- /// in json it would now be `"10"` and `"#FF00FF"` respectively.
166
- ///
167
- /// See the [`Color`] documentation for more information on color names.
168
- ///
169
- /// # Examples
170
- ///
171
- /// ```
172
- /// use std::str::FromStr;
173
- ///
174
- /// use ratatui_core::style::Color;
175
- ///
176
- /// #[derive(Debug, serde::Deserialize)]
177
- /// struct Theme {
178
- /// color: Color,
179
- /// }
180
- ///
181
- /// # fn get_theme() -> Result<(), serde_json::Error> {
182
- /// let theme: Theme = serde_json::from_str(r#"{"color": "bright-white"}"#)?;
183
- /// assert_eq!(theme.color, Color::White);
184
- ///
185
- /// let theme: Theme = serde_json::from_str(r##"{"color": "#00FF00"}"##)?;
186
- /// assert_eq!(theme.color, Color::Rgb(0, 255, 0));
187
- ///
188
- /// let theme: Theme = serde_json::from_str(r#"{"color": "42"}"#)?;
189
- /// assert_eq!(theme.color, Color::Indexed(42));
190
- ///
191
- /// let err = serde_json::from_str::<Theme>(r#"{"color": "invalid"}"#).unwrap_err();
192
- /// assert!(err.is_data());
193
- /// assert_eq!(
194
- /// err.to_string(),
195
- /// "Failed to parse Colors at line 1 column 20"
196
- /// );
197
- ///
198
- /// // Deserializing from the previous serialization implementation
199
- /// let theme: Theme = serde_json::from_str(r#"{"color": {"Rgb":[255,0,255]}}"#)?;
200
- /// assert_eq!(theme.color, Color::Rgb(255, 0, 255));
201
- ///
202
- /// let theme: Theme = serde_json::from_str(r#"{"color": {"Indexed":10}}"#)?;
203
- /// assert_eq!(theme.color, Color::Indexed(10));
204
- /// # Ok(())
205
- /// # }
206
- /// ```
207
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
208
- where
209
- D: serde::Deserializer<'de>,
210
- {
211
- use alloc::format;
212
- use alloc::string::String;
213
-
214
- /// Colors are currently serialized with the `Display` implementation, so
215
- /// RGB values are serialized via hex, for example "#FFFFFF".
216
- ///
217
- /// Previously they were serialized using serde derive, which encoded
218
- /// RGB values as a map, for example { "rgb": [255, 255, 255] }.
219
- ///
220
- /// The deserialization implementation utilises a `Helper` struct
221
- /// to be able to support both formats for backwards compatibility.
222
- #[derive(serde::Deserialize)]
223
- enum ColorWrapper {
224
- Rgb(u8, u8, u8),
225
- Indexed(u8),
226
- }
227
-
228
- #[derive(serde::Deserialize)]
229
- #[serde(untagged)]
230
- enum ColorFormat {
231
- V2(String),
232
- V1(ColorWrapper),
233
- }
234
-
235
- let multi_type = ColorFormat::deserialize(deserializer)
236
- .map_err(|err| serde::de::Error::custom(format!("Failed to parse Colors: {err}")))?;
237
- match multi_type {
238
- ColorFormat::V2(s) => FromStr::from_str(&s).map_err(serde::de::Error::custom),
239
- ColorFormat::V1(color_wrapper) => match color_wrapper {
240
- ColorWrapper::Rgb(red, green, blue) => Ok(Self::Rgb(red, green, blue)),
241
- ColorWrapper::Indexed(index) => Ok(Self::Indexed(index)),
242
- },
243
- }
244
- }
245
- }
246
-
247
- /// Error type indicating a failure to parse a color string.
248
- #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
249
- pub struct ParseColorError;
250
-
251
- impl fmt::Display for ParseColorError {
252
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253
- write!(f, "Failed to parse Colors")
254
- }
255
- }
256
-
257
- impl core::error::Error for ParseColorError {}
258
-
259
- /// Converts a string representation to a `Color` instance.
260
- ///
261
- /// The `from_str` function attempts to parse the given string and convert it to the corresponding
262
- /// `Color` variant. It supports named colors, RGB values, and indexed colors. If the string cannot
263
- /// be parsed, a `ParseColorError` is returned.
264
- ///
265
- /// See the [`Color`] documentation for more information on the supported color names.
266
- ///
267
- /// # Examples
268
- ///
269
- /// ```
270
- /// use std::str::FromStr;
271
- ///
272
- /// use ratatui_core::style::Color;
273
- ///
274
- /// let color: Color = Color::from_str("blue").unwrap();
275
- /// assert_eq!(color, Color::Blue);
276
- ///
277
- /// let color: Color = Color::from_str("#FF0000").unwrap();
278
- /// assert_eq!(color, Color::Rgb(255, 0, 0));
279
- ///
280
- /// let color: Color = Color::from_str("10").unwrap();
281
- /// assert_eq!(color, Color::Indexed(10));
282
- ///
283
- /// let color: Result<Color, _> = Color::from_str("invalid_color");
284
- /// assert!(color.is_err());
285
- /// ```
286
- impl FromStr for Color {
287
- type Err = ParseColorError;
288
-
289
- fn from_str(s: &str) -> Result<Self, Self::Err> {
290
- Ok(
291
- // There is a mix of different color names and formats in the wild.
292
- // This is an attempt to support as many as possible.
293
- match s
294
- .to_lowercase()
295
- .replace([' ', '-', '_'], "")
296
- .replace("bright", "light")
297
- .replace("grey", "gray")
298
- .replace("silver", "gray")
299
- .replace("lightblack", "darkgray")
300
- .replace("lightwhite", "white")
301
- .replace("lightgray", "white")
302
- .as_ref()
303
- {
304
- "reset" => Self::Reset,
305
- "black" => Self::Black,
306
- "red" => Self::Red,
307
- "green" => Self::Green,
308
- "yellow" => Self::Yellow,
309
- "blue" => Self::Blue,
310
- "magenta" => Self::Magenta,
311
- "cyan" => Self::Cyan,
312
- "gray" => Self::Gray,
313
- "darkgray" => Self::DarkGray,
314
- "lightred" => Self::LightRed,
315
- "lightgreen" => Self::LightGreen,
316
- "lightyellow" => Self::LightYellow,
317
- "lightblue" => Self::LightBlue,
318
- "lightmagenta" => Self::LightMagenta,
319
- "lightcyan" => Self::LightCyan,
320
- "white" => Self::White,
321
- _ => {
322
- if let Ok(index) = s.parse::<u8>() {
323
- Self::Indexed(index)
324
- } else if let Some((r, g, b)) = parse_hex_color(s) {
325
- Self::Rgb(r, g, b)
326
- } else {
327
- return Err(ParseColorError);
328
- }
329
- }
330
- },
331
- )
332
- }
333
- }
334
-
335
- fn parse_hex_color(input: &str) -> Option<(u8, u8, u8)> {
336
- if !input.starts_with('#') || input.len() != 7 {
337
- return None;
338
- }
339
- let r = u8::from_str_radix(input.get(1..3)?, 16).ok()?;
340
- let g = u8::from_str_radix(input.get(3..5)?, 16).ok()?;
341
- let b = u8::from_str_radix(input.get(5..7)?, 16).ok()?;
342
- Some((r, g, b))
343
- }
344
-
345
- impl fmt::Display for Color {
346
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347
- match self {
348
- Self::Reset => write!(f, "Reset"),
349
- Self::Black => write!(f, "Black"),
350
- Self::Red => write!(f, "Red"),
351
- Self::Green => write!(f, "Green"),
352
- Self::Yellow => write!(f, "Yellow"),
353
- Self::Blue => write!(f, "Blue"),
354
- Self::Magenta => write!(f, "Magenta"),
355
- Self::Cyan => write!(f, "Cyan"),
356
- Self::Gray => write!(f, "Gray"),
357
- Self::DarkGray => write!(f, "DarkGray"),
358
- Self::LightRed => write!(f, "LightRed"),
359
- Self::LightGreen => write!(f, "LightGreen"),
360
- Self::LightYellow => write!(f, "LightYellow"),
361
- Self::LightBlue => write!(f, "LightBlue"),
362
- Self::LightMagenta => write!(f, "LightMagenta"),
363
- Self::LightCyan => write!(f, "LightCyan"),
364
- Self::White => write!(f, "White"),
365
- Self::Rgb(r, g, b) => write!(f, "#{r:02X}{g:02X}{b:02X}"),
366
- Self::Indexed(i) => write!(f, "{i}"),
367
- }
368
- }
369
- }
370
-
371
- impl Color {
372
- pub(crate) const fn stylize_debug(self, kind: ColorDebugKind) -> ColorDebug {
373
- ColorDebug { kind, color: self }
374
- }
375
-
376
- /// Converts a HSL representation to a `Color::Rgb` instance.
377
- ///
378
- /// The `from_hsl` function converts the Hue, Saturation and Lightness values to a corresponding
379
- /// `Color` RGB equivalent.
380
- ///
381
- /// Hue values should be in the range [-180..180]. Values outside this range are normalized by
382
- /// wrapping.
383
- ///
384
- /// Saturation and L values should be in the range [0.0..1.0]. Values outside this range are
385
- /// clamped.
386
- ///
387
- /// Clamping to valid ranges happens before conversion to RGB.
388
- ///
389
- /// # Examples
390
- ///
391
- /// ```
392
- /// use palette::Hsl;
393
- /// use ratatui_core::style::Color;
394
- ///
395
- /// // Minimum Lightness is black
396
- /// let color: Color = Color::from_hsl(Hsl::new(0.0, 0.0, 0.0));
397
- /// assert_eq!(color, Color::Rgb(0, 0, 0));
398
- ///
399
- /// // Maximum Lightness is white
400
- /// let color: Color = Color::from_hsl(Hsl::new(0.0, 0.0, 1.0));
401
- /// assert_eq!(color, Color::Rgb(255, 255, 255));
402
- ///
403
- /// // Minimum Saturation is fully desaturated red = gray
404
- /// let color: Color = Color::from_hsl(Hsl::new(0.0, 0.0, 0.5));
405
- /// assert_eq!(color, Color::Rgb(128, 128, 128));
406
- ///
407
- /// // Bright red
408
- /// let color: Color = Color::from_hsl(Hsl::new(0.0, 1.0, 0.5));
409
- /// assert_eq!(color, Color::Rgb(255, 0, 0));
410
- ///
411
- /// // Bright blue
412
- /// let color: Color = Color::from_hsl(Hsl::new(-120.0, 1.0, 0.5));
413
- /// assert_eq!(color, Color::Rgb(0, 0, 255));
414
- /// ```
415
- #[cfg(feature = "palette")]
416
- pub fn from_hsl(hsl: palette::Hsl) -> Self {
417
- use palette::{Clamp, FromColor, Srgb};
418
- let hsl = hsl.clamp();
419
- let Srgb {
420
- red,
421
- green,
422
- blue,
423
- standard: _,
424
- }: Srgb<u8> = Srgb::from_color(hsl).into();
425
-
426
- Self::Rgb(red, green, blue)
427
- }
428
-
429
- /// Converts a `HSLuv` representation to a `Color::Rgb` instance.
430
- ///
431
- /// The `from_hsluv` function converts the Hue, Saturation and Lightness values to a
432
- /// corresponding `Color` RGB equivalent.
433
- ///
434
- /// Hue values should be in the range [-180.0..180.0]. Values outside this range are normalized
435
- /// by wrapping.
436
- ///
437
- /// Saturation and L values should be in the range [0.0..100.0]. Values outside this range are
438
- /// clamped.
439
- ///
440
- /// Clamping to valid ranges happens before conversion to RGB.
441
- ///
442
- /// # Examples
443
- ///
444
- /// ```
445
- /// use palette::Hsluv;
446
- /// use ratatui_core::style::Color;
447
- ///
448
- /// // Minimum Lightness is black
449
- /// let color: Color = Color::from_hsluv(Hsluv::new(0.0, 100.0, 0.0));
450
- /// assert_eq!(color, Color::Rgb(0, 0, 0));
451
- ///
452
- /// // Maximum Lightness is white
453
- /// let color: Color = Color::from_hsluv(Hsluv::new(0.0, 0.0, 100.0));
454
- /// assert_eq!(color, Color::Rgb(255, 255, 255));
455
- ///
456
- /// // Minimum Saturation is fully desaturated red = gray
457
- /// let color = Color::from_hsluv(Hsluv::new(0.0, 0.0, 50.0));
458
- /// assert_eq!(color, Color::Rgb(119, 119, 119));
459
- ///
460
- /// // Bright Red
461
- /// let color = Color::from_hsluv(Hsluv::new(12.18, 100.0, 53.2));
462
- /// assert_eq!(color, Color::Rgb(255, 0, 0));
463
- ///
464
- /// // Bright Blue
465
- /// let color = Color::from_hsluv(Hsluv::new(-94.13, 100.0, 32.3));
466
- /// assert_eq!(color, Color::Rgb(0, 0, 255));
467
- /// ```
468
- #[cfg(feature = "palette")]
469
- pub fn from_hsluv(hsluv: palette::Hsluv) -> Self {
470
- use palette::{Clamp, FromColor, Srgb};
471
- let hsluv = hsluv.clamp();
472
- let Srgb {
473
- red,
474
- green,
475
- blue,
476
- standard: _,
477
- }: Srgb<u8> = Srgb::from_color(hsluv).into();
478
-
479
- Self::Rgb(red, green, blue)
480
- }
481
- }
482
-
483
- impl From<[u8; 3]> for Color {
484
- /// Converts an array of 3 u8 values to a `Color::Rgb` instance.
485
- fn from([r, g, b]: [u8; 3]) -> Self {
486
- Self::Rgb(r, g, b)
487
- }
488
- }
489
-
490
- impl From<(u8, u8, u8)> for Color {
491
- /// Converts a tuple of 3 u8 values to a `Color::Rgb` instance.
492
- fn from((r, g, b): (u8, u8, u8)) -> Self {
493
- Self::Rgb(r, g, b)
494
- }
495
- }
496
-
497
- impl From<[u8; 4]> for Color {
498
- /// Converts an array of 4 u8 values to a `Color::Rgb` instance (ignoring the alpha value).
499
- fn from([r, g, b, _]: [u8; 4]) -> Self {
500
- Self::Rgb(r, g, b)
501
- }
502
- }
503
-
504
- impl From<(u8, u8, u8, u8)> for Color {
505
- /// Converts a tuple of 4 u8 values to a `Color::Rgb` instance (ignoring the alpha value).
506
- fn from((r, g, b, _): (u8, u8, u8, u8)) -> Self {
507
- Self::Rgb(r, g, b)
508
- }
509
- }
510
-
511
- #[cfg(test)]
512
- mod tests {
513
- use alloc::boxed::Box;
514
- use alloc::format;
515
- use core::error::Error;
516
-
517
- #[cfg(feature = "palette")]
518
- use palette::{Hsl, Hsluv};
519
- #[cfg(feature = "palette")]
520
- use rstest::rstest;
521
- #[cfg(feature = "serde")]
522
- use serde::de::{Deserialize, IntoDeserializer};
523
-
524
- use super::*;
525
-
526
- #[cfg(feature = "palette")]
527
- #[rstest]
528
- #[case::black(Hsl::new(0.0, 0.0, 0.0), Color::Rgb(0, 0, 0))]
529
- #[case::white(Hsl::new(0.0, 0.0, 1.0), Color::Rgb(255, 255, 255))]
530
- #[case::valid(Hsl::new(120.0, 0.5, 0.75), Color::Rgb(159, 223, 159))]
531
- #[case::min_hue(Hsl::new(-180.0, 0.5, 0.75), Color::Rgb(159, 223, 223))]
532
- #[case::max_hue(Hsl::new(180.0, 0.5, 0.75), Color::Rgb(159, 223, 223))]
533
- #[case::min_saturation(Hsl::new(0.0, 0.0, 0.5), Color::Rgb(128, 128, 128))]
534
- #[case::max_saturation(Hsl::new(0.0, 1.0, 0.5), Color::Rgb(255, 0, 0))]
535
- #[case::min_lightness(Hsl::new(0.0, 0.5, 0.0), Color::Rgb(0, 0, 0))]
536
- #[case::max_lightness(Hsl::new(0.0, 0.5, 1.0), Color::Rgb(255, 255, 255))]
537
- #[case::under_hue_wraps(Hsl::new(-240.0, 0.5, 0.75), Color::Rgb(159, 223, 159))]
538
- #[case::over_hue_wraps(Hsl::new(480.0, 0.5, 0.75), Color::Rgb(159, 223, 159))]
539
- #[case::under_saturation_clamps(Hsl::new(0.0, -0.5, 0.75), Color::Rgb(191, 191, 191))]
540
- #[case::over_saturation_clamps(Hsl::new(0.0, 1.2, 0.75), Color::Rgb(255, 128, 128))]
541
- #[case::under_lightness_clamps(Hsl::new(0.0, 0.5, -0.20), Color::Rgb(0, 0, 0))]
542
- #[case::over_lightness_clamps(Hsl::new(0.0, 0.5, 1.5), Color::Rgb(255, 255, 255))]
543
- #[case::under_saturation_lightness_clamps(Hsl::new(0.0, -0.5, -0.20), Color::Rgb(0, 0, 0))]
544
- #[case::over_saturation_lightness_clamps(Hsl::new(0.0, 1.2, 1.5), Color::Rgb(255, 255, 255))]
545
- fn test_hsl_to_rgb(#[case] hsl: palette::Hsl, #[case] expected: Color) {
546
- assert_eq!(Color::from_hsl(hsl), expected);
547
- }
548
-
549
- #[cfg(feature = "palette")]
550
- #[rstest]
551
- #[case::black(Hsluv::new(0.0, 0.0, 0.0), Color::Rgb(0, 0, 0))]
552
- #[case::white(Hsluv::new(0.0, 0.0, 100.0), Color::Rgb(255, 255, 255))]
553
- #[case::valid(Hsluv::new(120.0, 50.0, 75.0), Color::Rgb(147, 198, 129))]
554
- #[case::min_hue(Hsluv::new(-180.0, 50.0, 75.0), Color::Rgb(135,196, 188))]
555
- #[case::max_hue(Hsluv::new(180.0, 50.0, 75.0), Color::Rgb(135, 196, 188))]
556
- #[case::min_saturation(Hsluv::new(0.0, 0.0, 75.0), Color::Rgb(185, 185, 185))]
557
- #[case::max_saturation(Hsluv::new(0.0, 100.0, 75.0), Color::Rgb(255, 156, 177))]
558
- #[case::min_lightness(Hsluv::new(0.0, 50.0, 0.0), Color::Rgb(0, 0, 0))]
559
- #[case::max_lightness(Hsluv::new(0.0, 50.0, 100.0), Color::Rgb(255, 255, 255))]
560
- #[case::under_hue_wraps(Hsluv::new(-240.0, 50.0, 75.0), Color::Rgb(147, 198, 129))]
561
- #[case::over_hue_wraps(Hsluv::new(480.0, 50.0, 75.0), Color::Rgb(147, 198, 129))]
562
- #[case::under_saturation_clamps(Hsluv::new(0.0, -50.0, 75.0), Color::Rgb(185, 185, 185))]
563
- #[case::over_saturation_clamps(Hsluv::new(0.0, 150.0, 75.0), Color::Rgb(255, 156, 177))]
564
- #[case::under_lightness_clamps(Hsluv::new(0.0, 50.0, -20.0), Color::Rgb(0, 0, 0))]
565
- #[case::over_lightness_clamps(Hsluv::new(0.0, 50.0, 150.0), Color::Rgb(255, 255, 255))]
566
- #[case::under_saturation_lightness_clamps(Hsluv::new(0.0, -50.0, -20.0), Color::Rgb(0, 0, 0))]
567
- #[case::over_saturation_lightness_clamps(
568
- Hsluv::new(0.0, 150.0, 150.0),
569
- Color::Rgb(255, 255, 255)
570
- )]
571
- fn test_hsluv_to_rgb(#[case] hsluv: palette::Hsluv, #[case] expected: Color) {
572
- assert_eq!(Color::from_hsluv(hsluv), expected);
573
- }
574
-
575
- #[test]
576
- fn from_u32() {
577
- assert_eq!(Color::from_u32(0x000000), Color::Rgb(0, 0, 0));
578
- assert_eq!(Color::from_u32(0xFF0000), Color::Rgb(255, 0, 0));
579
- assert_eq!(Color::from_u32(0x00FF00), Color::Rgb(0, 255, 0));
580
- assert_eq!(Color::from_u32(0x0000FF), Color::Rgb(0, 0, 255));
581
- assert_eq!(Color::from_u32(0xFFFFFF), Color::Rgb(255, 255, 255));
582
- }
583
-
584
- #[test]
585
- fn from_rgb_color() {
586
- let color: Color = Color::from_str("#FF0000").unwrap();
587
- assert_eq!(color, Color::Rgb(255, 0, 0));
588
- }
589
-
590
- #[test]
591
- fn from_indexed_color() {
592
- let color: Color = Color::from_str("10").unwrap();
593
- assert_eq!(color, Color::Indexed(10));
594
- }
595
-
596
- #[test]
597
- fn from_ansi_color() -> Result<(), Box<dyn Error>> {
598
- assert_eq!(Color::from_str("reset")?, Color::Reset);
599
- assert_eq!(Color::from_str("black")?, Color::Black);
600
- assert_eq!(Color::from_str("red")?, Color::Red);
601
- assert_eq!(Color::from_str("green")?, Color::Green);
602
- assert_eq!(Color::from_str("yellow")?, Color::Yellow);
603
- assert_eq!(Color::from_str("blue")?, Color::Blue);
604
- assert_eq!(Color::from_str("magenta")?, Color::Magenta);
605
- assert_eq!(Color::from_str("cyan")?, Color::Cyan);
606
- assert_eq!(Color::from_str("gray")?, Color::Gray);
607
- assert_eq!(Color::from_str("darkgray")?, Color::DarkGray);
608
- assert_eq!(Color::from_str("lightred")?, Color::LightRed);
609
- assert_eq!(Color::from_str("lightgreen")?, Color::LightGreen);
610
- assert_eq!(Color::from_str("lightyellow")?, Color::LightYellow);
611
- assert_eq!(Color::from_str("lightblue")?, Color::LightBlue);
612
- assert_eq!(Color::from_str("lightmagenta")?, Color::LightMagenta);
613
- assert_eq!(Color::from_str("lightcyan")?, Color::LightCyan);
614
- assert_eq!(Color::from_str("white")?, Color::White);
615
-
616
- // aliases
617
- assert_eq!(Color::from_str("lightblack")?, Color::DarkGray);
618
- assert_eq!(Color::from_str("lightwhite")?, Color::White);
619
- assert_eq!(Color::from_str("lightgray")?, Color::White);
620
-
621
- // silver = grey = gray
622
- assert_eq!(Color::from_str("grey")?, Color::Gray);
623
- assert_eq!(Color::from_str("silver")?, Color::Gray);
624
-
625
- // spaces are ignored
626
- assert_eq!(Color::from_str("light black")?, Color::DarkGray);
627
- assert_eq!(Color::from_str("light white")?, Color::White);
628
- assert_eq!(Color::from_str("light gray")?, Color::White);
629
-
630
- // dashes are ignored
631
- assert_eq!(Color::from_str("light-black")?, Color::DarkGray);
632
- assert_eq!(Color::from_str("light-white")?, Color::White);
633
- assert_eq!(Color::from_str("light-gray")?, Color::White);
634
-
635
- // underscores are ignored
636
- assert_eq!(Color::from_str("light_black")?, Color::DarkGray);
637
- assert_eq!(Color::from_str("light_white")?, Color::White);
638
- assert_eq!(Color::from_str("light_gray")?, Color::White);
639
-
640
- // bright = light
641
- assert_eq!(Color::from_str("bright-black")?, Color::DarkGray);
642
- assert_eq!(Color::from_str("bright-white")?, Color::White);
643
-
644
- // bright = light
645
- assert_eq!(Color::from_str("brightblack")?, Color::DarkGray);
646
- assert_eq!(Color::from_str("brightwhite")?, Color::White);
647
-
648
- Ok(())
649
- }
650
-
651
- #[test]
652
- fn from_invalid_colors() {
653
- let bad_colors = [
654
- "invalid_color", // not a color string
655
- "abcdef0", // 7 chars is not a color
656
- " bcdefa", // doesn't start with a '#'
657
- "#abcdef00", // too many chars
658
- "#1🦀2", // len 7 but on char boundaries shouldn't panic
659
- "resets", // typo
660
- "lightblackk", // typo
661
- ];
662
-
663
- for bad_color in bad_colors {
664
- assert!(
665
- Color::from_str(bad_color).is_err(),
666
- "bad color: '{bad_color}'"
667
- );
668
- }
669
- }
670
-
671
- #[test]
672
- fn display() {
673
- assert_eq!(format!("{}", Color::Black), "Black");
674
- assert_eq!(format!("{}", Color::Red), "Red");
675
- assert_eq!(format!("{}", Color::Green), "Green");
676
- assert_eq!(format!("{}", Color::Yellow), "Yellow");
677
- assert_eq!(format!("{}", Color::Blue), "Blue");
678
- assert_eq!(format!("{}", Color::Magenta), "Magenta");
679
- assert_eq!(format!("{}", Color::Cyan), "Cyan");
680
- assert_eq!(format!("{}", Color::Gray), "Gray");
681
- assert_eq!(format!("{}", Color::DarkGray), "DarkGray");
682
- assert_eq!(format!("{}", Color::LightRed), "LightRed");
683
- assert_eq!(format!("{}", Color::LightGreen), "LightGreen");
684
- assert_eq!(format!("{}", Color::LightYellow), "LightYellow");
685
- assert_eq!(format!("{}", Color::LightBlue), "LightBlue");
686
- assert_eq!(format!("{}", Color::LightMagenta), "LightMagenta");
687
- assert_eq!(format!("{}", Color::LightCyan), "LightCyan");
688
- assert_eq!(format!("{}", Color::White), "White");
689
- assert_eq!(format!("{}", Color::Indexed(10)), "10");
690
- assert_eq!(format!("{}", Color::Rgb(255, 0, 0)), "#FF0000");
691
- assert_eq!(format!("{}", Color::Reset), "Reset");
692
- }
693
-
694
- #[cfg(feature = "serde")]
695
- #[test]
696
- fn deserialize() -> Result<(), serde::de::value::Error> {
697
- assert_eq!(
698
- Color::Black,
699
- Color::deserialize("Black".into_deserializer())?
700
- );
701
- assert_eq!(
702
- Color::Magenta,
703
- Color::deserialize("magenta".into_deserializer())?
704
- );
705
- assert_eq!(
706
- Color::LightGreen,
707
- Color::deserialize("LightGreen".into_deserializer())?
708
- );
709
- assert_eq!(
710
- Color::White,
711
- Color::deserialize("bright-white".into_deserializer())?
712
- );
713
- assert_eq!(
714
- Color::Indexed(42),
715
- Color::deserialize("42".into_deserializer())?
716
- );
717
- assert_eq!(
718
- Color::Rgb(0, 255, 0),
719
- Color::deserialize("#00ff00".into_deserializer())?
720
- );
721
- Ok(())
722
- }
723
-
724
- #[cfg(feature = "serde")]
725
- #[test]
726
- fn deserialize_error() {
727
- let color: Result<_, serde::de::value::Error> =
728
- Color::deserialize("invalid".into_deserializer());
729
- assert!(color.is_err());
730
-
731
- let color: Result<_, serde::de::value::Error> =
732
- Color::deserialize("#00000000".into_deserializer());
733
- assert!(color.is_err());
734
- }
735
-
736
- #[cfg(feature = "serde")]
737
- #[test]
738
- fn serialize_then_deserialize() -> Result<(), serde_json::Error> {
739
- let json_rgb = serde_json::to_string(&Color::Rgb(255, 0, 255))?;
740
- assert_eq!(json_rgb, r##""#FF00FF""##);
741
- assert_eq!(
742
- serde_json::from_str::<Color>(&json_rgb)?,
743
- Color::Rgb(255, 0, 255)
744
- );
745
-
746
- let json_white = serde_json::to_string(&Color::White)?;
747
- assert_eq!(json_white, r#""White""#);
748
-
749
- let json_indexed = serde_json::to_string(&Color::Indexed(10))?;
750
- assert_eq!(json_indexed, r#""10""#);
751
- assert_eq!(
752
- serde_json::from_str::<Color>(&json_indexed)?,
753
- Color::Indexed(10)
754
- );
755
-
756
- Ok(())
757
- }
758
-
759
- #[cfg(feature = "serde")]
760
- #[test]
761
- fn deserialize_with_previous_format() -> Result<(), serde_json::Error> {
762
- assert_eq!(Color::White, serde_json::from_str::<Color>("\"White\"")?);
763
- assert_eq!(
764
- Color::Rgb(255, 0, 255),
765
- serde_json::from_str::<Color>(r#"{"Rgb":[255,0,255]}"#)?
766
- );
767
- assert_eq!(
768
- Color::Indexed(10),
769
- serde_json::from_str::<Color>(r#"{"Indexed":10}"#)?
770
- );
771
- Ok(())
772
- }
773
-
774
- #[test]
775
- fn test_from_array_and_tuple_conversions() {
776
- let from_array3 = Color::from([123, 45, 67]);
777
- assert_eq!(from_array3, Color::Rgb(123, 45, 67));
778
-
779
- let from_tuple3 = Color::from((89, 76, 54));
780
- assert_eq!(from_tuple3, Color::Rgb(89, 76, 54));
781
-
782
- let from_array4 = Color::from([10, 20, 30, 255]);
783
- assert_eq!(from_array4, Color::Rgb(10, 20, 30));
784
-
785
- let from_tuple4 = Color::from((200, 150, 100, 0));
786
- assert_eq!(from_tuple4, Color::Rgb(200, 150, 100));
787
- }
788
- }