Skip to content

Commit

Permalink
feat(text): Add Add and AddAssign implementations for Line, `Sp…
Browse files Browse the repository at this point in the history
…an`, and `Text` (#1236)

This enables:

```rust
let line = Span::raw("Red").red() + Span::raw("blue").blue();
let line = Line::raw("Red").red() + Span::raw("blue").blue();
let line = Line::raw("Red").red() + Line::raw("Blue").blue();
let text = Line::raw("Red").red() + Line::raw("Blue").blue();
let text = Text::raw("Red").red() + Line::raw("Blue").blue();

let mut line = Line::raw("Red").red();
line += Span::raw("Blue").blue();

let mut text = Text::raw("Red").red();
text += Line::raw("Blue").blue();

line.extend(vec![Span::raw("1"), Span::raw("2"), Span::raw("3")]);
```
  • Loading branch information
joshka authored Jul 26, 2024
1 parent 84f3341 commit 3725262
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 0 deletions.
87 changes: 87 additions & 0 deletions src/text/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,37 @@ where
}
}

/// Adds a `Span` to a `Line`, returning a new `Line` with the `Span` added.
impl<'a> std::ops::Add<Span<'a>> for Line<'a> {
type Output = Self;

fn add(mut self, rhs: Span<'a>) -> Self::Output {
self.spans.push(rhs);
self
}
}

/// Adds two `Line`s together, returning a new `Text` with the contents of the two `Line`s.
impl<'a> std::ops::Add<Self> for Line<'a> {
type Output = Text<'a>;

fn add(self, rhs: Self) -> Self::Output {
Text::from(vec![self, rhs])
}
}

impl<'a> std::ops::AddAssign<Span<'a>> for Line<'a> {
fn add_assign(&mut self, rhs: Span<'a>) {
self.spans.push(rhs);
}
}

impl<'a> Extend<Span<'a>> for Line<'a> {
fn extend<T: IntoIterator<Item = Span<'a>>>(&mut self, iter: T) {
self.spans.extend(iter);
}
}

impl Widget for Line<'_> {
fn render(self, area: Rect, buf: &mut Buffer) {
self.render_ref(area, buf);
Expand Down Expand Up @@ -896,6 +927,62 @@ mod tests {
assert_eq!(line.spans, vec![span],);
}

#[test]
fn add_span() {
assert_eq!(
Line::raw("Red").red() + Span::raw("blue").blue(),
Line {
spans: vec![Span::raw("Red"), Span::raw("blue").blue()],
style: Style::new().red(),
alignment: None,
},
);
}

#[test]
fn add_line() {
assert_eq!(
Line::raw("Red").red() + Line::raw("Blue").blue(),
Text {
lines: vec![Line::raw("Red").red(), Line::raw("Blue").blue()],
style: Style::default(),
alignment: None,
}
);
}

#[test]
fn add_assign_span() {
let mut line = Line::raw("Red").red();
line += Span::raw("Blue").blue();
assert_eq!(
line,
Line {
spans: vec![Span::raw("Red"), Span::raw("Blue").blue()],
style: Style::new().red(),
alignment: None,
},
);
}

#[test]
fn extend() {
let mut line = Line::from("Hello, ");
line.extend(vec![Span::raw("world!")]);
assert_eq!(line.spans, vec![Span::raw("Hello, "), Span::raw("world!")]);

let mut line = Line::from("Hello, ");
line.extend(vec![Span::raw("world! "), Span::raw("How are you?")]);
assert_eq!(
line.spans,
vec![
Span::raw("Hello, "),
Span::raw("world! "),
Span::raw("How are you?")
]
);
}

#[test]
fn into_string() {
let line = Line::from(vec![
Expand Down
31 changes: 31 additions & 0 deletions src/text/span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,14 @@ where
}
}

impl<'a> std::ops::Add<Self> for Span<'a> {
type Output = Line<'a>;

fn add(self, rhs: Self) -> Self::Output {
Line::from_iter([self, rhs])
}
}

impl<'a> Styled for Span<'a> {
type Item = Self;

Expand Down Expand Up @@ -773,4 +781,27 @@ mod tests {
]
);
}

#[test]
fn add() {
assert_eq!(
Span::default() + Span::default(),
Line::from(vec![Span::default(), Span::default()])
);

assert_eq!(
Span::default() + Span::raw("test"),
Line::from(vec![Span::default(), Span::raw("test")])
);

assert_eq!(
Span::raw("test") + Span::default(),
Line::from(vec![Span::raw("test"), Span::default()])
);

assert_eq!(
Span::raw("test") + Span::raw("content"),
Line::from(vec![Span::raw("test"), Span::raw("content")])
);
}
}
65 changes: 65 additions & 0 deletions src/text/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,33 @@ where
}
}

impl<'a> std::ops::Add<Line<'a>> for Text<'a> {
type Output = Self;

fn add(mut self, line: Line<'a>) -> Self::Output {
self.push_line(line);
self
}
}

/// Adds two `Text` together.
///
/// This ignores the style and alignment of the second `Text`.
impl<'a> std::ops::Add<Self> for Text<'a> {
type Output = Self;

fn add(mut self, text: Self) -> Self::Output {
self.lines.extend(text.lines);
self
}
}

impl<'a> std::ops::AddAssign<Line<'a>> for Text<'a> {
fn add_assign(&mut self, line: Line<'a>) {
self.push_line(line);
}
}

impl<'a, T> Extend<T> for Text<'a>
where
T: Into<Line<'a>>,
Expand Down Expand Up @@ -829,6 +856,44 @@ mod tests {
assert_eq!(iter.next(), None);
}

#[test]
fn add_line() {
assert_eq!(
Text::raw("Red").red() + Line::raw("Blue").blue(),
Text {
lines: vec![Line::raw("Red"), Line::raw("Blue").blue()],
style: Style::new().red(),
alignment: None,
}
);
}

#[test]
fn add_text() {
assert_eq!(
Text::raw("Red").red() + Text::raw("Blue").blue(),
Text {
lines: vec![Line::raw("Red"), Line::raw("Blue")],
style: Style::new().red(),
alignment: None,
}
);
}

#[test]
fn add_assign_line() {
let mut text = Text::raw("Red").red();
text += Line::raw("Blue").blue();
assert_eq!(
text,
Text {
lines: vec![Line::raw("Red"), Line::raw("Blue").blue()],
style: Style::new().red(),
alignment: None,
}
);
}

#[test]
fn extend() {
let mut text = Text::from("The first line\nThe second line");
Expand Down

0 comments on commit 3725262

Please sign in to comment.