pub use ratatui; pub use crossterm; pub use jack; pub use midly; pub use clap; pub use std::sync::{Arc, Mutex, LockResult, RwLock, RwLockReadGuard, RwLockWriteGuard}; pub use std::collections::BTreeMap; pub use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers}; pub use ratatui::prelude::{Rect, Style, Color, Buffer}; pub use ratatui::style::Stylize; pub use clojure_reader::{edn::{read, Edn}, error::Error as EdnError}; pub use once_cell::sync::Lazy; pub use std::sync::atomic::{Ordering, AtomicBool}; pub(crate) use std::error::Error; pub(crate) use std::io::{stdout}; pub(crate) use std::thread::{spawn, JoinHandle}; pub(crate) use std::time::Duration; pub(crate) use atomic_float::*; //pub(crate) use std::path::PathBuf; //pub(crate) use std::fs::read_dir; //pub(crate) use std::ffi::OsString; // Non-stdlib dependencies: //pub(crate) use microxdg::XdgApp; //pub(crate) use midly::{MidiMessage, live::LiveEvent, num::u7}; pub(crate) use crossterm::{ExecutableCommand}; use better_panic::{Settings, Verbosity}; use crossterm::terminal::{ EnterAlternateScreen, LeaveAlternateScreen, enable_raw_mode, disable_raw_mode }; /// Define and reexport submodules. #[macro_export] macro_rules! submod { ($($name:ident)*) => { $(mod $name; pub use self::$name::*;)* }; } /// Define and reexport public modules. #[macro_export] macro_rules! pubmod { ($($name:ident)*) => { $(pub mod $name;)* }; } submod! { exit handle jack_core jack_device jack_event jack_ports render render_axis render_border render_collect render_fill render_layered render_split render_theme time_base time_note time_tick } /// EDN parsing helper. #[macro_export] macro_rules! edn { ($edn:ident { $($pat:pat => $expr:expr),* $(,)? }) => { match $edn { $($pat => $expr),* } }; ($edn:ident in $args:ident { $($pat:pat => $expr:expr),* $(,)? }) => { for $edn in $args { edn!($edn { $($pat => $expr),* }) } }; } /// Standard result type. pub type Usually = Result>; /// A UI component. pub trait Component: Render + Handle + Sync { /// Perform type erasure for collecting heterogeneous components. fn boxed (self) -> Box where Self: Sized + 'static { Box::new(self) } } impl Component for T {} /// Marker trait for [Component]s that can [Exit] pub trait ExitableComponent: Exit + Component { /// Perform type erasure for collecting heterogeneous components. fn boxed (self) -> Box where Self: Sized + 'static { Box::new(self) } } impl ExitableComponent for T {} /// Run the main loop. pub fn run (state: Arc>) -> Usually>> where T: Render + Handle + Send + Sync + Sized + 'static { let exited = Arc::new(AtomicBool::new(false)); let _input_thread = input_thread(&exited, &state); terminal_setup()?; panic_hook_setup(); let main_thread = render_thread(&exited, &state)?; main_thread.join().expect("main thread failed"); terminal_teardown()?; Ok(state) } /// Set up panic hook pub fn panic_hook_setup () { let better_panic_handler = Settings::auto().verbosity(Verbosity::Full).create_panic_handler(); std::panic::set_hook(Box::new(move |info: &std::panic::PanicInfo|{ stdout().execute(LeaveAlternateScreen).unwrap(); disable_raw_mode().unwrap(); better_panic_handler(info); })); } /// Set up terminal pub fn terminal_setup () -> Usually<()> { stdout().execute(EnterAlternateScreen)?; enable_raw_mode()?; Ok(()) } /// Cleanup pub fn terminal_teardown () -> Usually<()> { stdout().execute(LeaveAlternateScreen)?; disable_raw_mode()?; Ok(()) }