use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
use crate::keyboard::{KeyCode, KeyEvent, KeyModifiers};
impl<'de> Deserialize<'de> for KeyEvent {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
s.parse().map_err(de::Error::custom)
}
}
fn deserialize_key_or_keys<'de, D>(deserializer: D) -> Result<Vec<KeyEvent>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum OneOrMany {
One(String),
Many(Vec<String>),
}
let keys = match OneOrMany::deserialize(deserializer)? {
OneOrMany::One(s) => vec![s],
OneOrMany::Many(v) => v,
};
keys.into_iter()
.map(|s| {
s.parse::<KeyEvent>()
.map_err(|e| de::Error::custom(format!("Invalid key binding '{s}': {e}")))
})
.collect()
}
fn serialize_key_or_keys<S>(keys: &Vec<KeyEvent>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if keys.len() == 1 {
keys[0].serialize(serializer)
} else {
keys.serialize(serializer)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Keys(Vec<KeyEvent>);
impl Keys {
pub fn new(keys: Vec<KeyEvent>) -> Self {
Self(keys)
}
}
impl<'de> Deserialize<'de> for Keys {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserialize_key_or_keys(deserializer).map(Keys)
}
}
impl Serialize for Keys {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serialize_key_or_keys(&self.0, serializer)
}
}
impl std::ops::Deref for Keys {
type Target = Vec<KeyEvent>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> IntoIterator for &'a Keys {
type Item = &'a KeyEvent;
type IntoIter = std::slice::Iter<'a, KeyEvent>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
#[macro_export]
macro_rules! keys {
($($item:expr),* $(,)?) => {
$crate::config::Keys::new(vec![$($item),*])
};
}
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
#[serde(deny_unknown_fields)]
pub struct KeysConfig {
#[serde(default)]
pub general: KeysGeneral,
#[serde(default)]
pub search: KeysSearch,
#[serde(default)]
pub performing_replacement: KeysPerformingReplacement,
#[serde(default)]
pub results: KeysResults,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[serde(deny_unknown_fields, default)]
pub struct KeysGeneral {
pub quit: Keys,
pub reset: Keys,
pub show_help_menu: Keys,
}
impl Default for KeysGeneral {
fn default() -> Self {
Self {
quit: keys![KeyEvent::new(KeyCode::Char('c'), KeyModifiers::CONTROL)],
reset: keys![KeyEvent::new(KeyCode::Char('r'), KeyModifiers::CONTROL)],
show_help_menu: keys![KeyEvent::new(KeyCode::Char('h'), KeyModifiers::CONTROL)],
}
}
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[serde(deny_unknown_fields, default)]
pub struct KeysSearch {
pub toggle_preview_wrapping: Keys,
pub toggle_hidden_files: Keys,
pub toggle_multiline: Keys,
pub toggle_interpret_escape_sequences: Keys,
#[serde(default)]
pub fields: KeysSearchFocusFields,
#[serde(default)]
pub results: KeysSearchFocusResults,
}
impl Default for KeysSearch {
fn default() -> Self {
Self {
toggle_preview_wrapping: keys![KeyEvent::new(
KeyCode::Char('l'),
KeyModifiers::CONTROL
)],
toggle_hidden_files: keys![KeyEvent::new(KeyCode::Char('t'), KeyModifiers::CONTROL)],
toggle_multiline: keys![KeyEvent::new(KeyCode::Char('m'), KeyModifiers::ALT)],
toggle_interpret_escape_sequences: keys![KeyEvent::new(
KeyCode::Char('e'),
KeyModifiers::ALT
)],
fields: KeysSearchFocusFields::default(),
results: KeysSearchFocusResults::default(),
}
}
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[serde(deny_unknown_fields, default)]
pub struct KeysSearchFocusFields {
pub unlock_prepopulated_fields: Keys,
pub trigger_search: Keys,
pub focus_next_field: Keys,
pub focus_previous_field: Keys,
}
impl Default for KeysSearchFocusFields {
fn default() -> Self {
Self {
unlock_prepopulated_fields: keys![KeyEvent::new(KeyCode::Char('u'), KeyModifiers::ALT)],
trigger_search: keys![KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)],
focus_next_field: keys![KeyEvent::new(KeyCode::Tab, KeyModifiers::NONE)],
focus_previous_field: keys![KeyEvent::new(KeyCode::Tab, KeyModifiers::SHIFT)],
}
}
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[serde(deny_unknown_fields, default)]
pub struct KeysSearchFocusResults {
pub trigger_replacement: Keys,
pub back_to_fields: Keys,
pub open_in_editor: Keys,
pub move_down: Keys,
pub move_up: Keys,
pub move_down_half_page: Keys,
pub move_up_half_page: Keys,
pub move_down_full_page: Keys,
pub move_up_full_page: Keys,
pub move_top: Keys,
pub move_bottom: Keys,
pub toggle_selected_inclusion: Keys,
pub toggle_all_selected: Keys,
pub toggle_multiselect_mode: Keys,
pub flip_multiselect_direction: Keys,
}
impl Default for KeysSearchFocusResults {
fn default() -> Self {
Self {
trigger_replacement: keys![KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)],
back_to_fields: keys![
KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE),
KeyEvent::new(KeyCode::Char('o'), KeyModifiers::CONTROL),
],
open_in_editor: keys![KeyEvent::new(KeyCode::Char('e'), KeyModifiers::NONE)],
move_down: keys![
KeyEvent::new(KeyCode::Char('j'), KeyModifiers::NONE),
KeyEvent::new(KeyCode::Down, KeyModifiers::NONE),
KeyEvent::new(KeyCode::Char('n'), KeyModifiers::CONTROL),
],
move_up: keys![
KeyEvent::new(KeyCode::Char('k'), KeyModifiers::NONE),
KeyEvent::new(KeyCode::Up, KeyModifiers::NONE),
KeyEvent::new(KeyCode::Char('p'), KeyModifiers::CONTROL),
],
move_down_half_page: keys![KeyEvent::new(KeyCode::Char('d'), KeyModifiers::CONTROL)],
move_down_full_page: keys![
KeyEvent::new(KeyCode::Char('f'), KeyModifiers::CONTROL),
KeyEvent::new(KeyCode::PageDown, KeyModifiers::NONE),
],
move_up_half_page: keys![KeyEvent::new(KeyCode::Char('u'), KeyModifiers::CONTROL)],
move_up_full_page: keys![
KeyEvent::new(KeyCode::Char('b'), KeyModifiers::CONTROL),
KeyEvent::new(KeyCode::PageUp, KeyModifiers::NONE),
],
move_top: keys![KeyEvent::new(KeyCode::Char('g'), KeyModifiers::NONE)],
move_bottom: keys![KeyEvent::new(KeyCode::Char('G'), KeyModifiers::NONE)],
toggle_selected_inclusion: keys![KeyEvent::new(KeyCode::Char(' '), KeyModifiers::NONE)],
toggle_all_selected: keys![KeyEvent::new(KeyCode::Char('a'), KeyModifiers::NONE)],
toggle_multiselect_mode: keys![KeyEvent::new(KeyCode::Char('v'), KeyModifiers::NONE)],
flip_multiselect_direction: keys![KeyEvent::new(KeyCode::Char(';'), KeyModifiers::ALT)],
}
}
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[serde(deny_unknown_fields, default)]
#[derive(Default)]
pub struct KeysPerformingReplacement {}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
#[serde(deny_unknown_fields, default)]
pub struct KeysResults {
pub scroll_errors_down: Keys,
pub scroll_errors_up: Keys,
pub quit: Keys,
}
impl Default for KeysResults {
fn default() -> Self {
Self {
scroll_errors_down: keys![
KeyEvent::new(KeyCode::Char('j'), KeyModifiers::NONE),
KeyEvent::new(KeyCode::Down, KeyModifiers::NONE),
KeyEvent::new(KeyCode::Char('n'), KeyModifiers::CONTROL),
],
scroll_errors_up: keys![
KeyEvent::new(KeyCode::Char('k'), KeyModifiers::NONE),
KeyEvent::new(KeyCode::Up, KeyModifiers::NONE),
KeyEvent::new(KeyCode::Char('p'), KeyModifiers::CONTROL),
],
quit: keys![
KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE),
KeyEvent::new(KeyCode::Char('q'), KeyModifiers::NONE),
],
}
}
}