refactor(bindigns): migrate to OneOrMany

This commit is contained in:
lalvarezt 2025-07-23 17:12:40 +02:00
parent 3cca8ad9bc
commit 088dc6ba83
4 changed files with 97 additions and 122 deletions

View File

@ -1,4 +1,5 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_with::{OneOrMany, serde_as};
use std::fmt::Display; use std::fmt::Display;
/// The different actions that can be performed by the application. /// The different actions that can be performed by the application.
@ -145,34 +146,44 @@ pub enum Action {
/// use television::action::{Action, Actions}; /// use television::action::{Action, Actions};
/// ///
/// // Single action /// // Single action
/// let single = Actions::Single(Action::Quit); /// let single = Actions::single(Action::Quit);
/// assert_eq!(single.as_slice(), &[Action::Quit]); /// assert_eq!(single.as_slice(), &[Action::Quit]);
/// ///
/// // Multiple actions /// // Multiple actions
/// let multiple = Actions::Multiple(vec![Action::ReloadSource, Action::Quit]); /// let multiple = Actions::multiple(vec![Action::ReloadSource, Action::Quit]);
/// assert_eq!(multiple.as_slice(), &[Action::ReloadSource, Action::Quit]); /// assert_eq!(multiple.as_slice(), &[Action::ReloadSource, Action::Quit]);
/// ///
/// // Convert to vector for execution /// // Convert to vector for execution
/// let actions_vec = multiple.into_vec(); /// let actions_vec = multiple.into_vec();
/// assert_eq!(actions_vec, vec![Action::ReloadSource, Action::Quit]); /// assert_eq!(actions_vec, vec![Action::ReloadSource, Action::Quit]);
/// ``` /// ```
#[serde_as]
#[derive( #[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, PartialOrd, Ord, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, PartialOrd, Ord,
)] )]
#[serde(untagged)] #[serde(transparent)]
pub enum Actions { pub struct Actions {
/// A single action binding #[serde_as(as = "OneOrMany<_>")]
Single(Action), inner: Vec<Action>,
/// Multiple actions executed in sequence
Multiple(Vec<Action>),
} }
impl Actions { impl Actions {
/// Creates a new `Actions` from a single action.
pub fn single(action: Action) -> Self {
Self {
inner: vec![action],
}
}
/// Creates a new `Actions` from multiple actions.
pub fn multiple(actions: Vec<Action>) -> Self {
Self { inner: actions }
}
/// Converts the `Actions` into a `Vec<Action>` for execution. /// Converts the `Actions` into a `Vec<Action>` for execution.
/// ///
/// This method consumes the `Actions` and returns a vector containing /// This method consumes the `Actions` and returns a vector containing
/// all actions to be executed. For `Single`, it returns a vector with /// all actions to be executed.
/// one element. For `Multiple`, it returns the contained vector.
/// ///
/// # Returns /// # Returns
/// ///
@ -183,17 +194,14 @@ impl Actions {
/// ```rust /// ```rust
/// use television::action::{Action, Actions}; /// use television::action::{Action, Actions};
/// ///
/// let single = Actions::Single(Action::Quit); /// let single = Actions::single(Action::Quit);
/// assert_eq!(single.into_vec(), vec![Action::Quit]); /// assert_eq!(single.into_vec(), vec![Action::Quit]);
/// ///
/// let multiple = Actions::Multiple(vec![Action::ReloadSource, Action::Quit]); /// let multiple = Actions::multiple(vec![Action::ReloadSource, Action::Quit]);
/// assert_eq!(multiple.into_vec(), vec![Action::ReloadSource, Action::Quit]); /// assert_eq!(multiple.into_vec(), vec![Action::ReloadSource, Action::Quit]);
/// ``` /// ```
pub fn into_vec(self) -> Vec<Action> { pub fn into_vec(self) -> Vec<Action> {
match self { self.inner
Actions::Single(action) => vec![action],
Actions::Multiple(actions) => actions,
}
} }
/// Returns a slice view of the actions without consuming the `Actions`. /// Returns a slice view of the actions without consuming the `Actions`.
@ -210,22 +218,34 @@ impl Actions {
/// ```rust /// ```rust
/// use television::action::{Action, Actions}; /// use television::action::{Action, Actions};
/// ///
/// let single = Actions::Single(Action::Quit); /// let single = Actions::single(Action::Quit);
/// assert_eq!(single.as_slice(), &[Action::Quit]); /// assert_eq!(single.as_slice(), &[Action::Quit]);
/// ///
/// let multiple = Actions::Multiple(vec![Action::ReloadSource, Action::Quit]); /// let multiple = Actions::multiple(vec![Action::ReloadSource, Action::Quit]);
/// assert_eq!(multiple.as_slice(), &[Action::ReloadSource, Action::Quit]); /// assert_eq!(multiple.as_slice(), &[Action::ReloadSource, Action::Quit]);
/// ``` /// ```
pub fn as_slice(&self) -> &[Action] { pub fn as_slice(&self) -> &[Action] {
match self { &self.inner
Actions::Single(action) => std::slice::from_ref(action), }
Actions::Multiple(actions) => actions.as_slice(),
} /// Returns `true` if this contains only a single action.
pub fn is_single(&self) -> bool {
self.inner.len() == 1
}
/// Returns `true` if this contains multiple actions.
pub fn is_multiple(&self) -> bool {
self.inner.len() > 1
}
/// Gets the first action, if any.
pub fn first(&self) -> Option<&Action> {
self.inner.first()
} }
} }
impl From<Action> for Actions { impl From<Action> for Actions {
/// Converts a single `Action` into `Actions::Single`. /// Converts a single `Action` into `Actions`.
/// ///
/// This conversion allows seamless use of single actions where /// This conversion allows seamless use of single actions where
/// `Actions` is expected, maintaining backward compatibility. /// `Actions` is expected, maintaining backward compatibility.
@ -236,49 +256,35 @@ impl From<Action> for Actions {
/// use television::action::{Action, Actions}; /// use television::action::{Action, Actions};
/// ///
/// let actions: Actions = Action::Quit.into(); /// let actions: Actions = Action::Quit.into();
/// assert_eq!(actions, Actions::Single(Action::Quit)); /// assert_eq!(actions, Actions::single(Action::Quit));
/// ``` /// ```
fn from(action: Action) -> Self { fn from(action: Action) -> Self {
Actions::Single(action) Self::single(action)
} }
} }
impl From<Vec<Action>> for Actions { impl From<Vec<Action>> for Actions {
/// Converts a `Vec<Action>` into `Actions`. /// Converts a `Vec<Action>` into `Actions`.
/// ///
/// This conversion optimizes single-element vectors into `Actions::Single`
/// for efficiency, while multi-element vectors become `Actions::Multiple`.
///
/// # Arguments /// # Arguments
/// ///
/// * `actions` - Vector of actions to convert /// * `actions` - Vector of actions to convert
/// ///
/// # Returns
///
/// - `Actions::Single` if the vector has exactly one element
/// - `Actions::Multiple` if the vector has zero or multiple elements
///
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// use television::action::{Action, Actions}; /// use television::action::{Action, Actions};
/// ///
/// // Single element becomes Single
/// let single_vec = vec![Action::Quit]; /// let single_vec = vec![Action::Quit];
/// let actions: Actions = single_vec.into(); /// let actions: Actions = single_vec.into();
/// assert_eq!(actions, Actions::Single(Action::Quit)); /// assert_eq!(actions, Action::Quit.into());
/// ///
/// // Multiple elements become Multiple
/// let multi_vec = vec![Action::ReloadSource, Action::Quit]; /// let multi_vec = vec![Action::ReloadSource, Action::Quit];
/// let actions: Actions = multi_vec.into(); /// let actions: Actions = multi_vec.into();
/// assert!(matches!(actions, Actions::Multiple(_))); /// assert_eq!(actions, vec![Action::ReloadSource, Action::Quit].into());
/// ``` /// ```
fn from(actions: Vec<Action>) -> Self { fn from(actions: Vec<Action>) -> Self {
if actions.len() == 1 { Self::multiple(actions)
Actions::Single(actions.into_iter().next().unwrap())
} else {
Actions::Multiple(actions)
}
} }
} }
@ -367,13 +373,13 @@ mod tests {
#[test] #[test]
fn test_actions_single() { fn test_actions_single() {
let single_action = Actions::Single(Action::Quit); let single_action = Actions::single(Action::Quit);
assert_eq!(single_action.into_vec(), vec![Action::Quit]); assert_eq!(single_action.into_vec(), vec![Action::Quit]);
let single_from_action = Actions::from(Action::SelectNextEntry); let single_from_action = Actions::from(Action::SelectNextEntry);
assert_eq!( assert_eq!(
single_from_action, single_from_action,
Actions::Single(Action::SelectNextEntry) Actions::single(Action::SelectNextEntry)
); );
assert_eq!(single_from_action.as_slice(), &[Action::SelectNextEntry]); assert_eq!(single_from_action.as_slice(), &[Action::SelectNextEntry]);
} }
@ -381,40 +387,20 @@ mod tests {
#[test] #[test]
fn test_actions_multiple() { fn test_actions_multiple() {
let actions_vec = vec![Action::CopyEntryToClipboard, Action::Quit]; let actions_vec = vec![Action::CopyEntryToClipboard, Action::Quit];
let multiple_actions = Actions::Multiple(actions_vec.clone()); let multiple_actions: Actions = Actions::multiple(actions_vec.clone());
assert_eq!(multiple_actions.into_vec(), actions_vec); assert_eq!(multiple_actions.into_vec(), actions_vec);
let multiple_from_vec = Actions::from(actions_vec.clone()); let multiple_from_vec = Actions::from(actions_vec.clone());
assert_eq!(multiple_from_vec, Actions::Multiple(actions_vec.clone())); assert_eq!(multiple_from_vec, Actions::multiple(actions_vec.clone()));
assert_eq!(multiple_from_vec.as_slice(), actions_vec.as_slice()); assert_eq!(multiple_from_vec.as_slice(), actions_vec.as_slice());
} }
#[test]
fn test_actions_from_single_vec_becomes_single() {
// When creating Actions from a Vec with only one element, it should become Single
let single_vec = vec![Action::TogglePreview];
let actions = Actions::from(single_vec);
assert_eq!(actions, Actions::Single(Action::TogglePreview));
}
#[test]
fn test_actions_from_multi_vec_becomes_multiple() {
// When creating Actions from a Vec with multiple elements, it should become Multiple
let multi_vec = vec![
Action::ReloadSource,
Action::SelectNextEntry,
Action::TogglePreview,
];
let actions = Actions::from(multi_vec.clone());
assert_eq!(actions, Actions::Multiple(multi_vec));
}
#[test] #[test]
fn test_actions_as_slice() { fn test_actions_as_slice() {
let single = Actions::Single(Action::DeleteLine); let single: Actions = Actions::single(Action::DeleteLine);
assert_eq!(single.as_slice(), &[Action::DeleteLine]); assert_eq!(single.as_slice(), &[Action::DeleteLine]);
let multiple = Actions::Multiple(vec![ let multiple: Actions = Actions::multiple(vec![
Action::ScrollPreviewUp, Action::ScrollPreviewUp,
Action::ScrollPreviewDown, Action::ScrollPreviewDown,
]); ]);
@ -426,10 +412,10 @@ mod tests {
#[test] #[test]
fn test_actions_into_vec() { fn test_actions_into_vec() {
let single = Actions::Single(Action::ConfirmSelection); let single: Actions = Actions::single(Action::ConfirmSelection);
assert_eq!(single.into_vec(), vec![Action::ConfirmSelection]); assert_eq!(single.into_vec(), vec![Action::ConfirmSelection]);
let multiple = Actions::Multiple(vec![ let multiple: Actions = Actions::multiple(vec![
Action::ToggleHelp, Action::ToggleHelp,
Action::ToggleStatusBar, Action::ToggleStatusBar,
]); ]);
@ -443,12 +429,12 @@ mod tests {
fn test_actions_hash_and_eq() { fn test_actions_hash_and_eq() {
use std::collections::HashMap; use std::collections::HashMap;
let actions1 = Actions::Single(Action::Quit); let actions1: Actions = Actions::single(Action::Quit);
let actions2 = Actions::Single(Action::Quit); let actions2: Actions = Actions::single(Action::Quit);
let actions3 = let actions3: Actions =
Actions::Multiple(vec![Action::Quit, Action::ClearScreen]); Actions::multiple(vec![Action::Quit, Action::ClearScreen]);
let actions4 = let actions4: Actions =
Actions::Multiple(vec![Action::Quit, Action::ClearScreen]); Actions::multiple(vec![Action::Quit, Action::ClearScreen]);
assert_eq!(actions1, actions2); assert_eq!(actions1, actions2);
assert_eq!(actions3, actions4); assert_eq!(actions3, actions4);

View File

@ -11,7 +11,6 @@ use std::ops::{Deref, DerefMut};
use std::str::FromStr; use std::str::FromStr;
use tracing::{debug, trace}; use tracing::{debug, trace};
/// Generic bindings structure that can map any key type to actions
/// Generic bindings structure that maps any key type to actions. /// Generic bindings structure that maps any key type to actions.
/// ///
/// This is the core structure for storing key/event bindings in Television. /// This is the core structure for storing key/event bindings in Television.
@ -1087,7 +1086,7 @@ mod tests {
// Multiple actions should work // Multiple actions should work
assert_eq!( assert_eq!(
keybindings.bindings.get(&Key::Ctrl('s')), keybindings.bindings.get(&Key::Ctrl('s')),
Some(&Actions::Multiple(vec![ Some(&Actions::multiple(vec![
Action::ReloadSource, Action::ReloadSource,
Action::CopyEntryToClipboard Action::CopyEntryToClipboard
])) ]))
@ -1096,7 +1095,7 @@ mod tests {
// Three actions should work // Three actions should work
assert_eq!( assert_eq!(
keybindings.bindings.get(&Key::F(1)), keybindings.bindings.get(&Key::F(1)),
Some(&Actions::Multiple(vec![ Some(&Actions::multiple(vec![
Action::ToggleHelp, Action::ToggleHelp,
Action::TogglePreview, Action::TogglePreview,
Action::ToggleStatusBar Action::ToggleStatusBar
@ -1114,7 +1113,7 @@ mod tests {
let mut custom_bindings = FxHashMap::default(); let mut custom_bindings = FxHashMap::default();
custom_bindings.insert( custom_bindings.insert(
Key::Ctrl('s'), Key::Ctrl('s'),
Actions::Multiple(vec![ Actions::multiple(vec![
Action::ReloadSource, Action::ReloadSource,
Action::CopyEntryToClipboard, Action::CopyEntryToClipboard,
]), ]),
@ -1129,7 +1128,7 @@ mod tests {
// Custom multiple actions should be present // Custom multiple actions should be present
assert_eq!( assert_eq!(
merged.bindings.get(&Key::Ctrl('s')), merged.bindings.get(&Key::Ctrl('s')),
Some(&Actions::Multiple(vec![ Some(&Actions::multiple(vec![
Action::ReloadSource, Action::ReloadSource,
Action::CopyEntryToClipboard Action::CopyEntryToClipboard
])) ]))
@ -1171,7 +1170,7 @@ mod tests {
// Verify all binding types work correctly // Verify all binding types work correctly
assert_eq!( assert_eq!(
keybindings.bindings.get(&Key::Esc), keybindings.bindings.get(&Key::Esc),
Some(&Actions::Single(Action::Quit)) Some(&Actions::single(Action::Quit))
); );
assert_eq!( assert_eq!(
keybindings.bindings.get(&Key::Enter), keybindings.bindings.get(&Key::Enter),
@ -1179,14 +1178,14 @@ mod tests {
); );
assert_eq!( assert_eq!(
keybindings.bindings.get(&Key::Ctrl('s')), keybindings.bindings.get(&Key::Ctrl('s')),
Some(&Actions::Multiple(vec![ Some(&Actions::multiple(vec![
Action::ReloadSource, Action::ReloadSource,
Action::CopyEntryToClipboard Action::CopyEntryToClipboard
])) ]))
); );
assert_eq!( assert_eq!(
keybindings.bindings.get(&Key::F(1)), keybindings.bindings.get(&Key::F(1)),
Some(&Actions::Multiple(vec![ Some(&Actions::multiple(vec![
Action::ToggleHelp, Action::ToggleHelp,
Action::TogglePreview, Action::TogglePreview,
Action::ToggleStatusBar Action::ToggleStatusBar
@ -1194,11 +1193,11 @@ mod tests {
); );
assert_eq!( assert_eq!(
keybindings.bindings.get(&Key::Ctrl('c')), keybindings.bindings.get(&Key::Ctrl('c')),
Some(&Actions::Single(Action::NoOp)) Some(&Actions::single(Action::NoOp))
); );
assert_eq!( assert_eq!(
keybindings.bindings.get(&Key::Tab), keybindings.bindings.get(&Key::Tab),
Some(&Actions::Multiple(vec![Action::ToggleSelectionDown])) Some(&Actions::multiple(vec![Action::ToggleSelectionDown]))
); );
} }
} }

View File

@ -95,7 +95,7 @@ impl InputMap {
/// use television::action::{Action, Actions}; /// use television::action::{Action, Actions};
/// ///
/// let mut input_map = InputMap::new(); /// let mut input_map = InputMap::new();
/// input_map.key_actions.insert(Key::Enter, Actions::Single(Action::ConfirmSelection)); /// input_map.key_actions.insert(Key::Enter, Actions::single(Action::ConfirmSelection));
/// ///
/// let actions = input_map.get_actions_for_key(&Key::Enter).unwrap(); /// let actions = input_map.get_actions_for_key(&Key::Enter).unwrap();
/// assert_eq!(actions.as_slice(), &[Action::ConfirmSelection]); /// assert_eq!(actions.as_slice(), &[Action::ConfirmSelection]);
@ -128,7 +128,7 @@ impl InputMap {
/// let mut input_map = InputMap::new(); /// let mut input_map = InputMap::new();
/// input_map.event_actions.insert( /// input_map.event_actions.insert(
/// EventType::MouseClick, /// EventType::MouseClick,
/// Actions::Single(Action::ConfirmSelection) /// Actions::single(Action::ConfirmSelection)
/// ); /// );
/// ///
/// let actions = input_map.get_actions_for_event(&EventType::MouseClick).unwrap(); /// let actions = input_map.get_actions_for_event(&EventType::MouseClick).unwrap();
@ -166,17 +166,16 @@ impl InputMap {
/// let mut input_map = InputMap::new(); /// let mut input_map = InputMap::new();
/// input_map.key_actions.insert( /// input_map.key_actions.insert(
/// Key::Ctrl('r'), /// Key::Ctrl('r'),
/// Actions::Multiple(vec![Action::ReloadSource, Action::ClearScreen]) /// Actions::multiple(vec![Action::ReloadSource, Action::ClearScreen])
/// ); /// );
/// ///
/// // Returns only the first action /// // Returns only the first action
/// assert_eq!(input_map.get_action_for_key(&Key::Ctrl('r')), Some(Action::ReloadSource)); /// assert_eq!(input_map.get_action_for_key(&Key::Ctrl('r')), Some(Action::ReloadSource));
/// ``` /// ```
pub fn get_action_for_key(&self, key: &Key) -> Option<Action> { pub fn get_action_for_key(&self, key: &Key) -> Option<Action> {
self.key_actions.get(key).and_then(|actions| match actions { self.key_actions
Actions::Single(action) => Some(action.clone()), .get(key)
Actions::Multiple(actions_vec) => actions_vec.first().cloned(), .and_then(|actions| actions.first().cloned())
})
} }
/// Gets the first action bound to a specific event type (backward compatibility). /// Gets the first action bound to a specific event type (backward compatibility).
@ -204,7 +203,7 @@ impl InputMap {
/// let mut input_map = InputMap::new(); /// let mut input_map = InputMap::new();
/// input_map.event_actions.insert( /// input_map.event_actions.insert(
/// EventType::MouseClick, /// EventType::MouseClick,
/// Actions::Multiple(vec![Action::ConfirmSelection, Action::TogglePreview]) /// Actions::multiple(vec![Action::ConfirmSelection, Action::TogglePreview])
/// ); /// );
/// ///
/// // Returns only the first action /// // Returns only the first action
@ -216,10 +215,7 @@ impl InputMap {
pub fn get_action_for_event(&self, event: &EventType) -> Option<Action> { pub fn get_action_for_event(&self, event: &EventType) -> Option<Action> {
self.event_actions self.event_actions
.get(event) .get(event)
.and_then(|actions| match actions { .and_then(|actions| actions.first().cloned())
Actions::Single(action) => Some(action.clone()),
Actions::Multiple(actions_vec) => actions_vec.first().cloned(),
})
} }
/// Gets all actions for any input event. /// Gets all actions for any input event.
@ -256,7 +252,7 @@ impl InputMap {
/// let mut input_map = InputMap::new(); /// let mut input_map = InputMap::new();
/// input_map.key_actions.insert( /// input_map.key_actions.insert(
/// Key::Ctrl('s'), /// Key::Ctrl('s'),
/// Actions::Multiple(vec![Action::ReloadSource, Action::CopyEntryToClipboard]) /// Actions::multiple(vec![Action::ReloadSource, Action::CopyEntryToClipboard])
/// ); /// );
/// ///
/// let key_input = InputEvent::Key(Key::Ctrl('s')); /// let key_input = InputEvent::Key(Key::Ctrl('s'));
@ -317,7 +313,7 @@ impl InputMap {
/// let mut input_map = InputMap::new(); /// let mut input_map = InputMap::new();
/// input_map.key_actions.insert( /// input_map.key_actions.insert(
/// Key::Enter, /// Key::Enter,
/// Actions::Multiple(vec![Action::ConfirmSelection, Action::Quit]) /// Actions::multiple(vec![Action::ConfirmSelection, Action::Quit])
/// ); /// );
/// ///
/// let key_input = InputEvent::Key(Key::Enter); /// let key_input = InputEvent::Key(Key::Enter);
@ -504,11 +500,11 @@ impl InputMap {
/// use television::action::{Action, Actions}; /// use television::action::{Action, Actions};
/// ///
/// let mut base_map = InputMap::new(); /// let mut base_map = InputMap::new();
/// base_map.key_actions.insert(Key::Enter, Actions::Single(Action::ConfirmSelection)); /// base_map.key_actions.insert(Key::Enter, Actions::single(Action::ConfirmSelection));
/// ///
/// let mut custom_map = InputMap::new(); /// let mut custom_map = InputMap::new();
/// custom_map.key_actions.insert(Key::Enter, Actions::Single(Action::Quit)); // Override /// custom_map.key_actions.insert(Key::Enter, Actions::single(Action::Quit)); // Override
/// custom_map.key_actions.insert(Key::Esc, Actions::Single(Action::Quit)); // New binding /// custom_map.key_actions.insert(Key::Esc, Actions::single(Action::Quit)); // New binding
/// ///
/// base_map.merge(&custom_map); /// base_map.merge(&custom_map);
/// assert_eq!(base_map.get_action_for_key(&Key::Enter), Some(Action::Quit)); /// assert_eq!(base_map.get_action_for_key(&Key::Enter), Some(Action::Quit));
@ -712,12 +708,12 @@ mod tests {
let mut key_actions = FxHashMap::default(); let mut key_actions = FxHashMap::default();
key_actions.insert( key_actions.insert(
Key::Ctrl('s'), Key::Ctrl('s'),
Actions::Multiple(vec![ Actions::multiple(vec![
Action::ReloadSource, Action::ReloadSource,
Action::CopyEntryToClipboard, Action::CopyEntryToClipboard,
]), ]),
); );
key_actions.insert(Key::Esc, Actions::Single(Action::Quit)); key_actions.insert(Key::Esc, Actions::single(Action::Quit));
let input_map = InputMap { let input_map = InputMap {
key_actions, key_actions,
@ -750,7 +746,7 @@ mod tests {
let mut input_map = InputMap::new(); let mut input_map = InputMap::new();
input_map.key_actions.insert( input_map.key_actions.insert(
Key::Char('j'), Key::Char('j'),
Actions::Multiple(vec![ Actions::multiple(vec![
Action::SelectNextEntry, Action::SelectNextEntry,
Action::ScrollPreviewDown, Action::ScrollPreviewDown,
]), ]),
@ -775,7 +771,7 @@ mod tests {
let mut event_actions = FxHashMap::default(); let mut event_actions = FxHashMap::default();
event_actions.insert( event_actions.insert(
EventType::MouseClick, EventType::MouseClick,
Actions::Multiple(vec![ Actions::multiple(vec![
Action::ConfirmSelection, Action::ConfirmSelection,
Action::TogglePreview, Action::TogglePreview,
]), ]),
@ -809,16 +805,16 @@ mod tests {
let mut input_map1 = InputMap::new(); let mut input_map1 = InputMap::new();
input_map1 input_map1
.key_actions .key_actions
.insert(Key::Char('a'), Actions::Single(Action::SelectNextEntry)); .insert(Key::Char('a'), Actions::single(Action::SelectNextEntry));
let mut input_map2 = InputMap::new(); let mut input_map2 = InputMap::new();
input_map2.key_actions.insert( input_map2.key_actions.insert(
Key::Char('a'), Key::Char('a'),
Actions::Multiple(vec![Action::ReloadSource, Action::Quit]), // This should overwrite Actions::multiple(vec![Action::ReloadSource, Action::Quit]), // This should overwrite
); );
input_map2.key_actions.insert( input_map2.key_actions.insert(
Key::Char('b'), Key::Char('b'),
Actions::Multiple(vec![Action::TogglePreview, Action::ToggleHelp]), Actions::multiple(vec![Action::TogglePreview, Action::ToggleHelp]),
); );
input_map1.merge(&input_map2); input_map1.merge(&input_map2);
@ -845,9 +841,9 @@ mod tests {
let mut bindings = FxHashMap::default(); let mut bindings = FxHashMap::default();
bindings.insert( bindings.insert(
Key::Ctrl('r'), Key::Ctrl('r'),
Actions::Multiple(vec![Action::ReloadSource, Action::ClearScreen]), Actions::multiple(vec![Action::ReloadSource, Action::ClearScreen]),
); );
bindings.insert(Key::Esc, Actions::Single(Action::Quit)); bindings.insert(Key::Esc, Actions::single(Action::Quit));
let keybindings = KeyBindings { bindings }; let keybindings = KeyBindings { bindings };
let input_map: InputMap = (&keybindings).into(); let input_map: InputMap = (&keybindings).into();

View File

@ -179,16 +179,10 @@ pub fn find_keys_for_single_action(
.iter() .iter()
.filter_map(|(key, actions)| { .filter_map(|(key, actions)| {
// Check if this actions contains the target action // Check if this actions contains the target action
match actions { if actions.as_slice().contains(target_action) {
Actions::Single(action) if action == target_action => { Some(key.to_string())
Some(key.to_string()) } else {
} None
Actions::Multiple(action_list)
if action_list.contains(target_action) =>
{
Some(key.to_string())
}
_ => None,
} }
}) })
.collect() .collect()