mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-02-22 02:59:02 +01:00
add Tui::new, remove View
This commit is contained in:
parent
85ccb0737f
commit
b294f2e62b
4 changed files with 40 additions and 57 deletions
|
|
@ -107,7 +107,7 @@ pub(crate) use ::std::{
|
|||
#[cfg(feature = "dsl")] pub fn evaluate_output_expression <'a, O: Out + 'a, S> (
|
||||
state: &S, output: &mut O, expr: &'a impl Expression
|
||||
) -> Usually<bool> where
|
||||
S: View<O, ()>
|
||||
S: Understand<O, ()>
|
||||
+ for<'b>Namespace<'b, bool>
|
||||
+ for<'b>Namespace<'b, O::Unit>
|
||||
{
|
||||
|
|
@ -282,7 +282,7 @@ pub(crate) use ::std::{
|
|||
#[macro_export] macro_rules! tui_main {
|
||||
($expr:expr) => {
|
||||
fn main () -> Usually<()> {
|
||||
tengri::Tui::run(true, $expr)?;
|
||||
tengri::Tui::new(stdout()).run(true, $expr)?;
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
|
|
@ -323,37 +323,6 @@ macro_rules! border {
|
|||
)+}
|
||||
}
|
||||
|
||||
/// Run an app in the main loop.
|
||||
pub fn tui_run <T: Send + Sync + Draw<TuiOut> + Handle<TuiIn> + 'static> (
|
||||
join: bool,
|
||||
state: &Arc<RwLock<T>>
|
||||
) -> Usually<Arc<RwLock<Tui>>> {
|
||||
let backend = CrosstermBackend::new(stdout());
|
||||
let Size { width, height } = backend.size()?;
|
||||
let tui = Arc::new(RwLock::new(Tui {
|
||||
exited: Arc::new(AtomicBool::new(false)),
|
||||
buffer: Buffer::empty(Rect { x: 0, y: 0, width, height }),
|
||||
area: [0, 0, width, height],
|
||||
perf: Default::default(),
|
||||
backend,
|
||||
}));
|
||||
let _input_thread = tui_input(tui.clone(), state, Duration::from_millis(100));
|
||||
tui.write().unwrap().setup()?;
|
||||
let render_thread = tui_output(tui.clone(), state, Duration::from_millis(10))?;
|
||||
if join {
|
||||
match render_thread.join() {
|
||||
Ok(result) => {
|
||||
tui.write().unwrap().teardown()?;
|
||||
println!("\n\rRan successfully: {result:?}\n\r");
|
||||
},
|
||||
Err(error) => {
|
||||
tui.write().unwrap().teardown()?;
|
||||
panic!("\n\rDraw thread failed: error={error:?}.\n\r")
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(tui)
|
||||
}
|
||||
|
||||
pub fn tui_setup <W: Write> (
|
||||
backend: &mut CrosstermBackend<W>
|
||||
|
|
@ -487,7 +456,7 @@ pub fn tui_input <T: Handle<TuiIn> + Send + Sync + 'static> (
|
|||
#[cfg(feature = "dsl")] pub fn evaluate_output_expression_tui <'a, S> (
|
||||
state: &S, output: &mut TuiOut, expr: impl Expression + 'a
|
||||
) -> Usually<bool> where
|
||||
S: View<TuiOut, ()>
|
||||
S: Understand<TuiOut, ()>
|
||||
+ for<'b>Namespace<'b, bool>
|
||||
+ for<'b>Namespace<'b, u16>
|
||||
+ for<'b>Namespace<'b, Color>
|
||||
|
|
@ -909,7 +878,8 @@ pub(crate) fn width_chars_max (max: u16, text: impl AsRef<str>) -> u16 {
|
|||
Ok(None)
|
||||
}
|
||||
}
|
||||
let engine = Tui::run(false, TestComponent("hello world".into()))?;
|
||||
let mut output = String::new();
|
||||
let engine = Tui::new(&mut output).run(false, TestComponent("hello world".into()))?;
|
||||
engine.read().unwrap().exited.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
//engine.run(&state)?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -983,11 +983,38 @@ impl PerfModel {
|
|||
}
|
||||
|
||||
impl Tui {
|
||||
pub fn new (output: Stdout) -> Usually<Self> {
|
||||
let backend = CrosstermBackend::new(output);
|
||||
let Size { width, height } = backend.size()?;
|
||||
Ok(Self {
|
||||
exited: Arc::new(AtomicBool::new(false)),
|
||||
buffer: Buffer::empty(Rect { x: 0, y: 0, width, height }),
|
||||
area: [0, 0, width, height],
|
||||
perf: Default::default(),
|
||||
backend,
|
||||
})
|
||||
}
|
||||
/// Create and launch a terminal user interface.
|
||||
pub fn run <T> (join: bool, state: T) -> Usually<Arc<RwLock<Self>>> where
|
||||
pub fn run <T> (self, join: bool, state: &Arc<RwLock<T>>) -> Usually<Arc<RwLock<Self>>> where
|
||||
T: Handle<TuiIn> + Draw<TuiOut> + Send + Sync + 'static
|
||||
{
|
||||
tui_run(join, &Arc::new(RwLock::new(state)))
|
||||
let tui = Arc::new(RwLock::new(self));
|
||||
let _input_thread = tui_input(tui.clone(), state, Duration::from_millis(100));
|
||||
tui.write().unwrap().setup()?;
|
||||
let render_thread = tui_output(tui.clone(), state, Duration::from_millis(10))?;
|
||||
if join {
|
||||
match render_thread.join() {
|
||||
Ok(result) => {
|
||||
tui.write().unwrap().teardown()?;
|
||||
println!("\n\rRan successfully: {result:?}\n\r");
|
||||
},
|
||||
Err(error) => {
|
||||
tui.write().unwrap().teardown()?;
|
||||
panic!("\n\rDraw thread failed: error={error:?}.\n\r")
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(tui)
|
||||
}
|
||||
/// True if done
|
||||
pub fn exited (&self) -> bool { self.exited.fetch_and(true, Relaxed) }
|
||||
|
|
@ -1021,6 +1048,11 @@ impl TuiEvent {
|
|||
Ok(TuiKey::from_dsl(dsl)?.to_crossterm().map(Self))
|
||||
}
|
||||
}
|
||||
impl From<char> for TuiEvent {
|
||||
fn from (c: char) -> Self {
|
||||
Self(Event::Key(KeyEvent::new(KeyCode::Char(c), KeyModifiers::NONE)))
|
||||
}
|
||||
}
|
||||
impl TuiKey {
|
||||
const SPLIT: char = '/';
|
||||
#[cfg(feature = "dsl")] pub fn from_dsl (dsl: impl Language) -> Usually<Self> {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ pub struct Tui {
|
|||
pub perf: PerfModel,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone)] pub struct TuiIn {
|
||||
/// Input event
|
||||
pub event: TuiEvent,
|
||||
|
|
|
|||
|
|
@ -112,26 +112,6 @@ pub trait Draw<O: Out> {
|
|||
fn draw (&self, to: &mut O);
|
||||
}
|
||||
|
||||
/// FIXME: This is a general implementation: should be called `Eval` and be part of [dizzle].
|
||||
/// Matches [Language] expressions to renderings for a given [Output] target.
|
||||
pub trait View<O, U> {
|
||||
fn view_expr <'a> (&'a self, _output: &mut O, expr: &'a impl Expression) -> Usually<U> {
|
||||
Err(format!("View::view_expr: no exprs defined: {expr:?}").into())
|
||||
}
|
||||
fn view_word <'a> (&'a self, _output: &mut O, word: &'a impl Symbol) -> Usually<U> {
|
||||
Err(format!("View::view_word: no words defined: {word:?}").into())
|
||||
}
|
||||
fn view <'a> (&'a self, output: &mut O, dsl: &'a impl Language) -> Usually<U> {
|
||||
match (dsl.expr(), dsl.word()) {
|
||||
(Ok(Some(e)), _ ) => self.view_expr(output, &e),
|
||||
(_, Ok(Some(w))) => self.view_word(output, &w),
|
||||
(Err(e), _ ) => Err(format!("invalid view expr:\n{dsl:?}\n{e}").into()),
|
||||
(_, Err(w) ) => Err(format!("invalid view word:\n{dsl:?}\n{w}").into()),
|
||||
(Ok(None), Ok(None) ) => Err(format!("empty view:\n{dsl:?}").into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Outputs combinator.
|
||||
pub trait Lay<O: Out>: Sized {}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue