mirror of
https://codeberg.org/unspeaker/tek.git
synced 2025-12-06 11:46:41 +01:00
fix keymap macros. rendering issue
This commit is contained in:
parent
6f51872856
commit
f3fd88a199
15 changed files with 303 additions and 180 deletions
|
|
@ -15,6 +15,7 @@ const fn digit (c: char) -> usize {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum ParseError {
|
||||
Unknown(u8),
|
||||
Empty,
|
||||
Incomplete,
|
||||
Unexpected(char),
|
||||
|
|
@ -25,27 +26,90 @@ impl std::fmt::Display for ParseError {
|
|||
Self::Empty => write!(f, "empty"),
|
||||
Self::Incomplete => write!(f, "incomplete"),
|
||||
Self::Unexpected(c) => write!(f, "unexpected '{c}'"),
|
||||
Self::Unknown(i) => write!(f, "unknown #{i}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::error::Error for ParseError {}
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
pub enum Item<T: std::fmt::Debug + Clone + Default + PartialEq> {
|
||||
#[default] Nil,
|
||||
pub enum EdnItem<T> {
|
||||
Nil,
|
||||
Num(usize),
|
||||
Sym(T),
|
||||
Key(T),
|
||||
Exp(Vec<Item<T>>),
|
||||
Exp(Vec<EdnItem<T>>),
|
||||
}
|
||||
impl<T> Default for EdnItem<T> {
|
||||
fn default () -> Self {
|
||||
Self::Nil
|
||||
}
|
||||
}
|
||||
|
||||
impl Item<String> {
|
||||
impl<T: AsRef<str> + PartialEq + Default + Clone + std::fmt::Debug> EdnItem<T> {
|
||||
pub fn to_ref (&self) -> EdnItem<&str> {
|
||||
match self {
|
||||
Self::Key(x) => EdnItem::Key(x.as_ref()),
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
pub fn to_str (&self) -> &str {
|
||||
match self {
|
||||
Self::Key(x) => x.as_ref(),
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Item<&'a str> {
|
||||
impl EdnItem<String> {
|
||||
fn from (other: EdnItem<impl AsRef<str>>) -> EdnItem<String> {
|
||||
use EdnItem::*;
|
||||
match other {
|
||||
Nil => Nil,
|
||||
Key(t) => Key(t.as_ref().to_string()),
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: std::fmt::Debug + Clone + Default + PartialEq + From<&'a str>> Item<T> {
|
||||
impl<'a> TryFrom<Token<'a>> for EdnItem<String> {
|
||||
type Error = ParseError;
|
||||
fn try_from (token: Token<'a>) -> Result<Self, Self::Error> {
|
||||
use Token::*;
|
||||
Ok(match token {
|
||||
Nil => Self::Nil,
|
||||
Num(chars, index, length) =>
|
||||
Self::Num(number(&chars[index..index+length])),
|
||||
Sym(chars, index, length) =>
|
||||
Self::Sym(String::from(&chars[index..index+length])),
|
||||
Key(chars, index, length) =>
|
||||
Self::Key(String::from(&chars[index..index+length])),
|
||||
Exp(chars, index, length, 0) =>
|
||||
Self::Exp(Self::read_all(&chars[index+1..(index+length).saturating_sub(1)])?),
|
||||
_ => panic!("unclosed delimiter")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<Token<'a>> for EdnItem<&'a str> {
|
||||
type Error = ParseError;
|
||||
fn try_from (token: Token<'a>) -> Result<Self, Self::Error> {
|
||||
use Token::*;
|
||||
Ok(match token {
|
||||
Nil => EdnItem::Nil,
|
||||
Num(chars, index, length) =>
|
||||
Self::Num(number(&chars[index..index+length])),
|
||||
Sym(chars, index, length) =>
|
||||
Self::Sym(&chars[index..index+length]),
|
||||
Key(chars, index, length) =>
|
||||
Self::Key(&chars[index..index+length]),
|
||||
Exp(chars, index, length, 0) =>
|
||||
Self::Exp(Self::read_all(&chars[index+1..(index+length).saturating_sub(1)])?),
|
||||
_ => panic!("unclosed delimiter")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: std::fmt::Debug + Clone + Default + PartialEq + From<&'a str>> EdnItem<T> {
|
||||
pub fn read_all (mut source: &'a str) -> Result<Vec<Self>, ParseError> {
|
||||
let mut items = vec![];
|
||||
loop {
|
||||
|
|
@ -53,15 +117,24 @@ impl<'a, T: std::fmt::Debug + Clone + Default + PartialEq + From<&'a str>> Item<
|
|||
break
|
||||
}
|
||||
let (remaining, token) = Token::chomp(source)?;
|
||||
match Item::read(token)? { Item::Nil => {}, item => items.push(item) };
|
||||
match Self::read(token)? { Self::Nil => {}, item => items.push(item) };
|
||||
source = remaining
|
||||
}
|
||||
Ok(items)
|
||||
}
|
||||
pub fn read_one (source: &'a str) -> Result<(Self, &'a str), ParseError> {
|
||||
Ok({
|
||||
if source.len() == 0 {
|
||||
return Err(ParseError::Unknown(5))
|
||||
}
|
||||
let (remaining, token) = Token::chomp(source)?;
|
||||
(Self::read(token)?, remaining)
|
||||
})
|
||||
}
|
||||
pub fn read (token: Token<'a>) -> Result<Self, ParseError> {
|
||||
use Token::*;
|
||||
Ok(match token {
|
||||
Nil => Item::Nil,
|
||||
Nil => EdnItem::Nil,
|
||||
Num(chars, index, length) =>
|
||||
Self::Num(number(&chars[index..index+length])),
|
||||
Sym(chars, index, length) =>
|
||||
|
|
@ -73,8 +146,8 @@ impl<'a, T: std::fmt::Debug + Clone + Default + PartialEq + From<&'a str>> Item<
|
|||
_ => panic!("unclosed delimiter")
|
||||
})
|
||||
}
|
||||
//pub fn to_str <'a> (&'a self) -> Item<&'a str> {
|
||||
//use Item::*;
|
||||
//pub fn to_str <'a> (&'a self) -> EdnItem<&'a str> {
|
||||
//use EdnItem::*;
|
||||
//match self {
|
||||
//Nil => Nil,
|
||||
//Num(n) => Num(*n),
|
||||
|
|
|
|||
|
|
@ -1,68 +1,69 @@
|
|||
use crate::*;
|
||||
use std::marker::PhantomData;
|
||||
use ::tek_layout::{*, tek_engine::{Usually, Content, Render, Engine, Thunk}};
|
||||
use Item::*;
|
||||
|
||||
//pub struct EdnContent<'a, E, T: AsRef<str>>(PhantomData<E>, &'a [Item<T>]);
|
||||
|
||||
//impl<'a, E, T: AsRef<str>> From<&'a [Item<T>]> for EdnContent<'a, E, T> {
|
||||
//fn from (items: &'a [Item<T>]) -> Self {
|
||||
//Self(Default::default(), items)
|
||||
//}
|
||||
//}
|
||||
use EdnItem::*;
|
||||
|
||||
/// Compiles view from EDN form to Thunk
|
||||
pub struct EdnView<'a, E: Engine + 'a, T: EdnLayout<'a, E> + 'a>(
|
||||
PhantomData<&'a ()>,
|
||||
Box<dyn Fn(T)->Box<dyn Render<E> + Send + Sync> + Send + Sync>
|
||||
PhantomData<&'a (E, T)>,
|
||||
EdnItem<String>,
|
||||
//Box<dyn Fn(&'a T)->Box<dyn Render<E> + Send + Sync + 'a> + Send + Sync + 'a>
|
||||
);
|
||||
|
||||
impl<'a, E: Engine + 'a, T: EdnLayout<'a, E> + 'a> EdnView<'a, E, T> {
|
||||
fn from (source: &'a str) -> Usually<Self> {
|
||||
let items: Vec<Item<&'a str>> = Item::read_all(source)?;
|
||||
let layout = T::parse(items.iter().map(|x|x.to_str()).collect::<Vec<_>>().as_slice());
|
||||
Ok(Self(Default::default(), Box::new(move|_|{
|
||||
let _ = layout;
|
||||
Box::new(())
|
||||
})))
|
||||
pub fn new (source: &'a str) -> Usually<Self> {
|
||||
let (item, _): (EdnItem<String>, _) = EdnItem::read_one(&source)?;
|
||||
Ok(Self(Default::default(), item))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! edn_ns {
|
||||
(|$state:ident, $items:ident| { $($match:pat => $handle:expr),* $(,)? }) => {
|
||||
match $items {
|
||||
$($match => |$state|Box::new($handle),)*
|
||||
_ => |$state|Box::new(())
|
||||
pub type EdnRender<'a, Engine> =
|
||||
dyn Render<Engine> + Send + Sync + 'a;
|
||||
|
||||
pub type EdnCallback<'a, Engine, State> =
|
||||
dyn Fn(&'a State)->Box<EdnRender<'a, Engine>> + Send + Sync + 'a;
|
||||
|
||||
pub type EdnRenderCallback<'a, Engine, State> =
|
||||
Box<EdnCallback<'a, Engine, State>>;
|
||||
|
||||
pub trait EdnLayout<'a, E: Engine + 'a> where Self: 'a {
|
||||
fn get_bool (&self, _: &EdnItem<&str>) -> bool { false }
|
||||
fn get_unit (&self, _: &EdnItem<&str>) -> E::Unit { 0.into() }
|
||||
fn get_usize (&self, _: &EdnItem<&str>) -> usize { 0 }
|
||||
fn get_content (&'a self, _: &EdnItem<&str>) -> Box<EdnRender<'a, E>> { Box::new(()) }
|
||||
fn parse (items: &'a [EdnItem<String>]) -> EdnRenderCallback<'a, E, Self> {
|
||||
if let (Some(first), rest) = (items.get(0).map(EdnItem::to_str), &items[1..]) {
|
||||
match (first, rest) {
|
||||
("when", [c, a, ..]) => Box::new(move|state|Box::new(
|
||||
When(state.get_bool(&c.to_ref()), state.get_content(&a.to_ref())))),
|
||||
_ => Box::new(|_|Box::new(()))
|
||||
}
|
||||
} else {
|
||||
Box::new(|_|Box::new(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait EdnLayout<'a, E: Engine> where Self: 'a {
|
||||
fn get_bool (&self, _: &Item<&str>) -> bool { false }
|
||||
fn get_unit (&self, _: &Item<&str>) -> E::Unit { 0.into() }
|
||||
fn get_usize (&self, _: &Item<&str>) -> usize { 0 }
|
||||
fn get_content (&self, _: &Item<&str>) -> Box<dyn Render<E>> { Box::new(()) }
|
||||
fn parse (items: &'a [Item<&'a str>]) -> impl Fn(&'a Self)->Box<dyn Render<E> + 'a> + 'a {
|
||||
edn_ns!(|state, items|{
|
||||
[Key("when"), c, a, ..] => When(state.get_bool(c), state.get_content(a)),
|
||||
[Key("either"), c, a, b, ..] => Either(state.get_bool(c), state.get_content(a), state.get_content(b)),
|
||||
[Key("fill"), a, ..] => Fill::xy(state.get_content(a)),
|
||||
[Key("fill/x"), a, ..] => Fill::x(state.get_content(a)),
|
||||
[Key("fill/y"), a, ..] => Fill::y(state.get_content(a)),
|
||||
[Key("fixed"), x, y, a, ..] => Fixed::xy(state.get_unit(x), state.get_unit(y), state.get_content(a)),
|
||||
[Key("fixed/x"), x, a, ..] => Fixed::x(state.get_unit(x), state.get_content(a)),
|
||||
[Key("fixed/y"), y, a, ..] => Fixed::y(state.get_unit(y), state.get_content(a)),
|
||||
[Key("shrink"), x, y, a, ..] => Shrink::xy(state.get_unit(x), state.get_unit(y), state.get_content(a)),
|
||||
[Key("shrink/x"), x, a, ..] => Shrink::x(state.get_unit(x), state.get_content(a)),
|
||||
[Key("shrink/y"), y, a, ..] => Shrink::y(state.get_unit(y), state.get_content(a)),
|
||||
[Key("expand"), x, y, a, ..] => Expand::xy(state.get_unit(x), state.get_unit(y), state.get_content(a)),
|
||||
[Key("expand/x"), x, a, ..] => Expand::x(state.get_unit(x), state.get_content(a)),
|
||||
[Key("expand/y"), y, a, ..] => Expand::y(state.get_unit(y), state.get_content(a)),
|
||||
[Key("push"), x, y, a, ..] => Push::xy(state.get_unit(x), state.get_unit(y), state.get_content(a)),
|
||||
[Key("push/x"), x, a, ..] => Push::x(state.get_unit(x), state.get_content(a)),
|
||||
[Key("push/y"), y, a, ..] => Push::y(state.get_unit(y), state.get_content(a)),
|
||||
[Key("pull"), x, y, a, ..] => Pull::xy(state.get_unit(x), state.get_unit(y), state.get_content(a)),
|
||||
[Key("pull/x"), x, a, ..] => Pull::x(state.get_unit(x), state.get_content(a)),
|
||||
[Key("pull/y"), y, a, ..] => Pull::y(state.get_unit(y), state.get_content(a)),
|
||||
})
|
||||
}
|
||||
//Box::new(match [items.get(0).map(|x|x.to_str()), items[1..]] {
|
||||
//["when", [c, a, ..]] => When(state.get_bool(c), state.get_content(a)),
|
||||
//["either", [c, a, b, ..]] => Either(state.get_bool(c), state.get_content(a), state.get_content(b)),
|
||||
//["fill", [a, ..]] => Fill::xy(state.get_content(a)),
|
||||
//["fill/x", [a, ..]] => Fill::x(state.get_content(a)),
|
||||
//["fill/y", [a, ..]] => Fill::y(state.get_content(a)),
|
||||
//["fixed", [x, y, a, ..]] => Fixed::xy(state.get_unit(x), state.get_unit(y), state.get_content(a)),
|
||||
//["fixed/x", [x, a, ..]] => Fixed::x(state.get_unit(x), state.get_content(a)),
|
||||
//["fixed/y", [y, a, ..]] => Fixed::y(state.get_unit(y), state.get_content(a)),
|
||||
//["shrink", [x, y, a, ..]] => Shrink::xy(state.get_unit(x), state.get_unit(y), state.get_content(a)),
|
||||
//["shrink/x", [x, a, ..]] => Shrink::x(state.get_unit(x), state.get_content(a)),
|
||||
//["shrink/y", [y, a, ..]] => Shrink::y(state.get_unit(y), state.get_content(a)),
|
||||
//["expand", [x, y, a, ..]] => Expand::xy(state.get_unit(x), state.get_unit(y), state.get_content(a)),
|
||||
//["expand/x", [x, a, ..]] => Expand::x(state.get_unit(x), state.get_content(a)),
|
||||
//["expand/y", [y, a, ..]] => Expand::y(state.get_unit(y), state.get_content(a)),
|
||||
//["push", [x, y, a, ..]] => Push::xy(state.get_unit(x), state.get_unit(y), state.get_content(a)),
|
||||
//["push/x", [x, a, ..]] => Push::x(state.get_unit(x), state.get_content(a)),
|
||||
//["push/y", [y, a, ..]] => Push::y(state.get_unit(y), state.get_content(a)),
|
||||
//["pull", [x, y, a, ..]] => Pull::xy(state.get_unit(x), state.get_unit(y), state.get_content(a)),
|
||||
//["pull/x", [x, a, ..]] => Pull::x(state.get_unit(x), state.get_content(a)),
|
||||
//["pull/y", [y, a, ..]] => Pull::y(state.get_unit(y), state.get_content(a)),
|
||||
//_ => Box::
|
||||
//})
|
||||
//}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,29 +7,29 @@ mod edn_layout; pub use self::edn_layout::*;
|
|||
mod edn_token; pub use self::edn_token::*;
|
||||
|
||||
#[cfg(test)] #[test] fn test_edn () -> Result<(), ParseError> {
|
||||
use Item::*;
|
||||
assert_eq!(Item::read_all("")?,
|
||||
use EdnItem::*;
|
||||
assert_eq!(EdnItem::read_all("")?,
|
||||
vec![]);
|
||||
assert_eq!(Item::read_all(" ")?,
|
||||
assert_eq!(EdnItem::read_all(" ")?,
|
||||
vec![]);
|
||||
assert_eq!(Item::read_all("1234")?,
|
||||
assert_eq!(EdnItem::read_all("1234")?,
|
||||
vec![Num(1234)]);
|
||||
assert_eq!(Item::read_all("1234 5 67")?,
|
||||
assert_eq!(EdnItem::read_all("1234 5 67")?,
|
||||
vec![Num(1234), Num(5), Num(67)]);
|
||||
assert_eq!(Item::read_all("foo/bar")?,
|
||||
assert_eq!(EdnItem::read_all("foo/bar")?,
|
||||
vec![Key("foo/bar".into())]);
|
||||
assert_eq!(Item::read_all(":symbol")?,
|
||||
assert_eq!(EdnItem::read_all(":symbol")?,
|
||||
vec![Sym(":symbol".into())]);
|
||||
assert_eq!(Item::read_all(" foo/bar :baz 456")?,
|
||||
assert_eq!(EdnItem::read_all(" foo/bar :baz 456")?,
|
||||
vec![Key("foo/bar".into()), Sym(":baz".into()), Num(456)]);
|
||||
assert_eq!(Item::read_all(" (foo/bar :baz 456) ")?,
|
||||
assert_eq!(EdnItem::read_all(" (foo/bar :baz 456) ")?,
|
||||
vec![Exp(vec![Key("foo/bar".into()), Sym(":baz".into()), Num(456)])]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)] #[test] fn test_edn_layout () -> Result<(), ParseError> {
|
||||
let source = include_str!("example.edn");
|
||||
let layout = Item::read_all(source)?;
|
||||
let layout = EdnItem::read_all(source)?;
|
||||
//panic!("{layout:?}");
|
||||
//let content = <dyn EdnLayout<::tek_engine::tui::Tui>>::from(&layout);
|
||||
Ok(())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue