wip: updating tests
Some checks are pending
/ build (push) Waiting to run

This commit is contained in:
🪞👃🪞 2025-06-12 21:17:08 +03:00
parent 21832453d9
commit 17506726cb
36 changed files with 280 additions and 271 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'"
grcov-binary := "--binary-path ./target/coverage/deps/"
grcov-ignore := "--ignore-not-existing --ignore '../*' --ignore \"/*\" --ignore 'target/*'"
bacon:
{{covfig}} bacon -s
cov:
{{covfig}} time cargo test -j4 --workspace --profile coverage
rm -rf target/coverage/html || true

View file

@ -3,6 +3,10 @@ use crate::*;
/// CST stores strings as source references and expressions as new [SourceIter] instances.
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.
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub struct CstMeta<'source> {
pub source: &'source str,
@ -10,10 +14,6 @@ pub type CstValue<'source> = Value<&'source str, SourceIter<'source>>;
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> {
pub const fn new (
source: &'source str, start: usize, length: usize, value: CstValue<'source>

View file

@ -7,25 +7,32 @@ pub trait DslIter {
fn rest (self) -> Vec<Self::Token>;
}
#[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()
/// 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 }
}
fn next (&mut self) -> Option<Ast> {
self.0.pop_front()
impl$(<$l>)? ConstIntoIter for $Struct {
type Kind = IsIteratorKind;
type Item = $Item;
type IntoIter = Self;
}
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())
/// 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)
}
}
@ -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> {
fn from (source: &'source str) -> Self{
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));
#[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 {
use crate::*;
//use proptest::prelude::*;
#[test] fn test_iters () {
let mut iter = crate::SourceIter::new(&":foo :bar");
let _ = iter.next();
let mut iter = crate::TokenIter::new(&":foo :bar");
let _ = iter.next();
}
#[test] const fn test_const_iters () {
let mut iter = crate::SourceIter::new(&":foo :bar");
let iter = crate::SourceConstIter::new(&":foo :bar");
let _ = iter.next();
}
#[test] fn test_num () {
let digit = to_digit('0');
let digit = to_digit('x');
let number = to_number(&"123");
let number = to_number(&"12asdf3");
let _digit = to_digit('0');
let _digit = to_digit('x');
let _number = to_number(&"123");
let _number = to_number(&"12asdf3");
}
//proptest! {
//#[test] fn proptest_source_iter (
@ -33,67 +33,54 @@
//}
}
#[cfg(test)] mod test_token_prop {
use proptest::prelude::*;
proptest! {
#[test] fn test_token_prop (
source in "\\PC*",
start in usize::MIN..usize::MAX,
length in usize::MIN..usize::MAX,
) {
let token = crate::Token {
source: &source,
start,
length,
value: crate::Value::Nil
};
let _ = token.slice();
}
}
}
//#[cfg(test)] mod test_token_prop {
//use crate::{CstToken, CstMeta, Value::*};
//use proptest::prelude::*;
//proptest! {
//#[test] fn test_token_prop (
//source in "\\PC*",
//start in usize::MIN..usize::MAX,
//length in usize::MIN..usize::MAX,
//) {
//let token = CstToken(Nil, CstMeta { source: &source, start, length });
//let _ = token.slice();
//}
//}
//}
#[cfg(test)] #[test] fn test_token () -> Result<(), Box<dyn std::error::Error>> {
use crate::Value::*;
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();
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();
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();
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, SourceIter(src).next());
let src = " \n \r \t ";
assert_eq!(None, SourceIter(src).next());
let src = "7";
assert_eq!(Num(7), SourceIter(src).next().unwrap().0.value);
let src = " 100 ";
assert_eq!(Num(100), SourceIter(src).next().unwrap().0.value);
let src = " 9a ";
assert_eq!(Err(Unexpected('a')), SourceIter(src).next().unwrap().0.value);
let src = " :123foo ";
assert_eq!(Sym(":123foo"), SourceIter(src).next().unwrap().0.value);
let src = " \r\r\r\n\n\n@bar456\t\t\t\t\t\t";
assert_eq!(Sym("@bar456"), SourceIter(src).next().unwrap().0.value);
let src = "foo123";
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);
assert_eq!(None,
SourceIter::new("").next());
assert_eq!(None,
SourceIter::new(" \n \r \t ").next());
assert_eq!(&Num(7),
SourceIter::new("7").next().unwrap().0.value());
assert_eq!(&Num(100),
SourceIter::new(" 100 ").next().unwrap().0.value());
assert_eq!(&Err(Unexpected('a')),
SourceIter::new(" 9a ").next().unwrap().0.value());
assert_eq!(&Sym(":123foo"),
SourceIter::new(" :123foo ").next().unwrap().0.value());
assert_eq!(&Sym("@bar456"),
SourceIter::new(" \r\r\r\n\n\n@bar456\t\t\t\t\t\t").next().unwrap().0.value());
assert_eq!(&Key("foo123"),
SourceIter::new("foo123").next().unwrap().0.value());
assert_eq!(&Key("foo/bar"),
SourceIter::new("foo/bar").next().unwrap().0.value());
assert_eq!(&Str("foo/bar"),
SourceIter::new("\"foo/bar\"").next().unwrap().0.value());
assert_eq!(&Str("foo/bar"),
SourceIter::new(" \"foo/bar\" ").next().unwrap().0.value());
Ok(())
}
@ -108,7 +95,7 @@
//let mut expr = view.peek();
//assert_eq!(view.0.0, source);
//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!("{:#?}", expr);

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<()> {
let keymap = SourceIter::new("");
let _keymap = SourceIter::new("");
Ok(())
}

View file

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

View file

@ -1,5 +1,5 @@
use crate::*;
use proptest_derive::Arbitrary;
use crate::{*, Direction::*};
//use proptest_derive::Arbitrary;
use proptest::{prelude::*, option::of};
proptest! {
@ -86,7 +86,7 @@ macro_rules! test_op_transform {
if let Some(op) = match (op_x, op_y) {
(Some(x), Some(y)) => Some($Op::xy(x, y, 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
} {
assert_eq!(Content::layout(&op, [x, y, w, h]),
@ -142,7 +142,7 @@ proptest! {
fn area_mut (&mut self) -> &mut [u16;4] {
&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 () {
struct Foo;
impl<T: Output> Content<T> for Foo {}
fn make_map <T: Output, U: Content<T> + Send + Sync> (data: &Vec<U>) -> impl Content<T> {
Map::new(||data.iter(), |foo, index|{})
fn _make_map <T: Output, U: Content<T> + Send + Sync> (data: &Vec<U>) -> impl Content<T> {
Map::new(||data.iter(), |_foo, _index|{})
}
let data = vec![Foo, Foo, Foo];
let _data = vec![Foo, Foo, Foo];
//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);
// TODO
let x: crate::proc_view::ViewImpl = pq! {
let _x: crate::proc_view::ViewImpl = pq! {
impl Foo {
/// docstring1
#[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 () {}
}
};
let expected_target: Ident = pq! { Foo };
let _expected_target: Ident = pq! { Foo };
//assert_eq!(x.target, expected_target);
//assert_eq!(x.items.len(), 2);
//assert_eq!(x.items[0].item, pq! {

View file

@ -84,7 +84,7 @@ impl ToTokens for CommandDef {
let mut out = TokenStream2::new();
for (arg, _ty) in arm.args() {
write_quote_to(&mut out, quote! {
#arg: Take::take_or_fail(self, words)?,
#arg: Dsl::try_provide(self, words)?,
});
}
out
@ -149,8 +149,8 @@ impl ToTokens for CommandDef {
}
}
/// Generated by [tengri_proc::command].
impl ::tengri::dsl::Take<#state> for #command_enum {
fn take (state: &#state, mut words: ::tengri::dsl::Cst) -> Perhaps<Self> {
impl ::tengri::dsl::Dsl<#state> for #command_enum {
fn try_provide (state: &#state, mut words: ::tengri::dsl::Ast) -> Perhaps<Self> {
let mut words = words.clone();
let token = words.next();
todo!()//Ok(match token { #(#matchers)* _ => None })

View file

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

View file

@ -45,7 +45,7 @@ impl ToTokens for ViewDef {
// that operate over constants and symbols.
let builtin = builtins_with_boxes_output(quote! { #output }).map(|builtin|quote! {
::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
@ -63,11 +63,8 @@ impl ToTokens for ViewDef {
/// Makes [#self_ty] able to construct the [Render]able
/// which might correspond to a given [TokenStream],
/// while taking [#self_ty]'s state into consideration.
impl<'source, 'state: 'source>
Take<'state, 'source, #self_ty>
for Box<dyn Render<#output> + 'state>
{
fn take (state: &'state #self_ty, mut words: Cst<'source>) -> Perhaps<Self> {
impl<'state> ::tengri::dsl::Dsl<Box<dyn Render<#output> + 'state>> for #self_ty {
fn try_provide (state: &'state #self_ty, mut words: ::tengri::dsl::Ast) -> Perhaps<Box<dyn Render<#output> + 'state>> {
Ok(if let Some(::tengri::dsl::Token { value, .. }) = words.peek() {
match value { #(#builtin)* #(#exposed)* _ => None }
} else {

View file

@ -5,96 +5,4 @@ pub use ::tengri_core::*;
#[cfg(feature="tui")] pub use ::tengri_tui as tui;
#[cfg(test)] extern crate tengri_proc;
#[cfg(test)] #[test] fn test_subcommand () -> Usually<()> {
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));
//}
#[cfg(test)] mod test;

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 std::sync::{Arc, RwLock};
use crossterm::event::{*, KeyCode::*};
//use crossterm::event::{*, KeyCode::*};
use crate::ratatui::style::Color;
fn main () -> Usually<()> {
@ -13,23 +13,23 @@ fn main () -> Usually<()> {
const KEYMAP: &str = "(@left prev) (@right next)";
const EXAMPLES: &'static [&'static str] = &[
include_str!("edn01.edn"),
include_str!("edn02.edn"),
include_str!("edn03.edn"),
include_str!("edn04.edn"),
include_str!("edn05.edn"),
include_str!("edn06.edn"),
include_str!("edn07.edn"),
include_str!("edn08.edn"),
include_str!("edn09.edn"),
include_str!("edn10.edn"),
include_str!("edn11.edn"),
include_str!("edn12.edn"),
//include_str!("edn13.edn"),
include_str!("edn14.edn"),
include_str!("edn15.edn"),
include_str!("edn16.edn"),
include_str!("edn17.edn"),
include_str!("edn/edn01.edn"),
include_str!("edn/edn02.edn"),
include_str!("edn/edn03.edn"),
include_str!("edn/edn04.edn"),
include_str!("edn/edn05.edn"),
include_str!("edn/edn06.edn"),
include_str!("edn/edn07.edn"),
include_str!("edn/edn08.edn"),
include_str!("edn/edn09.edn"),
include_str!("edn/edn10.edn"),
include_str!("edn/edn11.edn"),
include_str!("edn/edn12.edn"),
//include_str!("edn/edn13.edn"),
include_str!("edn/edn14.edn"),
include_str!("edn/edn15.edn"),
include_str!("edn/edn16.edn"),
include_str!("edn/edn17.edn"),
];
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 wh = self.1.wh();
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 content = Tui::bg(Color::Rgb(10, 10, 60), View(self, TokenIter::new(src)));
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<()> {
use crate::*;
use std::sync::{Arc, RwLock};
//use std::sync::{Arc, RwLock};
struct TestComponent(String);
impl Content<TuiOut> for TestComponent {
fn content (&self) -> impl Render<TuiOut> {
@ -44,21 +44,21 @@ pub(crate) use std::io::{stdout, Stdout};
}
}
impl Handle<TuiIn> for TestComponent {
fn handle (&mut self, from: &TuiIn) -> Perhaps<bool> {
fn handle (&mut self, _from: &TuiIn) -> Perhaps<bool> {
Ok(None)
}
}
let engine = Tui::new()?;
engine.read().unwrap().exited.store(true, std::sync::atomic::Ordering::Relaxed);
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)?;
Ok(())
}
#[cfg(test)] #[test] fn test_parse_key () {
use KeyModifiers as Mods;
let test = |x: &str, y|assert_eq!(KeyMatcher::new(x).build(), Some(Event::Key(y)));
//use KeyModifiers as Mods;
let _test = |x: &str, y|assert_eq!(KeyMatcher::new(x).build(), Some(Event::Key(y)));
//test(":x",
//KeyEvent::new(KeyCode::Char('x'), Mods::NONE));
//test(":ctrl-x",

View file

@ -60,7 +60,7 @@ impl<T, U> Field<T, U> {
value_align: None,
}
}
fn label <L> (
pub fn label <L> (
self,
label: Option<L>,
align: Option<Direction>,
@ -75,7 +75,7 @@ impl<T, U> Field<T, U> {
..self
}
}
fn value <V> (
pub fn value <V> (
self,
value: Option<V>,
align: Option<Direction>,

View file

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