Mountain/Environment/
KeybindingProvider.rs

1// File: Mountain/Source/Environment/KeybindingProvider.rs
2// Role: Implements the `KeybindingProvider` trait for the
3// `MountainEnvironment`. Responsibilities:
4//   - Resolve the final, effective keymap for the application.
5//   - Collect default keybindings contributed by all scanned extensions.
6//   - Read and apply user-defined keybindings from `keybindings.json`, handling
7//     overrides and unbindings.
8
9//! # KeybindingProvider Implementation
10//!
11//! Implements the `KeybindingProvider` trait for the `MountainEnvironment`.
12
13#![allow(non_snake_case, non_camel_case_types)]
14
15use std::{collections::HashMap, sync::Arc};
16
17use Common::{
18	Effect::ApplicationRunTime::ApplicationRunTime as _,
19	Error::CommonError::CommonError,
20	FileSystem::ReadFile::ReadFile,
21	Keybinding::KeybindingProvider::KeybindingProvider,
22};
23use async_trait::async_trait;
24use log::{info, warn};
25use serde_json::{Value, json};
26use tauri::Manager;
27
28use super::{MountainEnvironment::MountainEnvironment, Utility};
29use crate::RunTime::ApplicationRunTime::ApplicationRunTime;
30
31#[derive(serde::Deserialize, serde::Serialize, Clone, Debug)]
32#[serde(rename_all = "camelCase")]
33struct KeybindingRule {
34	key:String,
35
36	command:String,
37
38	when:Option<String>,
39
40	args:Option<Value>,
41}
42
43#[async_trait]
44impl KeybindingProvider for MountainEnvironment {
45	async fn GetResolvedKeybinding(&self) -> Result<Value, CommonError> {
46		info!("[KeybindingProvider] Resolving all keybindings...");
47
48		let mut ResolvedKeybindings:HashMap<String, KeybindingRule> = HashMap::new();
49
50		// 1. Collect default keybindings from extensions
51		let Extensions = self
52			.ApplicationState
53			.ScannedExtensions
54			.lock()
55			.map_err(Utility::MapApplicationStateLockErrorToCommonError)?
56			.clone();
57
58		for Extension in Extensions.values() {
59			if let Some(Contributes) = Extension.Contributes.as_ref().and_then(|c| c.get("keybindings")) {
60				if let Some(KeybindingsArray) = Contributes.as_array() {
61					for KeybindingValue in KeybindingsArray {
62						if let Ok(KeybindingRule) = serde_json::from_value::<KeybindingRule>(KeybindingValue.clone()) {
63							let UniqueKey =
64								format!("{}{}", KeybindingRule.key, KeybindingRule.when.as_deref().unwrap_or(""));
65
66							ResolvedKeybindings.insert(UniqueKey, KeybindingRule);
67						}
68					}
69				}
70			}
71		}
72
73		// 2. Load and apply user-defined keybindings from keybindings.json
74		let UserKeybindingsPath = self
75			.ApplicationHandle
76			.path()
77			.app_config_dir()
78			.map_err(|Error| {
79				CommonError::ConfigurationLoad { Description:format!("Cannot find app config dir: {}", Error) }
80			})?
81			.join("keybindings.json");
82
83		let RunTime = self.ApplicationHandle.state::<Arc<ApplicationRunTime>>().inner().clone();
84
85		if let Ok(Content) = RunTime.Run(ReadFile(UserKeybindingsPath)).await {
86			if let Ok(UserKeybindings) = serde_json::from_slice::<Vec<KeybindingRule>>(&Content) {
87				for UserKeybinding in UserKeybindings {
88					let UniqueKey = format!("{}{}", UserKeybinding.key, UserKeybinding.when.as_deref().unwrap_or(""));
89
90					if UserKeybinding.command.starts_with('-') {
91						// Unbind rule
92						ResolvedKeybindings.remove(&UniqueKey);
93					} else {
94						// Override rule
95						ResolvedKeybindings.insert(UniqueKey, UserKeybinding);
96					}
97				}
98			} else {
99				warn!("[KeybindingProvider] Failed to parse user keybindings.json. It may be malformed.");
100			}
101		}
102
103		let FinalRules:Vec<KeybindingRule> = ResolvedKeybindings.into_values().collect();
104
105		Ok(json!(FinalRules))
106	}
107}