mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-22 20:53:19 +00:00
feat(text): extend Text
to be stylable and extendable (#361)
* Extend `Text` to be extendable * Add some documentation
This commit is contained in:
parent
ce32d5537d
commit
d00184a7c3
2 changed files with 101 additions and 4 deletions
|
@ -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,
|
||||
|
|
103
src/text.rs
103
src/text.rs
|
@ -257,6 +257,28 @@ impl<'a> From<Spans<'a>> 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<Spans<'a>>,
|
||||
|
@ -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<T>(content: T) -> Text<'a>
|
||||
where
|
||||
T: Into<Cow<'a, str>>,
|
||||
{
|
||||
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<T>(content: T, style: Style) -> Text<'a>
|
||||
where
|
||||
T: Into<Cow<'a, str>>,
|
||||
{
|
||||
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<String> 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<Vec<Spans<'a>>> for Text<'a> {
|
|||
Text { lines }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for Text<'a> {
|
||||
type Item = Spans<'a>;
|
||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.lines.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Extend<Spans<'a>> for Text<'a> {
|
||||
fn extend<T: IntoIterator<Item = Spans<'a>>>(&mut self, iter: T) {
|
||||
self.lines.extend(iter);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue