mudrs_milk/
text.rs

1use std::{
2    borrow::Cow,
3    convert::TryFrom,
4    mem,
5    ops::{
6        Deref,
7        DerefMut,
8    },
9};
10
11use thiserror::Error;
12use tui::{
13    style::Style,
14    text::{
15        Span,
16        Spans,
17    },
18};
19
20#[derive(Clone, Debug, Default)]
21pub struct Text(Spans<'static>);
22
23#[derive(Clone, Debug)]
24pub struct Line(Text);
25
26#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
27#[error("string contains a newline")]
28pub struct NewlineError;
29
30impl Text {
31    pub fn with_style(style: Style) -> Text {
32        let mut text = Text::new();
33        text.new_span(style);
34        text
35    }
36
37    pub fn new() -> Text {
38        Text::default()
39    }
40
41    pub fn push_str(&mut self, s: impl AsRef<str>) -> Result<(), NewlineError> {
42        no_newlines(&s)?;
43        self.current_span_mut()
44            .content
45            .to_mut()
46            .push_str(s.as_ref());
47        Ok(())
48    }
49
50    pub fn push_string(&mut self, s: String) -> Result<(), NewlineError> {
51        let current = self.current_span_mut();
52        if current.content.len() == 0 {
53            no_newlines(&s)?;
54            current.content = Cow::Owned(s);
55            return Ok(());
56        }
57        self.push_str(s)
58    }
59
60    pub fn current_span_mut(&mut self) -> &mut Span<'static> {
61        if self.spans().len() == 0 {
62            self.new_span(Default::default());
63        }
64        self.spans_mut().last_mut().unwrap()
65    }
66
67    pub fn set_style(&mut self, style: Style) {
68        let current = self.current_span_mut();
69        if current.content.is_empty() {
70            current.style = style;
71        } else {
72            self.new_span(style);
73        }
74    }
75
76    fn spans_mut(&mut self) -> &mut Vec<Span<'static>> {
77        &mut self.0 .0
78    }
79
80    pub fn new_span(&mut self, style: Style) {
81        self.spans_mut().push(Span {
82            content: Cow::Owned(String::new()),
83            style,
84        })
85    }
86
87    /// Extend self with more text.
88    /// Styles are patched along the way.
89    pub fn extend(&mut self, other: &mut Text) {
90        let mut style = self.style();
91        self.spans_mut()
92            .extend(other.spans_mut().drain(..).map(|mut span| {
93                span.style = style.patch(span.style);
94                style = span.style;
95                span
96            }));
97    }
98
99    pub fn spans(&self) -> &Vec<Span<'static>> {
100        &self.0 .0
101    }
102
103    pub fn complete(mut self, mut line: Line) -> Line {
104        self.extend(&mut *line);
105        self.into()
106    }
107
108    /// Replace `self` with a new `Text` which picks up where the provided line
109    /// appended to the current text leaves off stylistically.
110    pub fn swap_complete(&mut self, line: Line) -> Line {
111        let text = mem::replace(self, Text::new());
112        let line = text.complete(line);
113        self.set_style(line.style());
114        line
115    }
116
117    pub fn empty(&self) -> bool {
118        self.spans().len() == 0
119    }
120
121    pub fn style(&self) -> Style {
122        let spans = self.spans();
123        if spans.len() == 0 {
124            Style::default()
125        } else {
126            spans.last().unwrap().style
127        }
128    }
129}
130
131fn no_newlines(s: impl AsRef<str>) -> Result<(), NewlineError> {
132    if s.as_ref()
133        .as_bytes()
134        .iter()
135        .any(|c| matches!(c, b'\r' | b'\n'))
136    {
137        return Err(NewlineError);
138    }
139    Ok(())
140}
141
142impl<'a> TryFrom<&'a str> for Text {
143    type Error = NewlineError;
144
145    fn try_from(other: &'a str) -> Result<Self, Self::Error> {
146        let mut text = Text::new();
147        text.push_str(other)?;
148        Ok(text)
149    }
150}
151impl TryFrom<String> for Text {
152    type Error = NewlineError;
153    fn try_from(other: String) -> Result<Self, Self::Error> {
154        let mut text = Text::new();
155        text.push_string(other)?;
156        Ok(text)
157    }
158}
159
160impl From<Text> for Line {
161    fn from(other: Text) -> Self {
162        Line(other)
163    }
164}
165
166impl Deref for Line {
167    type Target = Text;
168    fn deref(&self) -> &Self::Target {
169        &self.0
170    }
171}
172
173impl DerefMut for Line {
174    fn deref_mut(&mut self) -> &mut Self::Target {
175        &mut self.0
176    }
177}
178
179impl Line {
180    pub fn new() -> Self {
181        Line(Text::new())
182    }
183}