mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-07 12:16:44 +01:00
Compare commits
5 commits
cb8fd26922
...
faecc2c304
| Author | SHA1 | Date | |
|---|---|---|---|
| faecc2c304 | |||
| 1868736597 | |||
| ed772b9872 | |||
| f18e01c220 | |||
| 8dda576c9d |
20 changed files with 249 additions and 205 deletions
28
Cargo.lock
generated
28
Cargo.lock
generated
|
|
@ -46,9 +46,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
|||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.74"
|
||||
version = "0.3.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
|
||||
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
|
|
@ -286,9 +286,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
|
@ -757,9 +757,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.11"
|
||||
version = "0.5.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
|
||||
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
|
@ -834,9 +834,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
|
||||
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
|
|
@ -926,7 +926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.2",
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix 1.0.7",
|
||||
"windows-sys 0.59.0",
|
||||
|
|
@ -938,6 +938,7 @@ version = "0.13.0"
|
|||
dependencies = [
|
||||
"crossterm",
|
||||
"tengri",
|
||||
"tengri_core",
|
||||
"tengri_dsl",
|
||||
"tengri_input",
|
||||
"tengri_output",
|
||||
|
|
@ -945,6 +946,10 @@ dependencies = [
|
|||
"tengri_tui",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tengri_core"
|
||||
version = "0.13.0"
|
||||
|
||||
[[package]]
|
||||
name = "tengri_dsl"
|
||||
version = "0.13.0"
|
||||
|
|
@ -952,6 +957,7 @@ dependencies = [
|
|||
"itertools 0.14.0",
|
||||
"konst",
|
||||
"proptest",
|
||||
"tengri_core",
|
||||
"tengri_tui",
|
||||
"thiserror",
|
||||
]
|
||||
|
|
@ -960,6 +966,7 @@ dependencies = [
|
|||
name = "tengri_input"
|
||||
version = "0.13.0"
|
||||
dependencies = [
|
||||
"tengri_core",
|
||||
"tengri_dsl",
|
||||
"tengri_tui",
|
||||
]
|
||||
|
|
@ -971,6 +978,7 @@ dependencies = [
|
|||
"proptest",
|
||||
"proptest-derive",
|
||||
"tengri",
|
||||
"tengri_core",
|
||||
"tengri_dsl",
|
||||
"tengri_tui",
|
||||
]
|
||||
|
|
@ -983,6 +991,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"tengri_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -998,6 +1007,7 @@ dependencies = [
|
|||
"rand",
|
||||
"ratatui",
|
||||
"tengri",
|
||||
"tengri_core",
|
||||
"tengri_dsl",
|
||||
"tengri_input",
|
||||
"tengri_output",
|
||||
|
|
|
|||
36
Cargo.toml
36
Cargo.toml
|
|
@ -1,11 +1,15 @@
|
|||
[workspace.package]
|
||||
version = "0.13.0"
|
||||
edition = "2024"
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
[profile.coverage]
|
||||
inherits = "test"
|
||||
lto = false
|
||||
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"./tengri",
|
||||
"./core",
|
||||
"./input",
|
||||
"./output",
|
||||
"./tui",
|
||||
|
|
@ -13,9 +17,25 @@ members = [
|
|||
"./proc",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
[workspace.package]
|
||||
version = "0.13.0"
|
||||
edition = "2024"
|
||||
|
||||
[profile.coverage]
|
||||
inherits = "test"
|
||||
lto = false
|
||||
[workspace.dependencies]
|
||||
atomic_float = { version = "1" }
|
||||
better-panic = { version = "0.3.0" }
|
||||
crossterm = { version = "0.28.1" }
|
||||
heck = { version = "0.5" }
|
||||
itertools = { version = "0.14.0" }
|
||||
konst = { version = "0.3.16", features = [ "rust_1_83" ] }
|
||||
palette = { version = "0.7.6", features = [ "random" ] }
|
||||
proc-macro2 = { version = "1", features = ["span-locations"] }
|
||||
proptest = { version = "^1" }
|
||||
proptest-derive = { version = "^0.5.1" }
|
||||
quanta = { version = "0.12.3" }
|
||||
quote = { version = "1" }
|
||||
rand = { version = "0.8.5" }
|
||||
ratatui = { version = "0.29.0", features = [ "unstable-widget-ref", "underline-color" ] }
|
||||
syn = { version = "2", features = ["full", "extra-traits"] }
|
||||
thiserror = { version = "2.0" }
|
||||
unicode-width = { version = "0.2" }
|
||||
|
|
|
|||
6
core/Cargo.toml
Normal file
6
core/Cargo.toml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "tengri_core"
|
||||
description = "UI metaframework, core definitions."
|
||||
version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
|
||||
7
core/src/lib.rs
Normal file
7
core/src/lib.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
use std::error::Error;
|
||||
|
||||
/// Standard result type.
|
||||
pub type Usually<T> = Result<T, Box<dyn Error>>;
|
||||
|
||||
/// Standard optional result type.
|
||||
pub type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
|
||||
|
|
@ -5,12 +5,10 @@ version = { workspace = true }
|
|||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
konst = { version = "0.3.16", features = [ "rust_1_83" ] }
|
||||
itertools = "0.14.0"
|
||||
thiserror = "2.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
tengri_core = { path = "../core" }
|
||||
konst = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tengri_tui = { path = "../tui" }
|
||||
|
|
|
|||
16
dsl/src/dsl_error.rs
Normal file
16
dsl/src/dsl_error.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
use crate::*;
|
||||
|
||||
pub type DslResult<T> = Result<T, DslError>;
|
||||
|
||||
#[derive(Error, Debug, Copy, Clone, PartialEq)] pub enum DslError {
|
||||
#[error("parse failed: not implemented")]
|
||||
Unimplemented,
|
||||
#[error("parse failed: empty")]
|
||||
Empty,
|
||||
#[error("parse failed: incomplete")]
|
||||
Incomplete,
|
||||
#[error("parse failed: unexpected character '{0}'")]
|
||||
Unexpected(char),
|
||||
#[error("parse failed: error #{0}")]
|
||||
Code(u8),
|
||||
}
|
||||
|
|
@ -1,55 +1,4 @@
|
|||
use crate::*;
|
||||
use thiserror::Error;
|
||||
|
||||
pub type ParseResult<T> = Result<T, ParseError>;
|
||||
|
||||
#[derive(Error, Debug, Copy, Clone, PartialEq)] pub enum ParseError {
|
||||
#[error("parse failed: not implemented")]
|
||||
Unimplemented,
|
||||
#[error("parse failed: empty")]
|
||||
Empty,
|
||||
#[error("parse failed: incomplete")]
|
||||
Incomplete,
|
||||
#[error("parse failed: unexpected character '{0}'")]
|
||||
Unexpected(char),
|
||||
#[error("parse failed: error #{0}")]
|
||||
Code(u8),
|
||||
}
|
||||
|
||||
pub trait TryFromDsl<'state, T>: Sized {
|
||||
fn try_from_expr <'source: 'state> (
|
||||
_state: &'state T, _iter: &mut TokenIter<'source>
|
||||
) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
fn try_from_atom <'source: 'state> (
|
||||
state: &'state T, value: Value<'source>
|
||||
) -> Option<Self> {
|
||||
if let Exp(0, mut iter) = value {
|
||||
return Self::try_from_expr(state, &mut iter)
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Map EDN tokens to parameters of a given type for a given context
|
||||
pub trait Context<'state, U>: Sized {
|
||||
fn get <'source> (&'state self, _iter: &mut TokenIter<'source>) -> Option<U> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'state, T: Context<'state, U>, U> Context<'state, U> for &T {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<U> {
|
||||
(*self).get(iter)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'state, T: Context<'state, U>, U> Context<'state, U> for Option<T> {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<U> {
|
||||
self.as_ref().map(|s|s.get(iter)).flatten()
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement the const iterator pattern.
|
||||
#[macro_export] macro_rules! const_iter {
|
||||
|
|
@ -138,6 +87,7 @@ impl<'a> SourceIter<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Static iteration helper.
|
||||
#[macro_export] macro_rules! iterate {
|
||||
($expr:expr => $arg: pat => $body:expr) => {
|
||||
|
|
@ -205,7 +155,7 @@ pub const fn peek_src <'a> (source: &'a str) -> Option<Token<'a>> {
|
|||
}
|
||||
}
|
||||
|
||||
pub const fn to_number (digits: &str) -> Result<usize, ParseError> {
|
||||
pub const fn to_number (digits: &str) -> DslResult<usize> {
|
||||
let mut value = 0;
|
||||
iterate!(char_indices(digits) => (_, c) => match to_digit(c) {
|
||||
Ok(digit) => value = 10 * value + digit,
|
||||
|
|
@ -214,7 +164,7 @@ pub const fn to_number (digits: &str) -> Result<usize, ParseError> {
|
|||
Ok(value)
|
||||
}
|
||||
|
||||
pub const fn to_digit (c: char) -> Result<usize, ParseError> {
|
||||
pub const fn to_digit (c: char) -> DslResult<usize> {
|
||||
Ok(match c {
|
||||
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4,
|
||||
'5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9,
|
||||
|
|
@ -231,7 +181,7 @@ pub const fn to_digit (c: char) -> Result<usize, ParseError> {
|
|||
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq)] pub enum Value<'source> {
|
||||
#[default] Nil,
|
||||
Err(ParseError),
|
||||
Err(DslError),
|
||||
Num(usize),
|
||||
Sym(&'source str),
|
||||
Key(&'source str),
|
||||
|
|
@ -240,7 +190,9 @@ pub const fn to_digit (c: char) -> Result<usize, ParseError> {
|
|||
}
|
||||
|
||||
impl<'source> Token<'source> {
|
||||
pub const fn new (source: &'source str, start: usize, length: usize, value: Value<'source>) -> Self {
|
||||
pub const fn new (
|
||||
source: &'source str, start: usize, length: usize, value: Value<'source>
|
||||
) -> Self {
|
||||
Self { source, start, length, value }
|
||||
}
|
||||
pub const fn end (&self) -> usize {
|
||||
|
|
@ -248,7 +200,6 @@ impl<'source> Token<'source> {
|
|||
}
|
||||
pub const fn slice (&'source self) -> &'source str {
|
||||
self.slice_source(self.source)
|
||||
//str_range(self.source, self.start, self.end())
|
||||
}
|
||||
pub const fn slice_source <'range> (&'source self, source: &'range str) -> &'range str {
|
||||
str_range(source, self.start, self.end())
|
||||
|
|
@ -256,10 +207,13 @@ impl<'source> Token<'source> {
|
|||
pub const fn slice_source_exp <'range> (&'source self, source: &'range str) -> &'range str {
|
||||
str_range(source, self.start.saturating_add(1), self.end())
|
||||
}
|
||||
pub const fn with_value (self, value: Value<'source>) -> Self {
|
||||
Self { value, ..self }
|
||||
}
|
||||
pub const fn value (&self) -> Value {
|
||||
self.value
|
||||
}
|
||||
pub const fn error (self, error: ParseError) -> Self {
|
||||
pub const fn error (self, error: DslError) -> Self {
|
||||
Self { value: Value::Err(error), ..self }
|
||||
}
|
||||
pub const fn grow (self) -> Self {
|
||||
|
|
@ -272,49 +226,43 @@ impl<'source> Token<'source> {
|
|||
}
|
||||
}
|
||||
pub const fn grow_key (self) -> Self {
|
||||
let mut token = self.grow();
|
||||
token.value = Key(token.slice_source(self.source));
|
||||
token
|
||||
let token = self.grow();
|
||||
token.with_value(Key(token.slice_source(self.source)))
|
||||
}
|
||||
pub const fn grow_sym (self) -> Self {
|
||||
let mut token = self.grow();
|
||||
token.value = Sym(token.slice_source(self.source));
|
||||
token
|
||||
let token = self.grow();
|
||||
token.with_value(Sym(token.slice_source(self.source)))
|
||||
}
|
||||
pub const fn grow_str (self) -> Self {
|
||||
let mut token = self.grow();
|
||||
token.value = Str(token.slice_source(self.source));
|
||||
token
|
||||
let token = self.grow();
|
||||
token.with_value(Str(token.slice_source(self.source)))
|
||||
}
|
||||
pub const fn grow_exp (self) -> Self {
|
||||
let mut token = self.grow();
|
||||
let token = self.grow();
|
||||
if let Exp(depth, _) = token.value {
|
||||
token.value = Exp(depth, TokenIter::new(token.slice_source_exp(self.source)));
|
||||
token.with_value(Exp(depth, TokenIter::new(token.slice_source_exp(self.source))))
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
token
|
||||
}
|
||||
pub const fn grow_in (self) -> Self {
|
||||
let mut token = self.grow_exp();
|
||||
let token = self.grow_exp();
|
||||
if let Value::Exp(depth, source) = token.value {
|
||||
token.value = Value::Exp(depth.saturating_add(1), source)
|
||||
token.with_value(Value::Exp(depth.saturating_add(1), source))
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
token
|
||||
}
|
||||
pub const fn grow_out (self) -> Self {
|
||||
let mut token = self.grow_exp();
|
||||
let token = self.grow_exp();
|
||||
if let Value::Exp(depth, source) = token.value {
|
||||
if depth > 0 {
|
||||
token.value = Value::Exp(depth - 1, source)
|
||||
token.with_value(Value::Exp(depth - 1, source))
|
||||
} else {
|
||||
return self.error(Unexpected(')'))
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
token
|
||||
}
|
||||
}
|
||||
55
dsl/src/dsl_provide.rs
Normal file
55
dsl/src/dsl_provide.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
use crate::*;
|
||||
|
||||
/// Map EDN tokens to parameters of a given type for a given context
|
||||
/// TODO: Replace both [Context] and [TryFromDsl] with this trait
|
||||
/// which returns a [Result].
|
||||
pub trait Dsl<U>: Sized {
|
||||
fn take <'state, 'source> (_: &'state Self, _: &mut TokenIter<'source>) -> Perhaps<U> {
|
||||
Ok(None)
|
||||
}
|
||||
fn take_or_fail <'state, 'source> (
|
||||
state: &'state Self, iter: &mut TokenIter<'source>
|
||||
) -> Usually<U> {
|
||||
if let Some(value) = Self::take(state, iter)? {
|
||||
Ok(value)
|
||||
} else {
|
||||
Result::Err("not found".into()) // TODO add info and error type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Map EDN tokens to parameters of a given type for a given context
|
||||
pub trait Context<'state, U>: Sized {
|
||||
fn get <'source> (&'state self, _iter: &mut TokenIter<'source>) -> Option<U> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'state, T: Context<'state, U>, U> Context<'state, U> for &T {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<U> {
|
||||
(*self).get(iter)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'state, T: Context<'state, U>, U> Context<'state, U> for Option<T> {
|
||||
fn get <'source> (&'state self, iter: &mut TokenIter<'source>) -> Option<U> {
|
||||
self.as_ref().map(|s|s.get(iter)).flatten()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TryFromDsl<'state, T>: Sized {
|
||||
fn try_from_expr <'source: 'state> (
|
||||
_state: &'state T, _iter: &mut TokenIter<'source>
|
||||
) -> Option<Self> {
|
||||
None
|
||||
}
|
||||
fn try_from_atom <'source: 'state> (
|
||||
state: &'state T, value: Value<'source>
|
||||
) -> Option<Self> {
|
||||
if let Exp(0, mut iter) = value {
|
||||
return Self::try_from_expr(state, &mut iter)
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
#![feature(adt_const_params)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_fn_trait_return)]
|
||||
|
||||
//! [Token]s are parsed substrings with an associated [Value].
|
||||
//!
|
||||
//! * [ ] FIXME: Value may be [Err] which may shadow [Result::Err]
|
||||
|
|
@ -31,17 +35,19 @@
|
|||
//! assert_eq!(view.0.0, src);
|
||||
//! assert_eq!(view.peek(), view.0.peek())
|
||||
//! ```
|
||||
#![feature(adt_const_params)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(impl_trait_in_fn_trait_return)]
|
||||
|
||||
pub(crate) use self::Value::*;
|
||||
pub(crate) use self::ParseError::*;
|
||||
pub(crate) use ::tengri_core::*;
|
||||
|
||||
pub(crate) use std::fmt::Debug;
|
||||
pub(crate) use konst::iter::{ConstIntoIter, IsIteratorKind};
|
||||
pub(crate) use konst::string::{split_at, str_range, char_indices};
|
||||
pub(crate) use std::fmt::Debug;
|
||||
pub(crate) use thiserror::Error;
|
||||
pub(crate) use self::Value::*;
|
||||
pub(crate) use self::DslError::*;
|
||||
|
||||
mod dsl; pub use self::dsl::*;
|
||||
mod dsl_error; pub use self::dsl_error::*;
|
||||
mod dsl_parse; pub use self::dsl_parse::*;
|
||||
mod dsl_provide; pub use self::dsl_provide::*;
|
||||
|
||||
#[cfg(test)] mod test_token_iter {
|
||||
use crate::*;
|
||||
|
|
@ -143,7 +149,7 @@ mod dsl; pub use self::dsl::*;
|
|||
Ok(())
|
||||
}
|
||||
|
||||
//#[cfg(test)] #[test] fn test_examples () -> Result<(), ParseError> {
|
||||
//#[cfg(test)] #[test] fn test_examples () -> Result<(), DslError> {
|
||||
//// Let's pretend to render some view.
|
||||
//let source = include_str!("../../tek/src/view_arranger.edn");
|
||||
//// The token iterator allows you to get the tokens represented by the source text.
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@ description = "UI metaframework, input layer."
|
|||
version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
tengri_dsl = { optional = true, path = "../dsl" }
|
||||
|
||||
[features]
|
||||
dsl = [ "tengri_dsl" ]
|
||||
|
||||
[dependencies]
|
||||
tengri_core = { path = "../core" }
|
||||
tengri_dsl = { optional = true, path = "../dsl" }
|
||||
|
||||
[dev-dependencies]
|
||||
tengri_tui = { path = "../tui" }
|
||||
tengri_dsl = { path = "../dsl" }
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
#![feature(associated_type_defaults)]
|
||||
pub(crate) use std::error::Error;
|
||||
pub(crate) type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
|
||||
#[cfg(test)] pub(crate) type Usually<T> = Result<T, Box<dyn Error>>;
|
||||
|
||||
#[cfg(feature = "dsl")] pub(crate) use ::tengri_dsl::*;
|
||||
#[cfg(feature = "dsl")] mod input_dsl;
|
||||
#[cfg(feature = "dsl")] pub use self::input_dsl::*;
|
||||
pub(crate) use tengri_core::*;
|
||||
|
||||
mod input_macros;
|
||||
mod input_command; pub use self::input_command::*;
|
||||
mod input_handle; pub use self::input_handle::*;
|
||||
|
||||
#[cfg(test)]
|
||||
#[test] fn test_stub_input () -> Usually<()> {
|
||||
#[cfg(feature = "dsl")] pub(crate) use ::tengri_dsl::*;
|
||||
#[cfg(feature = "dsl")] mod input_dsl;
|
||||
#[cfg(feature = "dsl")] pub use self::input_dsl::*;
|
||||
|
||||
#[cfg(test)] #[test] fn test_stub_input () -> Usually<()> {
|
||||
use crate::*;
|
||||
struct TestInput(bool);
|
||||
enum TestEvent { Test1 }
|
||||
|
|
@ -33,8 +31,7 @@ mod input_handle; pub use self::input_handle::*;
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[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("");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,15 +4,16 @@ description = "UI metaframework, output layer."
|
|||
version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
tengri_dsl = { optional = true, path = "../dsl" }
|
||||
|
||||
[features]
|
||||
dsl = [ "tengri_dsl" ]
|
||||
|
||||
[dependencies]
|
||||
tengri_core = { path = "../core" }
|
||||
tengri_dsl = { optional = true, path = "../dsl" }
|
||||
|
||||
[dev-dependencies]
|
||||
tengri = { path = "../tengri", features = [ "dsl", "tui" ] }
|
||||
tengri_tui = { path = "../tui" }
|
||||
tengri_dsl = { path = "../dsl" }
|
||||
proptest = "^1"
|
||||
proptest-derive = "^0.5.1"
|
||||
proptest = { workspace = true }
|
||||
proptest-derive = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -7,18 +7,13 @@ mod space; pub use self::space::*;
|
|||
mod ops; pub use self::ops::*;
|
||||
mod output; pub use self::output::*;
|
||||
|
||||
pub(crate) use tengri_core::*;
|
||||
pub(crate) use std::marker::PhantomData;
|
||||
pub(crate) use std::error::Error;
|
||||
|
||||
#[cfg(feature = "dsl")] pub(crate) use ::tengri_dsl::*;
|
||||
#[cfg(feature = "dsl")] mod view;
|
||||
#[cfg(feature = "dsl")] pub use self::view::*;
|
||||
|
||||
/// Standard result type.
|
||||
pub type Usually<T> = Result<T, Box<dyn Error>>;
|
||||
/// Standard optional result type.
|
||||
pub type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
|
||||
|
||||
#[cfg(test)] use proptest_derive::Arbitrary;
|
||||
|
||||
#[cfg(test)] #[test] fn test_stub_output () -> Usually<()> {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ edition = { workspace = true }
|
|||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "2", features = ["full", "extra-traits"] }
|
||||
quote = { version = "1" }
|
||||
proc-macro2 = { version = "1", features = ["span-locations"] }
|
||||
heck = { version = "0.5" }
|
||||
tengri_core = { path = "../core" }
|
||||
syn = { workspace = true }
|
||||
quote = { workspace = true }
|
||||
proc-macro2 = { workspace = true }
|
||||
heck = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -10,10 +10,7 @@ pub(crate) struct CommandMeta(Ident);
|
|||
pub(crate) struct CommandImpl(ItemImpl, BTreeMap<Arc<str>, CommandArm>);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct CommandArm(Ident, Vec<FnArg>, ReturnType);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct CommandVariant(Ident, Vec<FnArg>);
|
||||
struct CommandArm(Ident, Vec<FnArg>, #[allow(unused)] ReturnType);
|
||||
|
||||
impl Parse for CommandMeta {
|
||||
fn parse (input: ParseStream) -> Result<Self> {
|
||||
|
|
@ -73,7 +70,8 @@ impl ToTokens for CommandDef {
|
|||
state: &'state #target, iter: &mut ::tengri::dsl::TokenIter<'source>
|
||||
) -> Option<Self> {
|
||||
let mut iter = iter.clone();
|
||||
match iter.next() {
|
||||
let token = iter.next();
|
||||
match token {
|
||||
#(#matchers)*
|
||||
_ => None
|
||||
}
|
||||
|
|
@ -157,10 +155,12 @@ impl CommandArm {
|
|||
for (arg, ty) in self.args() {
|
||||
//let take_err = LitStr::new(&format!("{}: missing argument \"{}\" ({})",
|
||||
//quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site());
|
||||
let give_err = LitStr::new(&format!("{}: missing value for \"{}\" ({})",
|
||||
quote!{#ident}, quote!{#arg}, quote!{#ty}), Span::call_site());
|
||||
let give_err = format!("{}: missing value for \"{}\" ({}): {{:#?}}",
|
||||
quote!{#ident}, quote!{#arg}, quote!{#ty});
|
||||
let give_err = LitStr::new(&give_err, Span::call_site());
|
||||
write_quote_to(&mut out, quote! {
|
||||
#arg: ::tengri::dsl::Context::get(state, &mut iter).expect(#give_err),
|
||||
#arg: ::tengri::dsl::Context::get(state, &mut iter)
|
||||
.unwrap_or_else(||panic!(#give_err, token)),
|
||||
});
|
||||
}
|
||||
out
|
||||
|
|
@ -203,25 +203,3 @@ impl CommandArm {
|
|||
write_quote(quote! { Self::#variant => Self::#ident(state, #(#give_args)* #give_rest), })
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for CommandVariant {
|
||||
fn to_tokens (&self, out: &mut TokenStream2) {
|
||||
let Self(ident, args) = self;
|
||||
out.append(LitStr::new(&format!("{}", ident), Span::call_site())
|
||||
.token());
|
||||
out.append(Group::new(Delimiter::Parenthesis, {
|
||||
let mut out = TokenStream2::new();
|
||||
for arg in args.iter() {
|
||||
if let FnArg::Typed(PatType { ty, .. }) = arg {
|
||||
out.append(LitStr::new(
|
||||
&format!("{}", quote! { #ty }),
|
||||
Span::call_site()
|
||||
).token());
|
||||
out.append(Punct::new(',', Alone));
|
||||
}
|
||||
}
|
||||
out
|
||||
}));
|
||||
out.append(Punct::new(',', Alone));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,15 @@ edition = "2024"
|
|||
description = "UI metaframework."
|
||||
version = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = [ "input", "output", "tui" ]
|
||||
input = [ "tengri_input" ]
|
||||
output = [ "tengri_output" ]
|
||||
tui = [ "tengri_tui" ]
|
||||
dsl = [ "tengri_dsl", "tengri_input/dsl", "tengri_output/dsl", "tengri_tui/dsl" ]
|
||||
|
||||
[dependencies]
|
||||
tengri_core = { path = "../core" }
|
||||
tengri_dsl = { optional = true, path = "../dsl" }
|
||||
tengri_input = { optional = true, path = "../input" }
|
||||
tengri_output = { optional = true, path = "../output" }
|
||||
|
|
@ -13,11 +21,4 @@ tengri_tui = { optional = true, path = "../tui" }
|
|||
[dev-dependencies]
|
||||
tengri_proc = { path = "../proc" }
|
||||
tengri = { path = ".", features = [ "dsl" ] }
|
||||
crossterm = "0.28.1"
|
||||
|
||||
[features]
|
||||
default = [ "input", "output", "tui" ]
|
||||
input = [ "tengri_input" ]
|
||||
output = [ "tengri_output" ]
|
||||
tui = [ "tengri_tui" ]
|
||||
dsl = [ "tengri_dsl", "tengri_input/dsl", "tengri_output/dsl", "tengri_tui/dsl" ]
|
||||
crossterm = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
pub use ::tengri_core::*;
|
||||
#[cfg(feature="output")] pub use ::tengri_output as output;
|
||||
#[cfg(feature="input")] pub use ::tengri_input as input;
|
||||
#[cfg(feature="dsl")] pub use ::tengri_dsl as dsl;
|
||||
#[cfg(feature="tui")] pub use ::tengri_tui as tui;
|
||||
|
||||
#[cfg(test)] extern crate tengri_proc;
|
||||
#[cfg(test)] #[test] fn test_subcommand () -> crate::output::Usually<()> {
|
||||
use crate::output::Perhaps;
|
||||
#[cfg(test)] #[test] fn test_subcommand () -> Usually<()> {
|
||||
use crate::input::{Command, InputMap, KeyMap, Handle, handle};
|
||||
use crate::dsl::{TryFromDsl, TokenIter};
|
||||
use crate::tui::TuiIn;
|
||||
|
|
@ -80,20 +80,21 @@
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)] #[test] fn test_dsl_context () {
|
||||
use crate::dsl::Value;
|
||||
//FIXME:
|
||||
//#[cfg(test)] #[test] fn test_dsl_context () {
|
||||
//use crate::dsl::{Context, Value};
|
||||
|
||||
struct Test;
|
||||
#[tengri_proc::expose]
|
||||
impl Test {
|
||||
fn some_bool (&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
assert_eq!(Test.get(&Value::Sym(":false")), Some(false));
|
||||
assert_eq!(Test.get(&Value::Sym(":true")), Some(true));
|
||||
assert_eq!(Test.get(&Value::Sym(":some-bool")), Some(true));
|
||||
assert_eq!(Test.get(&Value::Sym(":missing-bool")), None);
|
||||
assert_eq!(Test.get(&Value::Num(0)), Some(false));
|
||||
assert_eq!(Test.get(&Value::Num(1)), Some(true));
|
||||
}
|
||||
//struct Test;
|
||||
//#[tengri_proc::expose]
|
||||
//impl Test {
|
||||
//fn some_bool (&self) -> bool {
|
||||
//true
|
||||
//}
|
||||
//}
|
||||
//assert_eq!(Context::get(&Test, &Value::Sym(":false")), Some(false));
|
||||
//assert_eq!(Context::get(&Test, &Value::Sym(":true")), Some(true));
|
||||
//assert_eq!(Context::get(&Test, &Value::Sym(":some-bool")), Some(true));
|
||||
//assert_eq!(Context::get(&Test, &Value::Sym(":missing-bool")), None);
|
||||
//assert_eq!(Context::get(&Test, &Value::Num(0)), Some(false));
|
||||
//assert_eq!(Context::get(&Test, &Value::Num(1)), Some(true));
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -4,25 +4,26 @@ description = "UI metaframework, Ratatui backend."
|
|||
version = { workspace = true }
|
||||
edition = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
palette = { version = "0.7.6", features = [ "random" ] }
|
||||
rand = "0.8.5"
|
||||
crossterm = "0.28.1"
|
||||
ratatui = { version = "0.29.0", features = [ "unstable-widget-ref", "underline-color" ] }
|
||||
better-panic = "0.3.0"
|
||||
konst = { version = "0.3.16", features = [ "rust_1_83" ] }
|
||||
atomic_float = "1"
|
||||
quanta = "0.12.3"
|
||||
unicode-width = "0.2"
|
||||
[features]
|
||||
dsl = [ "tengri_dsl", "tengri_input/dsl", "tengri_output/dsl" ]
|
||||
|
||||
[dependencies]
|
||||
tengri_core = { path = "../core" }
|
||||
tengri_input = { path = "../input" }
|
||||
tengri_output = { path = "../output" }
|
||||
tengri_dsl = { optional = true, path = "../dsl" }
|
||||
|
||||
palette = { workspace = true }
|
||||
rand = { workspace = true }
|
||||
crossterm = { workspace = true }
|
||||
ratatui = { workspace = true }
|
||||
better-panic = { workspace = true }
|
||||
konst = { workspace = true }
|
||||
atomic_float = { workspace = true }
|
||||
quanta = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
tengri = { path = "../tengri", features = [ "dsl" ] }
|
||||
tengri_dsl = { path = "../dsl" }
|
||||
tengri_proc = { path = "../proc" }
|
||||
|
||||
[features]
|
||||
dsl = [ "tengri_dsl", "tengri_input/dsl", "tengri_output/dsl" ]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use tengri::{self, input::*, output::*, tui::*, dsl::*};
|
||||
use tengri::{self, Usually, Perhaps, input::*, output::*, tui::*, dsl::*};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use crossterm::event::{*, KeyCode::*};
|
||||
use crate::ratatui::style::Color;
|
||||
|
|
@ -70,7 +70,7 @@ view!(TuiOut: |self: Example|{
|
|||
let heading = format!("Example {}/{} in {:?}", index, EXAMPLES.len(), &wh);
|
||||
let title = Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(heading)));
|
||||
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, SourceIter::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)))
|
||||
}; {
|
||||
":title" => Tui::bg(Color::Rgb(60, 10, 10), Push::y(1, Align::n(format!("Example {}/{}:", self.0 + 1, EXAMPLES.len())))).boxed(),
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
mod tui_engine; pub use self::tui_engine::*;
|
||||
mod tui_content; pub use self::tui_content::*;
|
||||
|
||||
pub(crate) use ::tengri_core::*;
|
||||
|
||||
pub use ::tengri_input as input;
|
||||
pub(crate) use ::tengri_input::*;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue