fixes and testing for the instructions -> set of components converter
This commit is contained in:
parent
4a3c5ac492
commit
ec6998ff30
|
@ -2,15 +2,39 @@ use crate::{
|
||||||
theme::{Color, ColorSet},
|
theme::{Color, ColorSet},
|
||||||
token::Token,
|
token::Token,
|
||||||
};
|
};
|
||||||
|
use std::iter::Extend;
|
||||||
|
|
||||||
#[derive(Eq, Debug, Clone)]
|
#[derive(Eq, Debug, Clone)]
|
||||||
pub enum Component {
|
pub enum Component {
|
||||||
|
NextLine,
|
||||||
X(usize),
|
X(usize),
|
||||||
String(String),
|
String(String),
|
||||||
Fg(Color),
|
Fg(Color),
|
||||||
Bg(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 {
|
impl PartialEq for Component {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
@ -30,6 +54,10 @@ impl PartialEq for Component {
|
||||||
Self::Bg(other_c) => c == other_c,
|
Self::Bg(other_c) => c == other_c,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
Self::NextLine => match other {
|
||||||
|
Self::NextLine => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +114,7 @@ impl Widget {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_line(&self, line: usize) -> Option<&Token> {
|
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 {
|
impl Instruction {
|
||||||
pub fn make(
|
pub fn into_components(
|
||||||
self,
|
self,
|
||||||
(term_width, term_height): (u16, u16),
|
line_width: usize,
|
||||||
) -> String {
|
height_left: usize,
|
||||||
todo!()
|
) -> 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 {
|
pub fn start() -> Self {
|
||||||
|
@ -251,13 +330,11 @@ impl Plan {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
fn test_widgets() -> (Widget, Widget, Widget) {
|
||||||
fn test_plan_to_instructions() {
|
(
|
||||||
const HEIGHT: usize = 40;
|
|
||||||
let (widget_1, widget_2, widget_3) = (
|
|
||||||
Widget::new(
|
Widget::new(
|
||||||
SectionWidth::Third,
|
SectionWidth::Third,
|
||||||
vec![Token::text("hello")],
|
vec![Token::text("hello").centered()],
|
||||||
),
|
),
|
||||||
Widget::new(
|
Widget::new(
|
||||||
SectionWidth::Third,
|
SectionWidth::Third,
|
||||||
|
@ -269,7 +346,108 @@ mod tests {
|
||||||
SectionWidth::Third,
|
SectionWidth::Third,
|
||||||
vec![Token::text("hello").limited(16).padded(20)],
|
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![
|
vec![
|
||||||
("end -> end", Plan::start(), Instruction::End),
|
("end -> end", Plan::start(), Instruction::End),
|
||||||
|
|
|
@ -76,7 +76,7 @@ impl Token {
|
||||||
Self::Bg(Box::new(self), c)
|
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 {
|
match self {
|
||||||
Token::String(t, s) => vec![Component::String(s)]
|
Token::String(t, s) => vec![Component::String(s)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
Loading…
Reference in New Issue