diff --git a/src/terminal.rs b/src/terminal.rs index 397652a..12521a6 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -31,7 +31,7 @@ impl Viewport { } #[derive(Debug, Clone, PartialEq)] -/// Options to pass to [`Terminal::draw_with_options`] +/// Options to pass to [`Terminal::with_options`] pub struct TerminalOptions { /// Viewport used to draw to the terminal pub viewport: Viewport, diff --git a/src/text.rs b/src/text.rs index e7ef4e2..eca59af 100644 --- a/src/text.rs +++ b/src/text.rs @@ -257,6 +257,28 @@ impl<'a> From> for String { /// A string split over multiple lines where each line is composed of several clusters, each with /// their own style. +/// +/// A [`Text`], like a [`Span`], can be constructed using one of the many `From` implementations +/// or via the [`Text::raw`] and [`Text::styled`] methods. Helpfully, [`Text`] also implements +/// [`core::iter::Extend`] which enables the concatenation of several [`Text`] blocks. +/// +/// ```rust +/// # use tui::text::Text; +/// # use tui::style::{Color, Modifier, Style}; +/// let style = Style::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC); +/// +/// // An initial two lines of `Text` built from a `&str` +/// let mut text = Text::from("The first line\nThe second line"); +/// assert_eq!(2, text.height()); +/// +/// // Adding two more unstyled lines +/// text.extend(Text::raw("These are two\nmore lines!")); +/// assert_eq!(4, text.height()); +/// +/// // Adding a final two styled lines +/// text.extend(Text::styled("Some more lines\nnow with more style!", style)); +/// assert_eq!(6, text.height()); +/// ``` #[derive(Debug, Clone, PartialEq)] pub struct Text<'a> { pub lines: Vec>, @@ -269,6 +291,47 @@ impl<'a> Default for Text<'a> { } impl<'a> Text<'a> { + /// Create some text (potentially multiple lines) with no style. + /// + /// ## Examples + /// + /// ```rust + /// # use tui::text::Text; + /// Text::raw("The first line\nThe second line"); + /// Text::raw(String::from("The first line\nThe second line")); + /// ``` + pub fn raw(content: T) -> Text<'a> + where + T: Into>, + { + Text { + lines: match content.into() { + Cow::Borrowed(s) => s.lines().map(Spans::from).collect(), + Cow::Owned(s) => s.lines().map(|l| Spans::from(l.to_owned())).collect(), + }, + } + } + + /// Create some text (potentially multiple lines) with a style. + /// + /// # Examples + /// + /// ```rust + /// # use tui::text::Text; + /// # use tui::style::{Color, Modifier, Style}; + /// let style = Style::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC); + /// Text::styled("The first line\nThe second line", style); + /// Text::styled(String::from("The first line\nThe second line"), style); + /// ``` + pub fn styled(content: T, style: Style) -> Text<'a> + where + T: Into>, + { + let mut text = Text::raw(content); + text.patch_style(style); + text + } + /// Returns the max width of all the lines. /// /// ## Examples @@ -299,6 +362,21 @@ impl<'a> Text<'a> { self.lines.len() } + /// Apply a new style to existing text. + /// + /// # Examples + /// + /// ```rust + /// # use tui::text::Text; + /// # use tui::style::{Color, Modifier, Style}; + /// let style = Style::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC); + /// let mut raw_text = Text::raw("The first line\nThe second line"); + /// let styled_text = Text::styled(String::from("The first line\nThe second line"), style); + /// assert_ne!(raw_text, styled_text); + /// + /// raw_text.patch_style(style); + /// assert_eq!(raw_text, styled_text); + /// ``` pub fn patch_style(&mut self, style: Style) { for line in &mut self.lines { for span in &mut line.0 { @@ -308,11 +386,15 @@ impl<'a> Text<'a> { } } +impl<'a> From for Text<'a> { + fn from(s: String) -> Text<'a> { + Text::raw(s) + } +} + impl<'a> From<&'a str> for Text<'a> { fn from(s: &'a str) -> Text<'a> { - Text { - lines: s.lines().map(Spans::from).collect(), - } + Text::raw(s) } } @@ -335,3 +417,18 @@ impl<'a> From>> for Text<'a> { Text { lines } } } + +impl<'a> IntoIterator for Text<'a> { + type Item = Spans<'a>; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.lines.into_iter() + } +} + +impl<'a> Extend> for Text<'a> { + fn extend>>(&mut self, iter: T) { + self.lines.extend(iter); + } +}