mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2026-07-17 15:56:57 +02:00
try to sort TuiKey/TuiEvent mess
This commit is contained in:
parent
dd7091bda1
commit
53c9438f7d
3 changed files with 108 additions and 113 deletions
121
src/term.rs
121
src/term.rs
|
|
@ -1,7 +1,7 @@
|
||||||
mod border;
|
mod border;
|
||||||
pub use self::border::*;
|
pub use self::border::*;
|
||||||
|
|
||||||
use crate::{*, lang::*, draw::*, task::*};
|
use crate::{*, lang::*, draw::*, task::*, exit::*};
|
||||||
//use unicode_width::{UnicodeWidthStr, UnicodeWidthChar};
|
//use unicode_width::{UnicodeWidthStr, UnicodeWidthChar};
|
||||||
//use rand::distributions::uniform::UniformSampler;
|
//use rand::distributions::uniform::UniformSampler;
|
||||||
use ::{
|
use ::{
|
||||||
|
|
@ -22,46 +22,37 @@ use ::{
|
||||||
//event::{poll, read, Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState},
|
//event::{poll, read, Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
crossterm::event::{
|
||||||
|
read, Event, KeyEvent, KeyModifiers, KeyCode, KeyEventKind, KeyEventState
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Implement standard [main] entrypoint for TUI apps.
|
||||||
#[macro_export] macro_rules! tui_main {
|
#[macro_export] macro_rules! tui_main {
|
||||||
($state:expr) => {
|
($state:expr) => { pub fn main () -> Usually<()> { tui_run_main($state) } }
|
||||||
pub fn main () -> Usually<()> {
|
}
|
||||||
use ::{
|
|
||||||
std::sync::{
|
pub fn tui_run_main <T> (state: T) -> Usually<()> where
|
||||||
Arc,
|
T: View<Tui> + Apply<TuiEvent, Usually<()>> + Send + Sync + 'static
|
||||||
RwLock
|
{
|
||||||
},
|
tui_setup_panic();
|
||||||
std::panic::{
|
Exit::run(|exit|{
|
||||||
set_hook,
|
let state = Arc::new(RwLock::new(state));
|
||||||
PanicHookInfo,
|
let scan = Duration::from_millis(100);
|
||||||
},
|
let input = tui_input(exit.as_ref(), &state, scan)?;
|
||||||
std::time::{
|
let frame = Duration::from_millis(10);
|
||||||
Duration
|
let output = tui_output(exit.as_ref(), &state, frame, std::io::stdout())?;
|
||||||
},
|
output.join();
|
||||||
better_panic::{
|
stdout().execute(LeaveAlternateScreen)?;
|
||||||
Settings,
|
CrosstermBackend::new(stdout()).show_cursor()?;
|
||||||
Verbosity
|
disable_raw_mode()?;
|
||||||
},
|
Ok(())
|
||||||
ratatui::{
|
})
|
||||||
backend::{
|
}
|
||||||
Backend,
|
|
||||||
CrosstermBackend
|
pub fn tui_setup_panic () {
|
||||||
},
|
use ::std::panic::{set_hook, PanicHookInfo};
|
||||||
crossterm::{
|
use ::better_panic::{Settings, Verbosity};
|
||||||
ExecutableCommand,
|
|
||||||
terminal::{
|
|
||||||
disable_raw_mode,
|
|
||||||
LeaveAlternateScreen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tengri::{
|
|
||||||
exit::Exit,
|
|
||||||
keys::tui_input,
|
|
||||||
term::tui_output,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let panic = Settings::auto()
|
let panic = Settings::auto()
|
||||||
.verbosity(Verbosity::Full)
|
.verbosity(Verbosity::Full)
|
||||||
.create_panic_handler();
|
.create_panic_handler();
|
||||||
|
|
@ -71,20 +62,44 @@ use ::{
|
||||||
disable_raw_mode().unwrap();
|
disable_raw_mode().unwrap();
|
||||||
panic(info);
|
panic(info);
|
||||||
}));
|
}));
|
||||||
Exit::run(|exit|{
|
}
|
||||||
let state = Arc::new(RwLock::new($state));
|
|
||||||
let scan = Duration::from_millis(100);
|
/// Enable TUI keyboard input for main state struct.
|
||||||
let input = tui_input(exit.as_ref(), &state, scan)?;
|
#[macro_export] macro_rules! tui_keys {
|
||||||
let frame = Duration::from_millis(10);
|
(|$self:ident:$State:ty,$input:ident|$body:block) => {
|
||||||
let output = tui_output(stdout(), exit.as_ref(), &state, frame)?;
|
impl Apply<TuiEvent, Usually<()>> for $State {
|
||||||
output.join();
|
fn apply (&mut $self, $input: &TuiEvent) -> Usually<()> $body
|
||||||
stdout().execute(LeaveAlternateScreen)?;
|
}
|
||||||
CrosstermBackend::new(stdout()).show_cursor()?;
|
};
|
||||||
disable_raw_mode()?;
|
}
|
||||||
Ok(())
|
|
||||||
|
/// Spawn the TUI input thread which reads keys from the terminal.
|
||||||
|
pub fn tui_input <T: Apply<TuiEvent, Usually<()>> + Send + Sync + 'static> (
|
||||||
|
exited: &Arc<AtomicBool>, state: &Arc<RwLock<T>>, poll: Duration
|
||||||
|
) -> Result<Task, std::io::Error> {
|
||||||
|
let exited = exited.clone();
|
||||||
|
let state = state.clone();
|
||||||
|
Task::new_poll(exited.clone(), poll, move |_| {
|
||||||
|
let event = read().unwrap();
|
||||||
|
match event {
|
||||||
|
|
||||||
|
// Hardcoded exit.
|
||||||
|
Event::Key(KeyEvent {
|
||||||
|
modifiers: KeyModifiers::CONTROL,
|
||||||
|
code: KeyCode::Char('c'),
|
||||||
|
kind: KeyEventKind::Press,
|
||||||
|
state: KeyEventState::NONE
|
||||||
|
}) => { exited.store(true, Relaxed); },
|
||||||
|
|
||||||
|
// Handle all other events by the state:
|
||||||
|
event => {
|
||||||
|
if let Err(e) = state.write().unwrap().apply(&TuiEvent(event)) {
|
||||||
|
panic!("{e}")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable TUI output for state struct.
|
/// Enable TUI output for state struct.
|
||||||
|
|
@ -549,6 +564,8 @@ use self::colors::*; mod colors {
|
||||||
pub const fn tui_yellow () -> Color { Color::Rgb(255,255,0) }
|
pub const fn tui_yellow () -> Color { Color::Rgb(255,255,0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Terminal keyboard input.
|
#[cfg(feature = "term")] pub mod event;
|
||||||
|
#[cfg(feature = "term")] pub use self::event::*;
|
||||||
|
|
||||||
#[cfg(feature = "term")] pub mod keys;
|
#[cfg(feature = "term")] pub mod keys;
|
||||||
#[cfg(feature = "term")] pub use self::keys::*;
|
#[cfg(feature = "term")] pub use self::keys::*;
|
||||||
|
|
|
||||||
25
src/term/event.rs
Normal file
25
src/term/event.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
use ::dizzle::impl_from;
|
||||||
|
use ::crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers};
|
||||||
|
|
||||||
|
/// TUI input loop event.
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]
|
||||||
|
pub struct TuiEvent(
|
||||||
|
/// Wrapped [crossterm::event::Event].
|
||||||
|
pub Event
|
||||||
|
);
|
||||||
|
|
||||||
|
impl_from!(TuiEvent: |e: Event| TuiEvent(
|
||||||
|
e));
|
||||||
|
impl_from!(TuiEvent: |e: KeyEvent| TuiEvent(
|
||||||
|
Event::Key(e)));
|
||||||
|
impl_from!(TuiEvent: |c: KeyCode| TuiEvent(
|
||||||
|
Event::Key(KeyEvent::new(c, KeyModifiers::NONE))));
|
||||||
|
impl_from!(TuiEvent: |c: char| TuiEvent(
|
||||||
|
Event::Key(KeyEvent::new(KeyCode::Char(c), KeyModifiers::NONE))));
|
||||||
|
|
||||||
|
impl Ord for TuiEvent {
|
||||||
|
fn cmp (&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.partial_cmp(other)
|
||||||
|
.unwrap_or_else(||format!("{:?}", self).cmp(&format!("{other:?}"))) // FIXME perf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,69 +1,22 @@
|
||||||
use crate::task::Task;
|
use crate::{task::Task, term::TuiEvent};
|
||||||
|
|
||||||
use ::std::sync::{Arc, RwLock, atomic::{AtomicBool, Ordering::*}};
|
use ::std::sync::{Arc, RwLock, atomic::{AtomicBool, Ordering::*}};
|
||||||
use ::std::time::Duration;
|
use ::std::time::Duration;
|
||||||
use ::dizzle::{Language, Symbol, Usually, Apply, impl_from};
|
use ::dizzle::{Language, Symbol, Usually, Apply};
|
||||||
use ::crossterm::event::{
|
use ::crossterm::event::{
|
||||||
read, Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState
|
read, Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Enable TUI keyboard input for main state struct.
|
/// TUI key spec.
|
||||||
#[macro_export] macro_rules! tui_keys {
|
|
||||||
(|$self:ident:$State:ty,$input:ident|$body:block) => {
|
|
||||||
impl Apply<TuiEvent, Usually<()>> for $State {
|
|
||||||
fn apply (&mut $self, $input: &TuiEvent) -> Usually<()> $body
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Spawn the TUI input thread which reads keys from the terminal.
|
|
||||||
pub fn tui_input <T: Apply<TuiEvent, Usually<()>> + Send + Sync + 'static> (
|
|
||||||
exited: &Arc<AtomicBool>, state: &Arc<RwLock<T>>, poll: Duration
|
|
||||||
) -> Result<Task, std::io::Error> {
|
|
||||||
let exited = exited.clone();
|
|
||||||
let state = state.clone();
|
|
||||||
Task::new_poll(exited.clone(), poll, move |_| {
|
|
||||||
let event = read().unwrap();
|
|
||||||
match event {
|
|
||||||
|
|
||||||
// Hardcoded exit.
|
|
||||||
Event::Key(KeyEvent {
|
|
||||||
modifiers: KeyModifiers::CONTROL,
|
|
||||||
code: KeyCode::Char('c'),
|
|
||||||
kind: KeyEventKind::Press,
|
|
||||||
state: KeyEventState::NONE
|
|
||||||
}) => { exited.store(true, Relaxed); },
|
|
||||||
|
|
||||||
// Handle all other events by the state:
|
|
||||||
event => {
|
|
||||||
if let Err(e) = state.write().unwrap().apply(&TuiEvent(event)) {
|
|
||||||
panic!("{e}")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TUI input loop event.
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]
|
||||||
pub struct TuiEvent(pub Event);
|
pub struct TuiKey(pub Option<KeyCode>, pub KeyModifiers);
|
||||||
|
|
||||||
impl_from!(TuiEvent: |e: Event| TuiEvent(e));
|
impl Ord for TuiKey {
|
||||||
|
|
||||||
impl_from!(TuiEvent: |c: char| TuiEvent(Event::Key(KeyEvent::new(KeyCode::Char(c), KeyModifiers::NONE))));
|
|
||||||
|
|
||||||
impl Ord for TuiEvent {
|
|
||||||
fn cmp (&self, other: &Self) -> std::cmp::Ordering {
|
fn cmp (&self, other: &Self) -> std::cmp::Ordering {
|
||||||
self.partial_cmp(other)
|
self.partial_cmp(other)
|
||||||
.unwrap_or_else(||format!("{:?}", self).cmp(&format!("{other:?}"))) // FIXME perf
|
.unwrap_or_else(||format!("{:?}", self).cmp(&format!("{other:?}"))) // FIXME perf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TUI key spec.
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd)]
|
|
||||||
pub struct TuiKey(pub Option<KeyCode>, pub KeyModifiers);
|
|
||||||
|
|
||||||
impl TuiKey {
|
impl TuiKey {
|
||||||
const SPLIT: char = '/';
|
const SPLIT: char = '/';
|
||||||
pub fn from_crossterm (event: KeyEvent) -> Self {
|
pub fn from_crossterm (event: KeyEvent) -> Self {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue