@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,1434 +0,0 @@
1
- #![warn(missing_docs)]
2
- use alloc::borrow::{Cow, ToOwned};
3
- use alloc::string::{String, ToString};
4
- use alloc::vec;
5
- use alloc::vec::Vec;
6
- use core::fmt;
7
-
8
- use unicode_width::UnicodeWidthStr;
9
-
10
- use crate::buffer::Buffer;
11
- use crate::layout::{Alignment, Rect};
12
- use crate::style::{Style, Styled};
13
- use crate::text::{Line, Span};
14
- use crate::widgets::Widget;
15
-
16
- /// A string split over one or more lines.
17
- ///
18
- /// [`Text`] is used wherever text is displayed in the terminal and represents one or more [`Line`]s
19
- /// of text. When a [`Text`] is rendered, each line is rendered as a single line of text from top to
20
- /// bottom of the area. The text can be styled and aligned.
21
- ///
22
- /// # Constructor Methods
23
- ///
24
- /// - [`Text::raw`] creates a `Text` (potentially multiple lines) with no style.
25
- /// - [`Text::styled`] creates a `Text` (potentially multiple lines) with a style.
26
- /// - [`Text::default`] creates a `Text` with empty content and the default style.
27
- ///
28
- /// # Conversion Methods
29
- ///
30
- /// - [`Text::from`] creates a `Text` from a `String`.
31
- /// - [`Text::from`] creates a `Text` from a `&str`.
32
- /// - [`Text::from`] creates a `Text` from a `Cow<str>`.
33
- /// - [`Text::from`] creates a `Text` from a [`Span`].
34
- /// - [`Text::from`] creates a `Text` from a [`Line`].
35
- /// - [`Text::from`] creates a `Text` from a `Vec<Line>`.
36
- /// - [`Text::from_iter`] creates a `Text` from an iterator of items that can be converted into
37
- /// `Line`.
38
- ///
39
- /// # Setter Methods
40
- ///
41
- /// These methods are fluent setters. They return a `Text` with the property set.
42
- ///
43
- /// - [`Text::style`] sets the style of this `Text`.
44
- /// - [`Text::alignment`] sets the alignment for this `Text`.
45
- /// - [`Text::left_aligned`] sets the alignment to [`Alignment::Left`].
46
- /// - [`Text::centered`] sets the alignment to [`Alignment::Center`].
47
- /// - [`Text::right_aligned`] sets the alignment to [`Alignment::Right`].
48
- ///
49
- /// # Iteration Methods
50
- ///
51
- /// - [`Text::iter`] returns an iterator over the lines of the text.
52
- /// - [`Text::iter_mut`] returns an iterator that allows modifying each line.
53
- /// - [`Text::into_iter`] returns an iterator over the lines of the text.
54
- ///
55
- /// # Other Methods
56
- ///
57
- /// - [`Text::width`] returns the max width of all the lines.
58
- /// - [`Text::height`] returns the height.
59
- /// - [`Text::patch_style`] patches the style of this `Text`, adding modifiers from the given style.
60
- /// - [`Text::reset_style`] resets the style of the `Text`.
61
- /// - [`Text::push_line`] adds a line to the text.
62
- /// - [`Text::push_span`] adds a span to the last line of the text.
63
- ///
64
- /// # Examples
65
- ///
66
- /// ## Creating Text
67
- ///
68
- /// A [`Text`], like a [`Line`], can be constructed using one of the many `From` implementations or
69
- /// via the [`Text::raw`] and [`Text::styled`] methods. Helpfully, [`Text`] also implements
70
- /// [`core::iter::Extend`] which enables the concatenation of several [`Text`] blocks.
71
- ///
72
- /// ```rust
73
- /// use std::borrow::Cow;
74
- /// use std::iter;
75
- ///
76
- /// use ratatui_core::style::{Color, Modifier, Style, Stylize};
77
- /// use ratatui_core::text::{Line, Span, Text};
78
- ///
79
- /// let style = Style::new().yellow().italic();
80
- /// let text = Text::raw("The first line\nThe second line").style(style);
81
- /// let text = Text::styled("The first line\nThe second line", style);
82
- /// let text = Text::styled(
83
- /// "The first line\nThe second line",
84
- /// (Color::Yellow, Modifier::ITALIC),
85
- /// );
86
- ///
87
- /// let text = Text::from("The first line\nThe second line");
88
- /// let text = Text::from(String::from("The first line\nThe second line"));
89
- /// let text = Text::from(Cow::Borrowed("The first line\nThe second line"));
90
- /// let text = Text::from(Span::styled("The first line\nThe second line", style));
91
- /// let text = Text::from(Line::from("The first line"));
92
- /// let text = Text::from(vec![
93
- /// Line::from("The first line"),
94
- /// Line::from("The second line"),
95
- /// ]);
96
- /// let text = Text::from_iter(iter::once("The first line").chain(iter::once("The second line")));
97
- ///
98
- /// let mut text = Text::default();
99
- /// text.extend(vec![
100
- /// Line::from("The first line"),
101
- /// Line::from("The second line"),
102
- /// ]);
103
- /// text.extend(Text::from("The third line\nThe fourth line"));
104
- /// ```
105
- ///
106
- /// ## Styling Text
107
- ///
108
- /// The text's [`Style`] is used by the rendering widget to determine how to style the text. Each
109
- /// [`Line`] in the text will be styled with the [`Style`] of the text, and then with its own
110
- /// [`Style`]. `Text` also implements [`Styled`] which means you can use the methods of the
111
- /// [`Stylize`] trait.
112
- ///
113
- /// ```rust
114
- /// use ratatui_core::style::{Color, Modifier, Style, Stylize};
115
- /// use ratatui_core::text::{Line, Text};
116
- ///
117
- /// let text = Text::from("The first line\nThe second line").style(Style::new().yellow().italic());
118
- /// let text = Text::from("The first line\nThe second line")
119
- /// .yellow()
120
- /// .italic();
121
- /// let text = Text::from(vec![
122
- /// Line::from("The first line").yellow(),
123
- /// Line::from("The second line").yellow(),
124
- /// ])
125
- /// .italic();
126
- /// ```
127
- ///
128
- /// ## Aligning Text
129
- /// The text's [`Alignment`] can be set using [`Text::alignment`] or the related helper methods.
130
- /// Lines composing the text can also be individually aligned with [`Line::alignment`].
131
- ///
132
- /// ```rust
133
- /// use ratatui_core::layout::Alignment;
134
- /// use ratatui_core::text::{Line, Text};
135
- ///
136
- /// let text = Text::from("The first line\nThe second line").alignment(Alignment::Right);
137
- /// let text = Text::from("The first line\nThe second line").right_aligned();
138
- /// let text = Text::from(vec![
139
- /// Line::from("The first line").left_aligned(),
140
- /// Line::from("The second line").right_aligned(),
141
- /// Line::from("The third line"),
142
- /// ])
143
- /// .centered();
144
- /// ```
145
- ///
146
- /// ## Rendering Text
147
- /// `Text` implements the [`Widget`] trait, which means it can be rendered to a [`Buffer`] or to a
148
- /// `Frame`.
149
- ///
150
- /// ```rust
151
- /// # use ratatui_core::{buffer::Buffer, layout::Rect};
152
- /// use ratatui_core::text::Text;
153
- /// use ratatui_core::widgets::Widget;
154
- ///
155
- /// // within another widget's `render` method:
156
- /// # fn render(area: Rect, buf: &mut Buffer) {
157
- /// let text = Text::from("The first line\nThe second line");
158
- /// text.render(area, buf);
159
- /// # }
160
- /// ```
161
- ///
162
- /// Or you can use the `render_widget` method on a `Frame` within a `Terminal::draw` closure.
163
- ///
164
- /// ```rust,ignore
165
- /// # use ratatui::{Frame, layout::Rect, text::Text};
166
- /// # fn draw(frame: &mut Frame, area: Rect) {
167
- /// let text = Text::from("The first line\nThe second line");
168
- /// frame.render_widget(text, area);
169
- /// # }
170
- /// ```
171
- ///
172
- /// ## Rendering Text with a Paragraph Widget
173
- ///
174
- /// Usually apps will use the `Paragraph` widget instead of rendering a `Text` directly as it
175
- /// provides more functionality.
176
- ///
177
- /// ```rust,ignore
178
- /// use ratatui::{
179
- /// buffer::Buffer,
180
- /// layout::Rect,
181
- /// text::Text,
182
- /// widgets::{Paragraph, Widget, Wrap},
183
- /// };
184
- ///
185
- /// # fn render(area: Rect, buf: &mut Buffer) {
186
- /// let text = Text::from("The first line\nThe second line");
187
- /// let paragraph = Paragraph::new(text)
188
- /// .wrap(Wrap { trim: true })
189
- /// .scroll((1, 1))
190
- /// .render(area, buf);
191
- /// # }
192
- /// ```
193
- ///
194
- /// [`Stylize`]: crate::style::Stylize
195
- #[derive(Default, Clone, Eq, PartialEq, Hash)]
196
- pub struct Text<'a> {
197
- /// The alignment of this text.
198
- pub alignment: Option<Alignment>,
199
- /// The style of this text.
200
- pub style: Style,
201
- /// The lines that make up this piece of text.
202
- pub lines: Vec<Line<'a>>,
203
- }
204
-
205
- impl fmt::Debug for Text<'_> {
206
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207
- if self.lines.is_empty() {
208
- f.write_str("Text::default()")?;
209
- } else if self.lines.len() == 1 {
210
- write!(f, "Text::from({:?})", self.lines[0])?;
211
- } else {
212
- f.write_str("Text::from_iter(")?;
213
- f.debug_list().entries(self.lines.iter()).finish()?;
214
- f.write_str(")")?;
215
- }
216
- self.style.fmt_stylize(f)?;
217
- match self.alignment {
218
- Some(Alignment::Left) => f.write_str(".left_aligned()")?,
219
- Some(Alignment::Center) => f.write_str(".centered()")?,
220
- Some(Alignment::Right) => f.write_str(".right_aligned()")?,
221
- _ => (),
222
- }
223
- Ok(())
224
- }
225
- }
226
-
227
- impl<'a> Text<'a> {
228
- /// Create some text (potentially multiple lines) with no style.
229
- ///
230
- /// # Examples
231
- ///
232
- /// ```rust
233
- /// use ratatui_core::text::Text;
234
- ///
235
- /// Text::raw("The first line\nThe second line");
236
- /// Text::raw(String::from("The first line\nThe second line"));
237
- /// ```
238
- pub fn raw<T>(content: T) -> Self
239
- where
240
- T: Into<Cow<'a, str>>,
241
- {
242
- let lines: Vec<_> = match content.into() {
243
- Cow::Borrowed("") => vec![Line::from("")],
244
- Cow::Borrowed(s) => s.lines().map(Line::from).collect(),
245
- Cow::Owned(s) if s.is_empty() => vec![Line::from("")],
246
- Cow::Owned(s) => s.lines().map(|l| Line::from(l.to_owned())).collect(),
247
- };
248
- Self::from(lines)
249
- }
250
-
251
- /// Create some text (potentially multiple lines) with a style.
252
- ///
253
- /// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
254
- /// your own type that implements [`Into<Style>`]).
255
- ///
256
- /// # Examples
257
- ///
258
- /// ```rust
259
- /// use ratatui_core::style::{Color, Modifier, Style};
260
- /// use ratatui_core::text::Text;
261
- ///
262
- /// let style = Style::default()
263
- /// .fg(Color::Yellow)
264
- /// .add_modifier(Modifier::ITALIC);
265
- /// Text::styled("The first line\nThe second line", style);
266
- /// Text::styled(String::from("The first line\nThe second line"), style);
267
- /// ```
268
- ///
269
- /// [`Color`]: crate::style::Color
270
- pub fn styled<T, S>(content: T, style: S) -> Self
271
- where
272
- T: Into<Cow<'a, str>>,
273
- S: Into<Style>,
274
- {
275
- Self::raw(content).patch_style(style)
276
- }
277
-
278
- /// Returns the max width of all the lines.
279
- ///
280
- /// # Examples
281
- ///
282
- /// ```rust
283
- /// use ratatui_core::text::Text;
284
- ///
285
- /// let text = Text::from("The first line\nThe second line");
286
- /// assert_eq!(15, text.width());
287
- /// ```
288
- pub fn width(&self) -> usize {
289
- UnicodeWidthStr::width(self)
290
- }
291
-
292
- /// Returns the height.
293
- ///
294
- /// # Examples
295
- ///
296
- /// ```rust
297
- /// use ratatui_core::text::Text;
298
- ///
299
- /// let text = Text::from("The first line\nThe second line");
300
- /// assert_eq!(2, text.height());
301
- /// ```
302
- pub fn height(&self) -> usize {
303
- self.lines.len()
304
- }
305
-
306
- /// Sets the style of this text.
307
- ///
308
- /// Defaults to [`Style::default()`].
309
- ///
310
- /// Note: This field was added in v0.26.0. Prior to that, the style of a text was determined
311
- /// only by the style of each [`Line`] contained in the line. For this reason, this field may
312
- /// not be supported by all widgets (outside of the `ratatui` crate itself).
313
- ///
314
- /// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
315
- /// your own type that implements [`Into<Style>`]).
316
- ///
317
- /// # Examples
318
- /// ```rust
319
- /// use ratatui_core::style::{Style, Stylize};
320
- /// use ratatui_core::text::Text;
321
- ///
322
- /// let mut line = Text::from("foo").style(Style::new().red());
323
- /// ```
324
- ///
325
- /// [`Color`]: crate::style::Color
326
- #[must_use = "method moves the value of self and returns the modified value"]
327
- pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
328
- self.style = style.into();
329
- self
330
- }
331
-
332
- /// Patches the style of this Text, adding modifiers from the given style.
333
- ///
334
- /// This is useful for when you want to apply a style to a text that already has some styling.
335
- /// In contrast to [`Text::style`], this method will not overwrite the existing style, but
336
- /// instead will add the given style's modifiers to this text's style.
337
- ///
338
- /// `Text` also implements [`Styled`] which means you can use the methods of the [`Stylize`]
339
- /// trait.
340
- ///
341
- /// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
342
- /// your own type that implements [`Into<Style>`]).
343
- ///
344
- /// This is a fluent setter method which must be chained or used as it consumes self
345
- ///
346
- /// # Examples
347
- ///
348
- /// ```rust
349
- /// use ratatui_core::style::{Color, Modifier};
350
- /// use ratatui_core::text::Text;
351
- ///
352
- /// let raw_text = Text::styled("The first line\nThe second line", Modifier::ITALIC);
353
- /// let styled_text = Text::styled(
354
- /// String::from("The first line\nThe second line"),
355
- /// (Color::Yellow, Modifier::ITALIC),
356
- /// );
357
- /// assert_ne!(raw_text, styled_text);
358
- ///
359
- /// let raw_text = raw_text.patch_style(Color::Yellow);
360
- /// assert_eq!(raw_text, styled_text);
361
- /// ```
362
- ///
363
- /// [`Color`]: crate::style::Color
364
- /// [`Stylize`]: crate::style::Stylize
365
- #[must_use = "method moves the value of self and returns the modified value"]
366
- pub fn patch_style<S: Into<Style>>(mut self, style: S) -> Self {
367
- self.style = self.style.patch(style);
368
- self
369
- }
370
-
371
- /// Resets the style of the Text.
372
- ///
373
- /// Equivalent to calling [`patch_style(Style::reset())`](Text::patch_style).
374
- ///
375
- /// This is a fluent setter method which must be chained or used as it consumes self
376
- ///
377
- /// # Examples
378
- ///
379
- /// ```rust
380
- /// use ratatui_core::style::{Color, Modifier, Style};
381
- /// use ratatui_core::text::Text;
382
- ///
383
- /// let text = Text::styled(
384
- /// "The first line\nThe second line",
385
- /// (Color::Yellow, Modifier::ITALIC),
386
- /// );
387
- ///
388
- /// let text = text.reset_style();
389
- /// assert_eq!(Style::reset(), text.style);
390
- /// ```
391
- #[must_use = "method moves the value of self and returns the modified value"]
392
- pub fn reset_style(self) -> Self {
393
- self.patch_style(Style::reset())
394
- }
395
-
396
- /// Sets the alignment for this text.
397
- ///
398
- /// Defaults to: [`None`], meaning the alignment is determined by the rendering widget.
399
- /// Setting the alignment of a Text generally overrides the alignment of its
400
- /// parent Widget.
401
- ///
402
- /// Alignment can be set individually on each line to override this text's alignment.
403
- ///
404
- /// # Examples
405
- ///
406
- /// Set alignment to the whole text.
407
- ///
408
- /// ```rust
409
- /// use ratatui_core::layout::Alignment;
410
- /// use ratatui_core::text::Text;
411
- ///
412
- /// let mut text = Text::from("Hi, what's up?");
413
- /// assert_eq!(None, text.alignment);
414
- /// assert_eq!(
415
- /// Some(Alignment::Right),
416
- /// text.alignment(Alignment::Right).alignment
417
- /// )
418
- /// ```
419
- ///
420
- /// Set a default alignment and override it on a per line basis.
421
- ///
422
- /// ```rust
423
- /// use ratatui_core::layout::Alignment;
424
- /// use ratatui_core::text::{Line, Text};
425
- ///
426
- /// let text = Text::from(vec![
427
- /// Line::from("left").alignment(Alignment::Left),
428
- /// Line::from("default"),
429
- /// Line::from("default"),
430
- /// Line::from("right").alignment(Alignment::Right),
431
- /// ])
432
- /// .alignment(Alignment::Center);
433
- /// ```
434
- ///
435
- /// Will render the following
436
- ///
437
- /// ```plain
438
- /// left
439
- /// default
440
- /// default
441
- /// right
442
- /// ```
443
- #[must_use = "method moves the value of self and returns the modified value"]
444
- pub fn alignment(self, alignment: Alignment) -> Self {
445
- Self {
446
- alignment: Some(alignment),
447
- ..self
448
- }
449
- }
450
-
451
- /// Left-aligns the whole text.
452
- ///
453
- /// Convenience shortcut for `Text::alignment(Alignment::Left)`.
454
- /// Setting the alignment of a Text generally overrides the alignment of its
455
- /// parent Widget, with the default alignment being inherited from the parent.
456
- ///
457
- /// Alignment can be set individually on each line to override this text's alignment.
458
- ///
459
- /// # Examples
460
- ///
461
- /// ```rust
462
- /// use ratatui_core::text::Text;
463
- ///
464
- /// let text = Text::from("Hi, what's up?").left_aligned();
465
- /// ```
466
- #[must_use = "method moves the value of self and returns the modified value"]
467
- pub fn left_aligned(self) -> Self {
468
- self.alignment(Alignment::Left)
469
- }
470
-
471
- /// Center-aligns the whole text.
472
- ///
473
- /// Convenience shortcut for `Text::alignment(Alignment::Center)`.
474
- /// Setting the alignment of a Text generally overrides the alignment of its
475
- /// parent Widget, with the default alignment being inherited from the parent.
476
- ///
477
- /// Alignment can be set individually on each line to override this text's alignment.
478
- ///
479
- /// # Examples
480
- ///
481
- /// ```rust
482
- /// use ratatui_core::text::Text;
483
- ///
484
- /// let text = Text::from("Hi, what's up?").centered();
485
- /// ```
486
- #[must_use = "method moves the value of self and returns the modified value"]
487
- pub fn centered(self) -> Self {
488
- self.alignment(Alignment::Center)
489
- }
490
-
491
- /// Right-aligns the whole text.
492
- ///
493
- /// Convenience shortcut for `Text::alignment(Alignment::Right)`.
494
- /// Setting the alignment of a Text generally overrides the alignment of its
495
- /// parent Widget, with the default alignment being inherited from the parent.
496
- ///
497
- /// Alignment can be set individually on each line to override this text's alignment.
498
- ///
499
- /// # Examples
500
- ///
501
- /// ```rust
502
- /// use ratatui_core::text::Text;
503
- ///
504
- /// let text = Text::from("Hi, what's up?").right_aligned();
505
- /// ```
506
- #[must_use = "method moves the value of self and returns the modified value"]
507
- pub fn right_aligned(self) -> Self {
508
- self.alignment(Alignment::Right)
509
- }
510
-
511
- /// Returns an iterator over the lines of the text.
512
- pub fn iter(&self) -> core::slice::Iter<'_, Line<'a>> {
513
- self.lines.iter()
514
- }
515
-
516
- /// Returns an iterator that allows modifying each line.
517
- pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, Line<'a>> {
518
- self.lines.iter_mut()
519
- }
520
-
521
- /// Adds a line to the text.
522
- ///
523
- /// `line` can be any type that can be converted into a `Line`. For example, you can pass a
524
- /// `&str`, a `String`, a `Span`, or a `Line`.
525
- ///
526
- /// # Examples
527
- ///
528
- /// ```rust
529
- /// use ratatui_core::text::{Line, Span, Text};
530
- ///
531
- /// let mut text = Text::from("Hello, world!");
532
- /// text.push_line(Line::from("How are you?"));
533
- /// text.push_line(Span::from("How are you?"));
534
- /// text.push_line("How are you?");
535
- /// ```
536
- pub fn push_line<T: Into<Line<'a>>>(&mut self, line: T) {
537
- self.lines.push(line.into());
538
- }
539
-
540
- /// Adds a span to the last line of the text.
541
- ///
542
- /// `span` can be any type that is convertible into a `Span`. For example, you can pass a
543
- /// `&str`, a `String`, or a `Span`.
544
- ///
545
- /// # Examples
546
- ///
547
- /// ```rust
548
- /// use ratatui_core::text::{Span, Text};
549
- ///
550
- /// let mut text = Text::from("Hello, world!");
551
- /// text.push_span(Span::from("How are you?"));
552
- /// text.push_span("How are you?");
553
- /// ```
554
- pub fn push_span<T: Into<Span<'a>>>(&mut self, span: T) {
555
- let span = span.into();
556
- if let Some(last) = self.lines.last_mut() {
557
- last.push_span(span);
558
- } else {
559
- self.lines.push(Line::from(span));
560
- }
561
- }
562
- }
563
-
564
- impl UnicodeWidthStr for Text<'_> {
565
- /// Returns the max width of all the lines.
566
- fn width(&self) -> usize {
567
- self.lines
568
- .iter()
569
- .map(UnicodeWidthStr::width)
570
- .max()
571
- .unwrap_or_default()
572
- }
573
-
574
- fn width_cjk(&self) -> usize {
575
- self.lines
576
- .iter()
577
- .map(UnicodeWidthStr::width_cjk)
578
- .max()
579
- .unwrap_or_default()
580
- }
581
- }
582
-
583
- impl<'a> IntoIterator for Text<'a> {
584
- type Item = Line<'a>;
585
- type IntoIter = alloc::vec::IntoIter<Self::Item>;
586
-
587
- fn into_iter(self) -> Self::IntoIter {
588
- self.lines.into_iter()
589
- }
590
- }
591
-
592
- impl<'a> IntoIterator for &'a Text<'a> {
593
- type Item = &'a Line<'a>;
594
- type IntoIter = core::slice::Iter<'a, Line<'a>>;
595
-
596
- fn into_iter(self) -> Self::IntoIter {
597
- self.iter()
598
- }
599
- }
600
-
601
- impl<'a> IntoIterator for &'a mut Text<'a> {
602
- type Item = &'a mut Line<'a>;
603
- type IntoIter = core::slice::IterMut<'a, Line<'a>>;
604
-
605
- fn into_iter(self) -> Self::IntoIter {
606
- self.iter_mut()
607
- }
608
- }
609
-
610
- impl From<String> for Text<'_> {
611
- fn from(s: String) -> Self {
612
- Self::raw(s)
613
- }
614
- }
615
-
616
- impl<'a> From<&'a str> for Text<'a> {
617
- fn from(s: &'a str) -> Self {
618
- Self::raw(s)
619
- }
620
- }
621
-
622
- impl<'a> From<Cow<'a, str>> for Text<'a> {
623
- fn from(s: Cow<'a, str>) -> Self {
624
- Self::raw(s)
625
- }
626
- }
627
-
628
- impl<'a> From<Span<'a>> for Text<'a> {
629
- fn from(span: Span<'a>) -> Self {
630
- Self {
631
- lines: vec![Line::from(span)],
632
- ..Default::default()
633
- }
634
- }
635
- }
636
-
637
- impl<'a> From<Line<'a>> for Text<'a> {
638
- fn from(line: Line<'a>) -> Self {
639
- Self {
640
- lines: vec![line],
641
- ..Default::default()
642
- }
643
- }
644
- }
645
-
646
- impl<'a> From<Vec<Line<'a>>> for Text<'a> {
647
- fn from(lines: Vec<Line<'a>>) -> Self {
648
- Self {
649
- lines,
650
- ..Default::default()
651
- }
652
- }
653
- }
654
-
655
- impl<'a, T> FromIterator<T> for Text<'a>
656
- where
657
- T: Into<Line<'a>>,
658
- {
659
- fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
660
- let lines = iter.into_iter().map(Into::into).collect();
661
- Self {
662
- lines,
663
- ..Default::default()
664
- }
665
- }
666
- }
667
-
668
- impl<'a> core::ops::Add<Line<'a>> for Text<'a> {
669
- type Output = Self;
670
-
671
- fn add(mut self, line: Line<'a>) -> Self::Output {
672
- self.push_line(line);
673
- self
674
- }
675
- }
676
-
677
- /// Adds two `Text` together.
678
- ///
679
- /// This ignores the style and alignment of the second `Text`.
680
- impl core::ops::Add<Self> for Text<'_> {
681
- type Output = Self;
682
-
683
- fn add(mut self, text: Self) -> Self::Output {
684
- self.lines.extend(text.lines);
685
- self
686
- }
687
- }
688
-
689
- /// Adds two `Text` together.
690
- ///
691
- /// This ignores the style and alignment of the second `Text`.
692
- impl core::ops::AddAssign for Text<'_> {
693
- fn add_assign(&mut self, rhs: Self) {
694
- self.lines.extend(rhs.lines);
695
- }
696
- }
697
-
698
- impl<'a> core::ops::AddAssign<Line<'a>> for Text<'a> {
699
- fn add_assign(&mut self, line: Line<'a>) {
700
- self.push_line(line);
701
- }
702
- }
703
-
704
- impl<'a, T> Extend<T> for Text<'a>
705
- where
706
- T: Into<Line<'a>>,
707
- {
708
- fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
709
- let lines = iter.into_iter().map(Into::into);
710
- self.lines.extend(lines);
711
- }
712
- }
713
-
714
- /// A trait for converting a value to a [`Text`].
715
- ///
716
- /// This trait is automatically implemented for any type that implements the [`Display`] trait. As
717
- /// such, `ToText` shouldn't be implemented directly: [`Display`] should be implemented instead, and
718
- /// you get the `ToText` implementation for free.
719
- ///
720
- /// [`Display`]: std::fmt::Display
721
- pub trait ToText {
722
- /// Converts the value to a [`Text`].
723
- fn to_text(&self) -> Text<'_>;
724
- }
725
-
726
- /// # Panics
727
- ///
728
- /// In this implementation, the `to_text` method panics if the `Display` implementation returns an
729
- /// error. This indicates an incorrect `Display` implementation since `fmt::Write for String` never
730
- /// returns an error itself.
731
- impl<T: fmt::Display> ToText for T {
732
- fn to_text(&self) -> Text<'_> {
733
- Text::raw(self.to_string())
734
- }
735
- }
736
-
737
- impl fmt::Display for Text<'_> {
738
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
739
- if let Some((last, rest)) = self.lines.split_last() {
740
- for line in rest {
741
- writeln!(f, "{line}")?;
742
- }
743
- write!(f, "{last}")?;
744
- }
745
- Ok(())
746
- }
747
- }
748
-
749
- impl Widget for Text<'_> {
750
- fn render(self, area: Rect, buf: &mut Buffer) {
751
- Widget::render(&self, area, buf);
752
- }
753
- }
754
-
755
- impl Widget for &Text<'_> {
756
- fn render(self, area: Rect, buf: &mut Buffer) {
757
- let area = area.intersection(buf.area);
758
- buf.set_style(area, self.style);
759
- for (line, line_area) in self.iter().zip(area.rows()) {
760
- line.render_with_alignment(line_area, buf, self.alignment);
761
- }
762
- }
763
- }
764
-
765
- impl Styled for Text<'_> {
766
- type Item = Self;
767
-
768
- fn style(&self) -> Style {
769
- self.style
770
- }
771
-
772
- fn set_style<S: Into<Style>>(self, style: S) -> Self::Item {
773
- self.style(style)
774
- }
775
- }
776
-
777
- #[cfg(test)]
778
- mod tests {
779
- use alloc::format;
780
- use core::iter;
781
-
782
- use rstest::{fixture, rstest};
783
-
784
- use super::*;
785
- use crate::style::{Color, Modifier, Stylize};
786
-
787
- #[fixture]
788
- fn small_buf() -> Buffer {
789
- Buffer::empty(Rect::new(0, 0, 10, 1))
790
- }
791
-
792
- #[test]
793
- fn raw() {
794
- let text = Text::raw("The first line\nThe second line");
795
- assert_eq!(
796
- text.lines,
797
- vec![Line::from("The first line"), Line::from("The second line")]
798
- );
799
- }
800
-
801
- #[test]
802
- fn styled() {
803
- let style = Style::new().yellow().italic();
804
- let styled_text = Text::styled("The first line\nThe second line", style);
805
-
806
- let mut text = Text::raw("The first line\nThe second line");
807
- text.style = style;
808
-
809
- assert_eq!(styled_text, text);
810
- }
811
-
812
- #[test]
813
- fn width() {
814
- let text = Text::from("The first line\nThe second line");
815
- assert_eq!(15, text.width());
816
- }
817
-
818
- #[test]
819
- fn height() {
820
- let text = Text::from("The first line\nThe second line");
821
- assert_eq!(2, text.height());
822
- }
823
-
824
- #[test]
825
- fn patch_style() {
826
- let style = Style::new().yellow().italic();
827
- let style2 = Style::new().red().underlined();
828
- let text = Text::styled("The first line\nThe second line", style).patch_style(style2);
829
-
830
- let expected_style = Style::new().red().italic().underlined();
831
- let expected_text = Text::styled("The first line\nThe second line", expected_style);
832
-
833
- assert_eq!(text, expected_text);
834
- }
835
-
836
- #[test]
837
- fn reset_style() {
838
- let style = Style::new().yellow().italic();
839
- let text = Text::styled("The first line\nThe second line", style).reset_style();
840
-
841
- assert_eq!(text.style, Style::reset());
842
- }
843
-
844
- #[test]
845
- fn from_string() {
846
- let text = Text::from(String::from("The first line\nThe second line"));
847
- assert_eq!(
848
- text.lines,
849
- vec![Line::from("The first line"), Line::from("The second line")]
850
- );
851
- }
852
-
853
- #[test]
854
- fn from_str() {
855
- let text = Text::from("The first line\nThe second line");
856
- assert_eq!(
857
- text.lines,
858
- vec![Line::from("The first line"), Line::from("The second line")]
859
- );
860
- }
861
-
862
- #[test]
863
- fn from_cow() {
864
- let text = Text::from(Cow::Borrowed("The first line\nThe second line"));
865
- assert_eq!(
866
- text.lines,
867
- vec![Line::from("The first line"), Line::from("The second line")]
868
- );
869
- }
870
-
871
- #[test]
872
- fn from_span() {
873
- let style = Style::new().yellow().italic();
874
- let text = Text::from(Span::styled("The first line\nThe second line", style));
875
- assert_eq!(
876
- text.lines,
877
- vec![Line::from(Span::styled(
878
- "The first line\nThe second line",
879
- style
880
- ))]
881
- );
882
- }
883
-
884
- #[test]
885
- fn from_line() {
886
- let text = Text::from(Line::from("The first line"));
887
- assert_eq!(text.lines, [Line::from("The first line")]);
888
- }
889
-
890
- #[rstest]
891
- #[case(42, Text::from("42"))]
892
- #[case("just\ntesting", Text::from("just\ntesting"))]
893
- #[case(true, Text::from("true"))]
894
- #[case(6.66, Text::from("6.66"))]
895
- #[case('a', Text::from("a"))]
896
- #[case(String::from("hello"), Text::from("hello"))]
897
- #[case(-1, Text::from("-1"))]
898
- #[case("line1\nline2", Text::from("line1\nline2"))]
899
- #[case(
900
- "first line\nsecond line\nthird line",
901
- Text::from("first line\nsecond line\nthird line")
902
- )]
903
- #[case("trailing newline\n", Text::from("trailing newline\n"))]
904
- fn to_text(#[case] value: impl fmt::Display, #[case] expected: Text) {
905
- assert_eq!(value.to_text(), expected);
906
- }
907
-
908
- #[test]
909
- fn from_vec_line() {
910
- let text = Text::from(vec![
911
- Line::from("The first line"),
912
- Line::from("The second line"),
913
- ]);
914
- assert_eq!(
915
- text.lines,
916
- vec![Line::from("The first line"), Line::from("The second line")]
917
- );
918
- }
919
-
920
- #[test]
921
- fn from_iterator() {
922
- let text = Text::from_iter(vec!["The first line", "The second line"]);
923
- assert_eq!(
924
- text.lines,
925
- vec![Line::from("The first line"), Line::from("The second line")]
926
- );
927
- }
928
-
929
- #[test]
930
- fn collect() {
931
- let text: Text = iter::once("The first line")
932
- .chain(iter::once("The second line"))
933
- .collect();
934
- assert_eq!(
935
- text.lines,
936
- vec![Line::from("The first line"), Line::from("The second line")]
937
- );
938
- }
939
-
940
- #[test]
941
- fn into_iter() {
942
- let text = Text::from("The first line\nThe second line");
943
- let mut iter = text.into_iter();
944
- assert_eq!(iter.next(), Some(Line::from("The first line")));
945
- assert_eq!(iter.next(), Some(Line::from("The second line")));
946
- assert_eq!(iter.next(), None);
947
- }
948
-
949
- #[test]
950
- fn add_line() {
951
- assert_eq!(
952
- Text::raw("Red").red() + Line::raw("Blue").blue(),
953
- Text {
954
- lines: vec![Line::raw("Red"), Line::raw("Blue").blue()],
955
- style: Style::new().red(),
956
- alignment: None,
957
- }
958
- );
959
- }
960
-
961
- #[test]
962
- fn add_text() {
963
- assert_eq!(
964
- Text::raw("Red").red() + Text::raw("Blue").blue(),
965
- Text {
966
- lines: vec![Line::raw("Red"), Line::raw("Blue")],
967
- style: Style::new().red(),
968
- alignment: None,
969
- }
970
- );
971
- }
972
-
973
- #[test]
974
- fn add_assign_text() {
975
- let mut text = Text::raw("Red").red();
976
- text += Text::raw("Blue").blue();
977
- assert_eq!(
978
- text,
979
- Text {
980
- lines: vec![Line::raw("Red"), Line::raw("Blue")],
981
- style: Style::new().red(),
982
- alignment: None,
983
- }
984
- );
985
- }
986
-
987
- #[test]
988
- fn add_assign_line() {
989
- let mut text = Text::raw("Red").red();
990
- text += Line::raw("Blue").blue();
991
- assert_eq!(
992
- text,
993
- Text {
994
- lines: vec![Line::raw("Red"), Line::raw("Blue").blue()],
995
- style: Style::new().red(),
996
- alignment: None,
997
- }
998
- );
999
- }
1000
-
1001
- #[test]
1002
- fn extend() {
1003
- let mut text = Text::from("The first line\nThe second line");
1004
- text.extend(vec![
1005
- Line::from("The third line"),
1006
- Line::from("The fourth line"),
1007
- ]);
1008
- assert_eq!(
1009
- text.lines,
1010
- vec![
1011
- Line::from("The first line"),
1012
- Line::from("The second line"),
1013
- Line::from("The third line"),
1014
- Line::from("The fourth line"),
1015
- ]
1016
- );
1017
- }
1018
-
1019
- #[test]
1020
- fn extend_from_iter() {
1021
- let mut text = Text::from("The first line\nThe second line");
1022
- text.extend(vec![
1023
- Line::from("The third line"),
1024
- Line::from("The fourth line"),
1025
- ]);
1026
- assert_eq!(
1027
- text.lines,
1028
- vec![
1029
- Line::from("The first line"),
1030
- Line::from("The second line"),
1031
- Line::from("The third line"),
1032
- Line::from("The fourth line"),
1033
- ]
1034
- );
1035
- }
1036
-
1037
- #[test]
1038
- fn extend_from_iter_str() {
1039
- let mut text = Text::from("The first line\nThe second line");
1040
- text.extend(vec!["The third line", "The fourth line"]);
1041
- assert_eq!(
1042
- text.lines,
1043
- vec![
1044
- Line::from("The first line"),
1045
- Line::from("The second line"),
1046
- Line::from("The third line"),
1047
- Line::from("The fourth line"),
1048
- ]
1049
- );
1050
- }
1051
-
1052
- #[rstest]
1053
- #[case::one_line("The first line")]
1054
- #[case::multiple_lines("The first line\nThe second line")]
1055
- fn display_raw_text(#[case] value: &str) {
1056
- let text = Text::raw(value);
1057
- assert_eq!(format!("{text}"), value);
1058
- }
1059
-
1060
- #[test]
1061
- fn display_styled_text() {
1062
- let styled_text = Text::styled(
1063
- "The first line\nThe second line",
1064
- Style::new().yellow().italic(),
1065
- );
1066
-
1067
- assert_eq!(format!("{styled_text}"), "The first line\nThe second line");
1068
- }
1069
-
1070
- #[test]
1071
- fn display_text_from_vec() {
1072
- let text_from_vec = Text::from(vec![
1073
- Line::from("The first line"),
1074
- Line::from("The second line"),
1075
- ]);
1076
-
1077
- assert_eq!(
1078
- format!("{text_from_vec}"),
1079
- "The first line\nThe second line"
1080
- );
1081
- }
1082
-
1083
- #[test]
1084
- fn display_extended_text() {
1085
- let mut text = Text::from("The first line\nThe second line");
1086
-
1087
- assert_eq!(format!("{text}"), "The first line\nThe second line");
1088
-
1089
- text.extend(vec![
1090
- Line::from("The third line"),
1091
- Line::from("The fourth line"),
1092
- ]);
1093
-
1094
- assert_eq!(
1095
- format!("{text}"),
1096
- "The first line\nThe second line\nThe third line\nThe fourth line"
1097
- );
1098
- }
1099
-
1100
- #[test]
1101
- fn stylize() {
1102
- assert_eq!(Text::default().green().style, Color::Green.into());
1103
- assert_eq!(
1104
- Text::default().on_green().style,
1105
- Style::new().bg(Color::Green)
1106
- );
1107
- assert_eq!(Text::default().italic().style, Modifier::ITALIC.into());
1108
- }
1109
-
1110
- #[test]
1111
- fn left_aligned() {
1112
- let text = Text::from("Hello, world!").left_aligned();
1113
- assert_eq!(text.alignment, Some(Alignment::Left));
1114
- }
1115
-
1116
- #[test]
1117
- fn centered() {
1118
- let text = Text::from("Hello, world!").centered();
1119
- assert_eq!(text.alignment, Some(Alignment::Center));
1120
- }
1121
-
1122
- #[test]
1123
- fn right_aligned() {
1124
- let text = Text::from("Hello, world!").right_aligned();
1125
- assert_eq!(text.alignment, Some(Alignment::Right));
1126
- }
1127
-
1128
- #[test]
1129
- fn push_line() {
1130
- let mut text = Text::from("A");
1131
- text.push_line(Line::from("B"));
1132
- text.push_line(Span::from("C"));
1133
- text.push_line("D");
1134
- assert_eq!(
1135
- text.lines,
1136
- vec![
1137
- Line::raw("A"),
1138
- Line::raw("B"),
1139
- Line::raw("C"),
1140
- Line::raw("D")
1141
- ]
1142
- );
1143
- }
1144
-
1145
- #[test]
1146
- fn push_line_empty() {
1147
- let mut text = Text::default();
1148
- text.push_line(Line::from("Hello, world!"));
1149
- assert_eq!(text.lines, [Line::from("Hello, world!")]);
1150
- }
1151
-
1152
- #[test]
1153
- fn push_span() {
1154
- let mut text = Text::from("A");
1155
- text.push_span(Span::raw("B"));
1156
- text.push_span("C");
1157
- assert_eq!(
1158
- text.lines,
1159
- vec![Line::from(vec![
1160
- Span::raw("A"),
1161
- Span::raw("B"),
1162
- Span::raw("C")
1163
- ])],
1164
- );
1165
- }
1166
-
1167
- #[test]
1168
- fn push_span_empty() {
1169
- let mut text = Text::default();
1170
- text.push_span(Span::raw("Hello, world!"));
1171
- assert_eq!(text.lines, [Line::from(Span::raw("Hello, world!"))]);
1172
- }
1173
-
1174
- mod widget {
1175
- use super::*;
1176
-
1177
- #[test]
1178
- fn render() {
1179
- let text = Text::from("foo");
1180
- let area = Rect::new(0, 0, 5, 1);
1181
- let mut buf = Buffer::empty(area);
1182
- text.render(area, &mut buf);
1183
- assert_eq!(buf, Buffer::with_lines(["foo "]));
1184
- }
1185
-
1186
- #[rstest]
1187
- fn render_out_of_bounds(mut small_buf: Buffer) {
1188
- let out_of_bounds_area = Rect::new(20, 20, 10, 1);
1189
- Text::from("Hello, world!").render(out_of_bounds_area, &mut small_buf);
1190
- assert_eq!(small_buf, Buffer::empty(small_buf.area));
1191
- }
1192
-
1193
- #[test]
1194
- fn render_right_aligned() {
1195
- let text = Text::from("foo").alignment(Alignment::Right);
1196
- let area = Rect::new(0, 0, 5, 1);
1197
- let mut buf = Buffer::empty(area);
1198
- text.render(area, &mut buf);
1199
- assert_eq!(buf, Buffer::with_lines([" foo"]));
1200
- }
1201
-
1202
- #[test]
1203
- fn render_centered_odd() {
1204
- let text = Text::from("foo").alignment(Alignment::Center);
1205
- let area = Rect::new(0, 0, 5, 1);
1206
- let mut buf = Buffer::empty(area);
1207
- text.render(area, &mut buf);
1208
- assert_eq!(buf, Buffer::with_lines([" foo "]));
1209
- }
1210
-
1211
- #[test]
1212
- fn render_centered_even() {
1213
- let text = Text::from("foo").alignment(Alignment::Center);
1214
- let area = Rect::new(0, 0, 6, 1);
1215
- let mut buf = Buffer::empty(area);
1216
- text.render(area, &mut buf);
1217
- assert_eq!(buf, Buffer::with_lines([" foo "]));
1218
- }
1219
-
1220
- #[test]
1221
- fn render_right_aligned_with_truncation() {
1222
- let text = Text::from("123456789").alignment(Alignment::Right);
1223
- let area = Rect::new(0, 0, 5, 1);
1224
- let mut buf = Buffer::empty(area);
1225
- text.render(area, &mut buf);
1226
- assert_eq!(buf, Buffer::with_lines(["56789"]));
1227
- }
1228
-
1229
- #[test]
1230
- fn render_centered_odd_with_truncation() {
1231
- let text = Text::from("123456789").alignment(Alignment::Center);
1232
- let area = Rect::new(0, 0, 5, 1);
1233
- let mut buf = Buffer::empty(area);
1234
- text.render(area, &mut buf);
1235
- assert_eq!(buf, Buffer::with_lines(["34567"]));
1236
- }
1237
-
1238
- #[test]
1239
- fn render_centered_even_with_truncation() {
1240
- let text = Text::from("123456789").alignment(Alignment::Center);
1241
- let area = Rect::new(0, 0, 6, 1);
1242
- let mut buf = Buffer::empty(area);
1243
- text.render(area, &mut buf);
1244
- assert_eq!(buf, Buffer::with_lines(["234567"]));
1245
- }
1246
-
1247
- #[test]
1248
- fn render_one_line_right() {
1249
- let text = Text::from(vec![
1250
- "foo".into(),
1251
- Line::from("bar").alignment(Alignment::Center),
1252
- ])
1253
- .alignment(Alignment::Right);
1254
- let area = Rect::new(0, 0, 5, 2);
1255
- let mut buf = Buffer::empty(area);
1256
- text.render(area, &mut buf);
1257
- assert_eq!(buf, Buffer::with_lines([" foo", " bar "]));
1258
- }
1259
-
1260
- #[test]
1261
- fn render_only_styles_line_area() {
1262
- let area = Rect::new(0, 0, 5, 1);
1263
- let mut buf = Buffer::empty(area);
1264
- Text::from("foo".on_blue()).render(area, &mut buf);
1265
-
1266
- let mut expected = Buffer::with_lines(["foo "]);
1267
- expected.set_style(Rect::new(0, 0, 3, 1), Style::new().bg(Color::Blue));
1268
- assert_eq!(buf, expected);
1269
- }
1270
-
1271
- #[test]
1272
- fn render_truncates() {
1273
- let mut buf = Buffer::empty(Rect::new(0, 0, 6, 1));
1274
- Text::from("foobar".on_blue()).render(Rect::new(0, 0, 3, 1), &mut buf);
1275
-
1276
- let mut expected = Buffer::with_lines(["foo "]);
1277
- expected.set_style(Rect::new(0, 0, 3, 1), Style::new().bg(Color::Blue));
1278
- assert_eq!(buf, expected);
1279
- }
1280
- }
1281
-
1282
- mod iterators {
1283
- use super::*;
1284
-
1285
- /// a fixture used in the tests below to avoid repeating the same setup
1286
- #[fixture]
1287
- fn hello_world() -> Text<'static> {
1288
- Text::from(vec![
1289
- Line::styled("Hello ", Color::Blue),
1290
- Line::styled("world!", Color::Green),
1291
- ])
1292
- }
1293
-
1294
- #[rstest]
1295
- fn iter(hello_world: Text<'_>) {
1296
- let mut iter = hello_world.iter();
1297
- assert_eq!(iter.next(), Some(&Line::styled("Hello ", Color::Blue)));
1298
- assert_eq!(iter.next(), Some(&Line::styled("world!", Color::Green)));
1299
- assert_eq!(iter.next(), None);
1300
- }
1301
-
1302
- #[rstest]
1303
- fn iter_mut(mut hello_world: Text<'_>) {
1304
- let mut iter = hello_world.iter_mut();
1305
- assert_eq!(iter.next(), Some(&mut Line::styled("Hello ", Color::Blue)));
1306
- assert_eq!(iter.next(), Some(&mut Line::styled("world!", Color::Green)));
1307
- assert_eq!(iter.next(), None);
1308
- }
1309
-
1310
- #[rstest]
1311
- fn into_iter(hello_world: Text<'_>) {
1312
- let mut iter = hello_world.into_iter();
1313
- assert_eq!(iter.next(), Some(Line::styled("Hello ", Color::Blue)));
1314
- assert_eq!(iter.next(), Some(Line::styled("world!", Color::Green)));
1315
- assert_eq!(iter.next(), None);
1316
- }
1317
-
1318
- #[rstest]
1319
- fn into_iter_ref(hello_world: Text<'_>) {
1320
- let mut iter = (&hello_world).into_iter();
1321
- assert_eq!(iter.next(), Some(&Line::styled("Hello ", Color::Blue)));
1322
- assert_eq!(iter.next(), Some(&Line::styled("world!", Color::Green)));
1323
- assert_eq!(iter.next(), None);
1324
- }
1325
-
1326
- #[test]
1327
- fn into_iter_mut_ref() {
1328
- let mut hello_world = Text::from(vec![
1329
- Line::styled("Hello ", Color::Blue),
1330
- Line::styled("world!", Color::Green),
1331
- ]);
1332
- let mut iter = (&mut hello_world).into_iter();
1333
- assert_eq!(iter.next(), Some(&mut Line::styled("Hello ", Color::Blue)));
1334
- assert_eq!(iter.next(), Some(&mut Line::styled("world!", Color::Green)));
1335
- assert_eq!(iter.next(), None);
1336
- }
1337
-
1338
- #[rstest]
1339
- fn for_loop_ref(hello_world: Text<'_>) {
1340
- let mut result = String::new();
1341
- for line in &hello_world {
1342
- result.push_str(line.to_string().as_ref());
1343
- }
1344
- assert_eq!(result, "Hello world!");
1345
- }
1346
-
1347
- #[rstest]
1348
- fn for_loop_mut_ref() {
1349
- let mut hello_world = Text::from(vec![
1350
- Line::styled("Hello ", Color::Blue),
1351
- Line::styled("world!", Color::Green),
1352
- ]);
1353
- let mut result = String::new();
1354
- for line in &mut hello_world {
1355
- result.push_str(line.to_string().as_ref());
1356
- }
1357
- assert_eq!(result, "Hello world!");
1358
- }
1359
-
1360
- #[rstest]
1361
- fn for_loop_into(hello_world: Text<'_>) {
1362
- let mut result = String::new();
1363
- for line in hello_world {
1364
- result.push_str(line.to_string().as_ref());
1365
- }
1366
- assert_eq!(result, "Hello world!");
1367
- }
1368
- }
1369
-
1370
- #[rstest]
1371
- #[case::default(Text::default(), "Text::default()")]
1372
- // TODO jm: these could be improved to inspect the line / span if there's only one. e.g.
1373
- // Text::from("Hello, world!") and Text::from("Hello, world!".blue()) but the current
1374
- // implementation is good enough for now.
1375
- #[case::raw(
1376
- Text::raw("Hello, world!"),
1377
- r#"Text::from(Line::from("Hello, world!"))"#
1378
- )]
1379
- #[case::styled(
1380
- Text::styled("Hello, world!", Color::Yellow),
1381
- r#"Text::from(Line::from("Hello, world!")).yellow()"#
1382
- )]
1383
- #[case::complex_styled(
1384
- Text::from("Hello, world!").yellow().on_blue().bold().italic().not_dim().not_hidden(),
1385
- r#"Text::from(Line::from("Hello, world!")).yellow().on_blue().bold().italic().not_dim().not_hidden()"#
1386
- )]
1387
- #[case::alignment(
1388
- Text::from("Hello, world!").centered(),
1389
- r#"Text::from(Line::from("Hello, world!")).centered()"#
1390
- )]
1391
- #[case::styled_alignment(
1392
- Text::styled("Hello, world!", Color::Yellow).centered(),
1393
- r#"Text::from(Line::from("Hello, world!")).yellow().centered()"#
1394
- )]
1395
- #[case::multiple_lines(
1396
- Text::from(vec![
1397
- Line::from("Hello, world!"),
1398
- Line::from("How are you?")
1399
- ]),
1400
- r#"Text::from_iter([Line::from("Hello, world!"), Line::from("How are you?")])"#
1401
- )]
1402
- fn debug(#[case] text: Text, #[case] expected: &str) {
1403
- assert_eq!(format!("{text:?}"), expected);
1404
- }
1405
-
1406
- #[test]
1407
- fn debug_alternate() {
1408
- let text = Text::from_iter([
1409
- Line::from("Hello, world!"),
1410
- Line::from("How are you?").bold().left_aligned(),
1411
- Line::from_iter([
1412
- Span::from("I'm "),
1413
- Span::from("doing ").italic(),
1414
- Span::from("great!").bold(),
1415
- ]),
1416
- ])
1417
- .on_blue()
1418
- .italic()
1419
- .centered();
1420
- assert_eq!(
1421
- format!("{text:#?}"),
1422
- indoc::indoc! {r#"
1423
- Text::from_iter([
1424
- Line::from("Hello, world!"),
1425
- Line::from("How are you?").bold().left_aligned(),
1426
- Line::from_iter([
1427
- Span::from("I'm "),
1428
- Span::from("doing ").italic(),
1429
- Span::from("great!").bold(),
1430
- ]),
1431
- ]).on_blue().italic().centered()"#}
1432
- );
1433
- }
1434
- }