diff --git a/src/widgets.rs b/src/widgets.rs index cf2fe72..5c97fae 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -1,5 +1,6 @@ mod controls; mod formatted_log; +mod icons; mod lazy_paragraph; mod raw_log; mod root; @@ -8,6 +9,7 @@ mod state; pub use controls::*; pub use formatted_log::*; +pub use icons::*; pub use lazy_paragraph::*; pub use raw_log::*; pub use root::*; diff --git a/src/widgets/controls.rs b/src/widgets/controls.rs index 80851c1..0396ef7 100644 --- a/src/widgets/controls.rs +++ b/src/widgets/controls.rs @@ -1,8 +1,14 @@ -use crate::{events::AppEvent, widgets::State}; +use crate::{ + events::AppEvent, + widgets::{DefaultIconPack, IconPack, State}, +}; use crossterm::event::{KeyCode, KeyModifiers, MouseButton}; use indexmap::IndexMap; use itertools::Itertools; -use std::fmt::{Display, Formatter}; +use std::{ + fmt::{Display, Formatter}, + marker::PhantomData, +}; use tui::{ buffer::Buffer, layout::Rect, @@ -14,61 +20,32 @@ use unicode_width::UnicodeWidthStr; #[allow(dead_code)] // TODO: Add support for mouse events #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] -pub enum BindingDisplay { +pub enum BindingDisplay { Key { key_code: KeyCode, modifiers: KeyModifiers, }, Mouse(MouseButton), Custom(&'static str), + #[doc(hidden)] + __Marker(PhantomData<*const I>), } -impl BindingDisplay { - pub const CONTROL_ICON: &'static str = if cfg!(target_os = "macos") { - "\u{2318}" - } else { - "\u{2303}" - }; - pub const ALT_ICON: &'static str = "\u{2325}"; - pub const SHIFT_ICON: &'static str = "\u{21e7}"; - - pub const BACKSPACE_ICON: &'static str = "\u{232b}"; - pub const ENTER_ICON: &'static str = "\u{23ce}"; - pub const LEFT_ICON: &'static str = "\u{2190}"; - pub const RIGHT_ICON: &'static str = "\u{2192}"; - pub const UP_ICON: &'static str = "\u{2191}"; - pub const DOWN_ICON: &'static str = "\u{2193}"; - pub const HOME_ICON: &'static str = "\u{2196}"; - pub const END_ICON: &'static str = "\u{2198}"; - pub const PAGEUP_ICON: &'static str = "\u{21de}"; - pub const PAGEDOWN_ICON: &'static str = "\u{21df}"; - pub const TAB_ICON: &'static str = "\u{21e5}"; - pub const BACKTAB_ICON: &'static str = "\u{21e4}"; - pub const DELETE_ICON: &'static str = "\u{2326}"; - pub const INSERT_ICON: &'static str = "INS"; - pub const NULL_ICON: &'static str = "NUL"; - pub const ESC_ICON: &'static str = "\u{238b}"; - pub const SPACE_ICON: &'static str = "\u{2423}"; - - #[allow(dead_code)] // For future use - pub const UP_DOWN: &'static str = "\u{2191}\u{2193}"; - pub const LEFT_RIGHT: &'static str = "\u{2192}\u{2190}"; - pub const ARROWS: &'static str = "\u{2191}\u{2193}\u{2192}\u{2190}"; - +impl BindingDisplay { const MODIFIER_DISPLAYS: [(KeyModifiers, &'static str); 3] = [ - (KeyModifiers::CONTROL, BindingDisplay::CONTROL_ICON), - (KeyModifiers::ALT, BindingDisplay::ALT_ICON), - (KeyModifiers::SHIFT, BindingDisplay::SHIFT_ICON), + (KeyModifiers::CONTROL, I::CONTROL_ICON), + (KeyModifiers::ALT, I::ALT_ICON), + (KeyModifiers::SHIFT, I::SHIFT_ICON), ]; - pub const fn key(key_code: KeyCode, modifiers: KeyModifiers) -> Self { + pub fn key(key_code: KeyCode, modifiers: KeyModifiers) -> Self { BindingDisplay::Key { key_code, modifiers, } } - pub const fn simple_key(key_code: KeyCode) -> Self { + pub fn simple_key(key_code: KeyCode) -> Self { BindingDisplay::Key { key_code, modifiers: KeyModifiers::empty(), @@ -76,7 +53,7 @@ impl BindingDisplay { } } -impl Display for BindingDisplay { +impl Display for BindingDisplay { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { BindingDisplay::Key { @@ -94,31 +71,32 @@ impl Display for BindingDisplay { // Write key code match key_code { - KeyCode::BackTab => write!(f, "{}", Self::BACKTAB_ICON), - KeyCode::Backspace => write!(f, "{}", Self::BACKSPACE_ICON), - KeyCode::Char(' ') => write!(f, "{}", Self::SPACE_ICON), + KeyCode::BackTab => write!(f, "{}", I::BACKTAB_ICON), + KeyCode::Backspace => write!(f, "{}", I::BACKSPACE_ICON), + KeyCode::Char(' ') => write!(f, "{}", I::SPACE_ICON), KeyCode::Char(c) => write!(f, "{}", c), - KeyCode::Delete => write!(f, "{}", Self::DELETE_ICON), - KeyCode::Down => write!(f, "{}", Self::DOWN_ICON), - KeyCode::End => write!(f, "{}", Self::END_ICON), - KeyCode::Enter => write!(f, "{}", Self::ENTER_ICON), - KeyCode::Esc => write!(f, "{}", Self::ESC_ICON), + KeyCode::Delete => write!(f, "{}", I::DELETE_ICON), + KeyCode::Down => write!(f, "{}", I::DOWN_ICON), + KeyCode::End => write!(f, "{}", I::END_ICON), + KeyCode::Enter => write!(f, "{}", I::ENTER_ICON), + KeyCode::Esc => write!(f, "{}", I::ESC_ICON), KeyCode::F(n) => write!(f, "F{}", n), - KeyCode::Home => write!(f, "{}", Self::HOME_ICON), - KeyCode::Insert => write!(f, "{}", Self::INSERT_ICON), - KeyCode::Left => write!(f, "{}", Self::LEFT_ICON), - KeyCode::Null => write!(f, "{}", Self::NULL_ICON), - KeyCode::PageDown => write!(f, "{}", Self::PAGEDOWN_ICON), - KeyCode::PageUp => write!(f, "{}", Self::PAGEUP_ICON), - KeyCode::Right => write!(f, "{}", Self::RIGHT_ICON), - KeyCode::Tab => write!(f, "{}", Self::TAB_ICON), - KeyCode::Up => write!(f, "{}", Self::UP_ICON), + KeyCode::Home => write!(f, "{}", I::HOME_ICON), + KeyCode::Insert => write!(f, "{}", I::INSERT_ICON), + KeyCode::Left => write!(f, "{}", I::LEFT_ICON), + KeyCode::Null => write!(f, "{}", I::NULL_ICON), + KeyCode::PageDown => write!(f, "{}", I::PAGEDOWN_ICON), + KeyCode::PageUp => write!(f, "{}", I::PAGEUP_ICON), + KeyCode::Right => write!(f, "{}", I::RIGHT_ICON), + KeyCode::Tab => write!(f, "{}", I::TAB_ICON), + KeyCode::Up => write!(f, "{}", I::UP_ICON), } } BindingDisplay::Mouse(MouseButton::Left) => write!(f, "M1"), BindingDisplay::Mouse(MouseButton::Right) => write!(f, "M2"), BindingDisplay::Mouse(MouseButton::Middle) => write!(f, "M3"), BindingDisplay::Custom(label) => write!(f, "{}", label), + _ => Ok(()), } } } @@ -211,12 +189,15 @@ impl StatefulWidget for Controls { #[derive(Clone, Debug, Default)] pub struct ControlsState { - controls: IndexMap, + controls: IndexMap, &'static str>, page: usize, } impl ControlsState { - pub fn set_controls(&mut self, controls: IndexMap) -> &mut Self { + pub fn set_controls( + &mut self, + controls: IndexMap, &'static str>, + ) -> &mut Self { self.controls = controls; self } diff --git a/src/widgets/formatted_log.rs b/src/widgets/formatted_log.rs index 3c72559..c8406ec 100644 --- a/src/widgets/formatted_log.rs +++ b/src/widgets/formatted_log.rs @@ -2,7 +2,7 @@ use crate::{ ast::{Level, Message}, events::AppEvent, log::Log, - widgets::{BindingDisplay, LazyParagraph, LazyParagraphState, State, WithLog}, + widgets::{BindingDisplay, IconPack, LazyParagraph, LazyParagraphState, State, WithLog}, }; use crossterm::event::{Event, KeyCode}; use indexmap::IndexMap; @@ -287,7 +287,7 @@ impl<'i> State for FormattedLogState<'i> { } } - fn add_controls(&self, controls: &mut IndexMap) { + fn add_controls(&self, controls: &mut IndexMap, &'static str>) { match self.filters_list_state.as_ref() { None => { controls.insert(BindingDisplay::simple_key(KeyCode::Char('f')), "Filters"); @@ -591,8 +591,8 @@ impl State for FiltersListState { } } - fn add_controls(&self, controls: &mut IndexMap) { - controls.insert(BindingDisplay::Custom(BindingDisplay::LEFT_RIGHT), "Nav"); + fn add_controls(&self, controls: &mut IndexMap, &'static str>) { + controls.insert(BindingDisplay::Custom(I::LEFT_RIGHT), "Nav"); } } diff --git a/src/widgets/icons.rs b/src/widgets/icons.rs new file mode 100644 index 0000000..47dd380 --- /dev/null +++ b/src/widgets/icons.rs @@ -0,0 +1,101 @@ +use std::{fmt::Debug, hash::Hash}; + +pub trait IconPack: Clone + Copy + PartialEq + Eq + Debug + Hash + Default + 'static { + const CONTROL_ICON: &'static str; + const ALT_ICON: &'static str; + const SHIFT_ICON: &'static str; + + const LEFT_ICON: &'static str; + const RIGHT_ICON: &'static str; + const UP_ICON: &'static str; + const DOWN_ICON: &'static str; + const INSERT_ICON: &'static str; + const NULL_ICON: &'static str; + const BACKSPACE_ICON: &'static str; + const ENTER_ICON: &'static str; + const HOME_ICON: &'static str; + const END_ICON: &'static str; + const PAGEUP_ICON: &'static str; + const PAGEDOWN_ICON: &'static str; + const TAB_ICON: &'static str; + const BACKTAB_ICON: &'static str; + const DELETE_ICON: &'static str; + const ESC_ICON: &'static str; + const SPACE_ICON: &'static str; + + const UP_DOWN: &'static str; + const LEFT_RIGHT: &'static str; + const ARROWS: &'static str; +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Default)] +pub struct UnicodeIconPack; + +impl IconPack for UnicodeIconPack { + const CONTROL_ICON: &'static str = if cfg!(target_os = "macos") { + "\u{2318}" + } else { + "\u{2303}" + }; + const ALT_ICON: &'static str = "\u{2325}"; + const SHIFT_ICON: &'static str = "\u{21e7}"; + + const LEFT_ICON: &'static str = "\u{2190}"; + const RIGHT_ICON: &'static str = "\u{2192}"; + const UP_ICON: &'static str = "\u{2191}"; + const DOWN_ICON: &'static str = "\u{2193}"; + const INSERT_ICON: &'static str = "INS"; + const NULL_ICON: &'static str = "NUL"; + const BACKSPACE_ICON: &'static str = "\u{232b}"; + const ENTER_ICON: &'static str = "\u{23ce}"; + const HOME_ICON: &'static str = "\u{2196}"; + const END_ICON: &'static str = "\u{2198}"; + const PAGEUP_ICON: &'static str = "\u{21de}"; + const PAGEDOWN_ICON: &'static str = "\u{21df}"; + const TAB_ICON: &'static str = "\u{21e5}"; + const BACKTAB_ICON: &'static str = "\u{21e4}"; + const DELETE_ICON: &'static str = "\u{2326}"; + const ESC_ICON: &'static str = "\u{238b}"; + const SPACE_ICON: &'static str = "\u{2423}"; + + const UP_DOWN: &'static str = "\u{2191}\u{2193}"; + const LEFT_RIGHT: &'static str = "\u{2192}\u{2190}"; + const ARROWS: &'static str = "\u{2191}\u{2193}\u{2192}\u{2190}"; +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Default)] +pub struct NonUnicodeIconPack; + +impl IconPack for NonUnicodeIconPack { + const CONTROL_ICON: &'static str = "CTRL+"; + const ALT_ICON: &'static str = "ALT+"; + const SHIFT_ICON: &'static str = "SHFT+"; + + const LEFT_ICON: &'static str = UnicodeIconPack::LEFT_ICON; + const RIGHT_ICON: &'static str = UnicodeIconPack::RIGHT_ICON; + const UP_ICON: &'static str = UnicodeIconPack::UP_ICON; + const DOWN_ICON: &'static str = UnicodeIconPack::DOWN_ICON; + const INSERT_ICON: &'static str = "INS"; + const NULL_ICON: &'static str = "NUL"; + const BACKSPACE_ICON: &'static str = "BKSP"; + const ENTER_ICON: &'static str = "ENTR"; + const HOME_ICON: &'static str = "HOME"; + const END_ICON: &'static str = "END"; + const PAGEUP_ICON: &'static str = "PGUP"; + const PAGEDOWN_ICON: &'static str = "PGDN"; + const TAB_ICON: &'static str = "TAB"; + const BACKTAB_ICON: &'static str = "BTAB"; + const DELETE_ICON: &'static str = "DEL"; + const ESC_ICON: &'static str = "ESC"; + const SPACE_ICON: &'static str = "SPC"; + + const UP_DOWN: &'static str = UnicodeIconPack::UP_DOWN; + const LEFT_RIGHT: &'static str = UnicodeIconPack::LEFT_RIGHT; + const ARROWS: &'static str = UnicodeIconPack::ARROWS; +} + +#[cfg(not(target_os = "windows"))] +pub type DefaultIconPack = UnicodeIconPack; + +#[cfg(target_os = "windows")] +pub type DefaultIconPack = NonUnicodeIconPack; diff --git a/src/widgets/lazy_paragraph.rs b/src/widgets/lazy_paragraph.rs index f7ae073..cf4a887 100644 --- a/src/widgets/lazy_paragraph.rs +++ b/src/widgets/lazy_paragraph.rs @@ -1,6 +1,6 @@ use crate::{ events::AppEvent, - widgets::{BindingDisplay, Scrollbar, State}, + widgets::{BindingDisplay, IconPack, Scrollbar, State}, }; use crossterm::event::{Event, KeyCode}; use indexmap::IndexMap; @@ -238,8 +238,8 @@ impl State for LazyParagraphState { } } - fn add_controls(&self, controls: &mut IndexMap) { - controls.insert(BindingDisplay::Custom(BindingDisplay::ARROWS), "Nav"); + fn add_controls(&self, controls: &mut IndexMap, &'static str>) { + controls.insert(BindingDisplay::Custom(I::ARROWS), "Nav"); controls.insert(BindingDisplay::simple_key(KeyCode::PageUp), "Up 10"); controls.insert(BindingDisplay::simple_key(KeyCode::PageDown), "Down 10"); controls.insert(BindingDisplay::simple_key(KeyCode::Home), "Top"); diff --git a/src/widgets/raw_log.rs b/src/widgets/raw_log.rs index d302b78..beb9606 100644 --- a/src/widgets/raw_log.rs +++ b/src/widgets/raw_log.rs @@ -1,7 +1,7 @@ use crate::{ events::AppEvent, log::Log, - widgets::{BindingDisplay, LazyParagraph, LazyParagraphState, State, WithLog}, + widgets::{BindingDisplay, IconPack, LazyParagraph, LazyParagraphState, State, WithLog}, }; use indexmap::IndexMap; use std::marker::PhantomData; @@ -67,7 +67,7 @@ impl<'i> State for RawLogState<'i> { self.paragraph_state.update(event) } - fn add_controls(&self, controls: &mut IndexMap) { + fn add_controls(&self, controls: &mut IndexMap, &'static str>) { self.paragraph_state.add_controls(controls); } } diff --git a/src/widgets/root.rs b/src/widgets/root.rs index 295809a..8317d61 100644 --- a/src/widgets/root.rs +++ b/src/widgets/root.rs @@ -2,7 +2,7 @@ use crate::{ events::AppEvent, log::Log, widgets::{ - BindingDisplay, Controls, ControlsState, FormattedLog, FormattedLogState, RawLog, + BindingDisplay, Controls, ControlsState, FormattedLog, FormattedLogState, IconPack, RawLog, RawLogState, State, WithLog, }, }; @@ -124,7 +124,7 @@ impl<'i> State for RootState<'i> { } } - fn add_controls(&self, controls: &mut IndexMap) { + fn add_controls(&self, controls: &mut IndexMap, &'static str>) { // Root controls controls.insert( BindingDisplay::key(KeyCode::Char('c'), KeyModifiers::CONTROL), diff --git a/src/widgets/state.rs b/src/widgets/state.rs index e4f69c8..ca91bd0 100644 --- a/src/widgets/state.rs +++ b/src/widgets/state.rs @@ -1,9 +1,14 @@ -use crate::{events::AppEvent, log::Log, widgets::BindingDisplay}; +use crate::{ + events::AppEvent, + log::Log, + widgets::{BindingDisplay, IconPack}, +}; use indexmap::IndexMap; pub trait State { fn update(&mut self, event: &AppEvent) -> bool; - fn add_controls(&self, _controls: &mut IndexMap) {} + fn add_controls(&self, _controls: &mut IndexMap, &'static str>) { + } } impl State for () {