fixes and testing for the instructions -> set of components converter

This commit is contained in:
emilis 2023-01-18 12:04:18 +00:00
parent 4a3c5ac492
commit ec6998ff30
2 changed files with 190 additions and 12 deletions

View File

@ -2,15 +2,39 @@ use crate::{
theme::{Color, ColorSet},
token::Token,
};
use std::iter::Extend;
#[derive(Eq, Debug, Clone)]
pub enum Component {
NextLine,
X(usize),
String(String),
Fg(Color),
Bg(Color),
}
impl Component {
fn make_for_line(
comp: Vec<Component>,
line: usize,
offset: usize,
) -> String {
comp.into_iter()
.map(|c| match c {
Component::X(x) => termion::cursor::Goto(
(x + offset) as u16,
line as u16,
)
.into(),
Component::String(s) => s,
Component::Fg(c) => c.fg(),
Component::Bg(c) => c.bg(),
Component::NextLine => "\r\n".into(),
})
.collect()
}
}
impl PartialEq for Component {
fn eq(&self, other: &Self) -> bool {
match self {
@ -30,6 +54,10 @@ impl PartialEq for Component {
Self::Bg(other_c) => c == other_c,
_ => false,
},
Self::NextLine => match other {
Self::NextLine => true,
_ => false,
},
}
}
}
@ -86,7 +114,7 @@ impl Widget {
}
fn get_line(&self, line: usize) -> Option<&Token> {
self.per_line.get(line - 1)
self.per_line.get(line)
}
}
@ -131,11 +159,62 @@ impl PartialEq for Instruction {
}
impl Instruction {
pub fn make(
pub fn into_components(
self,
(term_width, term_height): (u16, u16),
) -> String {
todo!()
line_width: usize,
height_left: usize,
) -> Vec<Component> {
if height_left == 0 {
return vec![];
}
match self {
Instruction::FixedHeight(next, lines, wdg) => (0..lines)
.map(|line| {
let mut offset = 0;
(&wdg)
.into_iter()
.map(|w| {
let (width, token) = (
w.want_width.abs_size(line_width),
w.get_line(line).map(|t| t.clone()),
);
let mut result = match token {
Some(tok) => tok
.with_width(width)
.into_iter()
.map(|comp| {
if let Component::X(x) = comp
{
Component::X(offset + x)
} else {
comp
}
})
.collect(),
None => Vec::new(),
};
offset += width;
if offset < line_width {
result.push(Component::X(offset));
}
result
})
.flatten()
.chain(vec![Component::NextLine])
.collect::<Vec<Component>>()
})
.flatten()
.chain(
next.into_components(
line_width,
height_left - lines,
),
)
.collect(),
Instruction::End => (0..height_left)
.map(|_| Component::NextLine)
.collect(),
}
}
pub fn start() -> Self {
@ -251,13 +330,11 @@ impl Plan {
mod tests {
use super::*;
#[test]
fn test_plan_to_instructions() {
const HEIGHT: usize = 40;
let (widget_1, widget_2, widget_3) = (
fn test_widgets() -> (Widget, Widget, Widget) {
(
Widget::new(
SectionWidth::Third,
vec![Token::text("hello")],
vec![Token::text("hello").centered()],
),
Widget::new(
SectionWidth::Third,
@ -269,7 +346,108 @@ mod tests {
SectionWidth::Third,
vec![Token::text("hello").limited(16).padded(20)],
),
)
}
#[test]
fn test_instructions_to_components() {
const WIDTH: usize = 120;
const HEIGHT: usize = 40;
let (w1, w2, w3) = test_widgets();
vec![
(
"all the widgets, 30 lines",
Instruction::start().fixed(
30,
vec![w1.clone(), w2.clone(), w3.clone()],
),
w1.clone()
.get_line(0)
.unwrap()
.clone()
.with_width(WIDTH / 3)
.into_iter()
.chain(vec![Component::X(WIDTH / 3)])
.chain(
w2.clone()
.get_line(0)
.unwrap()
.clone()
.with_width(WIDTH / 3),
)
.chain(vec![Component::X((WIDTH / 3) * 2)])
.chain(
w3.clone()
.get_line(0)
.unwrap()
.clone()
.with_width(WIDTH / 3),
)
.chain(vec![Component::NextLine])
.chain(
(1..30)
.map(|_| {
vec![
Component::X(WIDTH / 3),
Component::X((WIDTH / 3) * 2),
Component::NextLine,
]
})
.flatten(),
)
.chain(
(0..(HEIGHT - 30))
.map(|_| Component::NextLine),
)
.collect::<Vec<Component>>(),
),
(
"Single widget, single 10 lines section",
Instruction::start().fixed(10, vec![w1.clone()]),
w1.clone()
.get_line(0)
.unwrap()
.clone()
.with_width(WIDTH / 3)
.into_iter()
.chain(
(0..10)
.map(|_| {
vec![
Component::X(WIDTH / 3),
Component::NextLine,
]
})
.flatten(),
)
.chain(
(0..(HEIGHT - 10))
.map(|_| Component::NextLine),
)
.collect(),
),
]
.into_iter()
.for_each(|(name, instruction, expected)| {
let actual = instruction.into_components(WIDTH, HEIGHT);
assert!(
expected == actual,
"<{}>:
expected({}):\n{:#?}
actual({}):\n{:#?}",
name,
expected.len(),
expected,
actual.len(),
actual,
);
});
}
#[test]
fn test_plan_to_instructions() {
const HEIGHT: usize = 40;
let (widget_1, widget_2, widget_3) = test_widgets();
vec![
("end -> end", Plan::start(), Instruction::End),

View File

@ -76,7 +76,7 @@ impl Token {
Self::Bg(Box::new(self), c)
}
fn with_width(self, width: usize) -> Vec<Component> {
pub fn with_width(self, width: usize) -> Vec<Component> {
match self {
Token::String(t, s) => vec![Component::String(s)]
.into_iter()