1use std::collections::{BTreeMap, HashMap};
2
3use super::actions::Action;
4use crate::data::{BareKey, InputMode, KeyWithModifier, KeybindsVec};
5
6use serde::{Deserialize, Serialize};
7use std::fmt;
8
9#[derive(Clone, PartialEq, Deserialize, Serialize, Default)]
11pub struct Keybinds(pub HashMap<InputMode, HashMap<KeyWithModifier, Vec<Action>>>);
12
13impl fmt::Debug for Keybinds {
14 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15 let mut stable_sorted = BTreeMap::new();
16 for (mode, keybinds) in self.0.iter() {
17 let mut stable_sorted_mode_keybinds = BTreeMap::new();
18 for (key, actions) in keybinds {
19 stable_sorted_mode_keybinds.insert(key, actions);
20 }
21 stable_sorted.insert(mode, stable_sorted_mode_keybinds);
22 }
23 write!(f, "{:#?}", stable_sorted)
24 }
25}
26
27impl Keybinds {
28 pub fn get_actions_for_key_in_mode(
29 &self,
30 mode: &InputMode,
31 key: &KeyWithModifier,
32 ) -> Option<&Vec<Action>> {
33 self.0
34 .get(mode)
35 .and_then(|normal_mode_keybindings| normal_mode_keybindings.get(key))
36 }
37 pub fn get_actions_for_key_in_mode_or_default_action(
38 &self,
39 mode: &InputMode,
40 key_with_modifier: &KeyWithModifier,
41 raw_bytes: Vec<u8>,
42 default_input_mode: InputMode,
43 key_is_kitty_protocol: bool,
44 ) -> Vec<Action> {
45 self.0
46 .get(mode)
47 .and_then(|mode_keybindings| {
48 if raw_bytes == &[10] {
49 handle_ctrl_j(&mode_keybindings, &raw_bytes, key_is_kitty_protocol)
50 } else {
51 mode_keybindings.get(key_with_modifier).cloned()
52 }
53 })
54 .unwrap_or_else(|| {
55 vec![self.default_action_for_mode(
56 mode,
57 Some(key_with_modifier),
58 raw_bytes,
59 default_input_mode,
60 key_is_kitty_protocol,
61 )]
62 })
63 }
64 pub fn get_input_mode_mut(
65 &mut self,
66 input_mode: &InputMode,
67 ) -> &mut HashMap<KeyWithModifier, Vec<Action>> {
68 self.0.entry(*input_mode).or_insert_with(HashMap::new)
69 }
70 pub fn default_action_for_mode(
71 &self,
72 mode: &InputMode,
73 key_with_modifier: Option<&KeyWithModifier>,
74 raw_bytes: Vec<u8>,
75 default_input_mode: InputMode,
76 key_is_kitty_protocol: bool,
77 ) -> Action {
78 match *mode {
79 InputMode::Locked => Action::Write {
80 key_with_modifier: key_with_modifier.cloned(),
81 bytes: raw_bytes,
82 is_kitty_keyboard_protocol: key_is_kitty_protocol,
83 },
84 mode if mode == default_input_mode => Action::Write {
85 key_with_modifier: key_with_modifier.cloned(),
86 bytes: raw_bytes,
87 is_kitty_keyboard_protocol: key_is_kitty_protocol,
88 },
89 InputMode::RenameTab => Action::TabNameInput { input: raw_bytes },
90 InputMode::RenamePane => Action::PaneNameInput { input: raw_bytes },
91 InputMode::EnterSearch => Action::SearchInput { input: raw_bytes },
92 _ => Action::NoOp,
93 }
94 }
95 pub fn to_keybinds_vec(&self) -> KeybindsVec {
96 let mut ret = vec![];
97 for (mode, mode_binds) in &self.0 {
98 let mut mode_binds_vec: Vec<(KeyWithModifier, Vec<Action>)> = vec![];
99 for (key, actions) in mode_binds {
100 mode_binds_vec.push((key.clone(), actions.clone()));
101 }
102 ret.push((*mode, mode_binds_vec))
103 }
104 ret
105 }
106 pub fn merge(&mut self, mut other: Keybinds) {
107 for (other_input_mode, mut other_input_mode_keybinds) in other.0.drain() {
108 let input_mode_keybinds = self
109 .0
110 .entry(other_input_mode)
111 .or_insert_with(|| Default::default());
112 for (other_action, other_action_keybinds) in other_input_mode_keybinds.drain() {
113 input_mode_keybinds.insert(other_action, other_action_keybinds);
114 }
115 }
116 }
117}
118
119const MAX_SHORTCUT_SEARCH_DEPTH: usize = 4;
120
121pub fn shortcut_for_action(
122 keybinds: &KeybindsVec,
123 base_mode: InputMode,
124 is_target_action: impl Fn(&Action) -> bool,
125) -> Option<Vec<KeyWithModifier>> {
126 let mode_binds = |mode: InputMode| -> Vec<(KeyWithModifier, Vec<Action>)> {
127 let mut binds = keybinds
128 .iter()
129 .find(|(bind_mode, _)| *bind_mode == mode)
130 .map(|(_, binds)| binds.clone())
131 .unwrap_or_default();
132 binds.sort_by(|(a, _), (b, _)| a.cmp(b));
133 binds
134 };
135 let mut visited: Vec<InputMode> = vec![base_mode];
136 let mut queue: Vec<(InputMode, Vec<KeyWithModifier>)> = vec![(base_mode, vec![])];
137 for _ in 0..MAX_SHORTCUT_SEARCH_DEPTH {
138 let mut next_queue: Vec<(InputMode, Vec<KeyWithModifier>)> = vec![];
139 for (mode, path) in &queue {
140 for (key, actions) in mode_binds(*mode) {
141 if actions.iter().any(&is_target_action) {
142 let mut shortcut = path.clone();
143 shortcut.push(key);
144 return Some(shortcut);
145 }
146 }
147 }
148 for (mode, path) in &queue {
149 for (key, actions) in mode_binds(*mode) {
150 for action in &actions {
151 if let Action::SwitchToMode {
152 input_mode: next_mode,
153 } = action
154 {
155 if !visited.contains(next_mode) {
156 visited.push(*next_mode);
157 let mut next_path = path.clone();
158 next_path.push(key.clone());
159 next_queue.push((*next_mode, next_path));
160 }
161 }
162 }
163 }
164 }
165 if next_queue.is_empty() {
166 return None;
167 }
168 queue = next_queue;
169 }
170 None
171}
172
173fn handle_ctrl_j(
177 mode_keybindings: &HashMap<KeyWithModifier, Vec<Action>>,
178 raw_bytes: &[u8],
179 key_is_kitty_protocol: bool,
180) -> Option<Vec<Action>> {
181 let ctrl_j = KeyWithModifier::new(BareKey::Char('j')).with_ctrl_modifier();
182 if mode_keybindings.get(&ctrl_j).is_some() {
183 mode_keybindings.get(&ctrl_j).cloned()
184 } else {
185 Some(vec![Action::Write {
186 key_with_modifier: Some(ctrl_j),
187 bytes: raw_bytes.to_vec().clone(),
188 is_kitty_keyboard_protocol: key_is_kitty_protocol,
189 }])
190 }
191}
192
193#[cfg(test)]
195#[path = "./unit/keybinds_test.rs"]
196mod keybinds_test;