diff --git a/src/tui/app.rs b/src/tui/app.rs index bf244ab..a356f5b 100644 --- a/src/tui/app.rs +++ b/src/tui/app.rs @@ -9,7 +9,8 @@ use ratatui::crossterm::event; use ratatui::crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers}; use ratatui::layout::{Constraint, Direction, Layout, Rect}; use ratatui::prelude::{Color, Style, Widget}; -use ratatui::widgets::{Block, Borders, Padding, Tabs}; +use ratatui::text::Text; +use ratatui::widgets::{Block, Borders, Padding, Paragraph, Tabs, Wrap}; use ratatui::{DefaultTerminal, symbols}; use std::path::PathBuf; use std::time::Duration; @@ -93,7 +94,7 @@ impl<'a> App<'a> { Ok(()) } - fn draw_status(&self, area: Rect, buf: &mut Buffer) { + fn draw_top_status(&self, area: Rect, buf: &mut Buffer) { // TODO: Status bar should have drop down menus Tabs::new(["File", "Edit", "View", "Help"]) .style(Style::default()) @@ -101,6 +102,21 @@ impl<'a> App<'a> { .render(area, buf); } + fn draw_bottom_status(&self, area: Rect, buf: &mut Buffer) { + // TODO: Set help text based on most recent component enabled. + Paragraph::new( + self.get_component::() + .unwrap() + .component_state + .help_text + .clone(), + ) + .style(Color::Gray) + .wrap(Wrap { trim: false }) + .centered() + .render(area, buf); + } + fn draw_tabs(&self, area: Rect, buf: &mut Buffer) { // Determine the tab title from the current file (or use a fallback). let mut title: Option<&str> = None; @@ -153,9 +169,10 @@ impl<'a> Widget for &mut App<'a> { let vertical = Layout::default() .direction(Direction::Vertical) .constraints([ - Constraint::Length(3), // status bar + Constraint::Length(3), // top status bar Constraint::Percentage(70), // horizontal layout Constraint::Percentage(30), // terminal + Constraint::Length(3), // bottom status bar ]) .split(area); @@ -175,7 +192,8 @@ impl<'a> Widget for &mut App<'a> { ]) .split(horizontal[1]); - self.draw_status(vertical[0], buf); + self.draw_top_status(vertical[0], buf); + self.draw_bottom_status(vertical[3], buf); self.draw_tabs(editor_layout[0], buf); let id = self.id().to_string(); for component in &mut self.components { @@ -225,7 +243,7 @@ impl<'a> Component for App<'a> { AppComponents::AppEditor(e) => e as &mut dyn Component, AppComponents::AppExplorer(e) => e as &mut dyn Component, AppComponents::AppLogger(e) => e as &mut dyn Component, - AppComponents::AppComponent(e) => e.as_mut() as &mut dyn Component, + AppComponents::AppComponent(e) => e.as_mut(), }; if !c.is_active() { if let Some(mouse) = event.as_mouse_event() { diff --git a/src/tui/component.rs b/src/tui/component.rs index 0ac02dd..e06b86b 100644 --- a/src/tui/component.rs +++ b/src/tui/component.rs @@ -51,17 +51,24 @@ pub trait Component { } } -#[derive(Debug, Clone, Copy, Default)] +#[derive(Debug, Clone, Default)] pub struct ComponentState { pub(crate) focus: Focus, + pub(crate) help_text: String, } impl ComponentState { fn new() -> Self { Self { focus: Focus::Active, + help_text: String::new(), } } + + pub(crate) fn with_help_text(mut self, help_text: &str) -> Self { + self.help_text = help_text.into(); + self + } } #[derive(Debug, Clone, Copy, Default, PartialEq)] @@ -79,7 +86,10 @@ pub trait FocusState { impl FocusState for ComponentState { fn with_focus(self, focus: Focus) -> Self { - Self { focus } + Self { + focus, + help_text: self.help_text, + } } fn set_focus(&mut self, focus: Focus) { diff --git a/src/tui/editor.rs b/src/tui/editor.rs index 5bba941..282cd1e 100644 --- a/src/tui/editor.rs +++ b/src/tui/editor.rs @@ -46,7 +46,7 @@ impl Editor { event_handler: EditorEventHandler::default(), file_path: None, syntax_set: SyntaxSet::load_defaults_nonewlines(), - component_state: Default::default(), + component_state: ComponentState::default().with_help_text("TODO: Vim help text"), } } diff --git a/src/tui/explorer.rs b/src/tui/explorer.rs index fcb4a05..d914da5 100644 --- a/src/tui/explorer.rs +++ b/src/tui/explorer.rs @@ -39,7 +39,7 @@ impl<'a> Explorer<'a> { root_path: path.to_owned(), tree_items: Self::build_tree_from_path(path.to_owned())?, tree_state: TreeState::default(), - component_state: Default::default(), + component_state: ComponentState::default().with_help_text("TODO: Explorer help text."), }; Ok(explorer) } diff --git a/src/tui/logger.rs b/src/tui/logger.rs index abf33bb..3c859b0 100644 --- a/src/tui/logger.rs +++ b/src/tui/logger.rs @@ -33,7 +33,11 @@ impl Logger { pub fn new() -> Self { Self { state: TuiWidgetState::new(), - component_state: Default::default(), + component_state: ComponentState::default().with_help_text(concat!( + "Q: Quit | Tab: Switch state | ↑/↓: Select target | f: Focus target", + " | ←/→: Display level | +/-: Filter level | Space: Toggle hidden targets", + " | h: Hide target selector | PageUp/Down: Scroll | Esc: Cancel scroll" + )), } } }