mod app;
pub mod input;
pub mod scroll;
pub mod state;
pub mod widgets;
use anyhow::Result;
use app::App;
use crossterm::event::{KeyCode, KeyModifiers};
use ralph_adapters::pty_handle::PtyHandle;
use ralph_proto::{Event, HatId};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
pub use state::{LoopMode, TuiState};
pub use widgets::terminal::TerminalWidget;
pub use widgets::{footer, header};
pub struct Tui {
state: Arc<Mutex<TuiState>>,
pty_handle: Option<PtyHandle>,
prefix_key: KeyCode,
prefix_modifiers: KeyModifiers,
}
impl Tui {
pub fn new() -> Self {
Self {
state: Arc::new(Mutex::new(TuiState::new())),
pty_handle: None,
prefix_key: KeyCode::Char('a'),
prefix_modifiers: KeyModifiers::CONTROL,
}
}
#[must_use]
pub fn with_prefix(mut self, prefix_key: KeyCode, prefix_modifiers: KeyModifiers) -> Self {
self.prefix_key = prefix_key;
self.prefix_modifiers = prefix_modifiers;
self
}
#[must_use]
pub fn with_pty(mut self, pty_handle: PtyHandle) -> Self {
self.pty_handle = Some(pty_handle);
self
}
#[must_use]
pub fn with_hat_map(self, hat_map: HashMap<String, (HatId, String)>) -> Self {
if let Ok(mut state) = self.state.lock() {
*state = TuiState::with_hat_map(hat_map);
}
self
}
pub fn observer(&self) -> impl Fn(&Event) + Send + 'static {
let state = Arc::clone(&self.state);
move |event: &Event| {
if let Ok(mut s) = state.lock() {
s.update(event);
}
}
}
pub async fn run(self) -> Result<()> {
let pty_handle = self
.pty_handle
.expect("PTY handle not set - call with_pty() first");
let app = App::with_prefix(
Arc::clone(&self.state),
pty_handle,
self.prefix_key,
self.prefix_modifiers,
);
app.run().await
}
}
impl Default for Tui {
fn default() -> Self {
Self::new()
}
}