Compare commits

..

1 commit

Author SHA1 Message Date
277f96d5cc output: more big refactors
Some checks are pending
/ build (push) Waiting to run
2025-09-07 14:03:58 +03:00
25 changed files with 265 additions and 403 deletions

View file

@ -1,29 +1,17 @@
export 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-ignore := "--ignore-not-existing --ignore '../*' --ignore \"/*\" --ignore 'target/*'"
bacon:
bacon -s
{{covfig}} bacon -s
cov:
CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' \
time cargo test -j4 --workspace --profile coverage
{{covfig}} time cargo test -j4 --workspace --profile coverage
rm -rf target/coverage/html || true
time grcov . -s . {{grcov-binary}} {{grcov-ignore}} -t html -o target/coverage/html
{{covfig}} time grcov . -s . {{grcov-binary}} {{grcov-ignore}} -t html -o target/coverage/html
cov-md:
CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' \
time cargo test -j4 --workspace --profile coverage
time grcov . -s . {{grcov-binary}} {{grcov-ignore}} -t markdown | sort
{{covfig}} time cargo test -j4 --workspace --profile coverage
{{covfig}} time grcov . -s . {{grcov-binary}} {{grcov-ignore}} -t markdown | sort
cov-md-ci:
CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' \
time cargo test -j4 --workspace --profile coverage -- --skip test_tui_engine
time grcov . -s . {{grcov-binary}} {{grcov-ignore}} -t markdown | sort
{{covfig}} time cargo test -j4 --workspace --profile coverage -- --skip test_tui_engine
{{covfig}} time grcov . -s . {{grcov-binary}} {{grcov-ignore}} -t markdown | sort
doc:
CARGO_INCREMENTAL=0 RUSTFLAGS='-Cinstrument-coverage' RUSTDOCFLAGS='-Cinstrument-coverage' \
cargo doc
example-tui:
cargo run -p tengri_tui --example tui
cargo doc

View file

@ -1,18 +1,13 @@
mod core_macros;
pub(crate) 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>>;
/// Type-dispatched `get` and `get_mut`.
pub trait Has<T>: Send + Sync { fn get (&self) -> &T; fn get_mut (&mut self) -> &mut T; }
/// Type-dispatched `get` and `get_mut` that return an [Option]-wrapped result.
pub trait MaybeHas<T>: Send + Sync { fn get (&self) -> Option<&T>; fn get_mut (&mut self) -> Option<&mut T>; }
/// May compute a `RetVal` from `Args`.
pub trait Eval<Args, RetVal> {
/// A custom operation on [Args] that may return [Result::Err] or [Option::None].
@ -27,11 +22,3 @@ pub trait Eval<Args, RetVal> {
}
}
}
#[macro_export] macro_rules! as_ref {
($T:ty: |$self:ident : $S:ty| $x:expr) => {
impl AsRef<$T> for $S {
fn as_ref (&$self) -> &$T { &$x }
}
};
}

View file

@ -63,7 +63,7 @@ dsl_type!(DslExpr {
).into())
};
)*
Ok(Some($body/* as $Type*/))
Ok(Some($body as $Type))
};
($name, get)
}),* )? ];
@ -74,14 +74,12 @@ pub trait DslNsExprs<'a, T: 'a>: 'a {
const EXPRS: DslExprs<'a, Self, T> = &[];
/// Resolve an expression if known.
fn from_expr (&'a self, dsl: impl DslExpr + 'a) -> Perhaps<T> {
if let Some(dsl) = dsl.expr()? {
let head = dsl.head()?;
for (key, get) in Self::EXPRS.iter() {
if Some(*key) == head {
return get(self, dsl.tail()?.unwrap_or(""))
}
let head = dsl.head()?;
for (key, get) in Self::EXPRS.iter() {
if Some(*key) == head {
return get(self, dsl.tail()?.unwrap_or(""))
}
}
Ok(None)
return Ok(None)
}
}

View file

@ -16,31 +16,3 @@ pub trait DslNs<'a, T: 'a>: DslNsWords<'a, T> + DslNsExprs<'a, T> {
Ok(None)
}
}
#[macro_export] macro_rules! dsl_ns {
($State:ty: $Type:ty {
$(literal = |$dsl:ident| $literal:expr;)?
$(word = |$state_w:ident| {
$($word:literal => $body_w:expr),* $(,)?
};)?
$(expr = |$state_e:ident| {
$($head:literal $args:tt => $body_e:expr),* $(,)?
};)?
}) => {
impl<'a> DslNs<'a, $Type> for $State {
$(fn from_literal (&self, $dsl: impl Dsl) -> Perhaps<$Type> {
$literal
})?
}
impl<'a> DslNsWords<'a, $Type> for $State {
$(dsl_words! { 'a |$state_w| -> $Type {
$($word => $body_w),*
} })?
}
impl<'a> DslNsExprs<'a, $Type> for $State {
$(dsl_exprs! { 'a |$state_e| -> $Type {
$($head $args => $body_e),*
} })?
}
}
}

View file

@ -4,6 +4,37 @@ use crate::*;
pub trait Draw<O: Out> {
/// Write data to display.
fn draw (&self, to: &mut O);
fn boxed <'a> (self) -> Box<dyn Draw<O> + 'a> where Self: Sized + 'a {
Box::new(self) as Box<dyn Draw<O> + 'a>
}
fn rc <'a> (self) -> Rc<dyn Draw<O> + 'a> where Self: Sized + 'a {
Rc::new(self) as Rc<dyn Draw<O> + 'a>
}
}
impl<O: Out> Draw<O> for () {
fn draw (&self, _: &mut O) {}
}
impl<O: Out, T: Draw<O>> Draw<O> for &T {
fn draw (&self, to: &mut O) {
(*self).draw(to)
}
}
impl<O: Out, T: Draw<O>> Draw<O> for &mut T {
fn draw (&self, to: &mut O) {
(**self).draw(to)
}
}
impl<O: Out, T: Draw<O>> Draw<O> for [T] {
fn draw (&self, to: &mut O) {
for draw in self.iter() {
draw.draw(to)
}
}
}
impl<O: Out> Draw<O> for fn(&mut O) {
@ -12,12 +43,6 @@ impl<O: Out> Draw<O> for fn(&mut O) {
}
}
impl<O: Out> Draw<O> for () { fn draw (&self, _: &mut O) {} }
impl<O: Out, T: Draw<O>> Draw<O> for &T {
fn draw (&self, to: &mut O) { (*self).draw(to) }
}
impl<'x, O: Out> Draw<O> for &(dyn Draw<O> + 'x) {
fn draw (&self, to: &mut O) {
(*self).draw(to)
@ -30,32 +55,6 @@ impl<'x, O: Out> Draw<O> for &mut (dyn Draw<O> + 'x) {
}
}
impl<O: Out, T: Draw<O>> Draw<O> for RwLock<T> {
fn draw (&self, to: &mut O) { self.read().unwrap().draw(to) }
}
impl<O: Out, T: Draw<O>> Draw<O> for [T] {
fn draw (&self, to: &mut O) {
for draw in self.iter() {
draw.draw(to)
}
}
}
//impl<O: Out, T: Draw<O>> Draw<O> for &mut T {
//fn draw (&self, to: &mut O) {
//(**self).draw(to)
//}
//}
//impl<O: Out, T: Iterator<Item = U>, U: Draw<O>> Draw<O> for &mut T {
//fn draw (&self, to: &mut O) {
//for draw in *self {
//draw.draw(to)
//}
//}
//}
/// Implement custom drawing for a struct.
#[macro_export] macro_rules! draw {
@ -83,12 +82,4 @@ impl<O: Out, T: Draw<O>> Draw<O> for [T] {
draw!(|self: Arc<T: Draw<O>>, to|(**self).draw(to));
draw!(|self: Box<T: Draw<O>>, to|(**self).draw(to));
//draw!(|self: Option<T: Draw<O>>, to|if let Some(draw) = self { draw.draw(to) });
impl<O: Out, T: Draw<O>> Draw<O> for Option<T> {
fn draw (&self, to: &mut O) {
if let Some(draw) = self {
draw.draw(to)
}
}
}
draw!(|self: Option<T: Draw<O>>, to|if let Some(draw) = self { draw.draw(to) });

View file

@ -1,12 +0,0 @@
#[allow(unused)] use crate::*;
pub struct Group<T>(T);
impl<T> Group<T> {
pub const fn new () -> Group<()> {
Group(())
}
pub const fn add <U> (self, value: U) -> Group<(T, U)> {
Group((self.0, value))
}
}

View file

@ -32,7 +32,7 @@ pub trait Layout<O: Out> {
}
}
#[macro_export] macro_rules! layout {
macro_rules! layout {
// Implement for all [Out] backends.
(|$self:ident:$Struct:ident $(<
$($L:lifetime),* $($T:ident $(:$Trait:path)?),*
@ -63,24 +63,12 @@ impl<O: Out> Layout<O> for () {}
impl<O: Out, L: Layout<O>> Layout<O> for &L { /*FIXME*/ }
impl<O: Out, L: Layout<O>> Layout<O> for RwLock<L> { /*FIXME*/ }
impl<O: Out, L: Layout<O>> Layout<O> for Option<L> { /*FIXME*/ }
//impl<O: Out> Layout<O> for fn(&mut O) {}
impl<O: Out, L: Layout<O>> Layout<O> for Arc<L> {
fn layout (&self, to: O::Area) -> O::Area {
(**self).layout(to)
}
}
impl<'x, O: Out> Layout<O> for &(dyn Draw<O> + 'x) {
fn layout (&self, to: O::Area) -> O::Area {
Fill::xy(self).layout(to)
}
}
mod layout_align; pub use self::layout_align::*;
mod layout_bsp; pub use self::layout_bsp::*;
mod layout_cond; pub use self::layout_cond::*;
@ -95,4 +83,4 @@ mod layout_padding; pub use self::layout_padding::*;
mod layout_pull; pub use self::layout_pull::*;
mod layout_push; pub use self::layout_push::*;
mod layout_shrink; pub use self::layout_shrink::*;
mod layout_stack; //pub use self::layout_stack::*;
mod layout_stack; pub use self::layout_stack::*;

View file

@ -32,30 +32,30 @@ use crate::*;
#[derive(Debug, Copy, Clone, Default)]
pub enum Alignment { #[default] Center, X, Y, NW, N, NE, E, SE, S, SW, W }
pub struct Align<T>(Alignment, T);
pub struct Align<A>(Alignment, A);
impl<T> Align<T> {
#[inline] pub const fn c (a: T) -> Self { Self(Alignment::Center, a) }
#[inline] pub const fn x (a: T) -> Self { Self(Alignment::X, a) }
#[inline] pub const fn y (a: T) -> Self { Self(Alignment::Y, a) }
#[inline] pub const fn n (a: T) -> Self { Self(Alignment::N, a) }
#[inline] pub const fn s (a: T) -> Self { Self(Alignment::S, a) }
#[inline] pub const fn e (a: T) -> Self { Self(Alignment::E, a) }
#[inline] pub const fn w (a: T) -> Self { Self(Alignment::W, a) }
#[inline] pub const fn nw (a: T) -> Self { Self(Alignment::NW, a) }
#[inline] pub const fn sw (a: T) -> Self { Self(Alignment::SW, a) }
#[inline] pub const fn ne (a: T) -> Self { Self(Alignment::NE, a) }
#[inline] pub const fn se (a: T) -> Self { Self(Alignment::SE, a) }
impl<A> Align<A> {
#[inline] pub const fn c (a: A) -> Self { Self(Alignment::Center, a) }
#[inline] pub const fn x (a: A) -> Self { Self(Alignment::X, a) }
#[inline] pub const fn y (a: A) -> Self { Self(Alignment::Y, a) }
#[inline] pub const fn n (a: A) -> Self { Self(Alignment::N, a) }
#[inline] pub const fn s (a: A) -> Self { Self(Alignment::S, a) }
#[inline] pub const fn e (a: A) -> Self { Self(Alignment::E, a) }
#[inline] pub const fn w (a: A) -> Self { Self(Alignment::W, a) }
#[inline] pub const fn nw (a: A) -> Self { Self(Alignment::NW, a) }
#[inline] pub const fn sw (a: A) -> Self { Self(Alignment::SW, a) }
#[inline] pub const fn ne (a: A) -> Self { Self(Alignment::NE, a) }
#[inline] pub const fn se (a: A) -> Self { Self(Alignment::SE, a) }
}
impl<E: Out, T: Layout<E>> Layout<E> for Align<T> {
fn layout (&self, on: E::Area) -> E::Area {
self.0.align(on, &self.1)
impl<E: Out, A: Draw<E>> Draw<E> for Align<A> {
fn draw (&self, to: &mut E) {
self.1.draw(to)
}
}
impl<E: Out, T: Draw<E> + Layout<E>> Draw<E> for Align<T> {
fn draw (&self, to: &mut E) {
to.place_at(self.layout(to.area()), &self.1)
impl<E: Out, A: Layout<E>> Layout<E> for Align<A> {
fn layout (&self, on: E::Area) -> E::Area {
self.0.align(on, &self.1)
}
}

View file

@ -2,29 +2,26 @@ use crate::*;
use Direction::*;
/// A split or layer.
pub struct Bsp<Head, Tail>(
pub struct Bsp<A, B>(
pub(crate) Direction,
/// First element.
pub(crate) Head,
/// Second element.
pub(crate) Tail,
pub(crate) A,
pub(crate) B,
);
impl<Head, Tail> Bsp<Head, Tail> {
#[inline] pub const fn n (a: Head, b: Tail) -> Self { Self(North, a, b) }
#[inline] pub const fn s (a: Head, b: Tail) -> Self { Self(South, a, b) }
#[inline] pub const fn e (a: Head, b: Tail) -> Self { Self(East, a, b) }
#[inline] pub const fn w (a: Head, b: Tail) -> Self { Self(West, a, b) }
#[inline] pub const fn a (a: Head, b: Tail) -> Self { Self(Above, a, b) }
#[inline] pub const fn b (a: Head, b: Tail) -> Self { Self(Below, a, b) }
impl<A, B> Bsp<A, B> {
#[inline] pub const fn n (a: A, b: B) -> Self { Self(North, a, b) }
#[inline] pub const fn s (a: A, b: B) -> Self { Self(South, a, b) }
#[inline] pub const fn e (a: A, b: B) -> Self { Self(East, a, b) }
#[inline] pub const fn w (a: A, b: B) -> Self { Self(West, a, b) }
#[inline] pub const fn a (a: A, b: B) -> Self { Self(Above, a, b) }
#[inline] pub const fn b (a: A, b: B) -> Self { Self(Below, a, b) }
}
impl<
O: Out,
Head: Draw<O> + Layout<O>,
Tail: Draw<O> + Layout<O>
> Draw<O> for Bsp<Head, Tail> {
fn draw (&self, to: &mut O) {
impl<E: Out, A: Layout<E>, B: Layout<E>> Layout<E> for Bsp<A, B> {
fn layout (&self, area: E::Area) -> E::Area {
bsp_areas(area, self.0, &self.1, &self.2)[2]
}
}
impl<E: Out, A: Draw<E> + Layout<E>, B: Draw<E> + Layout<E>> Draw<E> for Bsp<A, B> {
fn draw (&self, to: &mut E) {
let [a, b, _] = bsp_areas(to.area(), self.0, &self.1, &self.2);
if self.0 == Below {
to.place_at(a, &self.1);
@ -35,16 +32,9 @@ impl<
}
}
}
impl<O: Out, Head: Layout<O>, Tail: Layout<O>> Layout<O> for Bsp<Head, Tail> {
fn layout (&self, area: O::Area) -> O::Area {
bsp_areas(area, self.0, &self.1, &self.2)[2]
}
}
fn bsp_areas <O: Out> (
area: O::Area, direction: Direction, a: &impl Layout<O>, b: &impl Layout<O>,
) -> [O::Area;3] {
fn bsp_areas <E: Out> (
area: E::Area, direction: Direction, a: &impl Layout<E>, b: &impl Layout<E>,
) -> [E::Area;3] {
let [x, y, w, h] = area.xywh();
let [aw, ah] = a.layout(area).wh();
let [bw, bh] = b.layout(match direction {

View file

@ -28,22 +28,20 @@ impl<E: Out, A: Draw<E>> Draw<E> for When<A> {
}
/// Show one item if a condition is true and another if the condition is false
pub struct Either<E: Out, A: Draw<E> + Layout<E>, B: Draw<E> + Layout<E>>(pub bool, pub A, pub B, pub PhantomData<E>);
impl<E: Out, A: Draw<E> + Layout<E>, B: Draw<E> + Layout<E>> Either<E, A, B> {
pub struct Either<A, B>(pub bool, pub A, pub B);
impl<A, B> Either<A, B> {
/// Create a ternary view condition.
pub const fn new (c: bool, a: A, b: B) -> Self {
Self(c, a, b, PhantomData)
}
pub const fn new (c: bool, a: A, b: B) -> Self { Self(c, a, b) }
}
impl<E: Out, A: Draw<E> + Layout<E>, B: Draw<E> + Layout<E>> Layout<E> for Either<E, A, B> {
impl<E: Out, A: Layout<E>, B: Layout<E>> Layout<E> for Either<A, B> {
fn layout (&self, to: E::Area) -> E::Area {
let Self(cond, a, b, ..) = self;
let Self(cond, a, b) = self;
if *cond { a.layout(to) } else { b.layout(to) }
}
}
impl<E: Out, A: Draw<E> + Layout<E>, B: Draw<E> + Layout<E>> Draw<E> for Either<E, A, B> {
impl<E: Out, A: Draw<E>, B: Draw<E>> Draw<E> for Either<A, B> {
fn draw (&self, to: &mut E) {
let Self(cond, a, b, ..) = self;
let Self(cond, a, b) = self;
if *cond { a.draw(to) } else { b.draw(to) }
}
}

View file

@ -1,11 +1,8 @@
use crate::*;
pub enum Fill<A> {
/// Use maximum width of area.
X(A),
/// Use maximum height of area.
Y(A),
/// Use maximum width and height of area.
XY(A)
}
@ -31,25 +28,25 @@ impl<T> Fill<T> {
}
}
impl<O: Out, T: Draw<O>> Draw<O> for Fill<T> {
fn draw (&self, to: &mut O) {
to.place_at(self.layout(to.area()), &self.content())
}
}
impl<O: Out, T: Draw<O>> Layout<O> for Fill<T> {
fn min_w (&self, area: O::Area) -> O::Unit {
impl<E: Out, T: Draw<E> + Layout<E>> Layout<E> for Fill<T> {
fn min_w (&self, area: E::Area) -> E::Unit {
if self.has_x() {
area.w()
} else {
0.into()
self.content().min_w(area)
}
}
fn min_h (&self, area: O::Area) -> O::Unit {
fn min_h (&self, area: E::Area) -> E::Unit {
if self.has_y() {
area.h()
} else {
0.into()
self.content().min_h(area)
}
}
}
impl<E: Out, T: Draw<E> + Layout<E>> Draw<E> for Fill<T> {
fn draw (&self, to: &mut E) {
to.place_at(self.layout(to.area()), &self.content())
}
}

View file

@ -29,19 +29,25 @@ impl<U: Coordinate, T> Fixed<U, T> {
}
}
impl<O: Out, T: Draw<O>> Draw<O> for Fixed<O::Unit, T> {
fn draw (&self, to: &mut O) {
let area = Layout::<O>::layout(&self, to.area());
to.place_at(area, &self.content())
impl<E: Out, T: Draw<E> + Layout<E>> Draw<E> for Fixed<E::Unit, T> {
fn draw (&self, to: &mut E) {
to.place_at(self.layout(to.area()), &self.content())
}
}
impl<O: Out, T> Layout<O> for Fixed<O::Unit, T> {
fn layout (&self, area: O::Area) -> O::Area {
[area.x(), area.y(), match self {
Fixed::X(w, _) | Fixed::XY(w, _, _) => *w, _ => area.w()
}, match self {
Fixed::Y(h, _) | Fixed::XY(_, h, _) => *h, _ => area.h()
}].into()
impl<E: Out, T: Layout<E>> Layout<E> for Fixed<E::Unit, T> {
fn layout (&self, area: E::Area) -> E::Area {
let [x, y, w, h] = area.xywh();
let [x, y, w, h] = self.content().layout(match self {
Self::X(fw, _) => [x, y, *fw, h],
Self::Y(fh, _) => [x, y, w, *fh],
Self::XY(fw, fh, _) => [x, y, *fw, *fh],
}.into()).xywh();
let fixed_area = match self {
Self::X(fw, _) => [x, y, *fw, h],
Self::Y(fh, _) => [x, y, w, *fh],
Self::XY(fw, fh, _) => [x, y, *fw, *fh],
};
fixed_area.into()
}
}

View file

@ -1,19 +1,19 @@
use crate::*;
/// Draws items from an iterator.
pub struct Map<O, A, B, I, F, G>
pub struct Map<E, A, B, I, F, G>
where
I: Iterator<Item = A> + Send + Sync,
F: Fn() -> I + Send + Sync,
{
__: PhantomData<(O, B)>,
__: PhantomData<(E, B)>,
/// Function that returns iterator over stacked components
get_iter: F,
/// Function that returns each stacked component
get_item: G,
}
impl<'a, O, A, B, I, F, G> Map<O, A, B, I, F, G> where
impl<'a, E, A, B, I, F, G> Map<E, A, B, I, F, G> where
I: Iterator<Item = A> + Send + Sync + 'a,
F: Fn() -> I + Send + Sync + 'a,
{
@ -27,30 +27,30 @@ impl<'a, O, A, B, I, F, G> Map<O, A, B, I, F, G> where
}
macro_rules! impl_map_direction (($name:ident, $axis:ident, $align:ident)=>{
impl<'a, O, A, B, I, F> Map<
O, A, Push<O::Unit, Align<Fixed<O::Unit, Fill<B>>>>, I, F, fn(A, usize)->B
impl<'a, E, A, B, I, F> Map<
E, A, Push<E::Unit, Align<Fixed<E::Unit, Fill<B>>>>, I, F, fn(A, usize)->B
> where
O: Out,
B: Draw<O> + Layout<O>,
E: Out,
B: Draw<E>,
I: Iterator<Item = A> + Send + Sync + 'a,
F: Fn() -> I + Send + Sync + 'a
{
pub const fn $name (
size: O::Unit,
size: E::Unit,
get_iter: F,
get_item: impl Fn(A, usize)->B + Send + Sync
) -> Map<
O, A,
Push<O::Unit, Align<Fixed<O::Unit, B>>>,
E, A,
Push<E::Unit, Align<Fixed<E::Unit, B>>>,
I, F,
impl Fn(A, usize)->Push<O::Unit, Align<Fixed<O::Unit, B>>> + Send + Sync
impl Fn(A, usize)->Push<E::Unit, Align<Fixed<E::Unit, B>>> + Send + Sync
> {
Map {
__: PhantomData,
get_iter,
get_item: move |item: A, index: usize|{
// FIXME: multiply
let mut push: O::Unit = O::Unit::from(0u16);
let mut push: E::Unit = E::Unit::from(0u16);
for _ in 0..index {
push = push + size;
}
@ -66,14 +66,14 @@ impl_map_direction!(south, y, n);
impl_map_direction!(west, x, e);
impl_map_direction!(north, y, s);
impl<'a, O, A, B, I, F, G> Layout<O> for Map<O, A, B, I, F, G> where
O: Out,
B: Draw<O> + Layout<O>,
impl<'a, E, A, B, I, F, G> Layout<E> for Map<E, A, B, I, F, G> where
E: Out,
B: Draw<E> + Layout<E>,
I: Iterator<Item = A> + Send + Sync + 'a,
F: Fn() -> I + Send + Sync + 'a,
G: Fn(A, usize)->B + Send + Sync
{
fn layout (&self, area: O::Area) -> O::Area {
fn layout (&self, area: E::Area) -> E::Area {
let Self { get_iter, get_item, .. } = self;
let mut index = 0;
let [mut min_x, mut min_y] = area.center();
@ -92,14 +92,14 @@ impl<'a, O, A, B, I, F, G> Layout<O> for Map<O, A, B, I, F, G> where
area.center_xy([w.into(), h.into()].into()).into()
}
}
impl<'a, O, A, B, I, F, G> Draw<O> for Map<O, A, B, I, F, G> where
O: Out,
B: Draw<O> + Layout<O>,
impl<'a, E, A, B, I, F, G> Draw<E> for Map<E, A, B, I, F, G> where
E: Out,
B: Draw<E> + Layout<E>,
I: Iterator<Item = A> + Send + Sync + 'a,
F: Fn() -> I + Send + Sync + 'a,
G: Fn(A, usize)->B + Send + Sync
{
fn draw (&self, to: &mut O) {
fn draw (&self, to: &mut E) {
let Self { get_iter, get_item, .. } = self;
let mut index = 0;
let area = self.layout(to.area());

View file

@ -7,7 +7,6 @@
mod content; pub use self::content::*;
mod draw; pub use self::draw::*;
mod group; pub use self::group::*;
mod layout; pub use self::layout::*;
mod space; pub use self::space::*;
mod thunk; pub use self::thunk::*;
@ -15,9 +14,11 @@ mod widget; pub use self::widget::*;
pub(crate) use self::Direction::*;
pub(crate) use std::fmt::{Debug, Display};
pub(crate) use std::marker::PhantomData;
pub(crate) use std::ops::{Add, Sub, Mul, Div};
pub(crate) use std::ops::{Add, Sub, Mul, Div, Deref};
pub(crate) use std::rc::Rc;
pub(crate) use std::sync::{Arc, RwLock, atomic::{AtomicUsize, Ordering::Relaxed}};
pub(crate) use tengri_core::*;
#[cfg(feature = "dsl")] pub(crate) use ::tengri_dsl::*;
/// Draw target.
pub trait Out: Send + Sync + Sized {

View file

@ -1,28 +1,39 @@
use crate::*;
pub struct Group<T>(T);
impl<T> Group<T> {
pub const fn new () -> Group<()> {
Group(())
}
pub const fn add <U> (self, value: U) -> Group<(T, U)> {
Group((self.0, value))
}
}
/// Lazily-evaluated [Draw]able.
pub struct Lazy<E, T, F>(PhantomData<(E, T)>, F);
impl<E: Out, T: Draw<E> + Layout<E>, F: Fn()->T> Lazy<E, T, F> {
pub struct Thunk<E: Out, T: Draw<E>, F: Fn()->T>(
PhantomData<E>,
F
);
impl<E: Out, T: Draw<E>, F: Fn()->T> Thunk<E, T, F> {
pub const fn new (thunk: F) -> Self {
Self(PhantomData, thunk)
}
}
impl<E: Out, T: Draw<E> + Layout<E>, F: Fn()->T> Content<E> for Lazy<E, T, F> {
impl<E: Out, T: Draw<E> + Layout<E>, F: Fn()->T> Content<E> for Thunk<E, T, F> {
fn content (&self) -> impl Draw<E> + Layout<E> + '_ {
(self.1)()
}
}
pub struct Thunk<E: Out, F: Fn(&mut E)>(PhantomData<E>, F);
impl<E: Out, F: Fn(&mut E)> Thunk<E, F> {
pub const fn new (draw: F) -> Self { Self(PhantomData, draw) }
pub struct ThunkDraw<E: Out, F: Fn(&mut E)>(PhantomData<E>, F);
impl<E: Out, F: Fn(&mut E)> ThunkDraw<E, F> {
pub fn new (render: F) -> Self { Self(PhantomData, render) }
}
impl<E: Out, F: Fn(&mut E)> Draw<E> for Thunk<E, F> {
impl<E: Out, F: Fn(&mut E)> Draw<E> for ThunkDraw<E, F> {
fn draw (&self, to: &mut E) { (self.1)(to) }
}
impl<E: Out, F: Fn(&mut E)> Layout<E> for Thunk<E, F> {
fn layout (&self, to: E::Area) -> E::Area { to }
}
#[derive(Debug, Default)] pub struct Memo<T, U> {
pub value: T,
@ -36,10 +47,10 @@ impl<T: PartialEq, U> Memo<T, U> {
pub fn update <R> (
&mut self,
newval: T,
draw: impl Fn(&mut U, &T, &T)->R
render: impl Fn(&mut U, &T, &T)->R
) -> Option<R> {
if newval != self.value {
let result = draw(&mut*self.view.write().unwrap(), &newval, &self.value);
let result = render(&mut*self.view.write().unwrap(), &newval, &self.value);
self.value = newval;
return Some(result);
}

View file

@ -13,6 +13,3 @@ syn = { workspace = true }
quote = { workspace = true }
proc-macro2 = { workspace = true }
heck = { workspace = true }
[target.'cfg(target_os = "linux")']
rustflags = ["-C", "link-arg=-fuse-ld=mold"]

View file

@ -9,8 +9,8 @@ pub(crate) struct ExposeMeta;
#[derive(Debug, Clone)]
pub(crate) struct ExposeImpl(ItemImpl, BTreeMap<ExposeType, BTreeMap<String, Ident>>);
//#[derive(Debug, Clone)]
//struct ExposeSym(LitStr);
#[derive(Debug, Clone)]
struct ExposeSym(LitStr);
#[derive(Debug, Clone)]
struct ExposeType(Box<Type>);
@ -169,33 +169,33 @@ impl ExposeImpl {
}
}
//impl From<LitStr> for ExposeSym { fn from (this: LitStr) -> Self { Self(this) } }
impl From<LitStr> for ExposeSym { fn from (this: LitStr) -> Self { Self(this) } }
//impl PartialOrd for ExposeSym {
//fn partial_cmp (&self, other: &Self) -> Option<Ordering> {
//let this = &self.0;
//let that = &other.0;
//Some(format!("{}", quote! { #this }).cmp(&format!("{}", quote! { #that })))
//}
//}
impl PartialOrd for ExposeSym {
fn partial_cmp (&self, other: &Self) -> Option<Ordering> {
let this = &self.0;
let that = &other.0;
Some(format!("{}", quote! { #this }).cmp(&format!("{}", quote! { #that })))
}
}
//impl Ord for ExposeSym {
//fn cmp (&self, other: &Self) -> Ordering {
//let this = &self.0;
//let that = &other.0;
//format!("{}", quote! { #this }).cmp(&format!("{}", quote! { #that }))
//}
//}
impl Ord for ExposeSym {
fn cmp (&self, other: &Self) -> Ordering {
let this = &self.0;
let that = &other.0;
format!("{}", quote! { #this }).cmp(&format!("{}", quote! { #that }))
}
}
//impl PartialEq for ExposeSym {
//fn eq (&self, other: &Self) -> bool {
//let this = &self.0;
//let that = &other.0;
//format!("{}", quote! { #this }) == format!("{}", quote! { #that })
//}
//}
impl PartialEq for ExposeSym {
fn eq (&self, other: &Self) -> bool {
let this = &self.0;
let that = &other.0;
format!("{}", quote! { #this }) == format!("{}", quote! { #that })
}
}
//impl Eq for ExposeSym {}
impl Eq for ExposeSym {}
impl From<Type> for ExposeType { fn from (this: Type) -> Self { Self(Box::new(this)) } }

View file

@ -2,10 +2,10 @@
{pkgs?import<nixpkgs>{}}:let
stdenv = pkgs.clang19Stdenv;
name = "tengri";
nativeBuildInputs = [ pkgs.pkg-config pkgs.libclang pkgs.mold ];
buildInputs = [ pkgs.libclang ];
nativeBuildInputs = with pkgs; [ pkg-config libclang ];
buildInputs = with pkgs; [ libclang ];
LIBCLANG_PATH = "${pkgs.libclang.lib.outPath}/lib";
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [];
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath (with pkgs; []);
in pkgs.mkShell.override {
inherit stdenv;
} {

View file

@ -22,6 +22,3 @@ tengri_tui = { optional = true, path = "../tui" }
tengri_proc = { path = "../proc" }
tengri = { path = ".", features = [ "dsl" ] }
crossterm = { workspace = true }
[target.'cfg(target_os = "linux")']
rustflags = ["-C", "link-arg=-fuse-ld=mold"]

View file

@ -63,7 +63,6 @@ impl ExampleCommand {
}
}
tui_draw!(|self: Example, to|to.place(&self.content()));
content!(TuiOut: |self: Example|{
let index = self.0 + 1;
let wh = self.1.wh();

View file

@ -21,7 +21,7 @@ impl Tui {
}
}
#[macro_export] macro_rules! tui_layout ((|$self:ident:$Self:ty, $to:ident|$expr:expr)=>{
macro_rules! tui_layout ((|$self:ident:$Self:ty, $to:ident|$expr:expr)=>{
impl Layout<TuiOut> for $Self {
fn layout (&$self, $to: [u16;4]) -> [u16;4] {
$expr
@ -29,7 +29,7 @@ impl Tui {
}
});
#[macro_export] macro_rules! tui_draw ((|$self:ident:$Self:ty, $to:ident|$expr:expr)=>{
macro_rules! tui_draw ((|$self:ident:$Self:ty, $to:ident|$expr:expr)=>{
impl Draw<TuiOut> for $Self {
fn draw (&$self, $to: &mut TuiOut) {
$expr
@ -37,74 +37,19 @@ impl Tui {
}
});
mod tui_border; pub use self::tui_border::*;
mod tui_button; pub use self::tui_button::*;
mod tui_color; pub use self::tui_color::*;
mod tui_error; pub use self::tui_error::*;
mod tui_field; pub use self::tui_field::*;
mod tui_phat; pub use self::tui_phat::*;
mod tui_repeat; pub use self::tui_repeat::*;
mod tui_scroll; pub use self::tui_scroll::*;
mod tui_string; pub use self::tui_string::*;
mod tui_border; pub use self::tui_border::*;
mod tui_button; //pub use self::tui_button::*;
mod tui_color; pub use self::tui_color::*;
mod tui_error; pub use self::tui_error::*;
mod tui_field; pub use self::tui_field::*;
mod tui_number; //pub use self::tui_number::*;
mod tui_phat; pub use self::tui_phat::*;
mod tui_repeat; pub use self::tui_repeat::*;
mod tui_scroll; pub use self::tui_scroll::*;
mod tui_string; pub use self::tui_string::*;
mod tui_style; pub use self::tui_style::*;
mod tui_tryptich; //pub use self::tui_tryptich::*;
pub struct TuiForeground<T>(pub(crate) Foreground<Color, T>);
pub struct TuiBackground<T>(pub(crate) Background<Color, T>);
pub struct Modify<T>(pub bool, pub Modifier, pub T);
pub struct Styled<T>(pub Option<Style>, pub T);
impl<T: Layout<TuiOut>> Layout<TuiOut> for TuiForeground<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
self.0.layout(to)
}
}
impl<T: Layout<TuiOut> + Draw<TuiOut>> Draw<TuiOut> for TuiForeground<T> {
fn draw (&self, to: &mut TuiOut) {
let area = self.layout(to.area());
to.fill_bg(area, self.0.0);
to.place_at(area, &self.0.1);
}
}
impl<T: Layout<TuiOut>> Layout<TuiOut> for TuiBackground<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
self.0.layout(to)
}
}
impl<T: Layout<TuiOut> + Draw<TuiOut>> Draw<TuiOut> for TuiBackground<T> {
fn draw (&self, to: &mut TuiOut) {
let area = self.layout(to.area());
to.fill_bg(area, self.0.0);
to.place_at(area, &self.0.1);
}
}
impl<T: Layout<TuiOut>> Layout<TuiOut> for Modify<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
self.2.layout(to)
}
}
impl<T: Draw<TuiOut>> Draw<TuiOut> for Modify<T> {
fn draw (&self, to: &mut TuiOut) {
to.fill_mod(to.area(), self.0, self.1);
self.2.draw(to)
}
}
impl<T: Layout<TuiOut>> Layout<TuiOut> for Styled<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
self.1.layout(to)
}
}
impl<T: Layout<TuiOut> + Draw<TuiOut>> Draw<TuiOut> for Styled<T> {
fn draw (&self, to: &mut TuiOut) {
to.place(&self.1);
// TODO write style over area
}
}
//impl<T: Draw<TuiOut> + Layout<TuiOut>> Content<TuiOut> for Result<T, Box<dyn std::error::Error>> {
//fn content (&self) -> impl Draw<TuiOut> + Layout<TuiOut> + '_ {
//Bsp::a(self.as_ref().ok(), self.as_ref().err().map(

View file

@ -1,38 +1 @@
use crate::{*, Color::*};
pub fn button_2 <'a> (
key: impl Draw<TuiOut> + Layout<TuiOut> + 'a,
label: impl Draw<TuiOut> + Layout<TuiOut> + 'a,
editing: bool,
) -> impl Draw<TuiOut> + Layout<TuiOut> + 'a {
let key = Tui::fg_bg(Tui::orange(), Tui::g(0), Bsp::e(
Tui::fg(Tui::g(0), ""),
Bsp::e(key, Tui::fg(Tui::g(96), ""))
));
let label = When::new(!editing, Tui::fg_bg(Tui::g(255), Tui::g(96), label));
Tui::bold(true, Bsp::e(key, label))
}
pub fn button_3 <'a> (
key: impl Draw<TuiOut> + Layout<TuiOut> + 'a,
label: impl Draw<TuiOut> + Layout<TuiOut> + 'a,
value: impl Draw<TuiOut> + Layout<TuiOut> + 'a,
editing: bool,
) -> impl Draw<TuiOut> + Layout<TuiOut> + 'a {
let key = Tui::fg_bg(Tui::orange(), Tui::g(0),
Bsp::e(Tui::fg(Tui::g(0), ""), Bsp::e(key, Tui::fg(if editing {
Tui::g(128)
} else {
Tui::g(96)
}, ""))));
let label = Bsp::e(
When::new(!editing, Bsp::e(
Tui::fg_bg(Tui::g(255), Tui::g(96), label),
Tui::fg_bg(Tui::g(128), Tui::g(96), ""),
)),
Bsp::e(
Tui::fg_bg(Tui::g(224), Tui::g(128), value),
Tui::fg_bg(Tui::g(128), Reset, ""),
));
Tui::bold(true, Bsp::e(key, label))
}
//use crate::{*, Color::*};

View file

@ -8,9 +8,6 @@ tui_draw!(|self: &str, to|{
to.text(&self, x, y, w)
});
tui_layout!(|self: Arc<str>, to|self.as_ref().layout(to));
tui_draw!(|self: Arc<str>, to|self.as_ref().draw(to));
tui_layout!(|self: String, to|self.as_str().layout(to));
tui_draw!(|self: String, to|self.as_str().draw(to));

View file

@ -1 +1,56 @@
use crate::*;
pub struct TuiForeground<T>(pub(crate) Foreground<Color, T>);
pub struct TuiBackground<T>(pub(crate) Background<Color, T>);
pub struct Modify<T>(pub bool, pub Modifier, pub T);
pub struct Styled<T>(pub Option<Style>, pub T);
impl<T: Layout<TuiOut>> Layout<TuiOut> for TuiForeground<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
self.0.layout(to)
}
}
impl<T: Layout<TuiOut> + Draw<TuiOut>> Draw<TuiOut> for TuiForeground<T> {
fn draw (&self, to: &mut TuiOut) {
let area = self.layout(to.area());
to.fill_bg(area, self.0.0);
to.place_at(area, &self.0.1);
}
}
impl<T: Layout<TuiOut>> Layout<TuiOut> for TuiBackground<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
self.0.layout(to)
}
}
impl<T: Layout<TuiOut> + Draw<TuiOut>> Draw<TuiOut> for TuiBackground<T> {
fn draw (&self, to: &mut TuiOut) {
let area = self.layout(to.area());
to.fill_bg(area, self.0.0);
to.place_at(area, &self.0.1);
}
}
impl<T: Layout<TuiOut>> Layout<TuiOut> for Modify<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
self.2.layout(to)
}
}
impl<T: Draw<TuiOut>> Draw<TuiOut> for Modify<T> {
fn draw (&self, to: &mut TuiOut) {
to.fill_mod(to.area(), self.0, self.1);
self.2.draw(to)
}
}
impl<T: Layout<TuiOut>> Layout<TuiOut> for Styled<T> {
fn layout (&self, to: [u16;4]) -> [u16;4] {
self.1.layout(to)
}
}
impl<T: Layout<TuiOut> + Draw<TuiOut>> Draw<TuiOut> for Styled<T> {
fn draw (&self, to: &mut TuiOut) {
to.place(&self.1);
// TODO write style over area
}
}

View file

@ -2,13 +2,11 @@ use crate::*;
use std::time::Duration;
use std::thread::{spawn, JoinHandle};
use unicode_width::*;
#[derive(Default)]
pub struct TuiOut {
pub buffer: Buffer,
pub area: [u16;4]
}
impl Out for TuiOut {
type Unit = u16;
type Size = [Self::Unit;2];
@ -26,10 +24,6 @@ impl Out for TuiOut {
*self.area_mut() = last;
}
}
impl Layout<TuiOut> for fn(&mut TuiOut) {}
impl TuiOut {
/// Spawn the output thread.
pub fn run_output <T: Draw<TuiOut> + Send + Sync + 'static> (