mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 19:56:42 +01:00
unify edn_view entrypoint
This commit is contained in:
parent
df50bb9f47
commit
9cd6e9f195
16 changed files with 603 additions and 541 deletions
|
|
@ -1,7 +1,8 @@
|
|||
use tek::*;
|
||||
use tek_tui::{*, tek_input::*, tek_output::*};
|
||||
use tek_edn::*;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use crossterm::event::{*, KeyCode::*};
|
||||
use crate::ratatui::style::Color;
|
||||
|
||||
const EDN: &'static [&'static str] = &[
|
||||
include_str!("edn01.edn"),
|
||||
|
|
@ -25,26 +26,15 @@ fn main () -> Usually<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub struct Example(usize, Measure<TuiOut>);
|
||||
#[derive(Debug)] pub struct Example(usize, Measure<TuiOut>);
|
||||
|
||||
impl EdnViewData<TuiOut> for &Example {
|
||||
fn get_content <'a> (&'a self, item: EdnItem<&'a str>) -> RenderBox<'a, TuiOut> {
|
||||
use EdnItem::*;
|
||||
match item {
|
||||
Nil => Box::new(()),
|
||||
Exp(items) => Box::new(EdnView::from_items(*self, items.as_slice())),
|
||||
//Sym(name) => self.get_sym(name), TODO
|
||||
Sym(":title") => Tui::bg(Color::Rgb(60,10,10), Push::y(1,
|
||||
Align::n(format!("Example {}/{}:", self.0 + 1, EDN.len())))).boxed(),
|
||||
Sym(":code") => Tui::bg(Color::Rgb(10,60,10), Push::y(2,
|
||||
Align::n(format!("{}", EDN[self.0])))).boxed(),
|
||||
Sym(":hello-world") => "Hello world!".boxed(),
|
||||
Sym(":hello") => Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed(),
|
||||
Sym(":world") => Tui::bg(Color::Rgb(100, 10, 10), "world").boxed(),
|
||||
_ => panic!("no content for {item:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
edn_provide_content!(|self: Example|{
|
||||
":title" => Tui::bg(Color::Rgb(60,10,10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, EDN.len())))).boxed(),
|
||||
":code" => Tui::bg(Color::Rgb(10,60,10), Push::y(2, Align::n(format!("{}", EDN[self.0])))).boxed(),
|
||||
":hello-world" => "Hello world!".boxed(),
|
||||
":hello" => Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed(),
|
||||
":world" => Tui::bg(Color::Rgb(100, 10, 10), "world").boxed(),
|
||||
});
|
||||
|
||||
impl Content<TuiOut> for Example {
|
||||
fn content (&self) -> impl Render<TuiOut> {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,42 @@
|
|||
use crate::*;
|
||||
use std::marker::PhantomData;
|
||||
use EdnItem::*;
|
||||
|
||||
#[macro_export] macro_rules! edn_view {
|
||||
($Output:ty: |$self:ident: $App:ty| $content:expr; {
|
||||
$( $type:ty { $($sym:literal => $value:expr),* } );*
|
||||
}) => {
|
||||
impl Content<$Output> for $App {
|
||||
fn content(&$self) -> impl Render<$Output> { $content }
|
||||
}
|
||||
$(
|
||||
impl<'a> EdnProvide<'a, $type> for $App {
|
||||
fn get <S: AsRef<str>> (&'a $self, edn: &'a EdnItem<S>) -> Option<$type> {
|
||||
Some(match edn.to_ref() {
|
||||
$(EdnItem::Sym($sym) => $value,)*
|
||||
_ => return None
|
||||
})
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements `EdnProvide` for content components and expressions
|
||||
#[macro_export] macro_rules! edn_provide_content {
|
||||
(|$self:ident:$Stat:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
|
||||
impl<'a> EdnProvide<'a, Box<dyn Render<TuiOut> + 'a>> for $State {
|
||||
fn get <S: AsRef<str>> (&'a $self, edn: &'a EdnItem<S>) -> Option<Box<dyn Render<TuiOut> + 'a>> {
|
||||
(|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
|
||||
impl<'a, E: Output> EdnProvide<'a, Box<dyn Render<E> + 'a>> for $State {
|
||||
fn get <S: AsRef<str>> (&'a $self, edn: &'a EdnItem<S>) -> Option<Box<dyn Render<E> + 'a>> {
|
||||
Some(match edn.to_ref() {
|
||||
$(EdnItem::Sym($pat) => $expr),*,
|
||||
_ => return None
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
($Output:ty: |$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => {
|
||||
impl<'a> EdnProvide<'a, Box<dyn Render<$Output> + 'a>> for $State {
|
||||
fn get <S: AsRef<str>> (&'a $self, edn: &'a EdnItem<S>) -> Option<Box<dyn Render<$Output> + 'a>> {
|
||||
Some(match edn.to_ref() {
|
||||
$(EdnItem::Sym($pat) => $expr),*,
|
||||
_ => return None
|
||||
|
|
@ -15,21 +46,23 @@ use EdnItem::*;
|
|||
}
|
||||
}
|
||||
/// Renders from EDN source and context.
|
||||
#[derive(Default)]
|
||||
pub enum EdnView<'a, E: Output, T: EdnViewData<'a, E> + std::fmt::Debug> {
|
||||
#[default]
|
||||
Inert,
|
||||
_Unused(PhantomData<&'a E>),
|
||||
#[derive(Default)] pub enum EdnView<'a, E: Output, T: EdnViewData<'a, E> + std::fmt::Debug> {
|
||||
#[default] Inert,
|
||||
Ok(T, EdnItem<&'a str>),
|
||||
//render: Box<dyn Fn(&'a T)->Box<dyn Render<E> + Send + Sync + 'a> + Send + Sync + 'a>
|
||||
Err(String)
|
||||
Err(String),
|
||||
_Unused(PhantomData<&'a E>),
|
||||
}
|
||||
impl<'a, E: Output, T: EdnViewData<'a, E> + std::fmt::Debug> std::fmt::Debug for EdnView<'a, E, T> {
|
||||
fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
match self {
|
||||
Self::Inert | Self::_Unused(_) => write!(f, "EdnView::Inert"),
|
||||
Self::Ok(state, view) => write!(f, "EdnView::Ok(state={state:?} view={view:?}"),
|
||||
Self::Err(error) => write!(f, "EdnView::Err({error})"),
|
||||
Self::Inert | Self::_Unused(_) =>
|
||||
write!(f, "EdnView::Inert"),
|
||||
Self::Ok(state, view) =>
|
||||
write!(f, "EdnView::Ok(state={state:?} view={view:?}"),
|
||||
Self::Err(error) =>
|
||||
write!(f, "EdnView::Err({error})"),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,42 +66,35 @@ pub type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
|
|||
#[cfg(test)] #[test] fn test_layout () -> Usually<()> {
|
||||
use ::tek_tui::{*, tek_output::*};
|
||||
let area: [u16;4] = [10, 10, 20, 20];
|
||||
|
||||
let unit = ();
|
||||
|
||||
assert_eq!(Content::<TuiOut>::layout(&unit, area), [20, 20, 0, 0]);
|
||||
|
||||
assert_eq!(Content::<TuiOut>::layout(&Fill::<()>::x(unit), area), [10, 20, 20, 0]);
|
||||
assert_eq!(Render::<TuiOut>::layout(&Fill::<()>::x(unit), area), [10, 20, 20, 0]);
|
||||
|
||||
assert_eq!(Fill::<()>::y(unit).layout(area), [20, 10, 0, 20]);
|
||||
assert_eq!(Fill::<()>::xy(unit).layout(area), area);
|
||||
|
||||
assert_eq!(Fixed::<TuiOut, u16>::x(4, unit).layout(area), [18, 20, 4, 0]);
|
||||
assert_eq!(Fixed::<TuiOut, u16>::y(4, unit).layout(area), [20, 18, 0, 4]);
|
||||
assert_eq!(Fixed::<TuiOut, u16>::xy(4, 4, unit).layout(area), [18, 18, 4, 4]);
|
||||
|
||||
let four = ||Fixed::<TuiOut, _>::xy(4, 4, unit);
|
||||
|
||||
assert_eq!(Align::nw(four()).layout(area), [10, 10, 4, 4]);
|
||||
assert_eq!(Align::n(four()).layout(area), [18, 10, 4, 4]);
|
||||
assert_eq!(Align::ne(four()).layout(area), [26, 10, 4, 4]);
|
||||
assert_eq!(Align::e(four()).layout(area), [26, 18, 4, 4]);
|
||||
assert_eq!(Align::se(four()).layout(area), [26, 26, 4, 4]);
|
||||
assert_eq!(Align::s(four()).layout(area), [18, 26, 4, 4]);
|
||||
assert_eq!(Align::sw(four()).layout(area), [10, 26, 4, 4]);
|
||||
assert_eq!(Align::w(four()).layout(area), [10, 18, 4, 4]);
|
||||
|
||||
let two_by_four = ||Fixed::<TuiOut, _>::xy(4, 2, unit);
|
||||
|
||||
assert_eq!(Align::nw(two_by_four()).layout(area), [10, 10, 4, 2]);
|
||||
assert_eq!(Align::n(two_by_four()).layout(area), [18, 10, 4, 2]);
|
||||
assert_eq!(Align::ne(two_by_four()).layout(area), [26, 10, 4, 2]);
|
||||
assert_eq!(Align::e(two_by_four()).layout(area), [26, 19, 4, 2]);
|
||||
assert_eq!(Align::se(two_by_four()).layout(area), [26, 28, 4, 2]);
|
||||
assert_eq!(Align::s(two_by_four()).layout(area), [18, 28, 4, 2]);
|
||||
assert_eq!(Align::sw(two_by_four()).layout(area), [10, 28, 4, 2]);
|
||||
assert_eq!(Align::w(two_by_four()).layout(area), [10, 19, 4, 2]);
|
||||
|
||||
fn test (area: [u16;4], item: &impl Content<TuiOut>, expected: [u16;4]) {
|
||||
assert_eq!(Content::layout(item, area), expected);
|
||||
assert_eq!(Render::layout(item, area), expected);
|
||||
};
|
||||
test(area, &(), [20, 20, 0, 0]);
|
||||
test(area, &Fill::xy(()), area);
|
||||
test(area, &Fill::x(()), [10, 20, 20, 0]);
|
||||
test(area, &Fill::y(()), [20, 10, 0, 20]);
|
||||
test(area, &Fixed::x(4, unit), [18, 20, 4, 0]);
|
||||
test(area, &Fixed::y(4, unit), [20, 18, 0, 4]);
|
||||
test(area, &Fixed::xy(4, 4, unit), [18, 18, 4, 4]);
|
||||
let four = ||Fixed::<TuiOut, _, _>::xy(4, 4, unit);
|
||||
test(area, &Align::nw(four()), [10, 10, 4, 4]);
|
||||
test(area, &Align::n(four()), [18, 10, 4, 4]);
|
||||
test(area, &Align::ne(four()), [26, 10, 4, 4]);
|
||||
test(area, &Align::e(four()), [26, 18, 4, 4]);
|
||||
test(area, &Align::se(four()), [26, 26, 4, 4]);
|
||||
test(area, &Align::s(four()), [18, 26, 4, 4]);
|
||||
test(area, &Align::sw(four()), [10, 26, 4, 4]);
|
||||
test(area, &Align::w(four()), [10, 18, 4, 4]);
|
||||
let two_by_four = ||Fixed::<TuiOut, _, _>::xy(4, 2, unit);
|
||||
test(area, &Align::nw(two_by_four()), [10, 10, 4, 2]);
|
||||
test(area, &Align::n(two_by_four()), [18, 10, 4, 2]);
|
||||
test(area, &Align::ne(two_by_four()), [26, 10, 4, 2]);
|
||||
test(area, &Align::e(two_by_four()), [26, 19, 4, 2]);
|
||||
test(area, &Align::se(two_by_four()), [26, 28, 4, 2]);
|
||||
test(area, &Align::s(two_by_four()), [18, 28, 4, 2]);
|
||||
test(area, &Align::sw(two_by_four()), [10, 28, 4, 2]);
|
||||
test(area, &Align::w(two_by_four()), [10, 19, 4, 2]);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue