1use std::collections::{BTreeMap, HashMap};
9
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12
13use crate::shortcut::{Chord, Platform, parse_list};
14use crate::{Host, Registry};
15
16const MAX_OVERRIDES: usize = 2000;
18const MAX_KEYS: usize = 8;
20const MAX_ID_LEN: usize = 128;
22
23#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
25pub struct Overrides {
26 #[serde(default)]
27 pub bindings: BTreeMap<String, Vec<String>>,
28}
29
30#[derive(Debug, Clone, PartialEq, Serialize)]
32pub struct Conflict {
33 pub chord: Chord,
34 pub ids: Vec<String>,
36}
37
38#[derive(Debug, Clone)]
39struct Binding {
40 id: String,
41 user: bool,
42 order: usize,
43}
44
45#[derive(Debug, Clone)]
47pub struct Keymap {
48 platform: Platform,
49 defaults: Vec<(String, Vec<Chord>)>,
51 positions: HashMap<String, usize>,
52 user: BTreeMap<String, Vec<Chord>>,
53 index: HashMap<Chord, Vec<Binding>>,
54 invalid: Vec<(String, String)>,
55}
56
57impl Keymap {
58 pub fn new<'a>(platform: Platform, defaults: impl IntoIterator<Item = (&'a str, Option<&'a str>)>) -> Self {
62 let mut map = Keymap { platform, defaults: vec![], positions: HashMap::new(), user: BTreeMap::new(), index: HashMap::new(), invalid: vec![] };
63 for (id, text) in defaults {
64 if map.positions.contains_key(id) {
65 continue;
66 }
67 let chords = match text.map(parse_list) {
68 None => vec![],
69 Some(Ok(c)) => c,
70 Some(Err(_)) => {
71 map.invalid.push((id.to_string(), text.unwrap_or_default().to_string()));
72 vec![]
73 }
74 };
75 map.positions.insert(id.to_string(), map.defaults.len());
76 map.defaults.push((id.to_string(), chords));
77 }
78 map.reindex();
79 map
80 }
81
82 pub fn from_registry<S: Host>(registry: &Registry<S>, platform: Platform) -> Self {
84 Self::new(platform, registry.specs().iter().map(|c| (c.id, c.shortcut)))
85 }
86
87 pub fn platform(&self) -> Platform {
88 self.platform
89 }
90
91 pub fn invalid_defaults(&self) -> &[(String, String)] {
93 &self.invalid
94 }
95
96 fn reindex(&mut self) {
97 self.index.clear();
98 let user = self.user.iter().map(|(id, c)| (id, c, true));
99 let defaults = self.defaults.iter().filter(|(id, _)| !self.user.contains_key(id)).map(|(id, c)| (id, c, false));
100 for (id, chords, is_user) in user.chain(defaults) {
101 let order = self.positions.get(id).copied().unwrap_or(usize::MAX);
102 for chord in chords {
103 let list = self.index.entry(chord.on(self.platform)).or_default();
104 if !list.iter().any(|b| &b.id == id) {
105 list.push(Binding { id: id.clone(), user: is_user, order });
106 }
107 }
108 }
109 for list in self.index.values_mut() {
110 list.sort_by_key(|b| (!b.user, b.order));
111 }
112 }
113
114 pub fn lookup(&self, chord: &Chord) -> Option<&str> {
116 self.index.get(&chord.on(self.platform)).and_then(|l| l.first()).map(|b| b.id.as_str())
117 }
118
119 pub fn commands_for(&self, chord: &Chord) -> Vec<&str> {
121 self.index.get(&chord.on(self.platform)).map(|l| l.iter().map(|b| b.id.as_str()).collect()).unwrap_or_default()
122 }
123
124 pub fn keys_for(&self, id: &str) -> &[Chord] {
126 if let Some(keys) = self.user.get(id) {
127 return keys;
128 }
129 self.positions.get(id).and_then(|&i| self.defaults.get(i)).map(|(_, c)| c.as_slice()).unwrap_or_default()
130 }
131
132 pub fn default_keys(&self, id: &str) -> &[Chord] {
134 self.positions.get(id).and_then(|&i| self.defaults.get(i)).map(|(_, c)| c.as_slice()).unwrap_or_default()
135 }
136
137 pub fn knows(&self, id: &str) -> bool {
139 self.positions.contains_key(id)
140 }
141
142 pub fn bind(&mut self, id: &str, mut keys: Vec<Chord>) -> bool {
144 if !self.knows(id) {
145 return false;
146 }
147 keys.truncate(MAX_KEYS);
148 keys.dedup();
149 if keys.as_slice() == self.default_keys(id) {
150 self.user.remove(id);
151 } else {
152 self.user.insert(id.to_string(), keys);
153 }
154 self.reindex();
155 true
156 }
157
158 pub fn reset(&mut self, id: &str) {
160 if self.user.remove(id).is_some() {
161 self.reindex();
162 }
163 }
164
165 pub fn reset_all(&mut self) {
166 self.user.clear();
167 self.reindex();
168 }
169
170 pub fn would_conflict(&self, id: &str, chord: &Chord) -> Vec<&str> {
172 self.commands_for(chord).into_iter().filter(|c| *c != id).collect()
173 }
174
175 pub fn conflicts(&self) -> Vec<Conflict> {
177 let mut out: Vec<Conflict> = self
178 .index
179 .iter()
180 .filter(|(_, l)| l.len() > 1)
181 .map(|(chord, l)| Conflict { chord: *chord, ids: l.iter().map(|b| b.id.clone()).collect() })
182 .collect();
183 out.sort_by_key(|c| c.chord);
184 out
185 }
186
187 pub fn overrides(&self) -> Overrides {
189 Overrides { bindings: self.user.iter().map(|(id, keys)| (id.clone(), keys.iter().map(Chord::portable).collect())).collect() }
190 }
191
192 pub fn apply_overrides(&mut self, overrides: &Overrides) -> usize {
195 let mut skipped = 0;
196 for (id, keys) in overrides.bindings.iter().take(MAX_OVERRIDES) {
197 if id.len() > MAX_ID_LEN || !self.knows(id) {
198 skipped += 1;
199 continue;
200 }
201 let mut chords = Vec::new();
202 for k in keys.iter().take(MAX_KEYS) {
203 match Chord::parse(k) {
204 Ok(c) => chords.push(c),
205 Err(_) => skipped += 1,
206 }
207 }
208 chords.dedup();
209 if chords.as_slice() == self.default_keys(id) {
210 self.user.remove(id);
211 } else {
212 self.user.insert(id.clone(), chords);
213 }
214 }
215 skipped += overrides.bindings.len().saturating_sub(MAX_OVERRIDES);
216 self.reindex();
217 skipped
218 }
219
220 pub fn apply_overrides_json(&mut self, value: &Value) -> usize {
222 let mut o = Overrides::default();
223 let Some(b) = value.get("bindings").and_then(Value::as_object) else { return 0 };
224 let mut skipped = 0;
225 for (id, keys) in b.iter().take(MAX_OVERRIDES) {
226 match keys.as_array() {
227 Some(a) => {
228 o.bindings.insert(id.clone(), a.iter().take(MAX_KEYS).filter_map(Value::as_str).map(str::to_string).collect());
229 }
230 None => skipped += 1,
231 }
232 }
233 skipped + self.apply_overrides(&o)
234 }
235}