diff --git a/.config/config.toml b/.config/config.toml index 1a5e4e0..435a9e8 100644 --- a/.config/config.toml +++ b/.config/config.toml @@ -75,8 +75,8 @@ theme = "Coldark-Dark" # Quit the application quit = "esc" # Scrolling through entries -select_next_entry = "down" -select_prev_entry = "up" +select_next_entry = ["down", "ctrl-n", "ctrl-j"] +select_prev_entry = ["up", "ctrl-p", "ctrl-k"] select_next_page = "pagedown" select_prev_page = "pageup" # Scrolling the preview pane @@ -102,8 +102,8 @@ toggle_preview = "ctrl-o" # Quit the application quit = "esc" # Scrolling through entries -select_next_entry = "down" -select_prev_entry = "up" +select_next_entry = ["down", "ctrl-n", "ctrl-j"] +select_prev_entry = ["up", "ctrl-p", "ctrl-k"] select_next_page = "pagedown" select_prev_page = "pageup" # Select an entry @@ -122,8 +122,8 @@ toggle_preview = "ctrl-o" # Quit the application quit = "esc" # Scrolling through entries -select_next_entry = "down" -select_prev_entry = "up" +select_next_entry = ["down", "ctrl-n", "ctrl-j"] +select_prev_entry = ["up", "ctrl-p", "ctrl-k"] select_next_page = "pagedown" select_prev_page = "pageup" # Select an entry diff --git a/crates/television/config.rs b/crates/television/config.rs index 906a682..3e6fd13 100644 --- a/crates/television/config.rs +++ b/crates/television/config.rs @@ -3,8 +3,7 @@ use std::{env, path::PathBuf}; use color_eyre::Result; use directories::ProjectDirs; -pub use keybindings::parse_key; -pub use keybindings::KeyBindings; +pub use keybindings::{parse_key, Binding, KeyBindings}; use lazy_static::lazy_static; use previewers::PreviewersConfig; use serde::Deserialize; @@ -118,7 +117,7 @@ impl Config { for (command, key) in default_bindings { user_bindings .entry(command.clone()) - .or_insert_with(|| *key); + .or_insert_with(|| key.clone()); } } diff --git a/crates/television/config/keybindings.rs b/crates/television/config/keybindings.rs index a1a8022..55dfc90 100644 --- a/crates/television/config/keybindings.rs +++ b/crates/television/config/keybindings.rs @@ -3,14 +3,34 @@ use crate::event::{convert_raw_event_to_key, Key}; use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use serde::{Deserialize, Deserializer}; use std::collections::HashMap; +use std::fmt::Display; use std::ops::{Deref, DerefMut}; use television_screen::mode::Mode; +#[derive(Clone, Debug, Deserialize)] +pub enum Binding { + SingleKey(Key), + MultipleKeys(Vec), +} + +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 = + keys.iter().map(|k| k.to_string()).collect(); + write!(f, "{}", keys_str.join(", ")) + } + } + } +} + #[derive(Clone, Debug, Default)] -pub struct KeyBindings(pub config::Map>); +pub struct KeyBindings(pub config::Map>); impl Deref for KeyBindings { - type Target = config::Map>; + type Target = config::Map>; fn deref(&self) -> &Self::Target { &self.0 } @@ -22,13 +42,20 @@ impl DerefMut for KeyBindings { } } +#[derive(Clone, Debug, Deserialize)] +#[serde(untagged)] +pub enum SerializedBinding { + SingleKey(String), + MultipleKeys(Vec), +} + impl<'de> Deserialize<'de> for KeyBindings { fn deserialize(deserializer: D) -> color_eyre::Result where D: Deserializer<'de>, { let parsed_map = - HashMap::>::deserialize( + HashMap::>::deserialize( deserializer, )?; @@ -37,7 +64,28 @@ impl<'de> Deserialize<'de> for KeyBindings { .map(|(mode, inner_map)| { let converted_inner_map = inner_map .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(); (mode, converted_inner_map) }) diff --git a/crates/television/keymap.rs b/crates/television/keymap.rs index 5833f7f..fa9e248 100644 --- a/crates/television/keymap.rs +++ b/crates/television/keymap.rs @@ -5,7 +5,7 @@ use color_eyre::Result; use television_screen::mode::Mode; use crate::action::Action; -use crate::config::KeyBindings; +use crate::config::{Binding, KeyBindings}; use crate::event::Key; #[derive(Default, Debug)] @@ -23,8 +23,17 @@ impl From<&KeyBindings> for Keymap { let mut keymap = HashMap::new(); for (mode, bindings) in keybindings.iter() { let mut mode_keymap = HashMap::new(); - for (action, key) in bindings { - mode_keymap.insert(*key, action.clone()); + for (action, binding) in bindings { + 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); } diff --git a/crates/television/television.rs b/crates/television/television.rs index 5041c33..72bd6bd 100644 --- a/crates/television/television.rs +++ b/crates/television/television.rs @@ -458,6 +458,7 @@ impl Television { .get(&self.mode) .unwrap() .get(&Action::ToggleHelp) + // just display the first keybinding .unwrap() .to_string(), &self @@ -466,6 +467,7 @@ impl Television { .get(&self.mode) .unwrap() .get(&Action::TogglePreview) + // just display the first keybinding .unwrap() .to_string(), )?;