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",
"itertools 0.14.0",
"konst",
"tek_layout",
"tek_input",
"tek_output",
]
[[package]]
name = "tek_engine"
name = "tek_input"
version = "0.2.0"
[[package]]
name = "tek_layout"
name = "tek_output"
version = "0.2.0"
dependencies = [
"tek_engine",
]
[[package]]
name = "tek_tui"
@ -1456,8 +1454,8 @@ dependencies = [
"rand",
"ratatui",
"tek_edn",
"tek_engine",
"tek_layout",
"tek_input",
"tek_output",
]
[[package]]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
[package]
name = "tek_engine"
name = "tek_input"
edition = "2021"
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 command; pub use self::command::*;
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.
pub type Usually<T> = Result<T, Box<dyn Error>>;
pub(crate) 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 }
}
};
}
pub(crate) type Perhaps<T> = Result<Option<T>, Box<dyn Error>>;
#[cfg(test)] #[test] fn test_dimensions () {
assert_eq!(Area::center(&[10u16, 10, 20, 20]), [20, 20]);

View file

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

View file

@ -1,6 +1,15 @@
#![feature(type_alias_impl_trait)]
#![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 either; pub use self::either::*;
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_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::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<()> {
use ::tek_tui::Tui;

View file

@ -1,33 +1,5 @@
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
pub trait Output: Send + Sync + Sized {
/// Unit of length

View file

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

View file

@ -5,12 +5,12 @@
#![feature(impl_trait_in_assoc_type)]
#![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::{
*,
tek_edn::*,
tek_layout::*,
tek_engine::*,
tek_input::*,
tek_output::*,
crossterm::{
self,
event::{

View file

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

View file

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

View file

@ -7,31 +7,6 @@ pub struct Tui {
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 {
/// Construct a new TUI engine and wrap it for shared ownership.
pub fn new () -> Usually<Arc<RwLock<Self>>> {
@ -44,6 +19,23 @@ impl Tui {
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.
pub fn flip (&mut self, mut buffer: Buffer, size: ratatui::prelude::Rect) -> Buffer {
if self.buffer.area != size {
@ -58,4 +50,10 @@ impl Tui {
buffer.reset();
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)
}
}