Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-tui/src/text.rs')
| -rw-r--r-- | helix-tui/src/text.rs | 121 |
1 files changed, 26 insertions, 95 deletions
diff --git a/helix-tui/src/text.rs b/helix-tui/src/text.rs index a9c36503..b8e52479 100644 --- a/helix-tui/src/text.rs +++ b/helix-tui/src/text.rs @@ -5,12 +5,12 @@ //! - A single line string where all graphemes have the same style is represented by a [`Span`]. //! - A single line string where each grapheme may have its own style is represented by [`Spans`]. //! - A multiple line string where each grapheme may have its own style is represented by a -//! [`Text`]. +//! [`Text`]. //! //! These types form a hierarchy: [`Spans`] is a collection of [`Span`] and each line of [`Text`] //! is a [`Spans`]. //! -//! Keep in mind that a lot of widgets will use those types to advertise what kind of string is +//! Keep it mind that a lot of widgets will use those types to advertise what kind of string is //! supported for their properties. Moreover, `tui` provides convenient `From` implementations so //! that you can start by using simple `String` or `&str` and then promote them to the previous //! primitives when you need additional styling capabilities. @@ -53,14 +53,14 @@ use std::borrow::Cow; use unicode_segmentation::UnicodeSegmentation; /// A grapheme associated to a style. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] pub struct StyledGrapheme<'a> { pub symbol: &'a str, pub style: Style, } /// A string where all graphemes have the same style. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] pub struct Span<'a> { pub content: Cow<'a, str>, pub style: Style, @@ -134,8 +134,6 @@ impl<'a> Span<'a> { /// style: Style { /// fg: Some(Color::Yellow), /// bg: Some(Color::Black), - /// underline_color: None, - /// underline_style: None, /// add_modifier: Modifier::empty(), /// sub_modifier: Modifier::empty(), /// }, @@ -145,8 +143,6 @@ impl<'a> Span<'a> { /// style: Style { /// fg: Some(Color::Yellow), /// bg: Some(Color::Black), - /// underline_color: None, - /// underline_style: None, /// add_modifier: Modifier::empty(), /// sub_modifier: Modifier::empty(), /// }, @@ -156,8 +152,6 @@ impl<'a> Span<'a> { /// style: Style { /// fg: Some(Color::Yellow), /// bg: Some(Color::Black), - /// underline_color: None, - /// underline_style: None, /// add_modifier: Modifier::empty(), /// sub_modifier: Modifier::empty(), /// }, @@ -167,8 +161,6 @@ impl<'a> Span<'a> { /// style: Style { /// fg: Some(Color::Yellow), /// bg: Some(Color::Black), - /// underline_color: None, - /// underline_style: None, /// add_modifier: Modifier::empty(), /// sub_modifier: Modifier::empty(), /// }, @@ -202,17 +194,17 @@ impl<'a> From<&'a str> for Span<'a> { } } -impl<'a> From<Cow<'a, str>> for Span<'a> { - fn from(s: Cow<'a, str>) -> Span<'a> { - Span::raw(s) - } -} - /// A string composed of clusters of graphemes, each with their own style. -#[derive(Debug, Default, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] pub struct Spans<'a>(pub Vec<Span<'a>>); -impl Spans<'_> { +impl<'a> Default for Spans<'a> { + fn default() -> Spans<'a> { + Spans(Vec::new()) + } +} + +impl<'a> Spans<'a> { /// Returns the width of the underlying string. /// /// ## Examples @@ -243,12 +235,6 @@ impl<'a> From<&'a str> for Spans<'a> { } } -impl<'a> From<Cow<'a, str>> for Spans<'a> { - fn from(s: Cow<'a, str>) -> Spans<'a> { - Spans(vec![Span::raw(s)]) - } -} - impl<'a> From<Vec<Span<'a>>> for Spans<'a> { fn from(spans: Vec<Span<'a>>) -> Spans<'a> { Spans(spans) @@ -263,13 +249,10 @@ impl<'a> From<Span<'a>> for Spans<'a> { impl<'a> From<Spans<'a>> for String { fn from(line: Spans<'a>) -> String { - line.0.iter().map(|s| &*s.content).collect() - } -} - -impl<'a> From<&Spans<'a>> for String { - fn from(line: &Spans<'a>) -> String { - line.0.iter().map(|s| &*s.content).collect() + line.0.iter().fold(String::new(), |mut acc, s| { + acc.push_str(s.content.as_ref()); + acc + }) } } @@ -297,11 +280,17 @@ impl<'a> From<&Spans<'a>> for String { /// text.extend(Text::styled("Some more lines\nnow with more style!", style)); /// assert_eq!(6, text.height()); /// ``` -#[derive(Debug, Default, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] pub struct Text<'a> { pub lines: Vec<Spans<'a>>, } +impl<'a> Default for Text<'a> { + fn default() -> Text<'a> { + Text { lines: Vec::new() } + } +} + impl<'a> Text<'a> { /// Create some text (potentially multiple lines) with no style. /// @@ -374,30 +363,6 @@ impl<'a> Text<'a> { self.lines.len() } - /// Patch text with a new style. Only updates fields that are in the new style. - /// - /// # Examples - /// - /// ```rust - /// # use helix_tui::text::Text; - /// # use helix_view::graphics::{Color, Style}; - /// let style1 = Style::default().fg(Color::Yellow); - /// let style2 = Style::default().fg(Color::Yellow).bg(Color::Black); - /// let mut half_styled_text = Text::styled(String::from("The first line\nThe second line"), style1); - /// let full_styled_text = Text::styled(String::from("The first line\nThe second line"), style2); - /// assert_ne!(half_styled_text, full_styled_text); - /// - /// half_styled_text.patch_style(Style::default().bg(Color::Black)); - /// assert_eq!(half_styled_text, full_styled_text); - /// ``` - pub fn patch_style(&mut self, style: Style) { - for line in &mut self.lines { - for span in &mut line.0 { - span.style = span.style.patch(style); - } - } - } - /// Apply a new style to existing text. /// /// # Examples @@ -410,13 +375,13 @@ impl<'a> Text<'a> { /// let styled_text = Text::styled(String::from("The first line\nThe second line"), style); /// assert_ne!(raw_text, styled_text); /// - /// raw_text.set_style(style); + /// raw_text.patch_style(style); /// assert_eq!(raw_text, styled_text); /// ``` - pub fn set_style(&mut self, style: Style) { + pub fn patch_style(&mut self, style: Style) { for line in &mut self.lines { for span in &mut line.0 { - span.style = style; + span.style = span.style.patch(style); } } } @@ -434,12 +399,6 @@ impl<'a> From<&'a str> for Text<'a> { } } -impl<'a> From<Cow<'a, str>> for Text<'a> { - fn from(s: Cow<'a, str>) -> Text<'a> { - Text::raw(s) - } -} - impl<'a> From<Span<'a>> for Text<'a> { fn from(span: Span<'a>) -> Text<'a> { Text { @@ -460,34 +419,6 @@ impl<'a> From<Vec<Spans<'a>>> for Text<'a> { } } -impl<'a> From<Text<'a>> for String { - fn from(text: Text<'a>) -> String { - String::from(&text) - } -} - -impl<'a> From<&Text<'a>> for String { - fn from(text: &Text<'a>) -> String { - let size = text - .lines - .iter() - .flat_map(|spans| spans.0.iter().map(|span| span.content.len())) - .sum::<usize>() - + text.lines.len().saturating_sub(1); // for newline after each line - let mut output = String::with_capacity(size); - - for spans in &text.lines { - if !output.is_empty() { - output.push('\n'); - } - for span in &spans.0 { - output.push_str(&span.content); - } - } - output - } -} - impl<'a> IntoIterator for Text<'a> { type Item = Spans<'a>; type IntoIter = std::vec::IntoIter<Self::Item>; |