feat(config): allow specifying multiple keymaps for the same action + better defaults (#149)

Fixes #135
This commit is contained in:
Alex Pasmantier 2024-12-28 15:56:12 +01:00 committed by GitHub
parent 499bfdb8e5
commit 557686e197
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 74 additions and 16 deletions

View File

@ -75,8 +75,8 @@ theme = "Coldark-Dark"
# Quit the application # Quit the application
quit = "esc" quit = "esc"
# Scrolling through entries # Scrolling through entries
select_next_entry = "down" select_next_entry = ["down", "ctrl-n", "ctrl-j"]
select_prev_entry = "up" select_prev_entry = ["up", "ctrl-p", "ctrl-k"]
select_next_page = "pagedown" select_next_page = "pagedown"
select_prev_page = "pageup" select_prev_page = "pageup"
# Scrolling the preview pane # Scrolling the preview pane
@ -102,8 +102,8 @@ toggle_preview = "ctrl-o"
# Quit the application # Quit the application
quit = "esc" quit = "esc"
# Scrolling through entries # Scrolling through entries
select_next_entry = "down" select_next_entry = ["down", "ctrl-n", "ctrl-j"]
select_prev_entry = "up" select_prev_entry = ["up", "ctrl-p", "ctrl-k"]
select_next_page = "pagedown" select_next_page = "pagedown"
select_prev_page = "pageup" select_prev_page = "pageup"
# Select an entry # Select an entry
@ -122,8 +122,8 @@ toggle_preview = "ctrl-o"
# Quit the application # Quit the application
quit = "esc" quit = "esc"
# Scrolling through entries # Scrolling through entries
select_next_entry = "down" select_next_entry = ["down", "ctrl-n", "ctrl-j"]
select_prev_entry = "up" select_prev_entry = ["up", "ctrl-p", "ctrl-k"]
select_next_page = "pagedown" select_next_page = "pagedown"
select_prev_page = "pageup" select_prev_page = "pageup"
# Select an entry # Select an entry

View File

@ -3,8 +3,7 @@ use std::{env, path::PathBuf};
use color_eyre::Result; use color_eyre::Result;
use directories::ProjectDirs; use directories::ProjectDirs;
pub use keybindings::parse_key; pub use keybindings::{parse_key, Binding, KeyBindings};
pub use keybindings::KeyBindings;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use previewers::PreviewersConfig; use previewers::PreviewersConfig;
use serde::Deserialize; use serde::Deserialize;
@ -118,7 +117,7 @@ impl Config {
for (command, key) in default_bindings { for (command, key) in default_bindings {
user_bindings user_bindings
.entry(command.clone()) .entry(command.clone())
.or_insert_with(|| *key); .or_insert_with(|| key.clone());
} }
} }

View File

@ -3,14 +3,34 @@ use crate::event::{convert_raw_event_to_key, Key};
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Display;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use television_screen::mode::Mode; use television_screen::mode::Mode;
#[derive(Clone, Debug, Deserialize)]
pub enum Binding {
SingleKey(Key),
MultipleKeys(Vec<Key>),
}
impl Display for Binding {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Binding::SingleKey(key) => write!(f, "{}", key),
Binding::MultipleKeys(keys) => {
let keys_str: Vec<String> =
keys.iter().map(|k| k.to_string()).collect();
write!(f, "{}", keys_str.join(", "))
}
}
}
}
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct KeyBindings(pub config::Map<Mode, config::Map<Action, Key>>); pub struct KeyBindings(pub config::Map<Mode, config::Map<Action, Binding>>);
impl Deref for KeyBindings { impl Deref for KeyBindings {
type Target = config::Map<Mode, config::Map<Action, Key>>; type Target = config::Map<Mode, config::Map<Action, Binding>>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.0
} }
@ -22,13 +42,20 @@ impl DerefMut for KeyBindings {
} }
} }
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum SerializedBinding {
SingleKey(String),
MultipleKeys(Vec<String>),
}
impl<'de> Deserialize<'de> for KeyBindings { impl<'de> Deserialize<'de> for KeyBindings {
fn deserialize<D>(deserializer: D) -> color_eyre::Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> color_eyre::Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let parsed_map = let parsed_map =
HashMap::<Mode, HashMap<Action, String>>::deserialize( HashMap::<Mode, HashMap<Action, SerializedBinding>>::deserialize(
deserializer, deserializer,
)?; )?;
@ -37,7 +64,28 @@ impl<'de> Deserialize<'de> for KeyBindings {
.map(|(mode, inner_map)| { .map(|(mode, inner_map)| {
let converted_inner_map = inner_map let converted_inner_map = inner_map
.into_iter() .into_iter()
.map(|(cmd, key_str)| (cmd, parse_key(&key_str).unwrap())) .map(|(cmd, binding)| {
(
cmd,
match binding {
SerializedBinding::SingleKey(key_str) => {
Binding::SingleKey(
parse_key(&key_str).unwrap(),
)
}
SerializedBinding::MultipleKeys(keys_str) => {
Binding::MultipleKeys(
keys_str
.iter()
.map(|key_str| {
parse_key(key_str).unwrap()
})
.collect(),
)
}
},
)
})
.collect(); .collect();
(mode, converted_inner_map) (mode, converted_inner_map)
}) })

View File

@ -5,7 +5,7 @@ use color_eyre::Result;
use television_screen::mode::Mode; use television_screen::mode::Mode;
use crate::action::Action; use crate::action::Action;
use crate::config::KeyBindings; use crate::config::{Binding, KeyBindings};
use crate::event::Key; use crate::event::Key;
#[derive(Default, Debug)] #[derive(Default, Debug)]
@ -23,8 +23,17 @@ impl From<&KeyBindings> for Keymap {
let mut keymap = HashMap::new(); let mut keymap = HashMap::new();
for (mode, bindings) in keybindings.iter() { for (mode, bindings) in keybindings.iter() {
let mut mode_keymap = HashMap::new(); let mut mode_keymap = HashMap::new();
for (action, key) in bindings { for (action, binding) in bindings {
mode_keymap.insert(*key, action.clone()); match binding {
Binding::SingleKey(key) => {
mode_keymap.insert(*key, action.clone());
}
Binding::MultipleKeys(keys) => {
for key in keys {
mode_keymap.insert(*key, action.clone());
}
}
}
} }
keymap.insert(*mode, mode_keymap); keymap.insert(*mode, mode_keymap);
} }

View File

@ -458,6 +458,7 @@ impl Television {
.get(&self.mode) .get(&self.mode)
.unwrap() .unwrap()
.get(&Action::ToggleHelp) .get(&Action::ToggleHelp)
// just display the first keybinding
.unwrap() .unwrap()
.to_string(), .to_string(),
&self &self
@ -466,6 +467,7 @@ impl Television {
.get(&self.mode) .get(&self.mode)
.unwrap() .unwrap()
.get(&Action::TogglePreview) .get(&Action::TogglePreview)
// just display the first keybinding
.unwrap() .unwrap()
.to_string(), .to_string(),
)?; )?;