Compare commits

...

3 commits

Author SHA1 Message Date
17506726cb wip: updating tests
Some checks are pending
/ build (push) Waiting to run
2025-06-12 21:56:59 +03:00
21832453d9 dsl,input,output,proc,tui: fix warnings 2025-06-12 19:29:12 +03:00
08593571fa output: fix expressions 2025-06-08 04:45:14 +03:00
47 changed files with 303 additions and 295 deletions

View file

@ -1,6 +1,8 @@
covfig := "CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' RUSTDOCFLAGS='-Cinstrument-coverage' LLVM_PROFILE_FILE='cov/cargo-test-%p-%m.profraw'" covfig := "CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' RUSTDOCFLAGS='-Cinstrument-coverage' LLVM_PROFILE_FILE='cov/cargo-test-%p-%m.profraw'"
grcov-binary := "--binary-path ./target/coverage/deps/" grcov-binary := "--binary-path ./target/coverage/deps/"
grcov-ignore := "--ignore-not-existing --ignore '../*' --ignore \"/*\" --ignore 'target/*'" grcov-ignore := "--ignore-not-existing --ignore '../*' --ignore \"/*\" --ignore 'target/*'"
bacon:
{{covfig}} bacon -s
cov: cov:
{{covfig}} time cargo test -j4 --workspace --profile coverage {{covfig}} time cargo test -j4 --workspace --profile coverage
rm -rf target/coverage/html || true rm -rf target/coverage/html || true

View file

@ -1,6 +1,5 @@
use crate::*; use crate::*;
use std::sync::Arc; use std::sync::Arc;
use std::borrow::Cow;
#[derive(Debug, Clone, Default, PartialEq)] #[derive(Debug, Clone, Default, PartialEq)]
pub struct Ast(pub Value<Arc<str>, AstIter>); pub struct Ast(pub Value<Arc<str>, AstIter>);

View file

@ -3,6 +3,10 @@ use crate::*;
/// CST stores strings as source references and expressions as new [SourceIter] instances. /// CST stores strings as source references and expressions as new [SourceIter] instances.
pub type CstValue<'source> = Value<&'source str, SourceIter<'source>>; pub type CstValue<'source> = Value<&'source str, SourceIter<'source>>;
/// Token sharing memory with source reference.
#[derive(Debug, Copy, Clone, Default, PartialEq)]
pub struct CstToken<'source>(pub CstValue<'source>, pub CstMeta<'source>);
/// Reference to the source slice. /// Reference to the source slice.
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct CstMeta<'source> { #[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct CstMeta<'source> {
pub source: &'source str, pub source: &'source str,
@ -10,10 +14,6 @@ pub type CstValue<'source> = Value<&'source str, SourceIter<'source>>;
pub length: usize, pub length: usize,
} }
/// Token sharing memory with source reference.
#[derive(Debug, Copy, Clone, Default, PartialEq)]
pub struct CstToken<'source>(pub CstValue<'source>, pub CstMeta<'source>);
impl<'source> CstToken<'source> { impl<'source> CstToken<'source> {
pub const fn new ( pub const fn new (
source: &'source str, start: usize, length: usize, value: CstValue<'source> source: &'source str, start: usize, length: usize, value: CstValue<'source>

View file

@ -1,5 +1,5 @@
use crate::*; use crate::*;
use std::fmt::{Debug, Display, Formatter, Error as FormatError}; use std::fmt::{Display, Formatter, Error as FormatError};
impl Display for Ast { impl Display for Ast {
fn fmt (&self, out: &mut Formatter) -> Result<(), FormatError> { fn fmt (&self, out: &mut Formatter) -> Result<(), FormatError> {
use Value::*; use Value::*;

View file

@ -7,25 +7,32 @@ pub trait DslIter {
fn rest (self) -> Vec<Self::Token>; fn rest (self) -> Vec<Self::Token>;
} }
#[derive(Debug, Clone, Default, PartialEq)] /// Implement the const iterator pattern.
pub struct AstIter(std::collections::VecDeque<Ast>); #[macro_export] macro_rules! const_iter {
($(<$l:lifetime>)?|$self:ident: $Struct:ty| => $Item:ty => $expr:expr) => {
impl DslIter for AstIter { impl$(<$l>)? Iterator for $Struct {
type Token = Ast; type Item = $Item;
fn peek (&self) -> Option<Ast> { fn next (&mut $self) -> Option<$Item> { $expr }
self.0.get(0).cloned() }
} impl$(<$l>)? ConstIntoIter for $Struct {
fn next (&mut self) -> Option<Ast> { type Kind = IsIteratorKind;
self.0.pop_front() type Item = $Item;
} type IntoIter = Self;
fn rest (self) -> Vec<Ast> { }
self.0.into()
} }
} }
impl<'source> From<SourceIter<'source>> for AstIter { /// Owns a reference to the source text.
fn from (source: SourceIter<'source>) -> Self { /// [SourceConstIter::next] emits subsequent pairs of:
Self(source.map(Into::into).collect()) /// * a [CstToken] and
/// * the source text remaining
/// * [ ] TODO: maybe [SourceConstIter::next] should wrap the remaining source in `Self` ?
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct SourceConstIter<'source>(pub &'source str);
impl<'source> From<SourceConstIter<'source>> for SourceIter<'source> {
fn from (source: SourceConstIter<'source>) -> Self{
Self(source)
} }
} }
@ -71,35 +78,6 @@ impl<'source> Into<Vec<Ast>> for SourceIter<'source> {
} }
} }
/// Implement the const iterator pattern.
#[macro_export] macro_rules! const_iter {
($(<$l:lifetime>)?|$self:ident: $Struct:ty| => $Item:ty => $expr:expr) => {
impl$(<$l>)? Iterator for $Struct {
type Item = $Item;
fn next (&mut $self) -> Option<$Item> { $expr }
}
impl$(<$l>)? ConstIntoIter for $Struct {
type Kind = IsIteratorKind;
type Item = $Item;
type IntoIter = Self;
}
}
}
/// Owns a reference to the source text.
/// [SourceConstIter::next] emits subsequent pairs of:
/// * a [CstToken] and
/// * the source text remaining
/// * [ ] TODO: maybe [SourceConstIter::next] should wrap the remaining source in `Self` ?
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct SourceConstIter<'source>(pub &'source str);
impl<'source> From<SourceConstIter<'source>> for SourceIter<'source> {
fn from (source: SourceConstIter<'source>) -> Self{
Self(source)
}
}
impl<'source> From<&'source str> for SourceConstIter<'source> { impl<'source> From<&'source str> for SourceConstIter<'source> {
fn from (source: &'source str) -> Self{ fn from (source: &'source str) -> Self{
Self::new(source) Self::new(source)
@ -128,3 +106,25 @@ impl<'source> SourceConstIter<'source> {
} }
const_iter!(<'source>|self: SourceConstIter<'source>| => CstToken<'source> => self.next_mut().map(|(result, _)|result)); const_iter!(<'source>|self: SourceConstIter<'source>| => CstToken<'source> => self.next_mut().map(|(result, _)|result));
#[derive(Debug, Clone, Default, PartialEq)]
pub struct AstIter(std::collections::VecDeque<Ast>);
impl DslIter for AstIter {
type Token = Ast;
fn peek (&self) -> Option<Ast> {
self.0.get(0).cloned()
}
fn next (&mut self) -> Option<Ast> {
self.0.pop_front()
}
fn rest (self) -> Vec<Ast> {
self.0.into()
}
}
impl<'source> From<SourceIter<'source>> for AstIter {
fn from (source: SourceIter<'source>) -> Self {
Self(source.map(Into::into).collect())
}
}

View file

@ -1,21 +1,21 @@
use crate::*;
#[cfg(test)] mod test_token_iter { #[cfg(test)] mod test_token_iter {
use crate::*; use crate::*;
//use proptest::prelude::*; //use proptest::prelude::*;
#[test] fn test_iters () { #[test] fn test_iters () {
let mut iter = crate::SourceIter::new(&":foo :bar"); let mut iter = crate::SourceIter::new(&":foo :bar");
let _ = iter.next(); let _ = iter.next();
let mut iter = crate::TokenIter::new(&":foo :bar");
let _ = iter.next();
} }
#[test] const fn test_const_iters () { #[test] const fn test_const_iters () {
let mut iter = crate::SourceIter::new(&":foo :bar"); let iter = crate::SourceConstIter::new(&":foo :bar");
let _ = iter.next(); let _ = iter.next();
} }
#[test] fn test_num () { #[test] fn test_num () {
let digit = to_digit('0'); let _digit = to_digit('0');
let digit = to_digit('x'); let _digit = to_digit('x');
let number = to_number(&"123"); let _number = to_number(&"123");
let number = to_number(&"12asdf3"); let _number = to_number(&"12asdf3");
} }
//proptest! { //proptest! {
//#[test] fn proptest_source_iter ( //#[test] fn proptest_source_iter (
@ -33,67 +33,54 @@
//} //}
} }
#[cfg(test)] mod test_token_prop { //#[cfg(test)] mod test_token_prop {
use proptest::prelude::*; //use crate::{CstToken, CstMeta, Value::*};
proptest! { //use proptest::prelude::*;
#[test] fn test_token_prop ( //proptest! {
source in "\\PC*", //#[test] fn test_token_prop (
start in usize::MIN..usize::MAX, //source in "\\PC*",
length in usize::MIN..usize::MAX, //start in usize::MIN..usize::MAX,
) { //length in usize::MIN..usize::MAX,
let token = crate::Token { //) {
source: &source, //let token = CstToken(Nil, CstMeta { source: &source, start, length });
start, //let _ = token.slice();
length, //}
value: crate::Value::Nil //}
}; //}
let _ = token.slice();
}
}
}
#[cfg(test)] #[test] fn test_token () -> Result<(), Box<dyn std::error::Error>> { #[cfg(test)] #[test] fn test_token () -> Result<(), Box<dyn std::error::Error>> {
use crate::Value::*;
let source = ":f00"; let source = ":f00";
let mut token = Token { source, start: 0, length: 1, value: Sym(":") }; let mut token = CstToken(Sym(":"), CstMeta { source, start: 0, length: 1 });
token = token.grow_sym(); token = token.grow_sym();
assert_eq!(token, Token { source, start: 0, length: 2, value: Sym(":f") }); assert_eq!(token, CstToken(Sym(":f"), CstMeta { source, start: 0, length: 2, }));
token = token.grow_sym(); token = token.grow_sym();
assert_eq!(token, Token { source, start: 0, length: 3, value: Sym(":f0") }); assert_eq!(token, CstToken(Sym(":f0"), CstMeta { source, start: 0, length: 3, }));
token = token.grow_sym(); token = token.grow_sym();
assert_eq!(token, Token { source, start: 0, length: 4, value: Sym(":f00") }); assert_eq!(token, CstToken(Sym(":f00"), CstMeta { source, start: 0, length: 4, }));
let src = ""; assert_eq!(None,
assert_eq!(None, SourceIter(src).next()); SourceIter::new("").next());
assert_eq!(None,
let src = " \n \r \t "; SourceIter::new(" \n \r \t ").next());
assert_eq!(None, SourceIter(src).next()); assert_eq!(&Num(7),
SourceIter::new("7").next().unwrap().0.value());
let src = "7"; assert_eq!(&Num(100),
assert_eq!(Num(7), SourceIter(src).next().unwrap().0.value); SourceIter::new(" 100 ").next().unwrap().0.value());
assert_eq!(&Err(Unexpected('a')),
let src = " 100 "; SourceIter::new(" 9a ").next().unwrap().0.value());
assert_eq!(Num(100), SourceIter(src).next().unwrap().0.value); assert_eq!(&Sym(":123foo"),
SourceIter::new(" :123foo ").next().unwrap().0.value());
let src = " 9a "; assert_eq!(&Sym("@bar456"),
assert_eq!(Err(Unexpected('a')), SourceIter(src).next().unwrap().0.value); SourceIter::new(" \r\r\r\n\n\n@bar456\t\t\t\t\t\t").next().unwrap().0.value());
assert_eq!(&Key("foo123"),
let src = " :123foo "; SourceIter::new("foo123").next().unwrap().0.value());
assert_eq!(Sym(":123foo"), SourceIter(src).next().unwrap().0.value); assert_eq!(&Key("foo/bar"),
SourceIter::new("foo/bar").next().unwrap().0.value());
let src = " \r\r\r\n\n\n@bar456\t\t\t\t\t\t"; assert_eq!(&Str("foo/bar"),
assert_eq!(Sym("@bar456"), SourceIter(src).next().unwrap().0.value); SourceIter::new("\"foo/bar\"").next().unwrap().0.value());
assert_eq!(&Str("foo/bar"),
let src = "foo123"; SourceIter::new(" \"foo/bar\" ").next().unwrap().0.value());
assert_eq!(Key("foo123"), SourceIter(src).next().unwrap().0.value);
let src = "foo/bar";
assert_eq!(Key("foo/bar"), SourceIter(src).next().unwrap().0.value);
let src = "\"foo/bar\"";
assert_eq!(Str("foo/bar"), SourceIter(src).next().unwrap().0.value);
let src = " \"foo/bar\" ";
assert_eq!(Str("foo/bar"), SourceIter(src).next().unwrap().0.value);
Ok(()) Ok(())
} }
@ -108,7 +95,7 @@
//let mut expr = view.peek(); //let mut expr = view.peek();
//assert_eq!(view.0.0, source); //assert_eq!(view.0.0, source);
//assert_eq!(expr, Some(Token { //assert_eq!(expr, Some(Token {
//source, start: 0, length: source.len() - 1, value: Exp(0, SourceIter(&source[1..])) //source, start: 0, length: source.len() - 1, value: Exp(0, SourceIter::new(&source[1..]))
//})); //}));
////panic!("{view:?}"); ////panic!("{view:?}");
////panic!("{:#?}", expr); ////panic!("{:#?}", expr);

View file

@ -73,12 +73,12 @@ impl<S: Clone, X: Clone,> Clone for Value<S, X> {
} }
impl<S: Copy, X: Copy,> Copy for Value<S, X> {} impl<S: Copy, X: Copy,> Copy for Value<S, X> {}
impl<S: Debug, X: Debug,> Debug for Value<S, X> { impl<S: Debug, X: Debug,> Debug for Value<S, X> {
fn fmt (&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { fn fmt (&self, _f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
todo!() todo!()
} }
} }
impl<S: Display, X: Display,> Display for Value<S, X> { impl<S: Display, X: Display,> Display for Value<S, X> {
fn fmt (&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { fn fmt (&self, _f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
todo!() todo!()
} }
} }

View file

@ -42,7 +42,7 @@ pub(crate) use thiserror::Error;
pub(crate) use self::DslError::*; pub(crate) use self::DslError::*;
mod dsl_ast; pub use self::dsl_ast::*; mod dsl_ast; pub use self::dsl_ast::*;
mod dsl_cst; pub use self::dsl_cst::*; mod dsl_cst; pub use self::dsl_cst::*;
mod dsl_display; pub use self::dsl_display::*; mod dsl_display; //pub use self::dsl_display::*;
mod dsl_domain; pub use self::dsl_domain::*; mod dsl_domain; pub use self::dsl_domain::*;
mod dsl_error; pub use self::dsl_error::*; mod dsl_error; pub use self::dsl_error::*;
mod dsl_iter; pub use self::dsl_iter::*; mod dsl_iter; pub use self::dsl_iter::*;

View file

@ -1,5 +1,5 @@
use crate::*; use crate::*;
use std::marker::PhantomData; //use std::marker::PhantomData;
use std::fmt::Debug; use std::fmt::Debug;
#[derive(Default, Debug)] pub struct InputLayers(Vec<InputLayer>); #[derive(Default, Debug)] pub struct InputLayers(Vec<InputLayer>);

View file

@ -33,6 +33,6 @@ mod input_handle; pub use self::input_handle::*;
} }
#[cfg(all(test, feature = "dsl"))] #[test] fn test_dsl_keymap () -> Usually<()> { #[cfg(all(test, feature = "dsl"))] #[test] fn test_dsl_keymap () -> Usually<()> {
let keymap = SourceIter::new(""); let _keymap = SourceIter::new("");
Ok(()) Ok(())
} }

View file

@ -16,3 +16,4 @@ mod ops; pub use self::ops::*;
mod output; pub use self::output::*; mod output; pub use self::output::*;
#[cfg(test)] mod test; #[cfg(test)] mod test;
#[cfg(test)] pub use proptest_derive::Arbitrary;

View file

@ -53,7 +53,7 @@ mod map; pub use self::map::*;
mod memo; pub use self::memo::*; mod memo; pub use self::memo::*;
mod stack; pub use self::stack::*; mod stack; pub use self::stack::*;
mod thunk; pub use self::thunk::*; mod thunk; pub use self::thunk::*;
mod transform; pub use self::transform::*; mod transform; //pub use self::transform::*;
/// Renders multiple things on top of each other, /// Renders multiple things on top of each other,
#[macro_export] macro_rules! lay { #[macro_export] macro_rules! lay {

View file

@ -1,4 +1,4 @@
use crate::*; //use crate::*;
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
#[derive(Debug, Default)] pub struct Memo<T, U> { #[derive(Debug, Default)] pub struct Memo<T, U> {

View file

@ -24,7 +24,7 @@ impl<E, F> Stack<E, F> {
} }
} }
impl<E: Output, F: Fn(&mut dyn FnMut(&dyn Render<E>)->())->()> Content<E> for Stack<E, F> { impl<E: Output, F: Fn(&mut dyn FnMut(&dyn Render<E>)->())->()> Content<E> for Stack<E, F> {
fn layout (&self, mut to: E::Area) -> E::Area { fn layout (&self, to: E::Area) -> E::Area {
let mut x = to.x(); let mut x = to.x();
let mut y = to.y(); let mut y = to.y();
let (mut w_used, mut w_remaining) = (E::Unit::zero(), to.w()); let (mut w_used, mut w_remaining) = (E::Unit::zero(), to.w());

View file

@ -3,7 +3,7 @@ use Value::*;
impl<S, A> Dsl<S> for When<A> where S: Eval<Ast, bool> + Eval<Ast, A> { impl<S, A> Dsl<S> for When<A> where S: Eval<Ast, bool> + Eval<Ast, A> {
fn try_provide (state: &S, source: Ast) -> Perhaps<Self> { fn try_provide (state: &S, source: Ast) -> Perhaps<Self> {
if let Exp(_, exp) = source.0 && let Some(Ast(Key(id))) = exp.peek() && *id == *"when" { if let Exp(_, mut exp) = source.0 && let Some(Ast(Key(id))) = exp.peek() && *id == *"when" {
let _ = exp.next(); let _ = exp.next();
return Ok(Some(Self( return Ok(Some(Self(
state.eval(exp.next().unwrap(), ||"when: expected condition")?, state.eval(exp.next().unwrap(), ||"when: expected condition")?,
@ -16,7 +16,7 @@ impl<S, A> Dsl<S> for When<A> where S: Eval<Ast, bool> + Eval<Ast, A> {
impl<S, A, B> Dsl<S> for Either<A, B> where S: Eval<Ast, bool> + Eval<Ast, A> + Eval<Ast, B> { impl<S, A, B> Dsl<S> for Either<A, B> where S: Eval<Ast, bool> + Eval<Ast, A> + Eval<Ast, B> {
fn try_provide (state: &S, source: Ast) -> Perhaps<Self> { fn try_provide (state: &S, source: Ast) -> Perhaps<Self> {
if let Exp(_, exp) = source.0 && let Some(Ast(Key(id))) = exp.peek() && *id == *"either" { if let Exp(_, mut exp) = source.0 && let Some(Ast(Key(id))) = exp.peek() && *id == *"either" {
let _ = exp.next(); let _ = exp.next();
return Ok(Some(Self( return Ok(Some(Self(
state.eval(exp.next().unwrap(), ||"either: expected condition")?, state.eval(exp.next().unwrap(), ||"either: expected condition")?,
@ -32,7 +32,7 @@ impl<S, A> Dsl<S> for Align<A> where S: Eval<Option<Ast>, A> {
fn try_provide (state: &S, source: Ast) -> Perhaps<Self> { fn try_provide (state: &S, source: Ast) -> Perhaps<Self> {
if let Exp(_, source) = source.0 { if let Exp(_, source) = source.0 {
let mut rest = source.clone(); let mut rest = source.clone();
return Ok(Some(match rest.next().and_then(|x|x.key()) { return Ok(Some(match rest.next().as_ref().and_then(|x|x.key()) {
Some("align/c") => Self::c(state.eval(rest.next(), ||"align/c: expected content")?), Some("align/c") => Self::c(state.eval(rest.next(), ||"align/c: expected content")?),
Some("align/x") => Self::x(state.eval(rest.next(), ||"align/x: expected content")?), Some("align/x") => Self::x(state.eval(rest.next(), ||"align/x: expected content")?),
Some("align/y") => Self::y(state.eval(rest.next(), ||"align/y: expected content")?), Some("align/y") => Self::y(state.eval(rest.next(), ||"align/y: expected content")?),
@ -55,7 +55,7 @@ impl<S, A, B> Dsl<S> for Bsp<A, B> where S: Eval<Option<Ast>, A> + Eval<Option<A
fn try_provide (state: &S, source: Ast) -> Perhaps<Self> { fn try_provide (state: &S, source: Ast) -> Perhaps<Self> {
if let Exp(_, exp) = source.0 { if let Exp(_, exp) = source.0 {
let mut rest = exp.clone(); let mut rest = exp.clone();
return Ok(Some(match rest.next().and_then(|x|x.key()) { return Ok(Some(match rest.next().as_ref().and_then(|x|x.key()) {
Some("bsp/n") => Self::n( Some("bsp/n") => Self::n(
state.eval(rest.next(), ||"bsp/n: expected content 1")?, state.eval(rest.next(), ||"bsp/n: expected content 1")?,
state.eval(rest.next(), ||"bsp/n: expected content 2")?, state.eval(rest.next(), ||"bsp/n: expected content 2")?,

View file

@ -1,5 +1,5 @@
use crate::*; use crate::{*, Direction::*};
use proptest_derive::Arbitrary; //use proptest_derive::Arbitrary;
use proptest::{prelude::*, option::of}; use proptest::{prelude::*, option::of};
proptest! { proptest! {
@ -86,7 +86,7 @@ macro_rules! test_op_transform {
if let Some(op) = match (op_x, op_y) { if let Some(op) = match (op_x, op_y) {
(Some(x), Some(y)) => Some($Op::xy(x, y, content)), (Some(x), Some(y)) => Some($Op::xy(x, y, content)),
(Some(x), None) => Some($Op::x(x, content)), (Some(x), None) => Some($Op::x(x, content)),
(Some(y), None) => Some($Op::y(y, content)), (None, Some(y)) => Some($Op::y(y, content)),
_ => None _ => None
} { } {
assert_eq!(Content::layout(&op, [x, y, w, h]), assert_eq!(Content::layout(&op, [x, y, w, h]),
@ -142,7 +142,7 @@ proptest! {
fn area_mut (&mut self) -> &mut [u16;4] { fn area_mut (&mut self) -> &mut [u16;4] {
&mut self.0 &mut self.0
} }
fn place (&mut self, _: [u16;4], _: &impl Render<TestOutput>) { fn place <T: Render<Self> + ?Sized> (&mut self, _: [u16;4], _: &T) {
() ()
} }
} }
@ -162,9 +162,9 @@ proptest! {
#[test] fn test_iter_map () { #[test] fn test_iter_map () {
struct Foo; struct Foo;
impl<T: Output> Content<T> for Foo {} impl<T: Output> Content<T> for Foo {}
fn make_map <T: Output, U: Content<T> + Send + Sync> (data: &Vec<U>) -> impl Content<T> { fn _make_map <T: Output, U: Content<T> + Send + Sync> (data: &Vec<U>) -> impl Content<T> {
Map::new(||data.iter(), |foo, index|{}) Map::new(||data.iter(), |_foo, _index|{})
} }
let data = vec![Foo, Foo, Foo]; let _data = vec![Foo, Foo, Foo];
//let map = make_map(&data); //let map = make_map(&data);
} }

View file

@ -76,7 +76,7 @@ pub(crate) fn write_quote_to (out: &mut TokenStream2, quote: TokenStream2) {
assert_eq!(x.output, output); assert_eq!(x.output, output);
// TODO // TODO
let x: crate::proc_view::ViewImpl = pq! { let _x: crate::proc_view::ViewImpl = pq! {
impl Foo { impl Foo {
/// docstring1 /// docstring1
#[tengri::view(":view1")] #[bar] fn a_view () {} #[tengri::view(":view1")] #[bar] fn a_view () {}
@ -86,7 +86,7 @@ pub(crate) fn write_quote_to (out: &mut TokenStream2, quote: TokenStream2) {
#[baz] fn is_not_view () {} #[baz] fn is_not_view () {}
} }
}; };
let expected_target: Ident = pq! { Foo }; let _expected_target: Ident = pq! { Foo };
//assert_eq!(x.target, expected_target); //assert_eq!(x.target, expected_target);
//assert_eq!(x.items.len(), 2); //assert_eq!(x.items.len(), 2);
//assert_eq!(x.items[0].item, pq! { //assert_eq!(x.items[0].item, pq! {

View file

@ -73,18 +73,18 @@ impl ToTokens for CommandDef {
out out
}); });
let matchers = exposed.values().map(|arm|{ let _matchers = exposed.values().map(|arm|{
let key = LitStr::new(&arm.to_key(), Span::call_site()); let key = LitStr::new(&arm.to_key(), Span::call_site());
let variant = { let variant = {
let mut out = TokenStream2::new(); let mut out = TokenStream2::new();
out.append(arm.to_enum_variant_ident()); out.append(arm.to_enum_variant_ident());
let ident = &arm.0; let _ident = &arm.0;
if arm.has_args() { if arm.has_args() {
out.append(Group::new(Delimiter::Brace, { out.append(Group::new(Delimiter::Brace, {
let mut out = TokenStream2::new(); let mut out = TokenStream2::new();
for (arg, ty) in arm.args() { for (arg, _ty) in arm.args() {
write_quote_to(&mut out, quote! { write_quote_to(&mut out, quote! {
#arg: Take::take_or_fail(self, words)?, #arg: Dsl::try_provide(self, words)?,
}); });
} }
out out
@ -149,8 +149,8 @@ impl ToTokens for CommandDef {
} }
} }
/// Generated by [tengri_proc::command]. /// Generated by [tengri_proc::command].
impl ::tengri::dsl::Take<#state> for #command_enum { impl ::tengri::dsl::Dsl<#state> for #command_enum {
fn take (state: &#state, mut words: ::tengri::dsl::Cst) -> Perhaps<Self> { fn try_provide (state: &#state, mut words: ::tengri::dsl::Ast) -> Perhaps<Self> {
let mut words = words.clone(); let mut words = words.clone();
let token = words.next(); let token = words.next();
todo!()//Ok(match token { #(#matchers)* _ => None }) todo!()//Ok(match token { #(#matchers)* _ => None })
@ -193,7 +193,7 @@ impl CommandArm {
unreachable!("only typed args should be present at this position"); unreachable!("only typed args should be present at this position");
}) })
} }
fn to_enum_variant_def (&self) -> TokenStream2 { fn _to_enum_variant_def (&self) -> TokenStream2 {
let mut out = TokenStream2::new(); let mut out = TokenStream2::new();
out.append(self.to_enum_variant_ident()); out.append(self.to_enum_variant_ident());
//let ident = &self.0; //let ident = &self.0;

View file

@ -85,8 +85,8 @@ impl ToTokens for ExposeImpl {
}); });
write_quote_to(out, quote! { write_quote_to(out, quote! {
/// Generated by [tengri_proc::expose]. /// Generated by [tengri_proc::expose].
impl ::tengri::dsl::Take<#state> for #t { impl ::tengri::dsl::Dsl<#state> for #t {
fn take (state: &#state, mut words: ::tengri::dsl::Cst) -> Perhaps<Self> { fn try_provide (state: &#state, mut words: ::tengri::dsl::Ast) -> Perhaps<Self> {
Ok(Some(match words.next().map(|x|x.value) { Ok(Some(match words.next().map(|x|x.value) {
#predefined #predefined
#(#values)* #(#values)*

View file

@ -45,7 +45,7 @@ impl ToTokens for ViewDef {
// that operate over constants and symbols. // that operate over constants and symbols.
let builtin = builtins_with_boxes_output(quote! { #output }).map(|builtin|quote! { let builtin = builtins_with_boxes_output(quote! { #output }).map(|builtin|quote! {
::tengri::dsl::Value::Exp(_, expr) => return Ok(Some( ::tengri::dsl::Value::Exp(_, expr) => return Ok(Some(
#builtin::take_or_fail(state, expr, ||"failed to load builtin")?.boxed() #builtin::try_provide(state, expr, ||"failed to load builtin")?.boxed()
)), )),
}); });
// Symbols are handled by user-taked functions // Symbols are handled by user-taked functions
@ -63,11 +63,8 @@ impl ToTokens for ViewDef {
/// Makes [#self_ty] able to construct the [Render]able /// Makes [#self_ty] able to construct the [Render]able
/// which might correspond to a given [TokenStream], /// which might correspond to a given [TokenStream],
/// while taking [#self_ty]'s state into consideration. /// while taking [#self_ty]'s state into consideration.
impl<'source, 'state: 'source> impl<'state> ::tengri::dsl::Dsl<Box<dyn Render<#output> + 'state>> for #self_ty {
Take<'state, 'source, #self_ty> fn try_provide (state: &'state #self_ty, mut words: ::tengri::dsl::Ast) -> Perhaps<Box<dyn Render<#output> + 'state>> {
for Box<dyn Render<#output> + 'state>
{
fn take (state: &'state #self_ty, mut words: Cst<'source>) -> Perhaps<Self> {
Ok(if let Some(::tengri::dsl::Token { value, .. }) = words.peek() { Ok(if let Some(::tengri::dsl::Token { value, .. }) = words.peek() {
match value { #(#builtin)* #(#exposed)* _ => None } match value { #(#builtin)* #(#exposed)* _ => None }
} else { } else {
@ -79,11 +76,11 @@ impl ToTokens for ViewDef {
} }
} }
fn builtins_with_holes () -> impl Iterator<Item=TokenStream2> { fn _builtins_with_holes () -> impl Iterator<Item=TokenStream2> {
builtins_with(quote! { _ }, quote! { _ }) builtins_with(quote! { _ }, quote! { _ })
} }
fn builtins_with_boxes () -> impl Iterator<Item=TokenStream2> { fn _builtins_with_boxes () -> impl Iterator<Item=TokenStream2> {
builtins_with(quote! { _ }, quote! { Box<dyn Render<_>> }) builtins_with(quote! { _ }, quote! { Box<dyn Render<_>> })
} }

View file

@ -5,96 +5,4 @@ pub use ::tengri_core::*;
#[cfg(feature="tui")] pub use ::tengri_tui as tui; #[cfg(feature="tui")] pub use ::tengri_tui as tui;
#[cfg(test)] extern crate tengri_proc; #[cfg(test)] extern crate tengri_proc;
#[cfg(test)] #[test] fn test_subcommand () -> Usually<()> { #[cfg(test)] mod test;
use crate::input::{Command, InputMap, KeyMap, Handle, handle};
use crate::dsl::TokenIter;
use crate::tui::TuiIn;
use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState};
//use crate::input::*;
//use crate::dsl::*;
struct Test {
keys: InputMap<'static, Test, TestCommand, TuiIn, TokenIter<'static>>
}
handle!(TuiIn: |self: Test, input|if let Some(command) = self.keys.command(self, input) {
Ok(Some(true))
} else {
Ok(None)
});
#[tengri_proc::command(Test)] impl TestCommand {
fn do_thing (state: &mut Test) -> Perhaps<Self> {
Ok(None)
}
fn do_thing_arg (state: &mut Test, arg: usize) -> Perhaps<Self> {
Ok(None)
}
fn do_sub (state: &mut Test, command: TestSubcommand) -> Perhaps<Self> {
Ok(command.execute(state)?.map(|command|Self::DoSub { command }))
}
}
#[tengri_proc::command(Test)] impl TestSubcommand {
fn do_other_thing (state: &mut Test) -> Perhaps<Self> {
Ok(None)
}
fn do_other_thing_arg (state: &mut Test, arg: usize) -> Perhaps<Self> {
Ok(None)
}
}
let mut test = Test {
keys: InputMap::new("
(@a do-thing)
(@b do-thing-arg 0)
(@c do-sub do-other-thing)
(@d do-sub do-other-thing-arg 0)
".into())
};
assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent {
kind: KeyEventKind::Press,
code: KeyCode::Char('a'),
modifiers: KeyModifiers::NONE,
state: KeyEventState::NONE,
})))?);
assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent {
kind: KeyEventKind::Press,
code: KeyCode::Char('b'),
modifiers: KeyModifiers::NONE,
state: KeyEventState::NONE,
})))?);
assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent {
kind: KeyEventKind::Press,
code: KeyCode::Char('c'),
modifiers: KeyModifiers::NONE,
state: KeyEventState::NONE,
})))?);
assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent {
kind: KeyEventKind::Press,
code: KeyCode::Char('d'),
modifiers: KeyModifiers::NONE,
state: KeyEventState::NONE,
})))?);
assert_eq!(None, test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent {
kind: KeyEventKind::Press,
code: KeyCode::Char('z'),
modifiers: KeyModifiers::NONE,
state: KeyEventState::NONE,
})))?);
Ok(())
}
//FIXME:
//#[cfg(test)] #[test] fn test_dsl_context () {
//use crate::dsl::{Dsl, Value};
//struct Test;
//#[tengri_proc::expose]
//impl Test {
//fn some_bool (&self) -> bool {
//true
//}
//}
//assert_eq!(Dsl::get(&Test, &Value::Sym(":false")), Some(false));
//assert_eq!(Dsl::get(&Test, &Value::Sym(":true")), Some(true));
//assert_eq!(Dsl::get(&Test, &Value::Sym(":some-bool")), Some(true));
//assert_eq!(Dsl::get(&Test, &Value::Sym(":missing-bool")), None);
//assert_eq!(Dsl::get(&Test, &Value::Num(0)), Some(false));
//assert_eq!(Dsl::get(&Test, &Value::Num(1)), Some(true));
//}

97
tengri/src/test.rs Normal file
View file

@ -0,0 +1,97 @@
use crate::*;
#[test] fn test_subcommand () -> Usually<()> {
use crate::input::{Command, Handle, handle};
//use crate::dsl::TokenIter;
use crate::tui::TuiIn;
use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState};
//use crate::input::*;
//use crate::dsl::*;
struct Test {
//keys: InputMap<'static, Test, TestCommand, TuiIn, TokenIter<'static>>
}
handle!(TuiIn: |self: Test, input|if let Some(command) = self.keys.command(self, input) {
Ok(Some(true))
} else {
Ok(None)
});
#[tengri_proc::command(Test)]
impl TestCommand {
fn do_thing (_state: &mut Test) -> Perhaps<Self> {
Ok(None)
}
fn do_thing_arg (_state: &mut Test, _arg: usize) -> Perhaps<Self> {
Ok(None)
}
fn do_sub (state: &mut Test, command: TestSubcommand) -> Perhaps<Self> {
Ok(command.execute(state)?.map(|command|Self::DoSub { command }))
}
}
#[tengri_proc::command(Test)]
impl TestSubcommand {
fn do_other_thing (_state: &mut Test) -> Perhaps<Self> {
Ok(None)
}
fn do_other_thing_arg (_state: &mut Test, _arg: usize) -> Perhaps<Self> {
Ok(None)
}
}
let mut test = Test {
keys: InputMap::new("
(@a do-thing)
(@b do-thing-arg 0)
(@c do-sub do-other-thing)
(@d do-sub do-other-thing-arg 0)
".into())
};
assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent {
kind: KeyEventKind::Press,
code: KeyCode::Char('a'),
modifiers: KeyModifiers::NONE,
state: KeyEventState::NONE,
})))?);
assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent {
kind: KeyEventKind::Press,
code: KeyCode::Char('b'),
modifiers: KeyModifiers::NONE,
state: KeyEventState::NONE,
})))?);
assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent {
kind: KeyEventKind::Press,
code: KeyCode::Char('c'),
modifiers: KeyModifiers::NONE,
state: KeyEventState::NONE,
})))?);
assert_eq!(Some(true), test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent {
kind: KeyEventKind::Press,
code: KeyCode::Char('d'),
modifiers: KeyModifiers::NONE,
state: KeyEventState::NONE,
})))?);
assert_eq!(None, test.handle(&TuiIn(Default::default(), Event::Key(KeyEvent {
kind: KeyEventKind::Press,
code: KeyCode::Char('z'),
modifiers: KeyModifiers::NONE,
state: KeyEventState::NONE,
})))?);
Ok(())
}
//FIXME:
//#[cfg(test)] #[test] fn test_dsl_context () {
//use crate::dsl::{Dsl, Value};
//struct Test;
//#[tengri_proc::expose]
//impl Test {
//fn some_bool (&self) -> bool {
//true
//}
//}
//assert_eq!(Dsl::get(&Test, &Value::Sym(":false")), Some(false));
//assert_eq!(Dsl::get(&Test, &Value::Sym(":true")), Some(true));
//assert_eq!(Dsl::get(&Test, &Value::Sym(":some-bool")), Some(true));
//assert_eq!(Dsl::get(&Test, &Value::Sym(":missing-bool")), None);
//assert_eq!(Dsl::get(&Test, &Value::Num(0)), Some(false));
//assert_eq!(Dsl::get(&Test, &Value::Num(1)), Some(true));
//}

View file

@ -1,6 +1,6 @@
use tengri::{self, Usually, Perhaps, input::*, output::*, tui::*, dsl::*}; use tengri::{self, Usually, Perhaps, input::*, output::*, tui::*, dsl::*};
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use crossterm::event::{*, KeyCode::*}; //use crossterm::event::{*, KeyCode::*};
use crate::ratatui::style::Color; use crate::ratatui::style::Color;
fn main () -> Usually<()> { fn main () -> Usually<()> {
@ -13,23 +13,23 @@ fn main () -> Usually<()> {
const KEYMAP: &str = "(@left prev) (@right next)"; const KEYMAP: &str = "(@left prev) (@right next)";
const EXAMPLES: &'static [&'static str] = &[ const EXAMPLES: &'static [&'static str] = &[
include_str!("edn01.edn"), include_str!("edn/edn01.edn"),
include_str!("edn02.edn"), include_str!("edn/edn02.edn"),
include_str!("edn03.edn"), include_str!("edn/edn03.edn"),
include_str!("edn04.edn"), include_str!("edn/edn04.edn"),
include_str!("edn05.edn"), include_str!("edn/edn05.edn"),
include_str!("edn06.edn"), include_str!("edn/edn06.edn"),
include_str!("edn07.edn"), include_str!("edn/edn07.edn"),
include_str!("edn08.edn"), include_str!("edn/edn08.edn"),
include_str!("edn09.edn"), include_str!("edn/edn09.edn"),
include_str!("edn10.edn"), include_str!("edn/edn10.edn"),
include_str!("edn11.edn"), include_str!("edn/edn11.edn"),
include_str!("edn12.edn"), include_str!("edn/edn12.edn"),
//include_str!("edn13.edn"), //include_str!("edn/edn13.edn"),
include_str!("edn14.edn"), include_str!("edn/edn14.edn"),
include_str!("edn15.edn"), include_str!("edn/edn15.edn"),
include_str!("edn16.edn"), include_str!("edn/edn16.edn"),
include_str!("edn17.edn"), include_str!("edn/edn17.edn"),
]; ];
handle!(TuiIn: |self: Example, input|{ handle!(TuiIn: |self: Example, input|{
@ -63,7 +63,7 @@ impl ExampleCommand {
} }
} }
view!(TuiOut: |self: Example|{ content!(TuiOut: |self: Example|{
let index = self.0 + 1; let index = self.0 + 1;
let wh = self.1.wh(); let wh = self.1.wh();
let src = EXAMPLES.get(self.0).unwrap_or(&""); let src = EXAMPLES.get(self.0).unwrap_or(&"");
@ -72,12 +72,29 @@ view!(TuiOut: |self: Example|{
let code = Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", src)))); let code = Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", src))));
let content = Tui::bg(Color::Rgb(10, 10, 60), View(self, TokenIter::new(src))); let content = Tui::bg(Color::Rgb(10, 10, 60), View(self, TokenIter::new(src)));
self.1.of(Bsp::s(title, Bsp::n(""/*code*/, content))) self.1.of(Bsp::s(title, Bsp::n(""/*code*/, content)))
}; {
":title" => Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, EXAMPLES.len())))).boxed(),
":code" => Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", EXAMPLES[self.0])))).boxed(),
":hello" => Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed(),
":world" => Tui::bg(Color::Rgb(100, 10, 10), "world").boxed(),
":hello-world" => "Hello world!".boxed(),
":map-e" => Map::east(5u16, ||0..5u16, |n, i|format!("{n}")).boxed(),
":map-s" => Map::south(5u16, ||0..5u16, |n, i|format!("{n}")).boxed(),
}); });
#[tengri_proc::view(TuiOut)]
impl Example {
pub fn title (&self) -> impl Content<TuiOut> + use<'_> {
Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, EXAMPLES.len())))).boxed()
}
pub fn code (&self) -> impl Content<TuiOut> + use<'_> {
Tui::bg(Color::Rgb(10, 60, 10), Push::y(2, Align::n(format!("{}", EXAMPLES[self.0])))).boxed()
}
pub fn hello (&self) -> impl Content<TuiOut> + use<'_> {
Tui::bg(Color::Rgb(10, 100, 10), "Hello").boxed()
}
pub fn world (&self) -> impl Content<TuiOut> + use<'_> {
Tui::bg(Color::Rgb(100, 10, 10), "world").boxed()
}
pub fn hello_world (&self) -> impl Content<TuiOut> + use<'_> {
"Hello world!".boxed()
}
pub fn map_e (&self) -> impl Content<TuiOut> + use<'_> {
Map::east(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed()
}
pub fn map_s (&self) -> impl Content<TuiOut> + use<'_> {
Map::south(5u16, ||0..5u16, |n, _i|format!("{n}")).boxed()
}
}

View file

@ -36,7 +36,7 @@ pub(crate) use std::io::{stdout, Stdout};
#[cfg(test)] #[test] fn test_tui_engine () -> Usually<()> { #[cfg(test)] #[test] fn test_tui_engine () -> Usually<()> {
use crate::*; use crate::*;
use std::sync::{Arc, RwLock}; //use std::sync::{Arc, RwLock};
struct TestComponent(String); struct TestComponent(String);
impl Content<TuiOut> for TestComponent { impl Content<TuiOut> for TestComponent {
fn content (&self) -> impl Render<TuiOut> { fn content (&self) -> impl Render<TuiOut> {
@ -44,21 +44,21 @@ pub(crate) use std::io::{stdout, Stdout};
} }
} }
impl Handle<TuiIn> for TestComponent { impl Handle<TuiIn> for TestComponent {
fn handle (&mut self, from: &TuiIn) -> Perhaps<bool> { fn handle (&mut self, _from: &TuiIn) -> Perhaps<bool> {
Ok(None) Ok(None)
} }
} }
let engine = Tui::new()?; let engine = Tui::new()?;
engine.read().unwrap().exited.store(true, std::sync::atomic::Ordering::Relaxed); engine.read().unwrap().exited.store(true, std::sync::atomic::Ordering::Relaxed);
let state = TestComponent("hello world".into()); let state = TestComponent("hello world".into());
let state = std::sync::Arc::new(std::sync::RwLock::new(state)); let _state = std::sync::Arc::new(std::sync::RwLock::new(state));
//engine.run(&state)?; //engine.run(&state)?;
Ok(()) Ok(())
} }
#[cfg(test)] #[test] fn test_parse_key () { #[cfg(test)] #[test] fn test_parse_key () {
use KeyModifiers as Mods; //use KeyModifiers as Mods;
let test = |x: &str, y|assert_eq!(KeyMatcher::new(x).build(), Some(Event::Key(y))); let _test = |x: &str, y|assert_eq!(KeyMatcher::new(x).build(), Some(Event::Key(y)));
//test(":x", //test(":x",
//KeyEvent::new(KeyCode::Char('x'), Mods::NONE)); //KeyEvent::new(KeyCode::Char('x'), Mods::NONE));
//test(":ctrl-x", //test(":ctrl-x",

View file

@ -13,12 +13,12 @@ macro_rules! impl_content_layout_render {
} }
mod tui_border; pub use self::tui_border::*; mod tui_border; pub use self::tui_border::*;
mod tui_button; pub use self::tui_button::*; mod tui_button; //pub use self::tui_button::*;
mod tui_color; pub use self::tui_color::*; mod tui_color; pub use self::tui_color::*;
mod tui_field; pub use self::tui_field::*; mod tui_field; pub use self::tui_field::*;
mod tui_phat; pub use self::tui_phat::*; mod tui_phat; pub use self::tui_phat::*;
mod tui_repeat; pub use self::tui_repeat::*; mod tui_repeat; pub use self::tui_repeat::*;
mod tui_number; pub use self::tui_number::*; mod tui_number; //pub use self::tui_number::*;
mod tui_scroll; pub use self::tui_scroll::*; mod tui_scroll; pub use self::tui_scroll::*;
mod tui_string; pub use self::tui_string::*; mod tui_string; pub use self::tui_string::*;
mod tui_style; pub use self::tui_style::*; mod tui_style; pub use self::tui_style::*;

View file

@ -1 +1 @@
use crate::{*, Color::*}; //use crate::{*, Color::*};

View file

@ -3,7 +3,7 @@ use crate::*;
pub struct FieldH<T, U>(pub ItemTheme, pub T, pub U); pub struct FieldH<T, U>(pub ItemTheme, pub T, pub U);
impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldH<T, U> { impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldH<T, U> {
fn content (&self) -> impl Render<TuiOut> { fn content (&self) -> impl Render<TuiOut> {
let Self(ItemTheme { darkest, dark, lighter, lightest, .. }, title, value) = self; let Self(ItemTheme { darkest, dark, lightest, .. }, title, value) = self;
row!( row!(
Tui::fg_bg(dark.rgb, darkest.rgb, ""), Tui::fg_bg(dark.rgb, darkest.rgb, ""),
Tui::fg_bg(lightest.rgb, dark.rgb, title), Tui::fg_bg(lightest.rgb, dark.rgb, title),
@ -16,7 +16,7 @@ impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldH<T, U> {
pub struct FieldV<T, U>(pub ItemTheme, pub T, pub U); pub struct FieldV<T, U>(pub ItemTheme, pub T, pub U);
impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldV<T, U> { impl<T: Content<TuiOut>, U: Content<TuiOut>> Content<TuiOut> for FieldV<T, U> {
fn content (&self) -> impl Render<TuiOut> { fn content (&self) -> impl Render<TuiOut> {
let Self(ItemTheme { darkest, dark, lighter, lightest, .. }, title, value) = self; let Self(ItemTheme { darkest, dark, lightest, .. }, title, value) = self;
Bsp::n( Bsp::n(
Align::w(Tui::bg(darkest.rgb, Tui::fg(lightest.rgb, Tui::bold(true, value)))), Align::w(Tui::bg(darkest.rgb, Tui::fg(lightest.rgb, Tui::bold(true, value)))),
Fill::x(Align::w(row!( Fill::x(Align::w(row!(
@ -60,7 +60,7 @@ impl<T, U> Field<T, U> {
value_align: None, value_align: None,
} }
} }
fn label <L> ( pub fn label <L> (
self, self,
label: Option<L>, label: Option<L>,
align: Option<Direction>, align: Option<Direction>,
@ -75,7 +75,7 @@ impl<T, U> Field<T, U> {
..self ..self
} }
} }
fn value <V> ( pub fn value <V> (
self, self,
value: Option<V>, value: Option<V>,
align: Option<Direction>, align: Option<Direction>,

View file

@ -1,5 +1,5 @@
use crate::*; use crate::*;
render!(TuiOut: |self: u64, to|todo!()); render!(TuiOut: |self: u64, _to|todo!());
render!(TuiOut: |self: f64, to|todo!()); render!(TuiOut: |self: f64, _to|todo!());

View file

@ -56,13 +56,13 @@ impl TuiIn {
} }
} }
#[cfg(feature = "dsl")] //#[cfg(feature = "dsl")]
impl DslInput for TuiIn { //impl DslInput for TuiIn {
fn matches_dsl (&self, token: &str) -> bool { //fn matches_dsl (&self, token: &str) -> bool {
if let Some(event) = KeyMatcher::new(token).build() { //if let Some(event) = KeyMatcher::new(token).build() {
&event == self.event() //&event == self.event()
} else { //} else {
false //false
} //}
} //}
} //}