1use crate::conflict::ConflictDetector;
4use crate::error::EngineError;
5use crate::help::KeybindHelp;
6use crate::models::{Keybind, KeyCombo};
7use crate::parser::ParserRegistry;
8use crate::persistence::KeybindPersistence;
9use crate::profile::ProfileManager;
10use crate::registry::KeybindRegistry;
11use std::path::Path;
12
13pub struct KeybindEngine {
15 registry: KeybindRegistry,
16 profile_manager: ProfileManager,
17 default_keybinds: Vec<Keybind>,
18}
19
20impl KeybindEngine {
21 pub fn new() -> Self {
23 KeybindEngine {
24 registry: KeybindRegistry::new(),
25 profile_manager: ProfileManager::new(),
26 default_keybinds: Vec::new(),
27 }
28 }
29
30 pub fn load_defaults_from_file(&mut self, path: impl AsRef<Path>) -> Result<(), EngineError> {
32 let content = std::fs::read_to_string(path.as_ref()).map_err(|e| {
33 EngineError::DefaultsLoadError(format!("Failed to read defaults file: {}", e))
34 })?;
35
36 let parser = ParserRegistry::new();
37 let keybinds = parser.parse(&content, "json").map_err(|e| {
38 EngineError::DefaultsLoadError(format!("Failed to parse defaults: {}", e))
39 })?;
40
41 self.default_keybinds = keybinds.clone();
42 Ok(())
43 }
44
45 pub fn apply_defaults(&mut self) -> Result<(), EngineError> {
47 if self.default_keybinds.is_empty() {
48 return Err(EngineError::DefaultsLoadError(
49 "No defaults loaded".to_string(),
50 ));
51 }
52
53 if self.profile_manager.active_profile_name().is_none() {
55 self.create_profile("default", self.default_keybinds.clone())?;
56 self.select_profile("default")?;
57 } else {
58 self.apply_keybinds(self.default_keybinds.clone())?;
60 }
61
62 Ok(())
63 }
64
65 pub fn reset_to_defaults(&mut self) -> Result<(), EngineError> {
67 if self.default_keybinds.is_empty() {
68 return Err(EngineError::DefaultsLoadError(
69 "No defaults available for reset".to_string(),
70 ));
71 }
72
73 for keybind in &self.default_keybinds {
75 if !keybind.is_default {
76 return Err(EngineError::DefaultsLoadError(
77 "Invalid default keybind: is_default flag not set".to_string(),
78 ));
79 }
80 }
81
82 self.apply_keybinds(self.default_keybinds.clone())?;
84
85 Ok(())
86 }
87
88 pub fn get_defaults(&self) -> &[Keybind] {
90 &self.default_keybinds
91 }
92
93 pub fn set_defaults(&mut self, keybinds: Vec<Keybind>) {
95 self.default_keybinds = keybinds;
96 }
97
98 pub fn apply_keybinds(&mut self, keybinds: Vec<Keybind>) -> Result<(), EngineError> {
100 self.registry.clear();
101
102 for keybind in keybinds {
103 self.registry.register(keybind)?;
104 }
105
106 Ok(())
107 }
108
109 pub fn get_action(&self, key: &KeyCombo) -> Option<&str> {
111 self.registry.lookup_by_key(key)
112 }
113
114 pub fn get_keybind(&self, action_id: &str) -> Option<&Keybind> {
116 self.registry.lookup_by_action(action_id)
117 }
118
119 pub fn all_keybinds(&self) -> Vec<&Keybind> {
121 self.registry.all_keybinds()
122 }
123
124 pub fn keybinds_by_category(&self, category: &str) -> Vec<&Keybind> {
126 self.registry.keybinds_by_category(category)
127 }
128
129 pub fn categories(&self) -> Vec<String> {
131 self.registry.categories()
132 }
133
134 pub fn create_profile(
136 &mut self,
137 name: impl Into<String>,
138 keybinds: Vec<Keybind>,
139 ) -> Result<(), EngineError> {
140 self.profile_manager.create_profile(name, keybinds)?;
141 Ok(())
142 }
143
144 pub fn select_profile(&mut self, name: &str) -> Result<(), EngineError> {
146 self.profile_manager.select_profile(name)?;
147
148 let profile = self.profile_manager.get_active_profile()?;
150 let keybinds = profile.keybinds.clone();
151 self.apply_keybinds(keybinds)?;
152
153 Ok(())
154 }
155
156 pub fn delete_profile(&mut self, name: &str) -> Result<(), EngineError> {
158 self.profile_manager.delete_profile(name)?;
159 Ok(())
160 }
161
162 pub fn active_profile_name(&self) -> Option<&str> {
164 self.profile_manager.active_profile_name()
165 }
166
167 pub fn keybind_count(&self) -> usize {
169 self.registry.len()
170 }
171
172 pub fn has_keybinds(&self) -> bool {
174 !self.registry.is_empty()
175 }
176
177 pub fn validate_keybinds(&self, keybinds: &[Keybind]) -> ValidationResult {
179 let conflicts = ConflictDetector::detect(keybinds);
181 let is_valid = conflicts.is_empty();
182
183 let mut resolutions = Vec::new();
185 for conflict in &conflicts {
186 let suggestions = ConflictDetector::suggest_resolution(conflict, keybinds);
187 resolutions.extend(suggestions);
188 }
189
190 ValidationResult {
191 is_valid,
192 conflicts,
193 resolutions,
194 applied_keybinds: keybinds.len(),
195 }
196 }
197
198 pub fn validate_and_apply_from_string(
200 &mut self,
201 content: &str,
202 format: &str,
203 ) -> Result<ValidationResult, EngineError> {
204 let parser = ParserRegistry::new();
206 let keybinds = parser.parse(content, format)?;
207
208 let validation = self.validate_keybinds(&keybinds);
210
211 if validation.is_valid {
213 self.apply_keybinds(keybinds)?;
214 }
215
216 Ok(validation)
217 }
218
219 pub fn validate_apply_and_persist_from_string(
221 &mut self,
222 content: &str,
223 format: &str,
224 profile_name: &str,
225 persistence: &dyn KeybindPersistence,
226 ) -> Result<ValidationResult, EngineError> {
227 let parser = ParserRegistry::new();
229 let keybinds = parser.parse(content, format)?;
230
231 let validation = self.validate_keybinds(&keybinds);
233
234 if validation.is_valid {
236 self.apply_keybinds(keybinds.clone())?;
237
238 self.create_profile(profile_name, keybinds)?;
240 let profile = self.profile_manager.get_active_profile()?;
241 persistence.save_profile(profile)?;
242 }
243
244 Ok(validation)
245 }
246
247 pub fn get_help_all(&self) -> String {
249 let keybinds = self.all_keybinds();
250 KeybindHelp::display_all(&keybinds)
251 }
252
253 pub fn get_help_by_category(&self, category: &str) -> String {
255 let keybinds = self.keybinds_by_category(category);
256 KeybindHelp::display_by_category(&keybinds, category)
257 }
258
259 pub fn search_keybinds(&self, query: &str) -> Vec<&Keybind> {
261 let keybinds = self.all_keybinds();
262 KeybindHelp::search(&keybinds, query)
263 }
264
265 pub fn get_keybinds_paginated(&self, page: usize, page_size: usize) -> crate::help::Page<&Keybind> {
267 let keybinds = self.all_keybinds();
268 KeybindHelp::paginate(&keybinds, page, page_size)
269 }
270
271 pub fn get_profile(&self, name: &str) -> Option<&crate::profile::Profile> {
273 self.profile_manager.get_profile(name)
274 }
275}
276
277impl Default for KeybindEngine {
278 fn default() -> Self {
279 Self::new()
280 }
281}
282
283#[derive(Debug, Clone)]
285pub struct ValidationResult {
286 pub is_valid: bool,
287 pub conflicts: Vec<crate::conflict::Conflict>,
288 pub resolutions: Vec<crate::conflict::Resolution>,
289 pub applied_keybinds: usize,
290}
291
292impl ValidationResult {
293 pub fn passed(&self) -> bool {
295 self.is_valid && self.conflicts.is_empty()
296 }
297
298 pub fn conflict_count(&self) -> usize {
300 self.conflicts.len()
301 }
302}
303
304pub fn initialize_engine_with_defaults(
306 defaults_path: impl AsRef<Path>,
307) -> Result<KeybindEngine, EngineError> {
308 let mut engine = KeybindEngine::new();
309 engine.load_defaults_from_file(defaults_path)?;
310 engine.apply_defaults()?;
311 Ok(engine)
312}
313
314pub fn get_default_persistence() -> Result<crate::persistence::FileSystemPersistence, EngineError> {
319 crate::persistence::FileSystemPersistence::with_default_location()
320 .map_err(EngineError::from)
321}
322
323#[cfg(test)]
324mod tests {
325 use super::*;
326 use std::str::FromStr;
327
328 #[test]
329 fn test_apply_keybinds() {
330 let mut engine = KeybindEngine::new();
331 let keybinds = vec![
332 Keybind::new("editor.save", "Ctrl+S", "editing", "Save"),
333 Keybind::new("editor.undo", "Ctrl+Z", "editing", "Undo"),
334 ];
335
336 assert!(engine.apply_keybinds(keybinds).is_ok());
337 assert_eq!(engine.keybind_count(), 2);
338 }
339
340 #[test]
341 fn test_get_action() {
342 let mut engine = KeybindEngine::new();
343 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
344
345 engine.apply_keybinds(keybinds).unwrap();
346
347 let key_combo = KeyCombo::from_str("Ctrl+S").unwrap();
348 let action = engine.get_action(&key_combo);
349 assert_eq!(action, Some("editor.save"));
350 }
351
352 #[test]
353 fn test_get_keybind() {
354 let mut engine = KeybindEngine::new();
355 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
356
357 engine.apply_keybinds(keybinds).unwrap();
358
359 let keybind = engine.get_keybind("editor.save");
360 assert!(keybind.is_some());
361 assert_eq!(keybind.unwrap().key, "Ctrl+S");
362 }
363
364 #[test]
365 fn test_all_keybinds() {
366 let mut engine = KeybindEngine::new();
367 let keybinds = vec![
368 Keybind::new("editor.save", "Ctrl+S", "editing", "Save"),
369 Keybind::new("editor.undo", "Ctrl+Z", "editing", "Undo"),
370 ];
371
372 engine.apply_keybinds(keybinds).unwrap();
373
374 let all = engine.all_keybinds();
375 assert_eq!(all.len(), 2);
376 }
377
378 #[test]
379 fn test_categories() {
380 let mut engine = KeybindEngine::new();
381 let keybinds = vec![
382 Keybind::new("editor.save", "Ctrl+S", "editing", "Save"),
383 Keybind::new("nav.next", "Tab", "navigation", "Next"),
384 ];
385
386 engine.apply_keybinds(keybinds).unwrap();
387
388 let categories = engine.categories();
389 assert_eq!(categories.len(), 2);
390 }
391
392 #[test]
393 fn test_create_profile() {
394 let mut engine = KeybindEngine::new();
395 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
396
397 assert!(engine.create_profile("default", keybinds).is_ok());
398 }
399
400 #[test]
401 fn test_select_profile_applies_keybinds() {
402 let mut engine = KeybindEngine::new();
403 let keybinds1 = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
404 let keybinds2 = vec![Keybind::new("editor.undo", "Ctrl+Z", "editing", "Undo")];
405
406 engine.create_profile("profile1", keybinds1).unwrap();
407 engine.create_profile("profile2", keybinds2).unwrap();
408
409 engine.select_profile("profile2").unwrap();
411 assert_eq!(engine.active_profile_name(), Some("profile2"));
412
413 let key_combo = KeyCombo::from_str("Ctrl+Z").unwrap();
415 assert_eq!(engine.get_action(&key_combo), Some("editor.undo"));
416 }
417
418 #[test]
419 fn test_delete_profile() {
420 let mut engine = KeybindEngine::new();
421 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
422
423 engine.create_profile("profile1", keybinds.clone()).unwrap();
424 engine.create_profile("profile2", keybinds).unwrap();
425
426 engine.select_profile("profile2").unwrap();
428 assert!(engine.delete_profile("profile1").is_ok());
429 }
430
431 #[test]
432 fn test_keybind_count() {
433 let mut engine = KeybindEngine::new();
434 let keybinds = vec![
435 Keybind::new("editor.save", "Ctrl+S", "editing", "Save"),
436 Keybind::new("editor.undo", "Ctrl+Z", "editing", "Undo"),
437 Keybind::new("nav.next", "Tab", "navigation", "Next"),
438 ];
439
440 engine.apply_keybinds(keybinds).unwrap();
441 assert_eq!(engine.keybind_count(), 3);
442 }
443
444 #[test]
445 fn test_has_keybinds() {
446 let mut engine = KeybindEngine::new();
447 assert!(!engine.has_keybinds());
448
449 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
450 engine.apply_keybinds(keybinds).unwrap();
451 assert!(engine.has_keybinds());
452 }
453
454 #[test]
455 fn test_keybinds_by_category() {
456 let mut engine = KeybindEngine::new();
457 let keybinds = vec![
458 Keybind::new("editor.save", "Ctrl+S", "editing", "Save"),
459 Keybind::new("editor.undo", "Ctrl+Z", "editing", "Undo"),
460 Keybind::new("nav.next", "Tab", "navigation", "Next"),
461 ];
462
463 engine.apply_keybinds(keybinds).unwrap();
464
465 let editing = engine.keybinds_by_category("editing");
466 assert_eq!(editing.len(), 2);
467
468 let navigation = engine.keybinds_by_category("navigation");
469 assert_eq!(navigation.len(), 1);
470 }
471
472 #[test]
473 fn test_apply_keybinds_clears_previous() {
474 let mut engine = KeybindEngine::new();
475 let keybinds1 = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
476 let keybinds2 = vec![Keybind::new("editor.undo", "Ctrl+Z", "editing", "Undo")];
477
478 engine.apply_keybinds(keybinds1).unwrap();
479 assert_eq!(engine.keybind_count(), 1);
480
481 engine.apply_keybinds(keybinds2).unwrap();
482 assert_eq!(engine.keybind_count(), 1);
483
484 let key_combo = KeyCombo::from_str("Ctrl+S").unwrap();
486 assert_eq!(engine.get_action(&key_combo), None);
487
488 let key_combo = KeyCombo::from_str("Ctrl+Z").unwrap();
490 assert_eq!(engine.get_action(&key_combo), Some("editor.undo"));
491 }
492
493 #[test]
494 fn test_get_keybind_returns_none_for_missing_action() {
495 let engine = KeybindEngine::new();
496 assert_eq!(engine.get_keybind("nonexistent.action"), None);
497 }
498
499 #[test]
500 fn test_get_action_returns_none_for_missing_key() {
501 let engine = KeybindEngine::new();
502 let key_combo = KeyCombo::from_str("Ctrl+X").unwrap();
503 assert_eq!(engine.get_action(&key_combo), None);
504 }
505
506 #[test]
507 fn test_active_profile_name() {
508 let mut engine = KeybindEngine::new();
509 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
510
511 engine.create_profile("default", keybinds).unwrap();
512 assert_eq!(engine.active_profile_name(), Some("default"));
513 }
514
515 #[test]
516 fn test_load_defaults_from_file() {
517 let mut engine = KeybindEngine::new();
518
519 let possible_paths = vec![
521 "../../../../config/keybinds/defaults.json",
522 "projects/ricecoder/config/keybinds/defaults.json",
523 "config/keybinds/defaults.json",
524 ];
525
526 let mut loaded = false;
527 for path in possible_paths {
528 if engine.load_defaults_from_file(path).is_ok() {
529 loaded = true;
530 break;
531 }
532 }
533
534 if loaded {
535 assert!(!engine.get_defaults().is_empty());
536
537 for keybind in engine.get_defaults() {
539 assert!(keybind.is_default);
540 }
541 }
542 }
543
544 #[test]
545 fn test_apply_defaults() {
546 let mut engine = KeybindEngine::new();
547
548 let possible_paths = vec![
550 "../../../../config/keybinds/defaults.json",
551 "projects/ricecoder/config/keybinds/defaults.json",
552 "config/keybinds/defaults.json",
553 ];
554
555 let mut loaded = false;
556 for path in possible_paths {
557 if engine.load_defaults_from_file(path).is_ok() {
558 loaded = true;
559 break;
560 }
561 }
562
563 if loaded {
564 assert!(engine.apply_defaults().is_ok());
565
566 assert_eq!(engine.active_profile_name(), Some("default"));
568
569 assert!(engine.keybind_count() > 0);
571 }
572 }
573
574 #[test]
575 fn test_reset_to_defaults() {
576 let mut engine = KeybindEngine::new();
577
578 let possible_paths = vec![
580 "../../../../config/keybinds/defaults.json",
581 "projects/ricecoder/config/keybinds/defaults.json",
582 "config/keybinds/defaults.json",
583 ];
584
585 let mut loaded = false;
586 for path in possible_paths {
587 if engine.load_defaults_from_file(path).is_ok() {
588 loaded = true;
589 break;
590 }
591 }
592
593 if loaded {
594 engine.apply_defaults().unwrap();
595
596 let initial_count = engine.keybind_count();
597
598 let custom_keybinds = vec![Keybind::new("custom.action", "Ctrl+Q", "custom", "Custom")];
600 engine.apply_keybinds(custom_keybinds).unwrap();
601 assert_eq!(engine.keybind_count(), 1);
602
603 assert!(engine.reset_to_defaults().is_ok());
605 assert_eq!(engine.keybind_count(), initial_count);
606
607 let key_combo = KeyCombo::from_str("Ctrl+S").unwrap();
609 assert_eq!(engine.get_action(&key_combo), Some("editor.save"));
610 }
611 }
612
613 #[test]
614 fn test_reset_to_defaults_without_loading() {
615 let mut engine = KeybindEngine::new();
616 assert!(engine.reset_to_defaults().is_err());
617 }
618
619 #[test]
620 fn test_apply_defaults_without_loading() {
621 let mut engine = KeybindEngine::new();
622 assert!(engine.apply_defaults().is_err());
623 }
624
625 #[test]
626 fn test_get_defaults() {
627 let mut engine = KeybindEngine::new();
628
629 let possible_paths = vec![
631 "../../../../config/keybinds/defaults.json",
632 "projects/ricecoder/config/keybinds/defaults.json",
633 "config/keybinds/defaults.json",
634 ];
635
636 let mut loaded = false;
637 for path in possible_paths {
638 if engine.load_defaults_from_file(path).is_ok() {
639 loaded = true;
640 break;
641 }
642 }
643
644 if loaded {
645 let defaults = engine.get_defaults();
646
647 assert!(!defaults.is_empty());
648 for keybind in defaults {
649 assert!(keybind.is_default);
650 }
651 }
652 }
653
654 #[test]
655 fn test_initialize_engine_with_defaults() {
656 let possible_paths = vec![
658 "../../../../config/keybinds/defaults.json",
659 "projects/ricecoder/config/keybinds/defaults.json",
660 "config/keybinds/defaults.json",
661 ];
662
663 let mut engine_result = Err(EngineError::DefaultsLoadError("No path found".to_string()));
664 for path in possible_paths {
665 if let Ok(engine) = initialize_engine_with_defaults(path) {
666 engine_result = Ok(engine);
667 break;
668 }
669 }
670
671 if let Ok(engine) = engine_result {
672 assert!(engine.keybind_count() > 0);
673 assert_eq!(engine.active_profile_name(), Some("default"));
674 }
675 }
676
677 #[test]
678 fn test_get_default_persistence() {
679 use crate::Profile;
680
681 let result = get_default_persistence();
682 assert!(result.is_ok());
683
684 let persistence = result.unwrap();
685
686 assert!(persistence.config_dir().exists());
688
689 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
691 let profile = Profile::new("test_default_persistence", keybinds);
692
693 assert!(persistence.save_profile(&profile).is_ok());
694 assert!(persistence.load_profile("test_default_persistence").is_ok());
695
696 let _ = persistence.delete_profile("test_default_persistence");
698 }
699}