mirror of
https://github.com/alexpasmantier/television.git
synced 2025-07-29 06:11:37 +00:00
refactor(bindigns): migrate to OneOrMany
This commit is contained in:
parent
3cca8ad9bc
commit
088dc6ba83
@ -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);
|
||||||
|
@ -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]))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user