Skip to content

Commit 7ef2dae

Browse files
authored
feat(text): support constructing Line and Text from usize (#1167)
Now you can create `Line` and `Text` from numbers like so: ```rust let line = Line::from(42); let text = Text::from(666); ``` (I was doing little testing for my TUI app and saw that this isn't supported - then I was like WHA and decided to make it happen ™️)
1 parent 46977d8 commit 7ef2dae

File tree

4 files changed

+102
-3
lines changed

4 files changed

+102
-3
lines changed

src/text.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ mod grapheme;
4848
pub use grapheme::StyledGrapheme;
4949

5050
mod line;
51-
pub use line::Line;
51+
pub use line::{Line, ToLine};
5252

5353
mod masked;
5454
pub use masked::Masked;
5555

5656
mod span;
57-
pub use span::Span;
57+
pub use span::{Span, ToSpan};
5858

5959
#[allow(clippy::module_inception)]
6060
mod text;
61-
pub use text::Text;
61+
pub use text::{Text, ToText};

src/text/line.rs

+29
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,29 @@ fn spans_after_width<'a>(
649649
})
650650
}
651651

652+
/// A trait for converting a value to a [`Line`].
653+
///
654+
/// This trait is automatically implemented for any type that implements the [`Display`] trait. As
655+
/// such, `ToLine` shouln't be implemented directly: [`Display`] should be implemented instead, and
656+
/// you get the `ToLine` implementation for free.
657+
///
658+
/// [`Display`]: std::fmt::Display
659+
pub trait ToLine {
660+
/// Converts the value to a [`Line`].
661+
fn to_line(&self) -> Line<'_>;
662+
}
663+
664+
/// # Panics
665+
///
666+
/// In this implementation, the `to_line` method panics if the `Display` implementation returns an
667+
/// error. This indicates an incorrect `Display` implementation since `fmt::Write for String` never
668+
/// returns an error itself.
669+
impl<T: fmt::Display> ToLine for T {
670+
fn to_line(&self) -> Line<'_> {
671+
Line::from(self.to_string())
672+
}
673+
}
674+
652675
impl fmt::Display for Line<'_> {
653676
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
654677
for span in &self.spans {
@@ -824,6 +847,12 @@ mod tests {
824847
assert_eq!(line.spans, vec![Span::from("Hello"), Span::from("world!")]);
825848
}
826849

850+
#[test]
851+
fn to_line() {
852+
let line = 42.to_line();
853+
assert_eq!(vec![Span::from("42")], line.spans);
854+
}
855+
827856
#[test]
828857
fn from_vec() {
829858
let spans = vec![

src/text/span.rs

+29
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,29 @@ impl WidgetRef for Span<'_> {
406406
}
407407
}
408408

409+
/// A trait for converting a value to a [`Span`].
410+
///
411+
/// This trait is automatically implemented for any type that implements the [`Display`] trait. As
412+
/// such, `ToSpan` shouln't be implemented directly: [`Display`] should be implemented instead, and
413+
/// you get the `ToSpan` implementation for free.
414+
///
415+
/// [`Display`]: std::fmt::Display
416+
pub trait ToSpan {
417+
/// Converts the value to a [`Span`].
418+
fn to_span(&self) -> Span<'_>;
419+
}
420+
421+
/// # Panics
422+
///
423+
/// In this implementation, the `to_span` method panics if the `Display` implementation returns an
424+
/// error. This indicates an incorrect `Display` implementation since `fmt::Write for String` never
425+
/// returns an error itself.
426+
impl<T: fmt::Display> ToSpan for T {
427+
fn to_span(&self) -> Span<'_> {
428+
Span::raw(self.to_string())
429+
}
430+
}
431+
409432
impl fmt::Display for Span<'_> {
410433
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411434
fmt::Display::fmt(&self.content, f)
@@ -507,6 +530,12 @@ mod tests {
507530
assert_eq!(span.style, Style::default());
508531
}
509532

533+
#[test]
534+
fn to_span() {
535+
assert_eq!(42.to_span(), Span::raw("42"));
536+
assert_eq!("test".to_span(), Span::raw("test"));
537+
}
538+
510539
#[test]
511540
fn reset_style() {
512541
let span = Span::styled("test content", Style::new().green()).reset_style();

src/text/text.rs

+41
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,29 @@ where
580580
}
581581
}
582582

583+
/// A trait for converting a value to a [`Text`].
584+
///
585+
/// This trait is automatically implemented for any type that implements the [`Display`] trait. As
586+
/// such, `ToText` shouldn't be implemented directly: [`Display`] should be implemented instead, and
587+
/// you get the `ToText` implementation for free.
588+
///
589+
/// [`Display`]: std::fmt::Display
590+
pub trait ToText<'a> {
591+
/// Converts the value to a [`Text`].
592+
fn to_text(&self) -> Text<'a>;
593+
}
594+
595+
/// # Panics
596+
///
597+
/// In this implementation, the `to_text` method panics if the `Display` implementation returns an
598+
/// error. This indicates an incorrect `Display` implementation since `fmt::Write for String` never
599+
/// returns an error itself.
600+
impl<'a, T: fmt::Display> ToText<'a> for T {
601+
fn to_text(&self) -> Text<'a> {
602+
Text::raw(self.to_string())
603+
}
604+
}
605+
583606
impl fmt::Display for Text<'_> {
584607
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
585608
for (position, line) in self.iter().with_position() {
@@ -747,6 +770,24 @@ mod tests {
747770
assert_eq!(text.lines, vec![Line::from("The first line")]);
748771
}
749772

773+
#[rstest]
774+
#[case(42, Text::from("42"))]
775+
#[case("just\ntesting", Text::from("just\ntesting"))]
776+
#[case(true, Text::from("true"))]
777+
#[case(6.66, Text::from("6.66"))]
778+
#[case('a', Text::from("a"))]
779+
#[case(String::from("hello"), Text::from("hello"))]
780+
#[case(-1, Text::from("-1"))]
781+
#[case("line1\nline2", Text::from("line1\nline2"))]
782+
#[case(
783+
"first line\nsecond line\nthird line",
784+
Text::from("first line\nsecond line\nthird line")
785+
)]
786+
#[case("trailing newline\n", Text::from("trailing newline\n"))]
787+
fn to_text(#[case] value: impl fmt::Display, #[case] expected: Text) {
788+
assert_eq!(value.to_text(), expected);
789+
}
790+
750791
#[test]
751792
fn from_vec_line() {
752793
let text = Text::from(vec![

0 commit comments

Comments
 (0)