use std::{
borrow::Cow,
convert::TryFrom,
mem,
ops::{
Deref,
DerefMut,
},
};
use thiserror::Error;
use tui::{
style::Style,
text::{
Span,
Spans,
},
};
#[derive(Clone, Debug, Default)]
pub struct Text(Spans<'static>);
#[derive(Clone, Debug)]
pub struct Line(Text);
#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
#[error("string contains a newline")]
pub struct NewlineError;
impl Text {
pub fn with_style(style: Style) -> Text {
let mut text = Text::new();
text.new_span(style);
text
}
pub fn new() -> Text {
Text::default()
}
pub fn push_str(&mut self, s: impl AsRef<str>) -> Result<(), NewlineError> {
no_newlines(&s)?;
self.current_span_mut()
.content
.to_mut()
.push_str(s.as_ref());
Ok(())
}
pub fn push_string(&mut self, s: String) -> Result<(), NewlineError> {
let current = self.current_span_mut();
if current.content.len() == 0 {
no_newlines(&s)?;
current.content = Cow::Owned(s);
return Ok(());
}
self.push_str(s)
}
pub fn current_span_mut(&mut self) -> &mut Span<'static> {
if self.spans().len() == 0 {
self.new_span(Default::default());
}
self.spans_mut().last_mut().unwrap()
}
pub fn set_style(&mut self, style: Style) {
let current = self.current_span_mut();
if current.content.is_empty() {
current.style = style;
} else {
self.new_span(style);
}
}
fn spans_mut(&mut self) -> &mut Vec<Span<'static>> {
&mut self.0 .0
}
pub fn new_span(&mut self, style: Style) {
self.spans_mut().push(Span {
content: Cow::Owned(String::new()),
style,
})
}
pub fn extend(&mut self, other: &mut Text) {
let mut style = self.style();
self.spans_mut()
.extend(other.spans_mut().drain(..).map(|mut span| {
span.style = style.patch(span.style);
style = span.style;
span
}));
}
pub fn spans(&self) -> &Vec<Span<'static>> {
&self.0 .0
}
pub fn complete(mut self, mut line: Line) -> Line {
self.extend(&mut *line);
self.into()
}
pub fn swap_complete(&mut self, line: Line) -> Line {
let text = mem::replace(self, Text::new());
let line = text.complete(line);
self.set_style(line.style());
line
}
pub fn empty(&self) -> bool {
self.spans().len() == 0
}
pub fn style(&self) -> Style {
let spans = self.spans();
if spans.len() == 0 {
Style::default()
} else {
spans.last().unwrap().style
}
}
}
fn no_newlines(s: impl AsRef<str>) -> Result<(), NewlineError> {
if s.as_ref()
.as_bytes()
.iter()
.any(|c| matches!(c, b'\r' | b'\n'))
{
return Err(NewlineError);
}
Ok(())
}
impl<'a> TryFrom<&'a str> for Text {
type Error = NewlineError;
fn try_from(other: &'a str) -> Result<Self, Self::Error> {
let mut text = Text::new();
text.push_str(other)?;
Ok(text)
}
}
impl TryFrom<String> for Text {
type Error = NewlineError;
fn try_from(other: String) -> Result<Self, Self::Error> {
let mut text = Text::new();
text.push_string(other)?;
Ok(text)
}
}
impl From<Text> for Line {
fn from(other: Text) -> Self {
Line(other)
}
}
impl Deref for Line {
type Target = Text;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Line {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Line {
pub fn new() -> Self {
Line(Text::new())
}
}