Skip to content

Commit

Permalink
Complete refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
nick42d committed Dec 2, 2024
1 parent 8f8f664 commit 3a38364
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 159 deletions.
167 changes: 87 additions & 80 deletions youtui/src/app/component/actionhandler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::{
};
use async_callback_manager::AsyncTask;
use crossterm::event::{Event, KeyEvent, MouseEvent};
use rodio::cpal::FromSample;
use std::{borrow::Cow, collections::HashMap, marker::PhantomData};
use tracing::warn;
use ytmapi_rs::common::SearchSuggestion;
Expand Down Expand Up @@ -87,10 +86,10 @@ pub type Keymap<A> = HashMap<Keybind, KeyActionTree<A>>;
pub trait KeyRouter<A: Action + 'static> {
/// Get the list of active keybinds that the component and its route
/// contain.
fn get_active_keybinds(&self) -> impl Iterator<Item = &'_ Keymap<A>> + '_;
fn get_active_keybinds(&self) -> impl Iterator<Item = &Keymap<A>>;
/// Get the list of keybinds that the component and any child items can
/// contain, regardless of current route.
fn get_all_keybinds(&self) -> impl Iterator<Item = &'_ Keymap<A>> + '_;
fn get_all_keybinds(&self) -> impl Iterator<Item = &Keymap<A>>;
}

/// A component of the application that can block parent keybinds.
Expand All @@ -110,7 +109,7 @@ pub fn get_all_visible_keybinds_as_readable_iter<K: KeyRouter<A>, A: Action + 's
) -> impl Iterator<Item = DisplayableCommand<'_>> + '_ {
component
.get_active_keybinds()
.flat_map(|keymap| keymap.into_iter())
.flat_map(|keymap| keymap.iter())
.filter(|(_, kt)| (*kt).get_visibility() != CommandVisibility::Hidden)
.map(|(kb, kt)| DisplayableCommand::from_command(kb, kt))
}
Expand All @@ -121,7 +120,7 @@ pub fn get_all_keybinds_as_readable_iter<K: KeyRouter<A>, A: Action + 'static>(
) -> impl Iterator<Item = DisplayableCommand<'_>> + '_ {
component
.get_all_keybinds()
.flat_map(|keymap| keymap.into_iter())
.flat_map(|keymap| keymap.iter())
.map(|(kb, kt)| DisplayableCommand::from_command(kb, kt))
}
/// Get a context-specific list of all keybinds marked global.
Expand All @@ -131,15 +130,15 @@ pub fn get_active_global_keybinds_as_readable_iter<K: KeyRouter<A>, A: Action +
) -> impl Iterator<Item = DisplayableCommand<'_>> + '_ {
component
.get_active_keybinds()
.flat_map(|keymap| keymap.into_iter())
.flat_map(|keymap| keymap.iter())
.filter(|(_, kt)| (*kt).get_visibility() == CommandVisibility::Global)
.map(|(kb, kt)| DisplayableCommand::from_command(kb, kt))
}
// e.g - for use in help menu.
pub fn count_visible_keybinds<K: KeyRouter<A>, A: Action + 'static>(component: &K) -> usize {
component
.get_active_keybinds()
.flat_map(|keymap| keymap.into_iter())
.flat_map(|keymap| keymap.iter())
.filter(|(_, kt)| (*kt).get_visibility() != CommandVisibility::Hidden)
.count()
}
Expand Down Expand Up @@ -276,18 +275,19 @@ pub fn handle_key_stack<'a, A>(
where
A: Action + Clone + 'a,
{
if let Some(subset) = get_key_subset(binds, key_stack) {
match &subset {
Keymap::Action(a) => {
// As Action is simply a message that is being passed around
// I am comfortable to clone it. Receiver should own the message.
// We may be able to improve on this using GATs or reference counting.
return KeyHandleAction::Action(a.clone());
}
Keymap::Mode(_) => return KeyHandleAction::Mode,
}
}
KeyHandleAction::NoMap
// if let Some(subset) = get_key_subset(binds, key_stack) {
// match &subset {
// Keymap::Action(a) => {
// // As Action is simply a message that is being passed around
// // I am comfortable to clone it. Receiver should own the message.
// // We may be able to improve on this using GATs or reference
// counting. return KeyHandleAction::Action(a.clone());
// }
// Keymap::Mode(_) => return KeyHandleAction::Mode,
// }
// }
// KeyHandleAction::NoMap
todo!()
}
/// Try to handle the passed key_stack if it processes an action.
/// Returns if it was handled or why it was not.
Expand All @@ -300,30 +300,32 @@ where
A: Action<State = B> + Clone + 'static,
B: KeyRouter<A> + Component,
{
if let Some(subset) = get_key_subset(handler.get_active_keybinds(), &key_stack) {
match &subset {
Keymap::Action(a) => {
// As Action is simply a message that is being passed around
// I am comfortable to clone it. Receiver should own the message.
// We may be able to improve on this using GATs or reference counting.
let effect = a.clone().apply(handler).await;
return KeyHandleOutcome::Action(effect);
}
Keymap::Mode(_) => return KeyHandleOutcome::Mode,
}
}
KeyHandleOutcome::NoMap
// if let Some(subset) = get_key_subset(handler.get_active_keybinds(),
// &key_stack) { match &subset {
// Keymap::Action(a) => {
// // As Action is simply a message that is being passed around
// // I am comfortable to clone it. Receiver should own the message.
// // We may be able to improve on this using GATs or reference
// counting. let effect = a.clone().apply(handler).await;
// return KeyHandleOutcome::Action(effect);
// }
// Keymap::Mode(_) => return KeyHandleOutcome::Mode,
// }
// }
// KeyHandleOutcome::NoMap
todo!()
}
/// If a list of Keybinds contains a binding for the index KeyEvent, return that
/// KeyEvent.
pub fn index_keybinds<'a, A: Action>(
binds: impl Iterator<Item = &'a KeyCommand<A>> + 'a,
index: &KeyEvent,
) -> Option<&'a Keymap<A>> {
let mut binds = binds;
binds
.find(|kb| kb.contains_keyevent(index))
.map(|kb| &kb.key_map)
// let mut binds = binds;
// binds
// .find(|kb| kb.contains_keyevent(index))
// .map(|kb| &kb.key_map)
todo!()
}
/// Recursively indexes into a Keymap using a list of KeyEvents. Yields the
/// presented Keymap,
Expand All @@ -332,12 +334,13 @@ pub fn index_keymap<'a, A: Action>(
map: &'a Keymap<A>,
indexes: &[KeyEvent],
) -> Option<&'a Keymap<A>> {
indexes
.iter()
.try_fold(map, move |target, i| match &target {
Keymap::Action(_) => None,
Keymap::Mode(m) => index_keybinds(Box::new(m.commands.iter()), i),
})
// indexes
// .iter()
// .try_fold(map, move |target, i| match &target {
// Keymap::Action(_) => None,
// Keymap::Mode(m) => index_keybinds(Box::new(m.commands.iter()), i),
// })
todo!()
}
#[cfg(test)]
mod tests {
Expand Down Expand Up @@ -402,10 +405,11 @@ mod tests {
let key_stack = [ks1, ks2];
let first = index_keybinds(Box::new(kb.iter()), key_stack.first().unwrap()).unwrap();
let act = index_keymap(first, key_stack.get(1..).unwrap());
let Some(Keymap::Action(a)) = act else {
panic!();
};
assert_eq!(*a, TestAction::TestStack);
// let Some(Keymap::Action(a)) = act else {
// panic!();
// };
// assert_eq!(*a, TestAction::TestStack);
todo!()
}
#[test]
fn test_key_stack() {
Expand All @@ -432,10 +436,11 @@ mod tests {
let key_stack = [ks1, ks2];
let first = index_keybinds(Box::new(kb.iter()), key_stack.first().unwrap()).unwrap();
let act = index_keymap(first, key_stack.get(1..).unwrap());
let Some(Keymap::Action(a)) = act else {
panic!();
};
assert_eq!(*a, TestAction::TestStack);
// let Some(Keymap::Action(a)) = act else {
// panic!();
// };
// assert_eq!(*a, TestAction::TestStack);
todo!()
}
#[test]
fn test_index_keybinds() {
Expand Down Expand Up @@ -464,38 +469,40 @@ mod tests {
"Play".into(),
)
.key_map;
assert_eq!(idx, Some(&eq));
// assert_eq!(idx, Some(&eq));
todo!()
}
#[test]
fn test_index_keymap() {
let kb = Keymap::Mode(Mode {
commands: vec![
KeyCommand::new_from_code(KeyCode::F(10), TestAction::Test1),
KeyCommand::new_from_code(KeyCode::F(12), TestAction::Test2),
KeyCommand::new_from_code(KeyCode::Left, TestAction::Test3),
KeyCommand::new_from_code(KeyCode::Right, TestAction::Test3),
KeyCommand::new_action_only_mode(
vec![
(KeyCode::Char('A'), TestAction::Test2),
(KeyCode::Char('a'), TestAction::Test3),
],
KeyCode::Enter,
"Play".into(),
),
],
name: "test".into(),
});
let ks = [KeyEvent::new(KeyCode::Enter, KeyModifiers::empty())];
let idx = index_keymap(&kb, &ks);
let eq = KeyCommand::new_action_only_mode(
vec![
(KeyCode::Char('A'), TestAction::Test2),
(KeyCode::Char('a'), TestAction::Test3),
],
KeyCode::Enter,
"Play".into(),
)
.key_map;
assert_eq!(idx, Some(&eq));
// let kb = Keymap::Mode(Mode {
// commands: vec![
// KeyCommand::new_from_code(KeyCode::F(10), TestAction::Test1),
// KeyCommand::new_from_code(KeyCode::F(12), TestAction::Test2),
// KeyCommand::new_from_code(KeyCode::Left, TestAction::Test3),
// KeyCommand::new_from_code(KeyCode::Right, TestAction::Test3),
// KeyCommand::new_action_only_mode(
// vec![
// (KeyCode::Char('A'), TestAction::Test2),
// (KeyCode::Char('a'), TestAction::Test3),
// ],
// KeyCode::Enter,
// "Play".into(),
// ),
// ],
// name: "test".into(),
// });
// let ks = [KeyEvent::new(KeyCode::Enter, KeyModifiers::empty())];
// let idx = index_keymap(&kb, &ks);
// let eq = KeyCommand::new_action_only_mode(
// vec![
// (KeyCode::Char('A'), TestAction::Test2),
// (KeyCode::Char('a'), TestAction::Test3),
// ],
// KeyCode::Enter,
// "Play".into(),
// )
// .key_map;
// assert_eq!(idx, Some(&eq));
todo!()
}
}
43 changes: 10 additions & 33 deletions youtui/src/app/ui/browser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub struct Browser {
pub prev_input_routing: InputRouting,
pub artist_list: ArtistSearchPanel,
pub album_songs_list: AlbumSongsPanel,
keybinds: Vec<KeyCommand<AppAction>>,
keybinds: Keymap<AppAction>,
}

#[derive(PartialEq, Clone, Copy, Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -183,28 +183,22 @@ impl DrawableMut for Browser {
}
impl KeyRouter<AppAction> for Browser {
fn get_all_keybinds(&self) -> impl Iterator<Item = &'_ Keymap<AppAction>> + '_ {
Box::new(
self.keybinds
.iter()
.chain(self.artist_list.get_all_keybinds())
.chain(self.album_songs_list.get_all_keybinds()),
)
std::iter::once(&self.keybinds)
.chain(self.artist_list.get_all_keybinds())
.chain(self.album_songs_list.get_all_keybinds())
}
fn get_active_keybinds(&self) -> impl Iterator<Item = &'_ Keymap<AppAction>> + '_ {
let additional_binds = match self.input_routing {
InputRouting::Song => Box::new(self.album_songs_list.get_active_keybinds())
as DynKeybindsIter<'_, AppAction>,
InputRouting::Artist => {
Box::new(self.artist_list.get_active_keybinds()) as DynKeybindsIter<'_, AppAction>
}
InputRouting::Song => Either::Left(self.album_songs_list.get_active_keybinds()),
InputRouting::Artist => Either::Right(self.artist_list.get_active_keybinds()),
};
// TODO: Better implementation
if self.album_songs_list.dominant_keybinds_active()
|| self.album_songs_list.dominant_keybinds_active()
{
additional_binds
Either::Left(additional_binds)
} else {
Box::new(self.keybinds.iter().chain(additional_binds)) as DynKeybindsIter<'_, AppAction>
Either::Right(std::iter::once(&self.keybinds).chain(additional_binds))
}
}
}
Expand Down Expand Up @@ -468,23 +462,6 @@ impl Component for Browser {
type Md = TaskMetadata;
}

fn browser_keybinds(config: &Config) -> Vec<KeyCommand<AppAction>> {
config
.keybinds
.browser
.iter()
.map(|(kb, ke)| match ke {
KeyActionTree::Key(KeyAction {
action,
value,
visibility,
}) => KeyCommand::new_modified_from_code_with_visibility(
kb.code,
kb.modifiers,
visibility.clone(),
action.clone(),
),
KeyActionTree::Mode { .. } => todo!(),
})
.collect()
fn browser_keybinds(config: &Config) -> Keymap<AppAction> {
config.keybinds.browser.clone()
}
Loading

0 comments on commit 3a38364

Please sign in to comment.