refactor engine and layout into input and output

This commit is contained in:
🪞👃🪞 2025-01-07 21:30:07 +01:00
parent f052891473
commit 4d0f98acd2
40 changed files with 104 additions and 109 deletions

14
Cargo.lock generated
View file

@ -1432,19 +1432,17 @@ dependencies = [
"clojure-reader", "clojure-reader",
"itertools 0.14.0", "itertools 0.14.0",
"konst", "konst",
"tek_layout", "tek_input",
"tek_output",
] ]
[[package]] [[package]]
name = "tek_engine" name = "tek_input"
version = "0.2.0" version = "0.2.0"
[[package]] [[package]]
name = "tek_layout" name = "tek_output"
version = "0.2.0" version = "0.2.0"
dependencies = [
"tek_engine",
]
[[package]] [[package]]
name = "tek_tui" name = "tek_tui"
@ -1456,8 +1454,8 @@ dependencies = [
"rand", "rand",
"ratatui", "ratatui",
"tek_edn", "tek_edn",
"tek_engine", "tek_input",
"tek_layout", "tek_output",
] ]
[[package]] [[package]]

View file

@ -27,8 +27,10 @@ wavers = "1.4.3"
#winit = { version = "0.30.4", features = [ "x11" ] } #winit = { version = "0.30.4", features = [ "x11" ] }
[features] [features]
default = ["edn"] default = ["tek_input", "tek_output", "tek_edn"]
edn = ["tek_tui/edn"] tek_input = [ "tek_tui/tek_input" ]
tek_output = [ "tek_tui/tek_output" ]
tek_edn = [ "tek_tui/tek_edn" ]
[[bin]] [[bin]]
name = "tek_arranger" name = "tek_arranger"

View file

@ -3,8 +3,8 @@
#[allow(unused_imports)] use tek::{ #[allow(unused_imports)] use tek::{
*, *,
jack::*, jack::*,
tek_layout::Measure, tek_input::*,
tek_engine::Usually, tek_output::*,
tek_tui::{Tui, TuiRun, ItemPalette, ItemColor, ratatui::prelude::Color} tek_tui::{Tui, TuiRun, ItemPalette, ItemColor, ratatui::prelude::Color}
}; };

View file

@ -7,11 +7,12 @@ version = "0.1.0"
clojure-reader = "0.3.0" clojure-reader = "0.3.0"
konst = "0.3.16" konst = "0.3.16"
itertools = "0.14.0" itertools = "0.14.0"
tek_layout = { optional = true, path = "../layout" }
tek_input = { optional = true, path = "../input" }
tek_output = { optional = true, path = "../output" }
[features] [features]
default = ["layout"] default = ["tek_input", "tek_output"]
layout = [ "tek_layout" ]
[dev-dependencies] [dev-dependencies]
tek_tui = { path = "../tui" } tek_tui = { path = "../tui" }

View file

@ -1,6 +1,6 @@
use crate::*; use crate::*;
use std::marker::PhantomData; use std::marker::PhantomData;
use ::tek_layout::{*, tek_engine::{Usually, Content, Render, RenderBox, Output, Thunk}}; use ::tek_output::*;
use EdnItem::*; use EdnItem::*;
pub type EdnCallback<'a, Output, State> = pub type EdnCallback<'a, Output, State> =

View file

@ -4,7 +4,7 @@
pub(crate) use std::{ pub(crate) use std::{
fmt::{Debug, Formatter, Error as FormatError} fmt::{Debug, Formatter, Error as FormatError}
}; };
pub use ::tek_layout; pub use ::tek_output;
mod edn_error; pub use self::edn_error::*; mod edn_error; pub use self::edn_error::*;
mod edn_item; pub use self::edn_item::*; mod edn_item; pub use self::edn_item::*;
@ -12,6 +12,9 @@ mod edn_iter; pub use self::edn_iter::*;
mod edn_token; pub use self::edn_token::*; mod edn_token; pub use self::edn_token::*;
mod edn_view; pub use self::edn_view::*; mod edn_view; pub use self::edn_view::*;
#[cfg(feature = "tek_output")]
pub(crate) use ::tek_output::*;
#[cfg(test)] #[test] fn test_edn () -> Result<(), ParseError> { #[cfg(test)] #[test] fn test_edn () -> Result<(), ParseError> {
use EdnItem::*; use EdnItem::*;
assert_eq!(EdnItem::<String>::read_all("")?, assert_eq!(EdnItem::<String>::read_all("")?,

View file

@ -1,5 +1,5 @@
[package] [package]
name = "tek_engine" name = "tek_input"
edition = "2021" edition = "2021"
version = "0.2.0" version = "0.2.0"

15
input/src/engine.rs Normal file
View file

@ -0,0 +1,15 @@
use crate::*;
/// Event source
pub trait Input: Send + Sync + Sized {
/// Type of input event
type Event;
/// Result of handling input
type Handled;
/// Currently handled event
fn event (&self) -> &Self::Event;
/// Whether component should exit
fn is_done (&self) -> bool;
/// Mark component as done
fn done (&self);
}

View file

@ -5,30 +5,15 @@ mod engine; pub use self::engine::*;
mod handle; pub use self::handle::*; mod handle; pub use self::handle::*;
mod command; pub use self::command::*; mod command; pub use self::command::*;
mod event_map; pub use self::event_map::*; mod event_map; pub use self::event_map::*;
mod coordinate; pub use self::coordinate::*;
mod size; pub use self::size::*;
mod area; pub use self::area::*;
mod render; pub use self::render::*;
mod content; pub use self::content::*;
mod thunk; pub use self::thunk::*;
pub use std::error::Error; pub(crate) use std::marker::PhantomData;
pub(crate) use std::error::Error;
/// Standard result type. /// Standard result type.
pub type Usually<T> = Result<T, Box<dyn Error>>; pub(crate) type Usually<T> = Result<T, Box<dyn Error>>;
/// Standard optional result type. /// Standard optional result type.
pub type Perhaps<T> = Result<Option<T>, Box<dyn Error>>; pub(crate) type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
/// Prototypal case of implementor macro.
/// Saves 4loc per data pats.
#[macro_export] macro_rules! from {
($(<$($lt:lifetime),+>)?|$state:ident:$Source:ty|$Target:ty=$cb:expr) => {
impl $(<$($lt),+>)? From<$Source> for $Target {
fn from ($state:$Source) -> Self { $cb }
}
};
}
#[cfg(test)] #[test] fn test_dimensions () { #[cfg(test)] #[test] fn test_dimensions () {
assert_eq!(Area::center(&[10u16, 10, 20, 20]), [20, 20]); assert_eq!(Area::center(&[10u16, 10, 20, 20]), [20, 20]);

View file

@ -1,10 +1,8 @@
[package] [package]
name = "tek_layout" name = "tek_output"
edition = "2021" edition = "2021"
version = "0.2.0" version = "0.2.0"
[dependencies]
tek_engine = { path = "../engine" }
[dev-dependencies] [dev-dependencies]
tek_tui = { path = "../tui" } tek_tui = { path = "../tui" }
tek_engine = { path = "../engine" }

View file

@ -1,6 +1,15 @@
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![feature(impl_trait_in_assoc_type)] #![feature(impl_trait_in_assoc_type)]
mod coordinate; pub use self::coordinate::*;
mod size; pub use self::size::*;
mod area; pub use self::area::*;
mod output; pub use self::output::*;
mod content; pub use self::content::*;
mod render; pub use self::render::*;
mod thunk; pub use self::thunk::*;
mod when; pub use self::when::*; mod when; pub use self::when::*;
mod either; pub use self::either::*; mod either; pub use self::either::*;
mod map; pub use self::map::*; mod map; pub use self::map::*;
@ -12,9 +21,24 @@ mod measure; pub use self::measure::*;
mod transform_xy; pub use self::transform_xy::*; mod transform_xy; pub use self::transform_xy::*;
mod transform_xy_unit; pub use self::transform_xy_unit::*; mod transform_xy_unit; pub use self::transform_xy_unit::*;
pub use ::tek_engine;
pub(crate) use ::tek_engine::*;
pub(crate) use std::marker::PhantomData; pub(crate) use std::marker::PhantomData;
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>>;
/// Prototypal case of implementor macro.
/// Saves 4loc per data pats.
#[macro_export] macro_rules! from {
($(<$($lt:lifetime),+>)?|$state:ident:$Source:ty|$Target:ty=$cb:expr) => {
impl $(<$($lt),+>)? From<$Source> for $Target {
fn from ($state:$Source) -> Self { $cb }
}
};
}
#[cfg(test)] #[test] fn test_layout () -> Usually<()> { #[cfg(test)] #[test] fn test_layout () -> Usually<()> {
use ::tek_tui::Tui; use ::tek_tui::Tui;

View file

@ -1,33 +1,5 @@
use crate::*; use crate::*;
/// Platform backend.
pub trait Engine: Send + Sync + Sized {
/// Input event type
type Input: Input;
/// Render target
type Output: Output;
/// Prepare before run
fn setup (&mut self) -> Usually<()> { Ok(()) }
/// True if done
fn exited (&self) -> bool;
/// Clean up after run
fn teardown (&mut self) -> Usually<()> { Ok(()) }
}
/// Event source
pub trait Input: Send + Sync + Sized {
/// Type of input event
type Event;
/// Result of handling input
type Handled;
/// Currently handled event
fn event (&self) -> &Self::Event;
/// Whether component should exit
fn is_done (&self) -> bool;
/// Mark component as done
fn done (&self);
}
/// Render target /// Render target
pub trait Output: Send + Sync + Sized { pub trait Output: Send + Sync + Sized {
/// Unit of length /// Unit of length

View file

@ -1,7 +1,6 @@
use crate::*; use crate::*;
use super::*; use super::*;
use std::marker::ConstParamTy; use std::marker::ConstParamTy;
use tek_engine::Render;
use EdnItem::*; use EdnItem::*;
const EDN: &'static str = include_str!("groovebox.edn"); const EDN: &'static str = include_str!("groovebox.edn");

View file

@ -5,12 +5,12 @@
#![feature(impl_trait_in_assoc_type)] #![feature(impl_trait_in_assoc_type)]
#![feature(associated_type_defaults)] #![feature(associated_type_defaults)]
pub use ::tek_tui::{self, tek_engine, tek_layout}; pub use ::tek_tui::{self, tek_edn, tek_input, tek_output};
pub(crate) use ::tek_tui::{ pub(crate) use ::tek_tui::{
*, *,
tek_edn::*, tek_edn::*,
tek_layout::*, tek_input::*,
tek_engine::*, tek_output::*,
crossterm::{ crossterm::{
self, self,
event::{ event::{

View file

@ -4,15 +4,15 @@ edition = "2021"
version = "0.2.0" version = "0.2.0"
[dependencies] [dependencies]
tek_engine = { path = "../engine" }
tek_layout = { path = "../layout" }
tek_edn = { optional = true, path = "../edn" }
palette = { version = "0.7.6", features = [ "random" ] } palette = { version = "0.7.6", features = [ "random" ] }
rand = "0.8.5" rand = "0.8.5"
crossterm = "0.28.1" crossterm = "0.28.1"
ratatui = { version = "0.29.0", features = [ "unstable-widget-ref", "underline-color" ] } ratatui = { version = "0.29.0", features = [ "unstable-widget-ref", "underline-color" ] }
better-panic = "0.3.0" better-panic = "0.3.0"
tek_edn = { optional = true, path = "../edn" }
tek_input = { optional = true, path = "../input" }
tek_output = { optional = true, path = "../output" }
[features] [features]
default = ["edn"] default = ["tek_input", "tek_output", "tek_edn"]
edn = ["tek_edn"]

View file

@ -1,8 +1,8 @@
pub use ::tek_engine; pub use ::tek_input;
pub use ::tek_layout; pub use ::tek_output;
pub use ::tek_edn; pub use ::tek_edn;
pub(crate) use tek_layout::*; pub(crate) use tek_input::*;
pub(crate) use tek_engine::*; pub(crate) use tek_output::*;
mod tui_engine; pub use self::tui_engine::*; mod tui_engine; pub use self::tui_engine::*;
mod tui_content; pub use self::tui_content::*; mod tui_content; pub use self::tui_content::*;

View file

@ -7,31 +7,6 @@ pub struct Tui {
pub area: [u16;4], // FIXME auto resize pub area: [u16;4], // FIXME auto resize
} }
impl Engine for Tui {
type Input = TuiIn;
type Output = TuiOut;
fn exited (&self) -> bool {
self.exited.fetch_and(true, Relaxed)
}
fn setup (&mut self) -> Usually<()> {
let better_panic_handler = Settings::auto().verbosity(Verbosity::Full).create_panic_handler();
std::panic::set_hook(Box::new(move |info: &std::panic::PanicHookInfo|{
stdout().execute(LeaveAlternateScreen).unwrap();
CrosstermBackend::new(stdout()).show_cursor().unwrap();
disable_raw_mode().unwrap();
better_panic_handler(info);
}));
stdout().execute(EnterAlternateScreen)?;
self.backend.hide_cursor()?;
enable_raw_mode().map_err(Into::into)
}
fn teardown (&mut self) -> Usually<()> {
stdout().execute(LeaveAlternateScreen)?;
self.backend.show_cursor()?;
disable_raw_mode().map_err(Into::into)
}
}
impl Tui { impl Tui {
/// Construct a new TUI engine and wrap it for shared ownership. /// Construct a new TUI engine and wrap it for shared ownership.
pub fn new () -> Usually<Arc<RwLock<Self>>> { pub fn new () -> Usually<Arc<RwLock<Self>>> {
@ -44,6 +19,23 @@ impl Tui {
backend, backend,
}))) })))
} }
/// True if done
pub fn exited (&self) -> bool {
self.exited.fetch_and(true, Relaxed)
}
/// Prepare before run
pub fn setup (&mut self) -> Usually<()> {
let better_panic_handler = Settings::auto().verbosity(Verbosity::Full).create_panic_handler();
std::panic::set_hook(Box::new(move |info: &std::panic::PanicHookInfo|{
stdout().execute(LeaveAlternateScreen).unwrap();
CrosstermBackend::new(stdout()).show_cursor().unwrap();
disable_raw_mode().unwrap();
better_panic_handler(info);
}));
stdout().execute(EnterAlternateScreen)?;
self.backend.hide_cursor()?;
enable_raw_mode().map_err(Into::into)
}
/// Update the display buffer. /// Update the display buffer.
pub fn flip (&mut self, mut buffer: Buffer, size: ratatui::prelude::Rect) -> Buffer { pub fn flip (&mut self, mut buffer: Buffer, size: ratatui::prelude::Rect) -> Buffer {
if self.buffer.area != size { if self.buffer.area != size {
@ -58,4 +50,10 @@ impl Tui {
buffer.reset(); buffer.reset();
buffer buffer
} }
/// Clean up after run
pub fn teardown (&mut self) -> Usually<()> {
stdout().execute(LeaveAlternateScreen)?;
self.backend.show_cursor()?;
disable_raw_mode().map_err(Into::into)
}
} }