diff --git a/Cargo.toml b/Cargo.toml index b0fd6fa..8657a68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ winit = { optional = true, version = "0.30.4", features = [ "x11" ]} [dev-dependencies] proptest = { version = "^1" } proptest-derive = { version = "^0.5.1" } -tengri = { path = ".", features = [ "dsl" ] } +tengri = { path = "." } #tengri_proc = { path = "./proc" } [profile.coverage] diff --git a/examples/tui_00.rs b/examples/tui_00.rs index 80e7acd..ff2ca2d 100644 --- a/examples/tui_00.rs +++ b/examples/tui_00.rs @@ -1,31 +1,57 @@ -use ::{std::{io::stdout, sync::{Arc, RwLock}}, ratatui::style::Color, tengri::*}; - tui_main!(State { cursor: 10, ..Default::default() }); -namespace!(State: bool {}); -namespace!(State: u16 {}); -namespace!(State: Color {}); - handle!(TuiIn: |self: State, input|Action::from(input).eval(self).map(|_|None)); - view!(State: TuiOut: [ evaluate_output_expression, evaluate_output_expression_tui ]); - draw!(State: TuiOut: [ draw_example ]); +use ::{ + std::{io::stdout, sync::{Arc, RwLock}}, + tengri::{*, term::*, lang::*, keys::*, draw::*, space::*}, + ratatui::style::Color, +}; + +tui_main!(State { cursor: 10, ..Default::default() }); + +//namespace!(State: bool {}); +//namespace!(State: u16 {}); +//namespace!(State: Color {}); + //handle!(TuiIn: |self: State, input|Action::from(input).eval(self).map(|_|None)); + //view!(State: Tui: [ evaluate_output_expression, evaluate_output_expression_tui ]); + //draw!(State: Tui: [ draw_example ]); + +impl Apply> for State { + fn apply (&mut self, input: &TuiEvent) -> Usually { + todo!() + } +} + +impl View for State { + fn view (&self) -> impl Draw { + let index = self.cursor + 1; + let wh = (self.size.w(), self.size.h()); + let src = VIEWS.get(self.cursor).unwrap_or(&""); + let heading = format!("State {}/{} in {:?}", index, VIEWS.len(), &wh); + let title = bg(Color::Rgb(60, 10, 10), push_y(1, align_n(heading))); + let code = bg(Color::Rgb(10, 60, 10), push_y(2, align_n(format!("{}", src)))); + //let content = ;//();//bg(Color::Rgb(10, 10, 60), View(self, CstIter::new(src))); + self.size.of(bsp_s(title, bsp_n(code, self.understand(to, &src).unwrap()))) + } +} + #[derive(Debug, Default)] struct State { - /** Rendered window size */ size: Measure, - /** Command history (undo/redo) */ history: Vec, - /** User-controllable value */ cursor: usize, + /** Command history (undo/redo). */ + history: Vec, + /** User-controllable value. */ + cursor: usize, + /** Rendered window size. */ + size: crate::space::Size, } -impl_from!(Action: |input: &TuiIn| todo!()); + +//impl_from!(Action: |input: &TuiIn| todo!()); #[derive(Debug)] enum Action { - /** Increment cursor */ Next, - /** Decrement cursor */ Prev + /** Increment cursor */ + Next, + /** Decrement cursor */ + Prev } -fn draw_example (state: &State, to: &mut TuiOut) { - let index = state.cursor + 1; - let wh = state.size.wh(); - let src = VIEWS.get(state.cursor).unwrap_or(&""); - let heading = format!("State {}/{} in {:?}", index, VIEWS.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(state, CstIter::new(src))); - state.size.of(Bsp::s(title, Bsp::n(code, state.understand(to, &src).unwrap()))).draw(to) + +fn draw_example (state: &State, to: &mut Tui) { } + impl Action { const BINDS: &'static str = stringify! { (@left prev) (@right next) }; fn eval (&self, state: &mut State) -> Perhaps { @@ -41,6 +67,7 @@ impl Action { Ok(Some(Self::Next)) } } + const VIEWS: &'static [&'static str] = &[ stringify! { :hello-world }, diff --git a/src/draw.rs b/src/draw.rs index d1b476b..ad47922 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -1,17 +1,5 @@ use crate::{*, lang::*, color::*, space::*}; -/// Emit a [Draw]able. -/// -/// Speculative. How to avoid conflicts with [Draw] proper? -pub trait View { - fn view (&self) -> impl Draw; -} -impl> Draw for &V { - fn draw (self, to: &mut T) -> Usually> { - self.view().draw(to) - } -} - /// Drawable that supports dynamic dispatch. /// /// Drawables are composable, e.g. the [when] and [either] conditionals @@ -42,18 +30,24 @@ impl> Draw for &V { pub trait Draw { fn draw (self, to: &mut T) -> Usually>; } -/// Empty draw -impl Draw for () { - fn draw (self, __: &mut T) -> Usually> { - Ok(Default::default()) +impl> Draw for &D { + fn draw (self, to: &mut T) -> Usually> { + todo!() } } impl> Draw for Option { fn draw (self, to: &mut T) -> Usually> { - Ok(self.map(|draw|draw.draw(to)).transpose()?.unwrap_or_default()) + todo!() } } +/// Emit a [Draw]able. +/// +/// Speculative. How to avoid conflicts with [Draw] proper? +pub trait View { + fn view (&self) -> impl Draw; +} + pub const fn thunk Usually>> (draw: F) -> Thunk { Thunk(draw, std::marker::PhantomData) } @@ -63,7 +57,6 @@ pub struct ThunkUsually>>( pub F, std::marker::PhantomData ); - implUsually>> Draw for Thunk { fn draw (self, to: &mut T) -> Usually> { (self.0)(to) diff --git a/src/exit.rs b/src/exit.rs index 2d07816..0b79708 100644 --- a/src/exit.rs +++ b/src/exit.rs @@ -8,3 +8,10 @@ impl Exit { run(Self(Arc::new(AtomicBool::new(false)))) } } + +impl AsRef> for Exit { + fn as_ref (&self) -> &Arc { + &self.0 + } +} + diff --git a/src/keys.rs b/src/keys.rs index 2d2037c..9cc54e1 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -2,13 +2,13 @@ use crate::task::Task; use ::std::sync::{Arc, RwLock, atomic::{AtomicBool, Ordering::*}}; use ::std::time::Duration; -use ::dizzle::{Usually, Do, impl_from}; +use ::dizzle::{Usually, Apply, impl_from}; use ::crossterm::event::{ read, Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState }; /// Spawn the TUI input thread which reads keys from the terminal. -pub fn tui_input > + Send + Sync + 'static> ( +pub fn tui_input > + Send + Sync + 'static> ( exited: &Arc, state: &Arc>, poll: Duration ) -> Result { let exited = exited.clone(); diff --git a/src/space.rs b/src/space.rs index e0aa498..b3916a5 100644 --- a/src/space.rs +++ b/src/space.rs @@ -1,4 +1,5 @@ use crate::{*, draw::*}; +#[cfg(test)] use proptest_derive::Arbitrary; /// Point with size. /// diff --git a/src/term.rs b/src/term.rs index 32081c4..ff8496d 100644 --- a/src/term.rs +++ b/src/term.rs @@ -21,6 +21,23 @@ use ::{ event::{poll, read, Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState}, } }; +#[macro_export] macro_rules! tui_main { + ($state:expr) => { + pub fn main () -> Usually<()> { + tengri::exit::Exit::run(|exit|{ + let state = Arc::new(RwLock::new($state)); + Ok(( + ::tengri::keys::tui_input( + exit.as_ref(), &state, std::time::Duration::from_millis(100) + )?, + ::tengri::term::tui_output( + stdout(), exit.as_ref(), &state, std::time::Duration::from_millis(10) + )? + )) + }) + } + } +} pub struct Tui(pub Buffer, pub XYWH); impl Screen for Tui { type Unit = u16; } impl Deref for Tui { type Target = Buffer; fn deref (&self) -> &Buffer { &self.0 } }