//! Help modal / command palette. use crate::{core::*, view::*}; /// Command palette. pub struct HelpModal { cursor: usize, search: Option, exited: bool, } impl HelpModal { pub fn new () -> Self { Self { cursor: 0, search: None, exited: false } } } impl Exit for HelpModal { fn exited (&self) -> bool { self.exited } fn exit (&mut self) { self.exited = true; } } render!(HelpModal |self, buf, area|{ for cell in buf.content.iter_mut() { cell.bg = ratatui::style::Color::Rgb(30,30,30); cell.fg = ratatui::style::Color::Rgb(100,100,100); cell.modifier = ratatui::style::Modifier::DIM; } let width = 64.min(area.width * 3 / 5); let height = 20.min(area.width * 3 / 5); let x = area.x + (area.width - width) / 2; let y = area.y + (area.height - height) / 2; let area = Rect { x, y, width, height }; fill_fg(buf, area, Color::Reset); fill_bg(buf, area, Nord::bg_lo(true, true)); fill_char(buf, area, ' '); let x = area.x + 2; let y = area.y + 1; "Command:" .blit(buf, x, y, Some(Style::default().bold()))?; " ".repeat(area.width as usize - 13) .blit(buf, x + 9, y, Some(Style::default().bg(Color::Reset)))?; if let Some(search) = self.search.as_ref() { search.blit(buf, x + 9, y, Some(Style::default().not_dim()))?; } let y = y + 1; fill_char(buf, Rect { y, height: 1, ..area }, '-'); let y = y + 1; for i in 0..height-3 { let y = y + i; if let Some(command) = crate::control::KEYMAP_FOCUS.get(i as usize) { format!("{:?}", command.0).blit(buf, x, y, Some(Style::default().white().bold()))?; command.2.blit(buf, x + 11, y, Some(Style::default().white().bold()))?; command.3.blit(buf, x + 26, y, Some(Style::default().white().dim()))?; } else if let Some(command) = crate::control::KEYMAP_GLOBAL.get((i as usize) - crate::control::KEYMAP_FOCUS.len()) { format!("{:?}", command.0).blit(buf, x, y, Some(Style::default().white().bold()))?; command.2.blit(buf, x + 11, y, Some(Style::default().white().bold()))?; command.3.blit(buf, x + 26, y, Some(Style::default().white().dim()))?; } else { break } } let hi_area = Rect { x: area.x + 1, width: area.width - 2, y: area.y + 3 + self.cursor as u16, height: 1 }; fill_bg(buf, hi_area, Nord::bg_hi(true, true)); fill_fg(buf, hi_area, Color::White); Lozenge(Style::default()).draw(buf, area) }); handle!(HelpModal |self, e| { if handle_keymap(self, e, KEYMAP_HELP)? { return Ok(true) } Ok(match e { AppEvent::Input(Event::Key(KeyEvent { code: KeyCode::Char(c), modifiers: KeyModifiers::NONE, .. })) => { if self.search.is_none() { self.search = Some(String::new()); } self.search.as_mut().unwrap().push(*c); true }, _ => true }) }); pub const KEYMAP_HELP: &'static [KeyBinding] = keymap!(HelpModal { [Esc, NONE, "help_close", "close help dialog", |modal: &mut HelpModal|{ modal.exit(); Ok(true) }], [Up, NONE, "help_prev", "select previous command", |modal: &mut HelpModal|{ modal.cursor = modal.cursor.saturating_sub(1); Ok(true) }], [Down, NONE, "help_next", "select next command", |modal: &mut HelpModal|{ modal.cursor = modal.cursor + 1; Ok(true) }], });