From 71dead51502f708e784966b72066e17d41e47ab8 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Sun, 16 Mar 2025 23:33:27 +0200 Subject: [PATCH] group tui_engine and tui_content; cargo update --- Cargo.lock | 98 +++++++++++-------- input/src/input.rs | 36 +++++++ tui/src/lib.rs | 8 +- tui/src/tui_content.rs | 9 ++ .../_tui_focus.rs} | 0 .../{tui_menu.rs => tui_content/_tui_menu.rs} | 0 tui/src/{ => tui_content}/tui_color.rs | 12 +++ tui/src/{ => tui_content}/tui_file.rs | 0 tui/src/tui_engine.rs | 53 +++++----- tui/src/{ => tui_engine}/tui_buffer.rs | 5 + tui/src/{ => tui_engine}/tui_input.rs | 1 + tui/src/{ => tui_engine}/tui_output.rs | 0 tui/src/{ => tui_engine}/tui_perf.rs | 0 13 files changed, 150 insertions(+), 72 deletions(-) create mode 100644 input/src/input.rs rename tui/src/{tui_focus.rs => tui_content/_tui_focus.rs} (100%) rename tui/src/{tui_menu.rs => tui_content/_tui_menu.rs} (100%) rename tui/src/{ => tui_content}/tui_color.rs (99%) rename tui/src/{ => tui_content}/tui_file.rs (100%) rename tui/src/{ => tui_engine}/tui_buffer.rs (99%) rename tui/src/{ => tui_engine}/tui_input.rs (99%) rename tui/src/{ => tui_engine}/tui_output.rs (100%) rename tui/src/{ => tui_engine}/tui_perf.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 3ddc94d..0d7c644 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,12 +102,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "cassowary" version = "0.3.0" @@ -177,7 +171,7 @@ dependencies = [ "crossterm_winapi", "mio", "parking_lot", - "rustix", + "rustix 0.38.44", "signal-hook", "signal-hook-mio", "winapi", @@ -229,9 +223,9 @@ dependencies = [ [[package]] name = "either" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "encode_unicode" @@ -275,9 +269,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "getrandom" @@ -333,9 +327,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indoc" -version = "2.0.5" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" [[package]] name = "instability" @@ -370,9 +364,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" @@ -419,9 +413,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.170" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "linux-raw-sys" @@ -429,6 +423,12 @@ version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +[[package]] +name = "linux-raw-sys" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" + [[package]] name = "lock_api" version = "0.4.12" @@ -501,9 +501,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" [[package]] name = "palette" @@ -603,9 +603,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] @@ -673,9 +673,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -742,9 +742,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.4.0" +version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529468c1335c1c03919960dfefdb1b3648858c20d7ec2d0663e728e4a717efbc" +checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ "bitflags", ] @@ -779,15 +779,28 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.9.3", "windows-sys 0.59.0", ] [[package]] name = "rustversion" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "rusty-fork" @@ -803,9 +816,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "scopeguard" @@ -891,9 +904,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.99" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -902,15 +915,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.17.1" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" +checksum = "488960f40a3fd53d72c2a29a58722561dee8afdd175bd88e3db4677d7b2ba600" dependencies = [ - "cfg-if", "fastrand", "getrandom 0.3.1", "once_cell", - "rustix", + "rustix 1.0.2", "windows-sys 0.59.0", ] @@ -949,6 +961,7 @@ version = "0.1.0" dependencies = [ "proptest", "proptest-derive", + "tengri", "tengri_dsl", "tengri_tui", ] @@ -1014,9 +1027,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-segmentation" @@ -1253,19 +1266,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" dependencies = [ "proc-macro2", "quote", diff --git a/input/src/input.rs b/input/src/input.rs new file mode 100644 index 0000000..24dd927 --- /dev/null +++ b/input/src/input.rs @@ -0,0 +1,36 @@ +use crate::*; +use std::time::Duration; +use std::thread::JoinHandle; + +/// Event source +pub trait Input: Send + Sync + Sized { + /// Type of input event + type Event; + /// Result of handling input + type Handled; // TODO: make this an Option> containing the undo + /// Currently handled event + fn event (&self) -> &Self::Event; + /// Whether component should exit + fn is_done (&self) -> bool; + /// Mark component as done + fn done (&self); +} + +/// Input thread entrypoint. +pub trait InputRun { + fn run_input (engine: T, state: Self, timer: Duration) -> JoinHandle<()>; +} + +/// Handle input through a mutable reference. +pub trait Handle: Send + Sync { + fn handle (&mut self, _input: &E) -> Perhaps { + Ok(None) + } +} + +/// Handle input through an immutable reference (e.g. [Arc] or [Arc]) +pub trait HandleRef: Send + Sync { + fn handle (&self, _input: &E) -> Perhaps { + Ok(None) + } +} diff --git a/tui/src/lib.rs b/tui/src/lib.rs index 33f3a6f..6ac4926 100644 --- a/tui/src/lib.rs +++ b/tui/src/lib.rs @@ -1,11 +1,5 @@ -mod tui_buffer; pub use self::tui_buffer::*; -mod tui_color; pub use self::tui_color::*; -mod tui_content; pub use self::tui_content::*; mod tui_engine; pub use self::tui_engine::*; -mod tui_file; pub use self::tui_file::*; -mod tui_input; pub use self::tui_input::*; -mod tui_output; pub use self::tui_output::*; -mod tui_perf; pub use self::tui_perf::*; +mod tui_content; pub use self::tui_content::*; pub use ::tengri_input as input; pub(crate) use ::tengri_input::*; diff --git a/tui/src/tui_content.rs b/tui/src/tui_content.rs index 5db1dac..66d7abf 100644 --- a/tui/src/tui_content.rs +++ b/tui/src/tui_content.rs @@ -1,6 +1,10 @@ use crate::*; use crate::Color::*; use ratatui::prelude::Position; + +mod tui_color; pub use self::tui_color::*; +mod tui_file; pub use self::tui_file::*; + macro_rules! impl_content_layout_render { ($Output:ty: |$self:ident: $Struct:ty, $to:ident| layout = $layout:expr; render = $render:expr) => { impl Content<$Output> for $Struct { @@ -13,19 +17,24 @@ impl_content_layout_render!(TuiOut: |self: &str, to| layout = to.center_xy([self.chars().count() as u16, 1]); render = {let [x, y, ..] = Content::layout(self, to.area()); to.blit(self, x, y, None)}); + impl_content_layout_render!(TuiOut: |self: String, to| layout = to.center_xy([self.chars().count() as u16, 1]); render = {let [x, y, ..] = Content::layout(self, to.area()); to.blit(self, x, y, None)}); + impl_content_layout_render!(TuiOut: |self: std::sync::RwLock, to| layout = Content::::layout(&self.read().unwrap(), to); render = Content::::render(&self.read().unwrap(), to)); + impl_content_layout_render!(TuiOut: |self: std::sync::RwLockReadGuard<'_, String>, to| layout = Content::::layout(&**self, to); render = Content::::render(&**self, to)); + impl_content_layout_render!(TuiOut: |self: Arc, to| layout = to.center_xy([self.chars().count() as u16, 1]); render = to.blit(self, to.area.x(), to.area.y(), None)); + impl> Content for std::sync::Arc { fn layout (&self, to: [u16;4]) -> [u16;4] { Content::::layout(&**self, to) diff --git a/tui/src/tui_focus.rs b/tui/src/tui_content/_tui_focus.rs similarity index 100% rename from tui/src/tui_focus.rs rename to tui/src/tui_content/_tui_focus.rs diff --git a/tui/src/tui_menu.rs b/tui/src/tui_content/_tui_menu.rs similarity index 100% rename from tui/src/tui_menu.rs rename to tui/src/tui_content/_tui_menu.rs diff --git a/tui/src/tui_color.rs b/tui/src/tui_content/tui_color.rs similarity index 99% rename from tui/src/tui_color.rs rename to tui/src/tui_content/tui_color.rs index cdf278e..6fd765c 100644 --- a/tui/src/tui_color.rs +++ b/tui/src/tui_content/tui_color.rs @@ -1,5 +1,6 @@ use crate::*; use rand::{thread_rng, distributions::uniform::UniformSampler}; + impl Tui { pub const fn null () -> Color { Color::Reset } pub const fn g (g: u8) -> Color { Color::Rgb(g, g, g) } @@ -23,7 +24,9 @@ impl Tui { //fn ti1 () -> Color { Color::Rgb(150, 160, 90) } //fn ti2 () -> Color { Color::Rgb(120, 130, 100) } } + pub trait HasColor { fn color (&self) -> ItemColor; } + #[macro_export] macro_rules! has_color { (|$self:ident:$Struct:ident$(<$($L:lifetime),*$($T:ident$(:$U:path)?),*>)?|$cb:expr) => { impl $(<$($L),*$($T $(: $U)?),*>)? HasColor for $Struct $(<$($L),*$($T),*>)? { @@ -31,17 +34,22 @@ pub trait HasColor { fn color (&self) -> ItemColor; } } } } + /// A color in OKHSL and RGB representations. #[derive(Debug, Default, Copy, Clone, PartialEq)] pub struct ItemColor { pub okhsl: Okhsl, pub rgb: Color, } + from!(|okhsl: Okhsl|ItemColor = Self { okhsl, rgb: okhsl_to_rgb(okhsl) }); + pub fn okhsl_to_rgb (color: Okhsl) -> Color { let Srgb { red, green, blue, .. }: Srgb = Srgb::from_color_unclamped(color); Color::Rgb((red * 255.0) as u8, (green * 255.0) as u8, (blue * 255.0) as u8,) } + from!(|rgb: Color|ItemColor = Self { rgb, okhsl: rgb_to_okhsl(rgb) }); + pub fn rgb_to_okhsl (color: Color) -> Okhsl { if let Color::Rgb(r, g, b) = color { Okhsl::from_color(Srgb::new(r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0)) @@ -49,6 +57,7 @@ pub fn rgb_to_okhsl (color: Color) -> Okhsl { unreachable!("only Color::Rgb is supported") } } + // A single color within item theme parameters, in OKHSL and RGB representations. impl ItemColor { pub const fn from_rgb (rgb: Color) -> Self { @@ -77,6 +86,7 @@ impl ItemColor { self.okhsl.mix(other.okhsl, distance).into() } } + /// A color in OKHSL and RGB with lighter and darker variants. #[derive(Debug, Default, Copy, Clone, PartialEq)] pub struct ItemPalette { pub base: ItemColor, @@ -87,6 +97,7 @@ impl ItemColor { pub darker: ItemColor, pub darkest: ItemColor, } + impl ItemPalette { pub const G: [Self;256] = { let mut builder = konst::array::ArrayBuilder::new(); @@ -159,5 +170,6 @@ impl ItemPalette { } } } + from!(|base: Color| ItemPalette = Self::from_tui_color(base)); from!(|base: ItemColor|ItemPalette = Self::from_item_color(base)); diff --git a/tui/src/tui_file.rs b/tui/src/tui_content/tui_file.rs similarity index 100% rename from tui/src/tui_file.rs rename to tui/src/tui_content/tui_file.rs diff --git a/tui/src/tui_engine.rs b/tui/src/tui_engine.rs index e53474a..8caa842 100644 --- a/tui/src/tui_engine.rs +++ b/tui/src/tui_engine.rs @@ -1,5 +1,11 @@ use crate::*; use std::time::Duration; + +mod tui_buffer; pub use self::tui_buffer::*; +mod tui_input; pub use self::tui_input::*; +mod tui_output; pub use self::tui_output::*; +mod tui_perf; pub use self::tui_perf::*; + pub struct Tui { pub exited: Arc, pub backend: CrosstermBackend, @@ -7,6 +13,31 @@ pub struct Tui { pub area: [u16;4], pub perf: PerfModel, } + +pub trait TuiRun + Handle + 'static> { + /// Run an app in the main loop. + fn run (&self, state: &Arc>) -> Usually<()>; +} + +impl + Handle + 'static> TuiRun for Arc> { + fn run (&self, state: &Arc>) -> Usually<()> { + let _input_thread = TuiIn::run_input(self, state, Duration::from_millis(100)); + self.write().unwrap().setup()?; + let render_thread = TuiOut::run_output(self, state, Duration::from_millis(10)); + match render_thread.join() { + Ok(result) => { + self.write().unwrap().teardown()?; + println!("\n\rRan successfully: {result:?}\n\r"); + }, + Err(error) => { + self.write().unwrap().teardown()?; + panic!("\n\rRender thread failed: {error:?}.\n\r") + }, + } + Ok(()) + } +} + impl Tui { /// Construct a new TUI engine and wrap it for shared ownership. pub fn new () -> Usually>> { @@ -58,25 +89,3 @@ impl Tui { disable_raw_mode().map_err(Into::into) } } -pub trait TuiRun + Handle + 'static> { - /// Run an app in the main loop. - fn run (&self, state: &Arc>) -> Usually<()>; -} -impl + Handle + 'static> TuiRun for Arc> { - fn run (&self, state: &Arc>) -> Usually<()> { - let _input_thread = TuiIn::run_input(self, state, Duration::from_millis(100)); - self.write().unwrap().setup()?; - let render_thread = TuiOut::run_output(self, state, Duration::from_millis(10)); - match render_thread.join() { - Ok(result) => { - self.write().unwrap().teardown()?; - println!("\n\rRan successfully: {result:?}\n\r"); - }, - Err(error) => { - self.write().unwrap().teardown()?; - panic!("\n\rRender thread failed: {error:?}.\n\r") - }, - } - Ok(()) - } -} diff --git a/tui/src/tui_buffer.rs b/tui/src/tui_engine/tui_buffer.rs similarity index 99% rename from tui/src/tui_buffer.rs rename to tui/src/tui_engine/tui_buffer.rs index d229008..7fc44b9 100644 --- a/tui/src/tui_buffer.rs +++ b/tui/src/tui_engine/tui_buffer.rs @@ -1,4 +1,5 @@ use crate::*; + pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut Cell, u16, u16)) { for row in 0..area.h() { let y = area.y() + row; @@ -12,16 +13,19 @@ pub fn buffer_update (buf: &mut Buffer, area: [u16;4], callback: &impl Fn(&mut C } } } + #[derive(Default)] pub struct BigBuffer { pub width: usize, pub height: usize, pub content: Vec } + impl std::fmt::Debug for BigBuffer { fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { write!(f, "[BB {}x{} ({})]", self.width, self.height, self.content.len()) } } + impl BigBuffer { pub fn new (width: usize, height: usize) -> Self { Self { width, height, content: vec![Cell::default(); width*height] } @@ -38,4 +42,5 @@ impl BigBuffer { y * self.width + x } } + from!(|size:(usize, usize)| BigBuffer = Self::new(size.0, size.1)); diff --git a/tui/src/tui_input.rs b/tui/src/tui_engine/tui_input.rs similarity index 99% rename from tui/src/tui_input.rs rename to tui/src/tui_engine/tui_input.rs index c46db32..d09aa86 100644 --- a/tui/src/tui_input.rs +++ b/tui/src/tui_engine/tui_input.rs @@ -2,6 +2,7 @@ use crate::*; use std::time::Duration; use std::thread::{spawn, JoinHandle}; use crossterm::event::{poll, read}; + #[derive(Debug, Clone)] pub struct TuiIn(pub Arc, pub Event); impl Input for TuiIn { type Event = Event; diff --git a/tui/src/tui_output.rs b/tui/src/tui_engine/tui_output.rs similarity index 100% rename from tui/src/tui_output.rs rename to tui/src/tui_engine/tui_output.rs diff --git a/tui/src/tui_perf.rs b/tui/src/tui_engine/tui_perf.rs similarity index 100% rename from tui/src/tui_perf.rs rename to tui/src/tui_engine/tui_perf.rs