use std::{
collections::HashMap,
fmt::{self, Display},
slice::Iter,
};
use crate::inputs::key::Key;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Action {
Quit,
Enter,
Up,
Down,
}
impl Action {
pub fn iterator() -> Iter<'static, Action> {
static ACTIONS: [Action; 4] = [Action::Quit, Action::Enter, Action::Up, Action::Down];
ACTIONS.iter()
}
pub fn keys(&self) -> &[Key] {
match self {
Action::Quit => &[Key::Ctrl('c'), Key::Char('q')],
Action::Enter => &[Key::Enter],
Action::Up => &[Key::Up, Key::Char('k')],
Action::Down => &[Key::Down, Key::Char('j')],
}
}
}
impl Display for Action {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let str = match self {
Action::Quit => "Quit",
Action::Enter => "Enter",
Action::Up => "Nav Up",
Action::Down => "Nav Down",
};
write!(f, "{}", str)
}
}
#[derive(Default, Debug, Clone)]
pub struct Actions(Vec<Action>);
impl Actions {
pub fn find(&self, key: Key) -> Option<&Action> {
Action::iterator()
.filter(|action| self.0.contains(action))
.find(|action| action.keys().contains(&key))
}
pub fn actions(&self) -> &[Action] {
self.0.as_slice()
}
}
impl From<Vec<Action>> for Actions {
fn from(actions: Vec<Action>) -> Self {
let mut map: HashMap<Key, Vec<Action>> = HashMap::new();
for action in actions.iter() {
for key in action.keys().iter() {
match map.get_mut(key) {
Some(vec) => vec.push(*action),
None => {
map.insert(*key, vec![*action]);
}
}
}
}
let errors = map
.iter()
.filter(|(_, actions)| actions.len() > 1) .map(|(key, actions)| {
let actions = actions
.iter()
.map(Action::to_string)
.collect::<Vec<_>>()
.join(", ");
format!("Conflict key {} with actions {}", key, actions)
})
.collect::<Vec<_>>();
if !errors.is_empty() {
panic!("{}", errors.join("; "))
}
Self(actions)
}
}