From 5929ae514e40e25a306c276bcbd61e459cb3c233 Mon Sep 17 00:00:00 2001 From: Lucas Colombo Date: Tue, 17 Sep 2024 17:49:38 -0300 Subject: [PATCH] =?UTF-8?q?refactor(cli):=20=F0=9F=94=A8=20refactor=20tui?= =?UTF-8?q?=20public=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/cli/tui/framework/component.rs | 12 ++++----- lib/cli/tui/framework/keyboard.rs | 37 ++++++++++++++++++---------- lib/cli/tui/framework/tui.rs | 4 +-- lib/cli/tui/mod.rs | 30 ++++++++++++++++++++--- lib/lib.rs | 39 ++++++++++++++++-------------- 5 files changed, 79 insertions(+), 43 deletions(-) diff --git a/lib/cli/tui/framework/component.rs b/lib/cli/tui/framework/component.rs index 602df7d..72e06cf 100644 --- a/lib/cli/tui/framework/component.rs +++ b/lib/cli/tui/framework/component.rs @@ -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(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(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( this: &mut T, message: String, @@ -284,8 +284,8 @@ pub fn pass_message_to_children( /// 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(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(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( this: &mut T, tx: UnboundedSender, diff --git a/lib/cli/tui/framework/keyboard.rs b/lib/cli/tui/framework/keyboard.rs index 54d96f4..3f52ff1 100644 --- a/lib/cli/tui/framework/keyboard.rs +++ b/lib/cli/tui/framework/keyboard.rs @@ -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, Action>); impl KeyBindings { @@ -35,12 +39,18 @@ impl KeyBindings { } } -fn parse_key_event(raw: &str) -> Result { +/// `@internal` +/// +/// Parses a string into a [`KeyEvent`] +fn parse_key_event(raw: &str) -> Result { 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 { +/// `@internal` +/// +/// Parses a string into a [`KeyEvent`] with modifiers +fn parse_key_code_with_modifiers(raw: &str, mut modifiers: KeyModifiers) -> Result { 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, String> { +pub fn parse_key_sequence(raw: &str) -> Result> { 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); diff --git a/lib/cli/tui/framework/tui.rs b/lib/cli/tui/framework/tui.rs index f8cc1cd..38c969a 100644 --- a/lib/cli/tui/framework/tui.rs +++ b/lib/cli/tui/framework/tui.rs @@ -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>; diff --git a/lib/cli/tui/mod.rs b/lib/cli/tui/mod.rs index f62cfae..3f86d2a 100644 --- a/lib/cli/tui/mod.rs +++ b/lib/cli/tui/mod.rs @@ -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 )* ),* ) => { diff --git a/lib/lib.rs b/lib/lib.rs index 53d5454..4c18623 100644 --- a/lib/lib.rs +++ b/lib/lib.rs @@ -1,18 +1,21 @@ -#![doc( - html_logo_url = "https://raw.githubusercontent.com/lucodear/lool/master/.github/img/logo.svg" -)] - -#[cfg(feature = "cli")] -pub mod cli; - -#[cfg(feature = "sched")] -pub mod sched; - -#[cfg(feature = "logger")] -pub mod logger; - -#[cfg(feature = "macros")] -pub mod macros; - -#[cfg(feature = "utils")] -pub mod utils; +#![doc( + html_logo_url = "https://raw.githubusercontent.com/lucodear/lool/master/.github/img/logo.svg" +)] + +#[cfg(feature = "cli")] +pub mod cli; + +#[cfg(feature = "cli.tui")] +pub use cli::tui; + +#[cfg(feature = "sched")] +pub mod sched; + +#[cfg(feature = "logger")] +pub mod logger; + +#[cfg(feature = "macros")] +pub mod macros; + +#[cfg(feature = "utils")] +pub mod utils;