use crate::Style;
#[derive(Debug, PartialEq, Eq)]
pub struct StyledBuffer<T>
where
T: Clone + PartialEq + Eq + Style,
{
lines: Vec<Vec<StyledChar<T>>>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct StyledChar<T>
where
T: Clone + PartialEq + Eq + Style,
{
chr: char,
style: Option<T>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StyledString<T>
where
T: Clone + PartialEq + Eq + Style,
{
pub text: String,
pub style: Option<T>,
}
impl<T> StyledString<T>
where
T: Clone + PartialEq + Eq + Style,
{
#[inline]
pub fn new(text: String, style: Option<T>) -> Self {
StyledString { text, style }
}
}
impl<T> StyledChar<T>
where
T: Clone + PartialEq + Eq + Style,
{
const SPACE: StyledChar<T> = StyledChar::new(' ', None);
const fn new(chr: char, style: Option<T>) -> Self {
StyledChar { chr, style }
}
}
impl<T> StyledBuffer<T>
where
T: Clone + PartialEq + Eq + Style,
{
pub fn new() -> StyledBuffer<T> {
StyledBuffer { lines: vec![] }
}
pub fn render(&self) -> Vec<Vec<StyledString<T>>> {
let mut output: Vec<Vec<StyledString<T>>> = vec![];
let mut styled_vec: Vec<StyledString<T>> = vec![];
for styled_line in &self.lines {
let mut current_style = None;
let mut current_text = String::new();
for sc in styled_line {
if sc.style != current_style {
if !current_text.is_empty() {
styled_vec.push(StyledString {
text: current_text,
style: current_style,
});
}
current_style = sc.style.clone();
current_text = String::new();
}
current_text.push(sc.chr);
}
if !current_text.is_empty() {
styled_vec.push(StyledString {
text: current_text,
style: current_style,
});
}
output.push(styled_vec);
styled_vec = vec![];
}
output
}
fn ensure_lines(&mut self, line: usize) {
if line >= self.lines.len() {
self.lines.resize(line + 1, Vec::new());
}
}
pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Option<T>) {
self.ensure_lines(line);
if col >= self.lines[line].len() {
self.lines[line].resize(col + 1, StyledChar::SPACE);
}
self.lines[line][col] = StyledChar::new(chr, style);
}
pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Option<T>) {
let mut n = col;
for c in string.chars() {
self.putc(line, n, c, style.clone());
n += 1;
}
}
pub fn pushs(&mut self, string: &str, style: Option<T>) {
let line = self.num_lines();
let mut col = 0;
for c in string.chars() {
self.putc(line, col, c, style.clone());
col += 1;
}
}
pub fn appendl(&mut self, string: &str, style: Option<T>) {
let line = if self.num_lines() > 0 {
self.num_lines() - 1
} else {
self.num_lines()
};
self.append(line, string, style);
}
pub fn prepend(&mut self, line: usize, string: &str, style: Option<T>) {
self.ensure_lines(line);
let string_len = string.chars().count();
if !self.lines[line].is_empty() {
for _ in 0..string_len {
self.lines[line].insert(0, StyledChar::SPACE);
}
}
self.puts(line, 0, string, style);
}
pub fn append(&mut self, line: usize, string: &str, style: Option<T>) {
if line >= self.lines.len() {
self.puts(line, 0, string, style);
} else {
let col = self.lines[line].len();
self.puts(line, col, string, style);
}
}
pub fn num_lines(&self) -> usize {
self.lines.len()
}
}