separate Input and Output impls

This commit is contained in:
🪞👃🪞 2025-01-05 22:01:54 +01:00
parent a6efde40f8
commit 0e821e098f
77 changed files with 465 additions and 454 deletions

View file

@ -17,23 +17,27 @@ fn main () -> Usually<()> {
pub struct Example(usize);
impl EdnViewData<Tui> for &Example {
fn get_content <'a> (&'a self, sym: &'a str) -> RenderBox<'a, Tui> {
fn get_content <'a> (&'a self, sym: EdnItem<&'a str>) -> RenderBox<'a, Tui> {
Box::new(Thunk::new(move||match sym {
":hello-world" => "Hello world!",
":hello" => "Hello",
":world" => "world",
EdnItem::Sym(":hello-world") => "Hello world!",
EdnItem::Sym(":hello") => "Hello",
EdnItem::Sym(":world") => "world",
_ => ""
}))
}
}
impl Content<Tui> for Example {
fn content (&self) -> impl Render<Tui> {
EdnView::new(self, EDN[self.0]).unwrap()
impl Content<TuiOut> for Example {
fn content (&self) -> impl Render<TuiOut> {
Bsp::a(
&format!("{}", self.0),
EdnView::new(self, EDN[self.0])
.unwrap_or_else(|e|format!("Failed to render {}: {e}", self.0))
)
}
}
impl Handle<Tui> for Example {
impl Handle<TuiIn> for Example {
fn handle (&mut self, input: &TuiIn) -> Perhaps<bool> {
match input.event() {
kpat!(Right) => self.0 = (self.0 + 1) % EDN.len(),

View file

@ -22,10 +22,10 @@ impl EdnViewData<Tui> for &Example {
}
}
impl Content<Tui> for Example {
fn content (&self) -> impl Render<Tui> {
impl Content<TuiOut> for Example {
fn content (&self) -> impl Render<TuiOut> {
EdnView::new(self, EDN).unwrap()
}
}
impl Handle<Tui> for Example {}
impl Handle<TuiIn> for Example {}

View file

@ -1,56 +1,62 @@
use crate::*;
use std::marker::PhantomData;
use ::tek_layout::{*, tek_engine::{Usually, Content, Render, RenderBox, Engine, Thunk}};
use ::tek_layout::{*, tek_engine::{Usually, Content, Render, RenderBox, Output, Thunk}};
use EdnItem::*;
pub type EdnCallback<'a, Engine, State> =
dyn Fn(&'a State)-> RenderBox<'a, Engine> + Send + Sync + 'a;
pub type EdnCallback<'a, Output, State> =
dyn Fn(&'a State)-> RenderBox<'a, Output> + Send + Sync + 'a;
pub type EdnRenderCallback<'a, Engine, State> =
Box<EdnCallback<'a, Engine, State>>;
pub type EdnRenderCallback<'a, Output, State> =
Box<EdnCallback<'a, Output, State>>;
pub trait EdnViewData<E: Engine> {
pub trait EdnViewData<E: Output> {
fn get_bool (&self, _sym: EdnItem<&str>) -> bool { false }
fn get_unit (&self, _sym: EdnItem<&str>) -> E::Unit { 0.into() }
fn get_usize (&self, _sym: EdnItem<&str>) -> usize { 0 }
fn get_content <'a> (&'a self, _sym: EdnItem<&str>) -> RenderBox<'a, E> { Box::new(()) }
fn get_content <'a> (&'a self, _sym: EdnItem<&'a str>) -> RenderBox<'a, E> { Box::new(()) }
}
/// Renders from EDN source and context.
pub struct EdnView<E: Engine, T: EdnViewData<E>> {
_engine: PhantomData<E>,
context: T,
layout: EdnItem<String>
pub enum EdnView<E: Output, T: EdnViewData<E>> {
_Unused(PhantomData<E>),
Ok(T, EdnItem<String>),
//render: Box<dyn Fn(&'a T)->Box<dyn Render<E> + Send + Sync + 'a> + Send + Sync + 'a>
Err(String)
}
impl<E: Engine, T: EdnViewData<E>> EdnView<E, T> {
impl<E: Output, T: EdnViewData<E>> EdnView<E, T> {
pub fn new (context: T, source: &str) -> Usually<Self> {
let layout = EdnItem::read_one(&source)?.0;
Ok(Self { _engine: Default::default(), context, layout, })
Ok(Self::Ok(context, layout))
}
}
impl<E: Engine, T: EdnViewData<E> + Send + Sync> Content<E> for EdnView<E, T> {
impl<E: Output, T: EdnViewData<E> + Send + Sync> Content<E> for EdnView<E, T> {
fn content (&self) -> impl Render<E> {
use EdnItem::*;
match &self.layout {
Nil => ().boxed(),
Sym(t) => self.context.get_content(Sym(t.as_str())).boxed(),
Key(t) => panic!("todo: add error handling to content() chain. unexpected key {t}"),
Num(n) => panic!("todo: add error handling to content() chain. unexpected num {n}"),
Exp(e) => if let [head, tail @ ..] = e.as_slice() {
let head = &head.to_ref();
let state = &self.context;
match (head, tail) {
(Key("when"), [c, a]) => When(state.get_bool(c.to_ref()), state.get_content(a.to_ref())).boxed(),
(Key("bsp/s"), [a, b]) => Bsp::s(state.get_content(a.to_ref()), state.get_content(b.to_ref()),).boxed(),
_ => todo!("{:?} {:?}", &head, &tail)
}
} else {
panic!("todo: add error handling to content() chain. invalid expression {e:?}")
match self {
Self::Ok(state, layout) => match layout {
Nil => ().boxed(),
Sym(t) => state.get_content(Sym(t.as_str())).boxed(),
Key(t) => panic!("todo: add error handling to content() chain. unexpected key {t}"),
Num(n) => panic!("todo: add error handling to content() chain. unexpected num {n}"),
Exp(e) => if let [head, tail @ ..] = e.as_slice() {
let head = &head.to_ref();
match (head, tail) {
(Key("when"), [c, a]) => When(state.get_bool(c.to_ref()), state.get_content(a.to_ref())).boxed(),
(Key("bsp/s"), [a, b]) => Bsp::s(state.get_content(a.to_ref()), state.get_content(b.to_ref()),).boxed(),
_ => todo!("{:?} {:?}", &head, &tail)
}
} else {
panic!("todo: add error handling to content() chain. invalid expression {e:?}")
},
},
Self::Err(error) => {
Box::new(())//&format!("EdnView error: {error:?}"))
},
_ => todo!()
}
//let items = &self.layout;
//if let (Some(first), rest) = (items.get(0).map(EdnItem::to_str), &items[1..]) {
//match (first, rest) {