Skip to content

Commit

Permalink
feat(text): add push methods for text and line (#998)
Browse files Browse the repository at this point in the history
Adds the following methods to the `Text` and `Line` structs:
- Text::push_line
- Text::push_span
- Line::push_span

This allows for adding lines and spans to a text object without having
to call methods on the fields directly, which is usefult for incremental
construction of text objects.
  • Loading branch information
joshka committed Mar 28, 2024
1 parent 07da90a commit 26af650
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 57 deletions.
65 changes: 47 additions & 18 deletions src/text/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ use crate::prelude::*;
/// - [`Line::reset_style`] resets the style of the line.
/// - [`Line::width`] returns the unicode width of the content held by this line.
/// - [`Line::styled_graphemes`] returns an iterator over the graphemes held by this line.
/// - [`Line::push_span`] adds a span to the line.
///
/// # Compatibility Notes
///
Expand Down Expand Up @@ -451,6 +452,23 @@ impl<'a> Line<'a> {
pub fn iter_mut(&mut self) -> std::slice::IterMut<Span<'a>> {
self.spans.iter_mut()
}

/// Adds a span to the line.
///
/// `span` can be any type that is convertible into a `Span`. For example, you can pass a
/// `&str`, a `String`, or a `Span`.
///
/// # Examples
///
/// ```rust
/// # use ratatui::prelude::*;
/// let mut line = Line::from("Hello, ");
/// line.push_span(Span::raw("world!"));
/// line.push_span(" How are you?");
/// ```
pub fn push_span<T: Into<Span<'a>>>(&mut self, span: T) {
self.spans.push(span.into());
}
}

impl<'a> IntoIterator for Line<'a> {
Expand Down Expand Up @@ -830,6 +848,35 @@ mod tests {
assert_eq!(format!("{line_from_styled_span}"), "Hello, world!");
}

#[test]
fn left_aligned() {
let line = Line::from("Hello, world!").left_aligned();
assert_eq!(line.alignment, Some(Alignment::Left));
}

#[test]
fn centered() {
let line = Line::from("Hello, world!").centered();
assert_eq!(line.alignment, Some(Alignment::Center));
}

#[test]
fn right_aligned() {
let line = Line::from("Hello, world!").right_aligned();
assert_eq!(line.alignment, Some(Alignment::Right));
}

#[test]
pub fn push_span() {
let mut line = Line::from("A");
line.push_span(Span::raw("B"));
line.push_span("C");
assert_eq!(
line.spans,
vec![Span::raw("A"), Span::raw("B"), Span::raw("C")]
);
}

mod widget {
use super::*;
use crate::assert_buffer_eq;
Expand Down Expand Up @@ -908,24 +955,6 @@ mod tests {
}
}

#[test]
fn left_aligned() {
let line = Line::from("Hello, world!").left_aligned();
assert_eq!(line.alignment, Some(Alignment::Left));
}

#[test]
fn centered() {
let line = Line::from("Hello, world!").centered();
assert_eq!(line.alignment, Some(Alignment::Center));
}

#[test]
fn right_aligned() {
let line = Line::from("Hello, world!").right_aligned();
assert_eq!(line.alignment, Some(Alignment::Right));
}

mod iterators {
use super::*;

Expand Down
42 changes: 21 additions & 21 deletions src/text/span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,27 @@ mod tests {
assert_eq!(format!("{stylized_span}"), "stylized test content");
}

#[test]
fn left_aligned() {
let span = Span::styled("Test Content", Style::new().green().italic());
let line = span.into_left_aligned_line();
assert_eq!(line.alignment, Some(Alignment::Left));
}

#[test]
fn centered() {
let span = Span::styled("Test Content", Style::new().green().italic());
let line = span.into_centered_line();
assert_eq!(line.alignment, Some(Alignment::Center));
}

#[test]
fn right_aligned() {
let span = Span::styled("Test Content", Style::new().green().italic());
let line = span.into_right_aligned_line();
assert_eq!(line.alignment, Some(Alignment::Right));
}

mod widget {
use rstest::rstest;

Expand Down Expand Up @@ -649,25 +670,4 @@ mod tests {
assert_buffer_eq!(buf, expected);
}
}

#[test]
fn left_aligned() {
let span = Span::styled("Test Content", Style::new().green().italic());
let line = span.into_left_aligned_line();
assert_eq!(line.alignment, Some(Alignment::Left));
}

#[test]
fn centered() {
let span = Span::styled("Test Content", Style::new().green().italic());
let line = span.into_centered_line();
assert_eq!(line.alignment, Some(Alignment::Center));
}

#[test]
fn right_aligned() {
let span = Span::styled("Test Content", Style::new().green().italic());
let line = span.into_right_aligned_line();
assert_eq!(line.alignment, Some(Alignment::Right));
}
}
124 changes: 106 additions & 18 deletions src/text/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ use crate::prelude::*;
/// - [`Text::height`] returns the height.
/// - [`Text::patch_style`] patches the style of this `Text`, adding modifiers from the given style.
/// - [`Text::reset_style`] resets the style of the `Text`.
/// - [`Text::push_line`] adds a line to the text.
/// - [`Text::push_span`] adds a span to the last line of the text.
///
/// # Examples
///
Expand Down Expand Up @@ -441,6 +443,46 @@ impl<'a> Text<'a> {
pub fn iter_mut(&mut self) -> std::slice::IterMut<Line<'a>> {
self.lines.iter_mut()
}

/// Adds a line to the text.
///
/// `line` can be any type that can be converted into a `Line`. For example, you can pass a
/// `&str`, a `String`, a `Span`, or a `Line`.
///
/// # Examples
///
/// ```rust
/// # use ratatui::prelude::*;
/// let mut text = Text::from("Hello, world!");
/// text.push_line(Line::from("How are you?"));
/// text.push_line(Span::from("How are you?"));
/// text.push_line("How are you?");
/// ```
pub fn push_line<T: Into<Line<'a>>>(&mut self, line: T) {
self.lines.push(line.into());
}

/// Adds a span to the last line of the text.
///
/// `span` can be any type that is convertible into a `Span`. For example, you can pass a
/// `&str`, a `String`, or a `Span`.
///
/// # Examples
///
/// ```rust
/// # use ratatui::prelude::*;
/// let mut text = Text::from("Hello, world!");
/// text.push_span(Span::from("How are you?"));
/// text.push_span("How are you?");
/// ```
pub fn push_span<T: Into<Span<'a>>>(&mut self, span: T) {
let span = span.into();
if let Some(last) = self.lines.last_mut() {
last.push_span(span);
} else {
self.lines.push(Line::from(span));
}
}
}

impl<'a> IntoIterator for Text<'a> {
Expand Down Expand Up @@ -854,6 +896,70 @@ mod tests {
assert_eq!(Text::default().italic().style, Modifier::ITALIC.into());
}

#[test]
fn left_aligned() {
let text = Text::from("Hello, world!").left_aligned();
assert_eq!(text.alignment, Some(Alignment::Left));
}

#[test]
fn centered() {
let text = Text::from("Hello, world!").centered();
assert_eq!(text.alignment, Some(Alignment::Center));
}

#[test]
fn right_aligned() {
let text = Text::from("Hello, world!").right_aligned();
assert_eq!(text.alignment, Some(Alignment::Right));
}

#[test]
fn push_line() {
let mut text = Text::from("A");
text.push_line(Line::from("B"));
text.push_line(Span::from("C"));
text.push_line("D");
assert_eq!(
text.lines,
vec![
Line::raw("A"),
Line::raw("B"),
Line::raw("C"),
Line::raw("D")
]
);
}

#[test]
fn push_line_empty() {
let mut text = Text::default();
text.push_line(Line::from("Hello, world!"));
assert_eq!(text.lines, vec![Line::from("Hello, world!")]);
}

#[test]
fn push_span() {
let mut text = Text::from("A");
text.push_span(Span::raw("B"));
text.push_span("C");
assert_eq!(
text.lines,
vec![Line::from(vec![
Span::raw("A"),
Span::raw("B"),
Span::raw("C")
])],
);
}

#[test]
fn push_span_empty() {
let mut text = Text::default();
text.push_span(Span::raw("Hello, world!"));
assert_eq!(text.lines, vec![Line::from(Span::raw("Hello, world!"))],);
}

mod widget {
use super::*;
use crate::assert_buffer_eq;
Expand Down Expand Up @@ -958,24 +1064,6 @@ mod tests {
}
}

#[test]
fn left_aligned() {
let text = Text::from("Hello, world!").left_aligned();
assert_eq!(text.alignment, Some(Alignment::Left));
}

#[test]
fn centered() {
let text = Text::from("Hello, world!").centered();
assert_eq!(text.alignment, Some(Alignment::Center));
}

#[test]
fn right_aligned() {
let text = Text::from("Hello, world!").right_aligned();
assert_eq!(text.alignment, Some(Alignment::Right));
}

mod iterators {
use super::*;

Expand Down

0 comments on commit 26af650

Please sign in to comment.