refactor(cli): 🔨 refactor tui public api

This commit is contained in:
Lucas Colombo 2024-09-17 17:49:38 -03:00
parent b28008d19d
commit 5929ae514e
Signed by: lucas
GPG Key ID: EF34786CFEFFAE35
5 changed files with 79 additions and 43 deletions

View File

@ -251,8 +251,8 @@ impl_downcast!(Component);
/// Update the children's state based on a received action.
///
/// This helper function is used to update the children's state based on a received action. It was
/// created to allow to easily override the default `update` method of a component implementation and
/// be able to call the children's `update` method.
/// created to allow to easily override the default `update` method of a component implementation
/// and still be able to call the children's `update` method.
pub fn update_children<T: Component + ?Sized>(this: &mut T, action: Action) -> Result<()> {
if let Some(children) = this.get_children() {
for child in children.values_mut() {
@ -267,7 +267,7 @@ pub fn update_children<T: Component + ?Sized>(this: &mut T, action: Action) -> R
///
/// This helper function is used to pass a message to the children of a component. It was created
/// to allow to easily override the default `receive_message` method of a component implementation
/// and be able pass the call to the children's `receive_message` method.
/// and still be able pass the call to the children's `receive_message` method.
pub fn pass_message_to_children<T: Component + ?Sized>(
this: &mut T,
message: String,
@ -284,8 +284,8 @@ pub fn pass_message_to_children<T: Component + ?Sized>(
/// Initialize the children of a component.
///
/// This helper function is used to initialize the children of a component. It was created to
/// allow to easily override the default `init` method of a component implementation and be able
/// to call the children's `init` method.
/// allow to easily override the default `init` method of a component implementation and still be
/// able to call the children's `init` method.
pub fn init_children<T: Component + ?Sized>(this: &mut T, area: Size) -> Result<()> {
if let Some(children) = this.get_children() {
for child in children.values_mut() {
@ -300,7 +300,7 @@ pub fn init_children<T: Component + ?Sized>(this: &mut T, area: Size) -> Result<
///
/// This helper function is used to pass the action handler to the children of a component. It was
/// created to allow to easily override the default `register_action_handler` method of a component
/// implementation and be able to call the children's `register_action_handler` method.
/// implementation and still be able to call the children's `register_action_handler` method.
pub fn pass_action_handler_to_children<T: Component + ?Sized>(
this: &mut T,
tx: UnboundedSender<String>,

View File

@ -6,11 +6,15 @@ use {
};
#[derive(Clone, Debug, Default)]
pub struct Config {
pub keybindings: KeyBindings,
}
#[derive(Clone, Debug, Default)]
/// A struct that holds key bindings
///
/// The key bindings are stored in a hashmap where the key is a vector of
/// [`crossterm::event::KeyEvent`] and the value is a
/// [`Action`](crate::tui::Action). This is constructed automatically by [`Kb`](crate::tui::Kb)
/// using a [`str`] to [`Action`](crate::tui::Action) mapping, using special syntax to represent
/// keys and key sequences (see
/// [`parse_key_sequence`](crate::tui::utils::keyboard::parse_key_sequence) and
/// [`Kb`](crate::tui::Kb) for more information).
pub struct KeyBindings(pub HashMap<Vec<KeyEvent>, Action>);
impl KeyBindings {
@ -35,12 +39,18 @@ impl KeyBindings {
}
}
fn parse_key_event(raw: &str) -> Result<KeyEvent, String> {
/// `@internal`
///
/// Parses a string into a [`KeyEvent`]
fn parse_key_event(raw: &str) -> Result<KeyEvent> {
let raw_lower = raw.to_ascii_lowercase();
let (remaining, modifiers) = extract_modifiers(&raw_lower);
parse_key_code_with_modifiers(remaining, modifiers)
}
/// `@internal`
///
/// Extracts the modifiers from a string formatted as `modifier-key`
fn extract_modifiers(raw: &str) -> (&str, KeyModifiers) {
let mut modifiers = KeyModifiers::empty();
let mut current = raw;
@ -66,10 +76,10 @@ fn extract_modifiers(raw: &str) -> (&str, KeyModifiers) {
(current, modifiers)
}
fn parse_key_code_with_modifiers(
raw: &str,
mut modifiers: KeyModifiers,
) -> Result<KeyEvent, String> {
/// `@internal`
///
/// Parses a string into a [`KeyEvent`] with modifiers
fn parse_key_code_with_modifiers(raw: &str, mut modifiers: KeyModifiers) -> Result<KeyEvent> {
let c = match raw {
"esc" => KeyCode::Esc,
"enter" => KeyCode::Enter,
@ -111,11 +121,12 @@ fn parse_key_code_with_modifiers(
}
KeyCode::Char(c)
}
_ => return Err(format!("Unable to parse {raw}")),
_ => return Err(eyre::eyre!("Unable to parse `{}`", raw)),
};
Ok(KeyEvent::new(c, modifiers))
}
/// Converts a [`KeyEvent`] to a string representation
pub fn key_event_to_string(key_event: &KeyEvent) -> String {
let char;
let key_code = match key_event.code {
@ -189,9 +200,9 @@ pub fn key_event_to_string(key_event: &KeyEvent) -> String {
key
}
pub fn parse_key_sequence(raw: &str) -> Result<Vec<KeyEvent>, String> {
pub fn parse_key_sequence(raw: &str) -> Result<Vec<KeyEvent>> {
if raw.chars().filter(|c| *c == '>').count() != raw.chars().filter(|c| *c == '<').count() {
return Err(format!("Unable to parse `{}`", raw));
return Err(eyre::eyre!("Invalid key sequence: `{}`", raw));
}
let raw = if !raw.contains("><") {
let raw = raw.strip_prefix('<').unwrap_or(raw);

View File

@ -22,10 +22,8 @@ use {
tokio_util::sync::CancellationToken,
};
pub use ratatui::prelude::{Color, Constraint, Direction, Layout, Rect, Size};
pub type IO = std::io::Stdout;
pub fn io() -> IO {
fn io() -> IO {
std::io::stdout()
}
pub type Frame<'a> = ratatui::Frame<'a>;

View File

@ -1,6 +1,4 @@
use {eyre::Result, palette::rgb::Rgb, ratatui::style::Color, std::str::FromStr};
pub mod framework {
mod framework {
pub mod app;
pub mod component;
pub mod events;
@ -8,6 +6,32 @@ pub mod framework {
pub mod tui;
}
use {eyre::Result, palette::rgb::Rgb, ratatui::style::Color, std::str::FromStr};
pub use framework::app::{App, Kb};
pub use framework::component::{Children, Component};
pub use framework::events::{Action, Event};
pub use framework::keyboard::KeyBindings;
pub use framework::tui::{Frame, Tui, IO};
pub mod utils {
pub mod component {
pub use super::super::framework::component::{
child_downcast, child_downcast_mut, init_children, pass_action_handler_to_children,
pass_message_to_children, update_children,
};
}
pub mod keyboard {
pub use super::super::framework::keyboard::{key_event_to_string, parse_key_sequence};
}
}
// ratatui prelude
pub mod rataui {
pub use ratatui::prelude::*;
}
#[macro_export]
macro_rules! components {
( $( $x:expr $( => $t:ty )* ),* ) => {

View File

@ -5,6 +5,9 @@
#[cfg(feature = "cli")]
pub mod cli;
#[cfg(feature = "cli.tui")]
pub use cli::tui;
#[cfg(feature = "sched")]
pub mod sched;