From b44dc02f33f7ce352d3eb11f20c182167be1e86c Mon Sep 17 00:00:00 2001 From: i do not exist Date: Thu, 23 Apr 2026 20:36:12 +0300 Subject: [PATCH] example 00 compiles again and exits, weirdly. wonder what's up here --- bacon.toml | 5 ++- dizzle | 2 +- examples/tui_00.rs | 47 ++++++++++++----------- shell.nix | 2 +- src/eval.rs | 36 +++++++++--------- src/lib.rs | 1 - src/sing.rs | 2 +- src/space.rs | 3 ++ src/term.rs | 92 ++++++++++++++++++++++++++++------------------ 9 files changed, 110 insertions(+), 80 deletions(-) diff --git a/bacon.toml b/bacon.toml index bbcf195..a189527 100644 --- a/bacon.toml +++ b/bacon.toml @@ -4,9 +4,10 @@ env.CARGO_TERM_COLOR = "always" [keybindings] c = "job:check" -d = "job:doc-open" +d = "job:doc" +D = "job:doc-open" t = "job:test" -n = "job:nextest" +T = "job:nextest" l = "job:clippy" [jobs] diff --git a/dizzle b/dizzle index 192a1d8..e984fbb 160000 --- a/dizzle +++ b/dizzle @@ -1 +1 @@ -Subproject commit 192a1d8257a9f2ad43ebceacb7b5ca348c601471 +Subproject commit e984fbb9fe8e588399744d50841d006454c16657 diff --git a/examples/tui_00.rs b/examples/tui_00.rs index 929c56d..730efa4 100644 --- a/examples/tui_00.rs +++ b/examples/tui_00.rs @@ -1,31 +1,32 @@ use ::{ std::{io::stdout, sync::{Arc, RwLock}}, - tengri::{*, term::*, lang::*, keys::*, draw::*, space::*}, + tengri::{*, term::*, lang::*, keys::*, draw::*, space::*, dizzle::*}, ratatui::style::Color, }; -tui_main!(State { cursor: 10, ..Default::default() }); +tui_main!(State { + cursor: 10, + ..Default::default() +}); -impl Apply> for State { - fn apply (&mut self, input: &TuiEvent) -> Usually { - todo!() - } -} +tui_keys!(|self: State, input| { + 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()))) - } -} +tui_view!(|self: State| { + 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), y_push(1, align_n(heading))); + let code = bg(Color::Rgb(10, 60, 10), y_push(2, align_n(format!("{}", src)))); + //let content = ;//();//bg(Color::Rgb(10, 10, 60), View(self, CstIter::new(src))); + let widget = thunk(move|to: &mut Tui|self.interpret(to, &src)); + self.size.of(south(title, north(code, widget))) +}); -#[derive(Debug, Default)] struct State { +#[derive(Debug, Default)] +struct State { /** Command history (undo/redo). */ history: Vec, /** User-controllable value. */ @@ -34,7 +35,9 @@ impl View for State { size: crate::space::Size, } -//impl_from!(Action: |input: &TuiIn| todo!()); +impl Interpret> for State { +} + #[derive(Debug)] enum Action { /** Increment cursor */ Next, @@ -42,6 +45,8 @@ impl View for State { Prev } +//impl_from!(Action: |input: &TuiIn| todo!()); + fn draw_example (state: &State, to: &mut Tui) { } diff --git a/shell.nix b/shell.nix index f34dc1f..dba3faf 100644 --- a/shell.nix +++ b/shell.nix @@ -2,7 +2,7 @@ {pkgs?import{}}:let stdenv = pkgs.clang19Stdenv; name = "tengri"; - nativeBuildInputs = [ pkgs.pkg-config pkgs.clang pkgs.libclang pkgs.mold ]; + nativeBuildInputs = [ pkgs.pkg-config pkgs.clang pkgs.libclang pkgs.mold pkgs.bacon ]; buildInputs = [ pkgs.libclang pkgs.jack2 ]; LIBCLANG_PATH = "${pkgs.libclang.lib.outPath}/lib"; LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath []; diff --git a/src/eval.rs b/src/eval.rs index 0089ee3..9cb0048 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -16,7 +16,7 @@ use dizzle::*; /// struct State {/*app-specific*/} /// impl<'b> Namespace<'b, bool> for State {} /// impl<'b> Namespace<'b, u16> for State {} -/// impl Understand for State {} +/// impl Interpret for State {} /// /// # fn main () -> tengri::Usually<()> { /// let state = State {}; @@ -30,7 +30,7 @@ use dizzle::*; #[cfg(feature = "dsl")] pub fn eval_view <'a, O: Screen + 'a, S> ( state: &S, output: &mut O, expr: &'a impl Expression ) -> Usually where - S: Understand + S: Interpret + for<'b>Namespace<'b, bool> + for<'b>Namespace<'b, O::Unit> { @@ -52,18 +52,18 @@ use dizzle::*; Some("when") => output.place(&when( state.namespace(arg0?)?.unwrap(), - move|output: &mut O|state.understand(output, &arg1) + move|output: &mut O|state.interpret(output, &arg1) )), Some("either") => output.place(&either( state.namespace(arg0?)?.unwrap(), - move|output: &mut O|state.understand(output, &arg1), - move|output: &mut O|state.understand(output, &arg2), + move|output: &mut O|state.interpret(output, &arg1), + move|output: &mut O|state.interpret(output, &arg2), )), Some("bsp") => output.place(&{ - let a = move|output: &mut O|state.understand(output, &arg0); - let b = move|output: &mut O|state.understand(output, &arg1); + let a = move|output: &mut O|state.interpret(output, &arg0); + let b = move|output: &mut O|state.interpret(output, &arg1); bsp(match frags.next() { Some("n") => Alignment::N, Some("s") => Alignment::S, @@ -76,7 +76,7 @@ use dizzle::*; }), Some("align") => output.place(&{ - let a = move|output: &mut O|state.understand(output, &arg0).unwrap(); + let a = move|output: &mut O|state.interpret(output, &arg0).unwrap(); align(match frags.next() { Some("c") => Alignment::Center, Some("n") => Alignment::N, @@ -90,7 +90,7 @@ use dizzle::*; }), Some("fill") => output.place(&{ - let a = move|output: &mut O|state.understand(output, &arg0).unwrap(); + let a = move|output: &mut O|state.interpret(output, &arg0).unwrap(); match frags.next() { Some("xy") | None => fill_wh(a), Some("x") => fill_w(a), @@ -102,7 +102,7 @@ use dizzle::*; Some("exact") => output.place(&{ let axis = frags.next(); let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("exact: unsupported axis {axis:?}") }; - let cb = move|output: &mut O|state.understand(output, &arg).unwrap(); + let cb = move|output: &mut O|state.interpret(output, &arg).unwrap(); match axis { Some("xy") | None => exact_wh(state.namespace(arg0?)?.unwrap(), state.namespace(arg1?)?.unwrap(), cb), Some("x") => exact_w(state.namespace(arg0?)?.unwrap(), cb), @@ -115,7 +115,7 @@ use dizzle::*; Some("min") => output.place(&{ let axis = frags.next(); let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("min: unsupported axis {axis:?}") }; - let cb = move|output: &mut O|state.understand(output, &arg).unwrap(); + let cb = move|output: &mut O|state.interpret(output, &arg).unwrap(); match axis { Some("xy") | None => min_wh(state.namespace(arg0?)?.unwrap(), state.namespace(arg1?)?.unwrap(), cb), Some("x") => min_w(state.namespace(arg0?)?.unwrap(), cb), @@ -127,7 +127,7 @@ use dizzle::*; Some("max") => output.place(&{ let axis = frags.next(); let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("max: unsupported axis {axis:?}") }; - let cb = move|output: &mut O|state.understand(output, &arg).unwrap(); + let cb = move|output: &mut O|state.interpret(output, &arg).unwrap(); match axis { Some("xy") | None => max_wh(state.namespace(arg0?)?.unwrap(), state.namespace(arg1?)?.unwrap(), cb), Some("x") => max_w(state.namespace(arg0?)?.unwrap(), cb), @@ -139,7 +139,7 @@ use dizzle::*; Some("push") => output.place(&{ let axis = frags.next(); let arg = match axis { Some("x") | Some("y") => arg1, Some("xy") | None => arg2, _ => panic!("push: unsupported axis {axis:?}") }; - let cb = move|output: &mut O|state.understand(output, &arg); + let cb = move|output: &mut O|state.interpret(output, &arg); match axis { Some("xy") | None => push_xy(state.namespace(arg0?)?.unwrap(), state.namespace(arg1?)?.unwrap(), cb), Some("x") => push_x(state.namespace(arg0?)?.unwrap(), cb), @@ -157,13 +157,13 @@ use dizzle::*; /// Interpret TUI-specific layout operation. /// /// ``` -/// use tengri::{Namespace, Understand, Tui, ratatui::prelude::Color}; +/// use tengri::{Namespace, Interpret, Tui, ratatui::prelude::Color}; /// /// struct State; /// impl<'b> Namespace<'b, bool> for State {} /// impl<'b> Namespace<'b, u16> for State {} /// impl<'b> Namespace<'b, Color> for State {} -/// impl Understand for State {} +/// impl Interpret for State {} /// # fn main () -> tengri::Usually<()> { /// let state = State; /// let mut out = Tui::default(); @@ -177,7 +177,7 @@ use dizzle::*; pub fn eval_view_tui <'a, S> ( state: &S, output: &mut Tui, expr: impl Expression + 'a ) -> Usually where - S: Understand + S: Interpret + for<'b>Namespace<'b, bool> + for<'b>Namespace<'b, u16> + for<'b>Namespace<'b, Color> @@ -201,7 +201,7 @@ pub fn eval_view_tui <'a, S> ( let arg0 = arg0?.expect("fg: expected arg 0 (color)"); let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("fg: {arg0:?}: not a color")); output.place(&fg(color, thunk(move|output: &mut Tui|{ - state.understand(output, &arg1)?; + state.interpret(output, &arg1)?; // FIXME?: don't max out the used area? Ok(output.area().into()) }))) @@ -211,7 +211,7 @@ pub fn eval_view_tui <'a, S> ( let arg0 = arg0?.expect("bg: expected arg 0 (color)"); let color = Namespace::namespace(state, arg0)?.unwrap_or_else(||panic!("bg: {arg0:?}: not a color")); output.place(&bg(color, thunk(move|output: &mut Tui|{ - state.understand(output, &arg1)?; + state.interpret(output, &arg1)?; // FIXME?: don't max out the used area? Ok(output.area().into()) }))) diff --git a/src/lib.rs b/src/lib.rs index a5668c3..e7d22ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,6 @@ pub(crate) use ::{ #[cfg(feature = "sing")] pub extern crate jack; #[cfg(feature = "sing")] pub mod sing; -#[cfg(feature = "sing")] pub use ::jack::{*, contrib::{*, ClosureProcessHandler}}; #[cfg(feature = "draw")] pub mod draw; #[cfg(feature = "draw")] pub mod space; diff --git a/src/sing.rs b/src/sing.rs index 9775585..a7903b8 100644 --- a/src/sing.rs +++ b/src/sing.rs @@ -1,5 +1,5 @@ +pub use ::jack::{*, contrib::{*, ClosureProcessHandler}}; use crate::{*, time::PerfModel}; -use ::jack::*; use JackState::*; /// Trait for thing that has a JACK process callback. diff --git a/src/space.rs b/src/space.rs index 0bb159a..2d2033f 100644 --- a/src/space.rs +++ b/src/space.rs @@ -136,6 +136,9 @@ impl Origin { pub fn align (origin: Origin, a: impl Draw) -> impl Draw { thunk(move|to: &mut T| { todo!() }) } +pub fn align_n (a: impl Draw) -> impl Draw { + align(Origin::N, a) +} /// A numeric type that can be used as coordinate. /// diff --git a/src/term.rs b/src/term.rs index ff8496d..2251432 100644 --- a/src/term.rs +++ b/src/term.rs @@ -1,6 +1,6 @@ use crate::{*, lang::*, draw::*, space::{*, Split::*}, color::*, text::*, task::*}; -use unicode_width::{UnicodeWidthStr, UnicodeWidthChar}; -use rand::distributions::uniform::UniformSampler; +//use unicode_width::{UnicodeWidthStr, UnicodeWidthChar}; +//use rand::distributions::uniform::UniformSampler; use ::{ std::{ io::{stdout, Write}, @@ -18,26 +18,72 @@ use ::{ crossterm::{ ExecutableCommand, terminal::{EnterAlternateScreen, LeaveAlternateScreen, enable_raw_mode, disable_raw_mode}, - event::{poll, read, Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState}, + //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) - )? - )) + let input = ::tengri::keys::tui_input( + exit.as_ref(), + &state, + ::std::time::Duration::from_millis(100) + )?; + let output = ::tengri::term::tui_output( + stdout(), + exit.as_ref(), + &state, + ::std::time::Duration::from_millis(10) + )?; + Ok(()) }) } } } + +#[macro_export] macro_rules! tui_keys { + (|$self:ident:$State:ty,$input:ident|$body:block) => { + impl Apply> for $State { + fn apply (&mut $self, $input: &TuiEvent) -> Usually $body + } + }; +} + +#[macro_export] macro_rules! tui_view { + (|$self:ident: $State:ty|$body:block) => { + impl View for $State { + fn view (&$self) -> impl Draw $body + } + } +} + +/// Spawn the TUI output thread which writes colored characters to the terminal. +pub fn tui_output + Send + Sync + 'static> ( + output: W, + exited: &Arc, + state: &Arc>, + sleep: Duration +) -> Usually { + let state = state.clone(); + tui_setup()?; + let mut backend = CrosstermBackend::new(output); + let Size { width, height } = backend.size().expect("get size failed"); + let mut buffer_a = Buffer::empty(Rect { x: 0, y: 0, width, height }); + let mut buffer_b = Buffer::empty(Rect { x: 0, y: 0, width, height }); + Ok(Task::new_sleep(exited.clone(), sleep, move |perf| { + let Size { width, height } = backend.size().expect("get size failed"); + if let Ok(state) = state.try_read() { + tui_resize(&mut backend, &mut buffer_a, Rect { x: 0, y: 0, width, height }); + tui_redraw(&mut backend, &mut buffer_a, &mut buffer_b); + } + let timer = format!("{:>3.3}ms", perf.used.load(Relaxed)); + buffer_a.set_string(0, 0, &timer, Style::default()); + })?) +} + 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 } } @@ -520,30 +566,6 @@ fn y_scroll () -> impl Draw { }) } -/// Spawn the TUI output thread which writes colored characters to the terminal. -pub fn tui_output + Send + Sync + 'static> ( - output: W, - exited: &Arc, - state: &Arc>, - sleep: Duration -) -> Usually { - let state = state.clone(); - tui_setup()?; - let mut backend = CrosstermBackend::new(output); - let Size { width, height } = backend.size().expect("get size failed"); - let mut buffer_a = Buffer::empty(Rect { x: 0, y: 0, width, height }); - let mut buffer_b = Buffer::empty(Rect { x: 0, y: 0, width, height }); - Ok(Task::new_sleep(exited.clone(), sleep, move |perf| { - let Size { width, height } = backend.size().expect("get size failed"); - if let Ok(state) = state.try_read() { - tui_resize(&mut backend, &mut buffer_a, Rect { x: 0, y: 0, width, height }); - tui_redraw(&mut backend, &mut buffer_a, &mut buffer_b); - } - let timer = format!("{:>3.3}ms", perf.used.load(Relaxed)); - buffer_a.set_string(0, 0, &timer, Style::default()); - })?) -} - pub fn tui_redraw <'b, W: Write> ( backend: &mut CrosstermBackend, mut prev_buffer: &'b mut Buffer,