stylish_core/
string.rs

1use crate::{Display, Formatter, Result, Style, Write};
2
3/// An attributed version of [`alloc::string::String`] which has a specific
4/// [`Style`] associated with each character.
5///
6/// The main interfaces to create an instance of this are [`stylish::format!`]
7/// and [`impl Write for String`](#impl-Write), and to inspect the content
8/// [`impl Display for String`](#impl-Display).
9///
10/// You can create an instance via [`stylish::format!`]:
11///
12/// ```rust
13/// let _: stylish::String = stylish::format!("Hello {:(fg=green)}!", "World");
14/// ```
15///
16/// You can append extra data via [`stylish::write!`]:
17///
18/// ```rust
19/// use stylish::Write;
20///
21/// let mut s = stylish::String::new();
22/// stylish::write!(s, "{:(fg=magenta)}", "fuchsia")?;
23/// # Ok::<(), std::fmt::Error>(())
24/// ```
25///
26/// To use the attributed data you must then write this string to a sink using
27/// the `{:s}` trait-selector.
28///
29/// ```rust
30/// use stylish::Write;
31///
32/// let mut s = stylish::format!("Hello {:(fg=green)}!", "World");
33/// stylish::write!(s, " Is it {:(fg=magenta)} or?", "fuchsia")?;
34///
35/// assert_eq!(
36///     stylish::html::format!("{:s}", s),
37///     "Hello <span style=color:green>World</span>! \
38///     Is it <span style=color:magenta>fuchsia</span> or?",
39/// );
40/// # Ok::<(), std::fmt::Error>(())
41/// ```
42#[derive(Default, Debug, Clone)]
43pub struct String {
44    string: alloc::string::String,
45    styles: alloc::vec::Vec<(usize, Style)>,
46}
47
48impl String {
49    /// Create an empty [`String`].
50    ///
51    /// ```rust
52    /// assert_eq!(stylish::html::format!("{:s}", stylish::String::new()), "");
53    /// ```
54    #[inline]
55    pub fn new() -> Self {
56        Self::default()
57    }
58}
59
60impl Write for String {
61    #[inline]
62    fn write_str(&mut self, s: &str, style: Style) -> Result {
63        if Some(style) != self.styles.last().map(|&(_, style)| style) {
64            self.styles.push((self.string.len(), style));
65        }
66        self.string.push_str(s);
67        Ok(())
68    }
69}
70
71impl Display for String {
72    #[inline]
73    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
74        let mut styles = self.styles.iter().peekable();
75        while let Some(&(start, style)) = styles.next() {
76            let end = styles
77                .peek()
78                .map(|&&(end, _)| end)
79                .unwrap_or_else(|| self.string.len());
80            f.with(style).write_str(&self.string[start..end])?;
81        }
82        Ok(())
83    }
84}