@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,1069 +0,0 @@
1
- //! `style` contains the primitives used to control how your user interface will look.
2
- //!
3
- //! There are two ways to set styles:
4
- //! - Creating and using the [`Style`] struct. (e.g. `Style::new().fg(Color::Red)`).
5
- //! - Using style shorthands. (e.g. `"hello".red()`).
6
- //!
7
- //! # Using the `Style` struct
8
- //!
9
- //! This is the original approach to styling and likely the most common. This is useful when
10
- //! creating style variables to reuse, however the shorthands are often more convenient and
11
- //! readable for most use cases.
12
- //!
13
- //! ## Example
14
- //!
15
- //! ```
16
- //! use ratatui_core::style::{Color, Modifier, Style};
17
- //! use ratatui_core::text::Span;
18
- //!
19
- //! let heading_style = Style::new()
20
- //! .fg(Color::Black)
21
- //! .bg(Color::Green)
22
- //! .add_modifier(Modifier::ITALIC | Modifier::BOLD);
23
- //! let span = Span::styled("hello", heading_style);
24
- //! ```
25
- //!
26
- //! # Using style shorthands
27
- //!
28
- //! Originally Ratatui only had the ability to set styles using the `Style` struct. This is still
29
- //! supported, but there are now shorthands for all the styles that can be set. These save you from
30
- //! having to create a `Style` struct every time you want to set a style.
31
- //!
32
- //! The shorthands are implemented in the [`Stylize`] trait which is automatically implemented for
33
- //! many types via the [`Styled`] trait. This means that you can use the shorthands on any type
34
- //! that implements [`Styled`]. E.g.:
35
- //! - Strings and string slices when styled return a [`Span`]
36
- //! - [`Span`]s can be styled again, which will merge the styles.
37
- //! - Many widget types can be styled directly rather than calling their `style()` method.
38
- //!
39
- //! See the [`Stylize`] and [`Styled`] traits for more information.
40
- //!
41
- //! ## Example
42
- //!
43
- //! ```
44
- //! use ratatui_core::style::{Color, Modifier, Style, Stylize};
45
- //! use ratatui_core::text::{Span, Text};
46
- //!
47
- //! assert_eq!(
48
- //! "hello".red().on_blue().bold(),
49
- //! Span::styled(
50
- //! "hello",
51
- //! Style::default()
52
- //! .fg(Color::Red)
53
- //! .bg(Color::Blue)
54
- //! .add_modifier(Modifier::BOLD)
55
- //! )
56
- //! );
57
- //!
58
- //! assert_eq!(
59
- //! Text::from("hello").red().on_blue().bold(),
60
- //! Text::from("hello").style(
61
- //! Style::default()
62
- //! .fg(Color::Red)
63
- //! .bg(Color::Blue)
64
- //! .add_modifier(Modifier::BOLD)
65
- //! )
66
- //! );
67
- //! ```
68
- //!
69
- //! [`Span`]: crate::text::Span
70
-
71
- use core::fmt;
72
-
73
- use bitflags::bitflags;
74
- pub use color::{Color, ParseColorError};
75
- use stylize::ColorDebugKind;
76
- pub use stylize::{Styled, Stylize};
77
-
78
- #[cfg(feature = "anstyle")]
79
- mod anstyle;
80
- mod color;
81
- pub mod palette;
82
- #[cfg(feature = "palette")]
83
- mod palette_conversion;
84
- #[macro_use]
85
- mod stylize;
86
-
87
- bitflags! {
88
- /// Modifier changes the way a piece of text is displayed.
89
- ///
90
- /// They are bitflags so they can easily be composed.
91
- ///
92
- /// `From<Modifier> for Style` is implemented so you can use `Modifier` anywhere that accepts
93
- /// `Into<Style>`.
94
- ///
95
- /// ## Examples
96
- ///
97
- /// ```rust
98
- /// use ratatui_core::style::Modifier;
99
- ///
100
- /// let m = Modifier::BOLD | Modifier::ITALIC;
101
- /// ```
102
- #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103
- #[derive(Default, Clone, Copy, Eq, PartialEq, Hash)]
104
- pub struct Modifier: u16 {
105
- const BOLD = 0b0000_0000_0001;
106
- const DIM = 0b0000_0000_0010;
107
- const ITALIC = 0b0000_0000_0100;
108
- const UNDERLINED = 0b0000_0000_1000;
109
- const SLOW_BLINK = 0b0000_0001_0000;
110
- const RAPID_BLINK = 0b0000_0010_0000;
111
- const REVERSED = 0b0000_0100_0000;
112
- const HIDDEN = 0b0000_1000_0000;
113
- const CROSSED_OUT = 0b0001_0000_0000;
114
- }
115
- }
116
-
117
- /// Implement the `Debug` trait for `Modifier` manually.
118
- ///
119
- /// This will avoid printing the empty modifier as 'Borders(0x0)' and instead print it as 'NONE'.
120
- impl fmt::Debug for Modifier {
121
- /// Format the modifier as `NONE` if the modifier is empty or as a list of flags separated by
122
- /// `|` otherwise.
123
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124
- if self.is_empty() {
125
- return write!(f, "NONE");
126
- }
127
- write!(f, "{}", self.0)
128
- }
129
- }
130
-
131
- /// Style lets you control the main characteristics of the displayed elements.
132
- ///
133
- /// ```rust
134
- /// use ratatui_core::style::{Color, Modifier, Style};
135
- ///
136
- /// Style::default()
137
- /// .fg(Color::Black)
138
- /// .bg(Color::Green)
139
- /// .add_modifier(Modifier::ITALIC | Modifier::BOLD);
140
- /// ```
141
- ///
142
- /// Styles can also be created with a [shorthand notation](crate::style#using-style-shorthands).
143
- ///
144
- /// ```rust
145
- /// use ratatui_core::style::{Style, Stylize};
146
- ///
147
- /// Style::new().black().on_green().italic().bold();
148
- /// ```
149
- ///
150
- /// For more information about the style shorthands, see the [`Stylize`] trait.
151
- ///
152
- /// We implement conversions from [`Color`] and [`Modifier`] to [`Style`] so you can use them
153
- /// anywhere that accepts `Into<Style>`.
154
- ///
155
- /// ```rust
156
- /// use ratatui_core::style::{Color, Modifier, Style};
157
- /// use ratatui_core::text::Line;
158
- ///
159
- /// Line::styled("hello", Style::new().fg(Color::Red));
160
- /// // simplifies to
161
- /// Line::styled("hello", Color::Red);
162
- ///
163
- /// Line::styled("hello", Style::new().add_modifier(Modifier::BOLD));
164
- /// // simplifies to
165
- /// Line::styled("hello", Modifier::BOLD);
166
- /// ```
167
- ///
168
- /// Styles represents an incremental change. If you apply the styles S1, S2, S3 to a cell of the
169
- /// terminal buffer, the style of this cell will be the result of the merge of S1, S2 and S3, not
170
- /// just S3.
171
- ///
172
- /// ```rust
173
- /// use ratatui_core::buffer::Buffer;
174
- /// use ratatui_core::layout::Rect;
175
- /// use ratatui_core::style::{Color, Modifier, Style};
176
- ///
177
- /// let styles = [
178
- /// Style::default()
179
- /// .fg(Color::Blue)
180
- /// .add_modifier(Modifier::BOLD | Modifier::ITALIC),
181
- /// Style::default()
182
- /// .bg(Color::Red)
183
- /// .add_modifier(Modifier::UNDERLINED),
184
- /// #[cfg(feature = "underline-color")]
185
- /// Style::default().underline_color(Color::Green),
186
- /// Style::default()
187
- /// .fg(Color::Yellow)
188
- /// .remove_modifier(Modifier::ITALIC),
189
- /// ];
190
- /// let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
191
- /// for style in &styles {
192
- /// buffer[(0, 0)].set_style(*style);
193
- /// }
194
- /// assert_eq!(
195
- /// Style {
196
- /// fg: Some(Color::Yellow),
197
- /// bg: Some(Color::Red),
198
- /// #[cfg(feature = "underline-color")]
199
- /// underline_color: Some(Color::Green),
200
- /// add_modifier: Modifier::BOLD | Modifier::UNDERLINED,
201
- /// sub_modifier: Modifier::empty(),
202
- /// },
203
- /// buffer[(0, 0)].style(),
204
- /// );
205
- /// ```
206
- ///
207
- /// The default implementation returns a `Style` that does not modify anything. If you wish to
208
- /// reset all properties until that point use [`Style::reset`].
209
- ///
210
- /// ```
211
- /// use ratatui_core::buffer::Buffer;
212
- /// use ratatui_core::layout::Rect;
213
- /// use ratatui_core::style::{Color, Modifier, Style};
214
- ///
215
- /// let styles = [
216
- /// Style::default()
217
- /// .fg(Color::Blue)
218
- /// .add_modifier(Modifier::BOLD | Modifier::ITALIC),
219
- /// Style::reset().fg(Color::Yellow),
220
- /// ];
221
- /// let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
222
- /// for style in &styles {
223
- /// buffer[(0, 0)].set_style(*style);
224
- /// }
225
- /// assert_eq!(
226
- /// Style {
227
- /// fg: Some(Color::Yellow),
228
- /// bg: Some(Color::Reset),
229
- /// #[cfg(feature = "underline-color")]
230
- /// underline_color: Some(Color::Reset),
231
- /// add_modifier: Modifier::empty(),
232
- /// sub_modifier: Modifier::empty(),
233
- /// },
234
- /// buffer[(0, 0)].style(),
235
- /// );
236
- /// ```
237
- #[derive(Default, Clone, Copy, Eq, PartialEq, Hash)]
238
- #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
239
- pub struct Style {
240
- /// The foreground color.
241
- #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
242
- pub fg: Option<Color>,
243
- /// The background color.
244
- #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
245
- pub bg: Option<Color>,
246
- /// The underline color.
247
- #[cfg(feature = "underline-color")]
248
- #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
249
- pub underline_color: Option<Color>,
250
- /// The modifiers to add.
251
- #[cfg_attr(
252
- feature = "serde",
253
- serde(
254
- default,
255
- skip_serializing_if = "Modifier::is_empty",
256
- deserialize_with = "deserialize_modifier"
257
- )
258
- )]
259
- pub add_modifier: Modifier,
260
- /// The modifiers to remove.
261
- #[cfg_attr(
262
- feature = "serde",
263
- serde(
264
- default,
265
- skip_serializing_if = "Modifier::is_empty",
266
- deserialize_with = "deserialize_modifier"
267
- )
268
- )]
269
- pub sub_modifier: Modifier,
270
- }
271
-
272
- #[cfg(feature = "serde")]
273
- /// Deserialize a [`Modifier`] while treating missing or `null` values as empty.
274
- ///
275
- /// This helper is used with serde to coerce absent or `null` modifier fields to
276
- /// [`Modifier::empty`], allowing configuration files to omit these fields
277
- /// without triggering deserialization errors.
278
- fn deserialize_modifier<'de, D>(deserializer: D) -> Result<Modifier, D::Error>
279
- where
280
- D: serde::Deserializer<'de>,
281
- {
282
- use serde::Deserialize;
283
-
284
- Option::<Modifier>::deserialize(deserializer)
285
- .map(|modifier| modifier.unwrap_or_else(Modifier::empty))
286
- }
287
-
288
- /// A custom debug implementation that prints only the fields that are not the default, and unwraps
289
- /// the `Option`s.
290
- impl fmt::Debug for Style {
291
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
292
- f.write_str("Style::new()")?;
293
- self.fmt_stylize(f)?;
294
- Ok(())
295
- }
296
- }
297
-
298
- impl Style {
299
- /// Returns a `Style` with default properties.
300
- pub const fn new() -> Self {
301
- Self {
302
- fg: None,
303
- bg: None,
304
- #[cfg(feature = "underline-color")]
305
- underline_color: None,
306
- add_modifier: Modifier::empty(),
307
- sub_modifier: Modifier::empty(),
308
- }
309
- }
310
-
311
- /// Returns a `Style` resetting all properties.
312
- pub const fn reset() -> Self {
313
- Self {
314
- fg: Some(Color::Reset),
315
- bg: Some(Color::Reset),
316
- #[cfg(feature = "underline-color")]
317
- underline_color: Some(Color::Reset),
318
- add_modifier: Modifier::empty(),
319
- sub_modifier: Modifier::all(),
320
- }
321
- }
322
-
323
- /// Changes the foreground color.
324
- ///
325
- /// ## Examples
326
- ///
327
- /// ```rust
328
- /// use ratatui_core::style::{Color, Style};
329
- ///
330
- /// let style = Style::default().fg(Color::Blue);
331
- /// let diff = Style::default().fg(Color::Red);
332
- /// assert_eq!(style.patch(diff), Style::default().fg(Color::Red));
333
- /// ```
334
- #[must_use = "`fg` returns the modified style without modifying the original"]
335
- pub const fn fg(mut self, color: Color) -> Self {
336
- self.fg = Some(color);
337
- self
338
- }
339
-
340
- /// Changes the background color.
341
- ///
342
- /// ## Examples
343
- ///
344
- /// ```rust
345
- /// use ratatui_core::style::{Color, Style};
346
- ///
347
- /// let style = Style::default().bg(Color::Blue);
348
- /// let diff = Style::default().bg(Color::Red);
349
- /// assert_eq!(style.patch(diff), Style::default().bg(Color::Red));
350
- /// ```
351
- #[must_use = "`bg` returns the modified style without modifying the original"]
352
- pub const fn bg(mut self, color: Color) -> Self {
353
- self.bg = Some(color);
354
- self
355
- }
356
-
357
- /// Changes the underline color. The text must be underlined with a modifier for this to work.
358
- ///
359
- /// This uses a non-standard ANSI escape sequence. It is supported by most terminal emulators,
360
- /// but is only implemented in the crossterm backend and enabled by the `underline-color`
361
- /// feature flag.
362
- ///
363
- /// See
364
- /// [Wikipedia](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters)
365
- /// code `58` and `59` for more information.
366
- ///
367
- /// ## Examples
368
- ///
369
- /// ```rust
370
- /// use ratatui_core::style::{Color, Modifier, Style};
371
- ///
372
- /// let style = Style::default()
373
- /// .underline_color(Color::Blue)
374
- /// .add_modifier(Modifier::UNDERLINED);
375
- /// let diff = Style::default()
376
- /// .underline_color(Color::Red)
377
- /// .add_modifier(Modifier::UNDERLINED);
378
- /// assert_eq!(
379
- /// style.patch(diff),
380
- /// Style::default()
381
- /// .underline_color(Color::Red)
382
- /// .add_modifier(Modifier::UNDERLINED)
383
- /// );
384
- /// ```
385
- #[cfg(feature = "underline-color")]
386
- #[must_use = "`underline_color` returns the modified style without modifying the original"]
387
- pub const fn underline_color(mut self, color: Color) -> Self {
388
- self.underline_color = Some(color);
389
- self
390
- }
391
-
392
- /// Changes the text emphasis.
393
- ///
394
- /// When applied, it adds the given modifier to the `Style` modifiers.
395
- ///
396
- /// ## Examples
397
- ///
398
- /// ```rust
399
- /// use ratatui_core::style::{Modifier, Style};
400
- ///
401
- /// let style = Style::default().add_modifier(Modifier::BOLD);
402
- /// let diff = Style::default().add_modifier(Modifier::ITALIC);
403
- /// let patched = style.patch(diff);
404
- /// assert_eq!(patched.add_modifier, Modifier::BOLD | Modifier::ITALIC);
405
- /// assert_eq!(patched.sub_modifier, Modifier::empty());
406
- /// ```
407
- #[must_use = "`add_modifier` returns the modified style without modifying the original"]
408
- pub const fn add_modifier(mut self, modifier: Modifier) -> Self {
409
- self.sub_modifier = self.sub_modifier.difference(modifier);
410
- self.add_modifier = self.add_modifier.union(modifier);
411
- self
412
- }
413
-
414
- /// Changes the text emphasis.
415
- ///
416
- /// When applied, it removes the given modifier from the `Style` modifiers.
417
- ///
418
- /// ## Examples
419
- ///
420
- /// ```rust
421
- /// use ratatui_core::style::{Modifier, Style};
422
- ///
423
- /// let style = Style::default().add_modifier(Modifier::BOLD | Modifier::ITALIC);
424
- /// let diff = Style::default().remove_modifier(Modifier::ITALIC);
425
- /// let patched = style.patch(diff);
426
- /// assert_eq!(patched.add_modifier, Modifier::BOLD);
427
- /// assert_eq!(patched.sub_modifier, Modifier::ITALIC);
428
- /// ```
429
- #[must_use = "`remove_modifier` returns the modified style without modifying the original"]
430
- pub const fn remove_modifier(mut self, modifier: Modifier) -> Self {
431
- self.add_modifier = self.add_modifier.difference(modifier);
432
- self.sub_modifier = self.sub_modifier.union(modifier);
433
- self
434
- }
435
-
436
- /// Returns `true` if the style has the given modifier set.
437
- ///
438
- /// ## Examples
439
- ///
440
- /// ```rust
441
- /// use ratatui_core::style::{Modifier, Style};
442
- ///
443
- /// let style = Style::default().add_modifier(Modifier::BOLD | Modifier::ITALIC);
444
- /// assert!(style.has_modifier(Modifier::BOLD));
445
- /// assert!(style.has_modifier(Modifier::ITALIC));
446
- /// assert!(!style.has_modifier(Modifier::UNDERLINED));
447
- /// ```
448
- pub const fn has_modifier(self, modifier: Modifier) -> bool {
449
- self.add_modifier.contains(modifier) && !self.sub_modifier.contains(modifier)
450
- }
451
-
452
- /// Results in a combined style that is equivalent to applying the two individual styles to
453
- /// a style one after the other.
454
- ///
455
- /// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
456
- /// your own type that implements [`Into<Style>`]).
457
- ///
458
- /// ## Examples
459
- /// ```
460
- /// use ratatui_core::style::{Color, Modifier, Style};
461
- ///
462
- /// let style_1 = Style::default().fg(Color::Yellow);
463
- /// let style_2 = Style::default().bg(Color::Red);
464
- /// let combined = style_1.patch(style_2);
465
- /// assert_eq!(
466
- /// Style::default().patch(style_1).patch(style_2),
467
- /// Style::default().patch(combined)
468
- /// );
469
- /// ```
470
- #[must_use = "`patch` returns the modified style without modifying the original"]
471
- pub fn patch<S: Into<Self>>(mut self, other: S) -> Self {
472
- let other = other.into();
473
- self.fg = other.fg.or(self.fg);
474
- self.bg = other.bg.or(self.bg);
475
-
476
- #[cfg(feature = "underline-color")]
477
- {
478
- self.underline_color = other.underline_color.or(self.underline_color);
479
- }
480
-
481
- self.add_modifier.remove(other.sub_modifier);
482
- self.add_modifier.insert(other.add_modifier);
483
- self.sub_modifier.remove(other.add_modifier);
484
- self.sub_modifier.insert(other.sub_modifier);
485
-
486
- self
487
- }
488
-
489
- /// Formats the style in a way that can be copy-pasted into code using the style shorthands.
490
- ///
491
- /// This is useful for debugging and for generating code snippets.
492
- pub(crate) fn fmt_stylize(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493
- use fmt::Debug;
494
- if let Some(fg) = self.fg {
495
- fg.stylize_debug(ColorDebugKind::Foreground).fmt(f)?;
496
- }
497
- if let Some(bg) = self.bg {
498
- bg.stylize_debug(ColorDebugKind::Background).fmt(f)?;
499
- }
500
- #[cfg(feature = "underline-color")]
501
- if let Some(underline_color) = self.underline_color {
502
- underline_color
503
- .stylize_debug(ColorDebugKind::Underline)
504
- .fmt(f)?;
505
- }
506
- for modifier in self.add_modifier.iter() {
507
- match modifier {
508
- Modifier::BOLD => f.write_str(".bold()")?,
509
- Modifier::DIM => f.write_str(".dim()")?,
510
- Modifier::ITALIC => f.write_str(".italic()")?,
511
- Modifier::UNDERLINED => f.write_str(".underlined()")?,
512
- Modifier::SLOW_BLINK => f.write_str(".slow_blink()")?,
513
- Modifier::RAPID_BLINK => f.write_str(".rapid_blink()")?,
514
- Modifier::REVERSED => f.write_str(".reversed()")?,
515
- Modifier::HIDDEN => f.write_str(".hidden()")?,
516
- Modifier::CROSSED_OUT => f.write_str(".crossed_out()")?,
517
- _ => f.write_fmt(format_args!(".add_modifier(Modifier::{modifier:?})"))?,
518
- }
519
- }
520
- for modifier in self.sub_modifier.iter() {
521
- match modifier {
522
- Modifier::BOLD => f.write_str(".not_bold()")?,
523
- Modifier::DIM => f.write_str(".not_dim()")?,
524
- Modifier::ITALIC => f.write_str(".not_italic()")?,
525
- Modifier::UNDERLINED => f.write_str(".not_underlined()")?,
526
- Modifier::SLOW_BLINK => f.write_str(".not_slow_blink()")?,
527
- Modifier::RAPID_BLINK => f.write_str(".not_rapid_blink()")?,
528
- Modifier::REVERSED => f.write_str(".not_reversed()")?,
529
- Modifier::HIDDEN => f.write_str(".not_hidden()")?,
530
- Modifier::CROSSED_OUT => f.write_str(".not_crossed_out()")?,
531
- _ => f.write_fmt(format_args!(".remove_modifier(Modifier::{modifier:?})"))?,
532
- }
533
- }
534
- Ok(())
535
- }
536
-
537
- color!(pub const Color::Black, black(), on_black() -> Self);
538
- color!(pub const Color::Red, red(), on_red() -> Self);
539
- color!(pub const Color::Green, green(), on_green() -> Self);
540
- color!(pub const Color::Yellow, yellow(), on_yellow() -> Self);
541
- color!(pub const Color::Blue, blue(), on_blue() -> Self);
542
- color!(pub const Color::Magenta, magenta(), on_magenta() -> Self);
543
- color!(pub const Color::Cyan, cyan(), on_cyan() -> Self);
544
- color!(pub const Color::Gray, gray(), on_gray() -> Self);
545
- color!(pub const Color::DarkGray, dark_gray(), on_dark_gray() -> Self);
546
- color!(pub const Color::LightRed, light_red(), on_light_red() -> Self);
547
- color!(pub const Color::LightGreen, light_green(), on_light_green() -> Self);
548
- color!(pub const Color::LightYellow, light_yellow(), on_light_yellow() -> Self);
549
- color!(pub const Color::LightBlue, light_blue(), on_light_blue() -> Self);
550
- color!(pub const Color::LightMagenta, light_magenta(), on_light_magenta() -> Self);
551
- color!(pub const Color::LightCyan, light_cyan(), on_light_cyan() -> Self);
552
- color!(pub const Color::White, white(), on_white() -> Self);
553
-
554
- modifier!(pub const Modifier::BOLD, bold(), not_bold() -> Self);
555
- modifier!(pub const Modifier::DIM, dim(), not_dim() -> Self);
556
- modifier!(pub const Modifier::ITALIC, italic(), not_italic() -> Self);
557
- modifier!(pub const Modifier::UNDERLINED, underlined(), not_underlined() -> Self);
558
- modifier!(pub const Modifier::SLOW_BLINK, slow_blink(), not_slow_blink() -> Self);
559
- modifier!(pub const Modifier::RAPID_BLINK, rapid_blink(), not_rapid_blink() -> Self);
560
- modifier!(pub const Modifier::REVERSED, reversed(), not_reversed() -> Self);
561
- modifier!(pub const Modifier::HIDDEN, hidden(), not_hidden() -> Self);
562
- modifier!(pub const Modifier::CROSSED_OUT, crossed_out(), not_crossed_out() -> Self);
563
- }
564
-
565
- impl From<Color> for Style {
566
- /// Creates a new `Style` with the given foreground color.
567
- ///
568
- /// To specify a foreground and background color, use the `from((fg, bg))` constructor.
569
- ///
570
- /// # Example
571
- ///
572
- /// ```rust
573
- /// use ratatui_core::style::{Color, Style};
574
- ///
575
- /// let style = Style::from(Color::Red);
576
- /// ```
577
- fn from(color: Color) -> Self {
578
- Self::new().fg(color)
579
- }
580
- }
581
-
582
- impl From<(Color, Color)> for Style {
583
- /// Creates a new `Style` with the given foreground and background colors.
584
- ///
585
- /// # Example
586
- ///
587
- /// ```rust
588
- /// use ratatui_core::style::{Color, Style};
589
- ///
590
- /// // red foreground, blue background
591
- /// let style = Style::from((Color::Red, Color::Blue));
592
- /// // default foreground, blue background
593
- /// let style = Style::from((Color::Reset, Color::Blue));
594
- /// ```
595
- fn from((fg, bg): (Color, Color)) -> Self {
596
- Self::new().fg(fg).bg(bg)
597
- }
598
- }
599
-
600
- impl From<Modifier> for Style {
601
- /// Creates a new `Style` with the given modifier added.
602
- ///
603
- /// To specify multiple modifiers, use the `|` operator.
604
- ///
605
- /// To specify modifiers to add and remove, use the `from((add_modifier, sub_modifier))`
606
- /// constructor.
607
- ///
608
- /// # Example
609
- ///
610
- /// ```rust
611
- /// use ratatui_core::style::{Style, Modifier};
612
- ///
613
- /// // add bold and italic
614
- /// let style = Style::from(Modifier::BOLD|Modifier::ITALIC);
615
- fn from(modifier: Modifier) -> Self {
616
- Self::new().add_modifier(modifier)
617
- }
618
- }
619
-
620
- impl From<(Modifier, Modifier)> for Style {
621
- /// Creates a new `Style` with the given modifiers added and removed.
622
- ///
623
- /// # Example
624
- ///
625
- /// ```rust
626
- /// use ratatui_core::style::{Modifier, Style};
627
- ///
628
- /// // add bold and italic, remove dim
629
- /// let style = Style::from((Modifier::BOLD | Modifier::ITALIC, Modifier::DIM));
630
- /// ```
631
- fn from((add_modifier, sub_modifier): (Modifier, Modifier)) -> Self {
632
- Self::new()
633
- .add_modifier(add_modifier)
634
- .remove_modifier(sub_modifier)
635
- }
636
- }
637
-
638
- impl From<(Color, Modifier)> for Style {
639
- /// Creates a new `Style` with the given foreground color and modifier added.
640
- ///
641
- /// To specify multiple modifiers, use the `|` operator.
642
- ///
643
- /// # Example
644
- ///
645
- /// ```rust
646
- /// use ratatui_core::style::{Color, Modifier, Style};
647
- ///
648
- /// // red foreground, add bold and italic
649
- /// let style = Style::from((Color::Red, Modifier::BOLD | Modifier::ITALIC));
650
- /// ```
651
- fn from((fg, modifier): (Color, Modifier)) -> Self {
652
- Self::new().fg(fg).add_modifier(modifier)
653
- }
654
- }
655
-
656
- impl From<(Color, Color, Modifier)> for Style {
657
- /// Creates a new `Style` with the given foreground and background colors and modifier added.
658
- ///
659
- /// To specify multiple modifiers, use the `|` operator.
660
- ///
661
- /// # Example
662
- ///
663
- /// ```rust
664
- /// use ratatui_core::style::{Color, Modifier, Style};
665
- ///
666
- /// // red foreground, blue background, add bold and italic
667
- /// let style = Style::from((Color::Red, Color::Blue, Modifier::BOLD | Modifier::ITALIC));
668
- /// ```
669
- fn from((fg, bg, modifier): (Color, Color, Modifier)) -> Self {
670
- Self::new().fg(fg).bg(bg).add_modifier(modifier)
671
- }
672
- }
673
-
674
- impl From<(Color, Color, Modifier, Modifier)> for Style {
675
- /// Creates a new `Style` with the given foreground and background colors and modifiers added
676
- /// and removed.
677
- ///
678
- /// # Example
679
- ///
680
- /// ```rust
681
- /// use ratatui_core::style::{Color, Modifier, Style};
682
- ///
683
- /// // red foreground, blue background, add bold and italic, remove dim
684
- /// let style = Style::from((
685
- /// Color::Red,
686
- /// Color::Blue,
687
- /// Modifier::BOLD | Modifier::ITALIC,
688
- /// Modifier::DIM,
689
- /// ));
690
- /// ```
691
- fn from((fg, bg, add_modifier, sub_modifier): (Color, Color, Modifier, Modifier)) -> Self {
692
- Self::new()
693
- .fg(fg)
694
- .bg(bg)
695
- .add_modifier(add_modifier)
696
- .remove_modifier(sub_modifier)
697
- }
698
- }
699
-
700
- #[cfg(test)]
701
- mod tests {
702
- use alloc::format;
703
-
704
- use rstest::rstest;
705
-
706
- use super::*;
707
-
708
- #[rstest]
709
- #[case(Style::new(), "Style::new()")]
710
- #[case(Style::default(), "Style::new()")]
711
- #[case(Style::new().red(), "Style::new().red()")]
712
- #[case(Style::new().on_blue(), "Style::new().on_blue()")]
713
- #[case(Style::new().bold(), "Style::new().bold()")]
714
- #[case(Style::new().not_italic(), "Style::new().not_italic()")]
715
- #[case(
716
- Style::new().red().on_blue().bold().italic().not_dim().not_hidden(),
717
- "Style::new().red().on_blue().bold().italic().not_dim().not_hidden()"
718
- )]
719
- fn debug(#[case] style: Style, #[case] expected: &'static str) {
720
- assert_eq!(format!("{style:?}"), expected);
721
- }
722
-
723
- #[test]
724
- fn combined_patch_gives_same_result_as_individual_patch() {
725
- let styles = [
726
- Style::new(),
727
- Style::new().fg(Color::Yellow),
728
- Style::new().bg(Color::Yellow),
729
- Style::new().add_modifier(Modifier::BOLD),
730
- Style::new().remove_modifier(Modifier::BOLD),
731
- Style::new().add_modifier(Modifier::ITALIC),
732
- Style::new().remove_modifier(Modifier::ITALIC),
733
- Style::new().add_modifier(Modifier::ITALIC | Modifier::BOLD),
734
- Style::new().remove_modifier(Modifier::ITALIC | Modifier::BOLD),
735
- ];
736
- for &a in &styles {
737
- for &b in &styles {
738
- for &c in &styles {
739
- for &d in &styles {
740
- assert_eq!(
741
- Style::new().patch(a).patch(b).patch(c).patch(d),
742
- Style::new().patch(a.patch(b.patch(c.patch(d))))
743
- );
744
- }
745
- }
746
- }
747
- }
748
- }
749
-
750
- #[test]
751
- fn combine_individual_modifiers() {
752
- use crate::buffer::Buffer;
753
- use crate::layout::Rect;
754
-
755
- let mods = [
756
- Modifier::BOLD,
757
- Modifier::DIM,
758
- Modifier::ITALIC,
759
- Modifier::UNDERLINED,
760
- Modifier::SLOW_BLINK,
761
- Modifier::RAPID_BLINK,
762
- Modifier::REVERSED,
763
- Modifier::HIDDEN,
764
- Modifier::CROSSED_OUT,
765
- ];
766
-
767
- let mut buffer = Buffer::empty(Rect::new(0, 0, 1, 1));
768
-
769
- for m in mods {
770
- buffer[(0, 0)].set_style(Style::reset());
771
- buffer[(0, 0)].set_style(Style::new().add_modifier(m));
772
- let style = buffer[(0, 0)].style();
773
- assert!(style.add_modifier.contains(m));
774
- assert!(!style.sub_modifier.contains(m));
775
- }
776
- }
777
-
778
- #[rstest]
779
- #[case(Modifier::empty(), "NONE")]
780
- #[case(Modifier::BOLD, "BOLD")]
781
- #[case(Modifier::DIM, "DIM")]
782
- #[case(Modifier::ITALIC, "ITALIC")]
783
- #[case(Modifier::UNDERLINED, "UNDERLINED")]
784
- #[case(Modifier::SLOW_BLINK, "SLOW_BLINK")]
785
- #[case(Modifier::RAPID_BLINK, "RAPID_BLINK")]
786
- #[case(Modifier::REVERSED, "REVERSED")]
787
- #[case(Modifier::HIDDEN, "HIDDEN")]
788
- #[case(Modifier::CROSSED_OUT, "CROSSED_OUT")]
789
- #[case(Modifier::BOLD | Modifier::DIM, "BOLD | DIM")]
790
- #[case(
791
- Modifier::all(),
792
- "BOLD | DIM | ITALIC | UNDERLINED | SLOW_BLINK | RAPID_BLINK | REVERSED | HIDDEN | CROSSED_OUT"
793
- )]
794
- fn modifier_debug(#[case] modifier: Modifier, #[case] expected: &str) {
795
- assert_eq!(format!("{modifier:?}"), expected);
796
- }
797
-
798
- #[test]
799
- fn style_can_be_const() {
800
- const RED: Color = Color::Red;
801
- const BLACK: Color = Color::Black;
802
- const BOLD: Modifier = Modifier::BOLD;
803
- const ITALIC: Modifier = Modifier::ITALIC;
804
-
805
- const _RESET: Style = Style::reset();
806
- const _RED_FG: Style = Style::new().fg(RED);
807
- const _RED_FG_SHORT: Style = Style::new().red();
808
- const _BLACK_BG: Style = Style::new().bg(BLACK);
809
- const _BLACK_BG_SHORT: Style = Style::new().on_black();
810
- const _ADD_BOLD: Style = Style::new().add_modifier(BOLD);
811
- const _ADD_BOLD_SHORT: Style = Style::new().bold();
812
- const _REMOVE_ITALIC: Style = Style::new().remove_modifier(ITALIC);
813
- const _REMOVE_ITALIC_SHORT: Style = Style::new().not_italic();
814
- const ALL: Style = Style::new()
815
- .fg(RED)
816
- .bg(BLACK)
817
- .add_modifier(BOLD)
818
- .remove_modifier(ITALIC);
819
- const ALL_SHORT: Style = Style::new().red().on_black().bold().not_italic();
820
- assert_eq!(
821
- ALL,
822
- Style::new()
823
- .fg(Color::Red)
824
- .bg(Color::Black)
825
- .add_modifier(Modifier::BOLD)
826
- .remove_modifier(Modifier::ITALIC)
827
- );
828
- assert_eq!(ALL, ALL_SHORT);
829
- }
830
-
831
- #[test]
832
- fn has_modifier_checks() {
833
- // basic presence
834
- let style = Style::new().add_modifier(Modifier::BOLD | Modifier::ITALIC);
835
- assert!(style.has_modifier(Modifier::BOLD));
836
- assert!(style.has_modifier(Modifier::ITALIC));
837
- assert!(!style.has_modifier(Modifier::UNDERLINED));
838
-
839
- // removal prevents the modifier from being reported as present
840
- let style = Style::new()
841
- .add_modifier(Modifier::BOLD | Modifier::ITALIC)
842
- .remove_modifier(Modifier::ITALIC);
843
- assert!(style.has_modifier(Modifier::BOLD));
844
- assert!(!style.has_modifier(Modifier::ITALIC));
845
-
846
- // patching with a style that removes a modifier clears it
847
- let style = Style::new().add_modifier(Modifier::BOLD | Modifier::ITALIC);
848
- let patched = style.patch(Style::new().remove_modifier(Modifier::ITALIC));
849
- assert!(patched.has_modifier(Modifier::BOLD));
850
- assert!(!patched.has_modifier(Modifier::ITALIC));
851
- }
852
-
853
- #[rstest]
854
- #[case(Style::new().black(), Color::Black)]
855
- #[case(Style::new().red(), Color::Red)]
856
- #[case(Style::new().green(), Color::Green)]
857
- #[case(Style::new().yellow(), Color::Yellow)]
858
- #[case(Style::new().blue(), Color::Blue)]
859
- #[case(Style::new().magenta(), Color::Magenta)]
860
- #[case(Style::new().cyan(), Color::Cyan)]
861
- #[case(Style::new().white(), Color::White)]
862
- #[case(Style::new().gray(), Color::Gray)]
863
- #[case(Style::new().dark_gray(), Color::DarkGray)]
864
- #[case(Style::new().light_red(), Color::LightRed)]
865
- #[case(Style::new().light_green(), Color::LightGreen)]
866
- #[case(Style::new().light_yellow(), Color::LightYellow)]
867
- #[case(Style::new().light_blue(), Color::LightBlue)]
868
- #[case(Style::new().light_magenta(), Color::LightMagenta)]
869
- #[case(Style::new().light_cyan(), Color::LightCyan)]
870
- #[case(Style::new().white(), Color::White)]
871
- fn fg_can_be_stylized(#[case] stylized: Style, #[case] expected: Color) {
872
- assert_eq!(stylized, Style::new().fg(expected));
873
- }
874
-
875
- #[rstest]
876
- #[case(Style::new().on_black(), Color::Black)]
877
- #[case(Style::new().on_red(), Color::Red)]
878
- #[case(Style::new().on_green(), Color::Green)]
879
- #[case(Style::new().on_yellow(), Color::Yellow)]
880
- #[case(Style::new().on_blue(), Color::Blue)]
881
- #[case(Style::new().on_magenta(), Color::Magenta)]
882
- #[case(Style::new().on_cyan(), Color::Cyan)]
883
- #[case(Style::new().on_white(), Color::White)]
884
- #[case(Style::new().on_gray(), Color::Gray)]
885
- #[case(Style::new().on_dark_gray(), Color::DarkGray)]
886
- #[case(Style::new().on_light_red(), Color::LightRed)]
887
- #[case(Style::new().on_light_green(), Color::LightGreen)]
888
- #[case(Style::new().on_light_yellow(), Color::LightYellow)]
889
- #[case(Style::new().on_light_blue(), Color::LightBlue)]
890
- #[case(Style::new().on_light_magenta(), Color::LightMagenta)]
891
- #[case(Style::new().on_light_cyan(), Color::LightCyan)]
892
- #[case(Style::new().on_white(), Color::White)]
893
- fn bg_can_be_stylized(#[case] stylized: Style, #[case] expected: Color) {
894
- assert_eq!(stylized, Style::new().bg(expected));
895
- }
896
-
897
- #[rstest]
898
- #[case(Style::new().bold(), Modifier::BOLD)]
899
- #[case(Style::new().dim(), Modifier::DIM)]
900
- #[case(Style::new().italic(), Modifier::ITALIC)]
901
- #[case(Style::new().underlined(), Modifier::UNDERLINED)]
902
- #[case(Style::new().slow_blink(), Modifier::SLOW_BLINK)]
903
- #[case(Style::new().rapid_blink(), Modifier::RAPID_BLINK)]
904
- #[case(Style::new().reversed(), Modifier::REVERSED)]
905
- #[case(Style::new().hidden(), Modifier::HIDDEN)]
906
- #[case(Style::new().crossed_out(), Modifier::CROSSED_OUT)]
907
- fn add_modifier_can_be_stylized(#[case] stylized: Style, #[case] expected: Modifier) {
908
- assert_eq!(stylized, Style::new().add_modifier(expected));
909
- }
910
-
911
- #[rstest]
912
- #[case(Style::new().not_bold(), Modifier::BOLD)]
913
- #[case(Style::new().not_dim(), Modifier::DIM)]
914
- #[case(Style::new().not_italic(), Modifier::ITALIC)]
915
- #[case(Style::new().not_underlined(), Modifier::UNDERLINED)]
916
- #[case(Style::new().not_slow_blink(), Modifier::SLOW_BLINK)]
917
- #[case(Style::new().not_rapid_blink(), Modifier::RAPID_BLINK)]
918
- #[case(Style::new().not_reversed(), Modifier::REVERSED)]
919
- #[case(Style::new().not_hidden(), Modifier::HIDDEN)]
920
- #[case(Style::new().not_crossed_out(), Modifier::CROSSED_OUT)]
921
- fn remove_modifier_can_be_stylized(#[case] stylized: Style, #[case] expected: Modifier) {
922
- assert_eq!(stylized, Style::new().remove_modifier(expected));
923
- }
924
-
925
- #[test]
926
- fn from_color() {
927
- assert_eq!(Style::from(Color::Red), Style::new().fg(Color::Red));
928
- }
929
-
930
- #[test]
931
- fn from_color_color() {
932
- assert_eq!(
933
- Style::from((Color::Red, Color::Blue)),
934
- Style::new().fg(Color::Red).bg(Color::Blue)
935
- );
936
- }
937
-
938
- #[test]
939
- fn from_modifier() {
940
- assert_eq!(
941
- Style::from(Modifier::BOLD | Modifier::ITALIC),
942
- Style::new()
943
- .add_modifier(Modifier::BOLD)
944
- .add_modifier(Modifier::ITALIC)
945
- );
946
- }
947
-
948
- #[test]
949
- fn from_modifier_modifier() {
950
- assert_eq!(
951
- Style::from((Modifier::BOLD | Modifier::ITALIC, Modifier::DIM)),
952
- Style::new()
953
- .add_modifier(Modifier::BOLD)
954
- .add_modifier(Modifier::ITALIC)
955
- .remove_modifier(Modifier::DIM)
956
- );
957
- }
958
-
959
- #[test]
960
- fn from_color_modifier() {
961
- assert_eq!(
962
- Style::from((Color::Red, Modifier::BOLD | Modifier::ITALIC)),
963
- Style::new()
964
- .fg(Color::Red)
965
- .add_modifier(Modifier::BOLD)
966
- .add_modifier(Modifier::ITALIC)
967
- );
968
- }
969
-
970
- #[test]
971
- fn from_color_color_modifier() {
972
- assert_eq!(
973
- Style::from((Color::Red, Color::Blue, Modifier::BOLD | Modifier::ITALIC)),
974
- Style::new()
975
- .fg(Color::Red)
976
- .bg(Color::Blue)
977
- .add_modifier(Modifier::BOLD)
978
- .add_modifier(Modifier::ITALIC)
979
- );
980
- }
981
-
982
- #[test]
983
- fn from_color_color_modifier_modifier() {
984
- assert_eq!(
985
- Style::from((
986
- Color::Red,
987
- Color::Blue,
988
- Modifier::BOLD | Modifier::ITALIC,
989
- Modifier::DIM
990
- )),
991
- Style::new()
992
- .fg(Color::Red)
993
- .bg(Color::Blue)
994
- .add_modifier(Modifier::BOLD)
995
- .add_modifier(Modifier::ITALIC)
996
- .remove_modifier(Modifier::DIM)
997
- );
998
- }
999
-
1000
- #[cfg(feature = "serde")]
1001
- #[test]
1002
- fn serialize_then_deserialize() {
1003
- let style = Style {
1004
- fg: Some(Color::Rgb(255, 0, 255)),
1005
- bg: Some(Color::White),
1006
- #[cfg(feature = "underline-color")]
1007
- underline_color: Some(Color::Indexed(3)),
1008
- add_modifier: Modifier::UNDERLINED,
1009
- sub_modifier: Modifier::CROSSED_OUT,
1010
- };
1011
-
1012
- let json_str = serde_json::to_string(&style).unwrap();
1013
- let json_value: serde_json::Value = serde_json::from_str(&json_str).unwrap();
1014
-
1015
- let mut expected_json = serde_json::json!({
1016
- "fg": "#FF00FF",
1017
- "bg": "White",
1018
- "add_modifier": "UNDERLINED",
1019
- "sub_modifier": "CROSSED_OUT"
1020
- });
1021
-
1022
- #[cfg(feature = "underline-color")]
1023
- {
1024
- expected_json
1025
- .as_object_mut()
1026
- .unwrap()
1027
- .insert("underline_color".into(), "3".into());
1028
- }
1029
-
1030
- assert_eq!(json_value, expected_json);
1031
-
1032
- let deserialized: Style = serde_json::from_str(&json_str).unwrap();
1033
- assert_eq!(deserialized, style);
1034
- }
1035
-
1036
- #[cfg(feature = "serde")]
1037
- #[test]
1038
- fn deserialize_defaults() {
1039
- let style = Style {
1040
- fg: None,
1041
- bg: None,
1042
- #[cfg(feature = "underline-color")]
1043
- underline_color: None,
1044
- add_modifier: Modifier::empty(),
1045
- sub_modifier: Modifier::empty(),
1046
- };
1047
-
1048
- let json_str = serde_json::to_string(&style).unwrap();
1049
- assert_eq!(json_str, "{}");
1050
-
1051
- let deserialized: Style = serde_json::from_str(&json_str).unwrap();
1052
- assert_eq!(deserialized, style);
1053
- }
1054
-
1055
- #[cfg(feature = "serde")]
1056
- #[test]
1057
- fn deserialize_null_modifiers() {
1058
- let json_value = serde_json::json!({
1059
- "add_modifier": serde_json::Value::Null,
1060
- "sub_modifier": serde_json::Value::Null
1061
- });
1062
- let json_str = serde_json::to_string(&json_value).unwrap();
1063
-
1064
- let style: Style = serde_json::from_str(&json_str).unwrap();
1065
-
1066
- assert!(style.add_modifier.is_empty());
1067
- assert!(style.sub_modifier.is_empty());
1068
- }
1069
- }