use super::palette_widget::PaletteWidget;
use super::{BuiltinId, ItemIndex};
use crate::plugin::PluginCmdItem;
use crate::theme::Theme;
use crossterm::event::{KeyCode, KeyEvent};
use ratatui::layout::Rect;
use ratatui::Frame;
pub(super) struct PaletteController {
palette: Option<PaletteWidget>,
}
pub(super) enum PaletteAction {
Execute(ItemIndex),
None,
}
impl PaletteController {
pub fn new() -> Self {
Self { palette: None }
}
pub fn open(&mut self) {
self.palette = Some(PaletteWidget::new());
}
pub fn is_open(&self) -> bool {
self.palette.is_some()
}
pub fn handle_key(
&mut self,
key: KeyEvent,
term_h: u16,
builtin_items: &[(BuiltinId, String, String)],
dynamic_items: &[(String, String, String)],
cmds: &[(usize, usize, PluginCmdItem)],
) -> PaletteAction {
let filtered = self
.palette
.as_ref()
.map(|p| p.filtered_items(builtin_items, dynamic_items, cmds))
.unwrap_or_default();
match key.code {
KeyCode::Char(c)
if c == 'p'
&& key
.modifiers
.contains(crossterm::event::KeyModifiers::CONTROL) =>
{
self.palette = None;
return PaletteAction::None;
}
KeyCode::Char(_) if !key.modifiers.is_empty() => {}
KeyCode::Char(c) => {
if let Some(ref mut p) = self.palette {
p.query.push(c);
p.cursor = 0;
p.scroll = 0;
}
}
KeyCode::Backspace => {
if let Some(ref mut p) = self.palette {
p.query.pop();
p.cursor = 0;
p.scroll = 0;
}
}
KeyCode::Up => {
if !filtered.is_empty() {
if let Some(ref mut p) = self.palette {
p.cursor = if p.cursor == 0 {
filtered.len() - 1
} else {
p.cursor - 1
};
}
}
}
KeyCode::Down => {
if !filtered.is_empty() {
if let Some(ref mut p) = self.palette {
p.cursor = if p.cursor + 1 >= filtered.len() {
0
} else {
p.cursor + 1
};
}
}
}
KeyCode::Enter => {
let cursor = self.palette.as_ref().map(|p| p.cursor).unwrap_or(0);
if let Some(&idx) = filtered.get(cursor) {
self.palette = None;
return PaletteAction::Execute(idx);
}
self.palette = None;
return PaletteAction::None;
}
KeyCode::Esc => {
self.palette = None;
return PaletteAction::None;
}
_ => {}
}
if let Some(ref mut p) = self.palette {
p.ensure_cursor_visible(term_h.saturating_sub(1), builtin_items, dynamic_items, cmds);
}
PaletteAction::None
}
#[allow(clippy::too_many_arguments)]
pub fn render(
&self,
f: &mut Frame,
area: Rect,
theme: &Theme,
tick: u64,
builtin_items: &[(BuiltinId, String, String)],
dynamic_items: &[(String, String, String)],
cmds: &[(usize, usize, PluginCmdItem)],
) {
if let Some(ref pal) = self.palette {
pal.render(f, area, theme, tick, builtin_items, dynamic_items, cmds);
}
}
}
impl Default for PaletteController {
fn default() -> Self {
Self::new()
}
}