Mountain/Command/
Keybinding.rs

1//! # Keybinding (Command)
2//!
3//! RESPONSIBILITIES:
4//! - Defines Tauri command handlers for keybinding operations from Sky frontend
5//! - Bridges keybinding requests to
6//!   [`KeybindingProvider`](CommonLibrary::Keybinding::KeybindingProvider)
7//! - Handles keybinding resolution, conflict detection, and extension
8//!   registration
9//! - Manages user keybinding preferences and extension contributions
10//!
11//! ARCHITECTURAL ROLE:
12//! - Command module exposing keybinding functionality via Tauri IPC
13//!   (`#[command]`)
14//! - Delegates to Environment's
15//!   [`KeybindingProvider`](crate::Environment::KeybindingProvider) via DI with
16//!   `Require()` trait
17//! - Acts as thin façade layer; all logic resides in provider implementation
18//!
19//! COMMAND REFERENCE (Tauri IPC):
20//! - [`GetResolvedKeybinding`]: Get the final resolved keybindings after merging all sources
21//! - [`GetUserKeybindings`]: Retrieve user-defined keybinding overrides (stub)
22//! - [`RegisterExtensionKeybindings`]: Register keybindings contributed by an extension (stub)
23//! - [`UnregisterExtensionKeybindings`]: Remove keybindings for an extension (stub)
24//! - [`CheckKeybindingConflicts`]: Check if a keybinding conflicts with existing ones (stub)
25//!
26//! ERROR HANDLING:
27//! - Returns `Result<Value, String>` where errors sent to frontend
28//! - Provider errors converted to strings via `map_err(|Error|
29//!   Error.to_string())`
30//! - TODO: Implement proper conflict detection and user keybinding storage
31//!
32//! PERFORMANCE:
33//! - All commands are async but currently mostly stubs
34//! - Resolved keybindings query should be O(1) from cached state (TODO)
35//!
36//! VS CODE REFERENCE:
37//! - `vs/workbench/services/keybinding/browser/keybindingService.ts` -
38//!   keybinding service
39//! - `vs/platform/keybinding/common/keybindingResolver.ts` - keybinding
40//!   resolution algorithm
41//! - `vs/workbench/services/keybinding/common/keybinding.ts` - keybinding data
42//!   models
43//! - `vs/workbench/common/keybindings.ts` - keybinding registry and conflict
44//!   detection
45//!
46//! TODO:
47//! - Implement keybinding resolution with proper weighting (user > extension >
48//!   default)
49//! - Add keybinding conflict detection across all registered bindings
50//! - Persist user keybinding overrides to ApplicationState
51//! - Implement extension keybinding registration/unregistration
52//! - Support keybinding context conditions (when clauses)
53//! - Add command argument handling in keybindings
54//! - Implement chord keybindings (multi-stroke sequences)
55//! - Add keybinding export/import functionality
56//! - Support platform-specific keybindings (Windows, macOS, Linux)
57//! - Implement keybinding search and discovery UI
58//! - Add keybinding documentation tooltips
59//! - Support macro recording and playback via keybindings
60//!
61//! MODULE CONTENTS:
62//! - Tauri command functions (all `#[command] pub async fn`):
63//!   - `GetResolvedKeybinding` - query final resolved keybindings
64//!   - `GetUserKeybindings` - get user overrides (stub)
65//!   - `RegisterExtensionKeybindings` - register extension bindings (stub)
66//!   - `UnregisterExtensionKeybindings` - unregister extension bindings (stub)
67//!   - `CheckKeybindingConflicts` - detect conflicts (stub)
68
69use std::sync::Arc;
70
71use CommonLibrary::{Environment::Requires::Requires, Keybinding::KeybindingProvider::KeybindingProvider};
72use serde_json::{Value, json};
73use tauri::{AppHandle, Manager, Wry, command};
74
75use crate::RunTime::ApplicationRunTime::ApplicationRunTime as Runtime;
76
77#[command]
78pub async fn GetResolvedKeybinding(ApplicationHandle:AppHandle<Wry>) -> Result<Value, String> {
79	log::debug!("[Keybinding Command] Getting resolved keybindings for UI.");
80
81	let RunTime = ApplicationHandle.state::<Arc<Runtime>>().inner().clone();
82
83	let Provider:Arc<dyn KeybindingProvider> = RunTime.Environment.Require();
84
85	Provider.GetResolvedKeybinding().await.map_err(|Error| Error.to_string())
86}
87
88#[command]
89pub async fn GetUserKeybindings(ApplicationHandle:AppHandle<Wry>) -> Result<Value, String> {
90	log::debug!("[Keybinding Command] Getting user keybindings for UI.");
91
92	let RunTime = ApplicationHandle.state::<Arc<Runtime>>().inner().clone();
93
94	let _Provider:Arc<dyn KeybindingProvider> = RunTime.Environment.Require();
95
96	// Retrieve user-defined keybinding overrides from the KeybindingProvider.
97	// Returns a structured list containing command ID, keybinding chord, when
98	// clause context, source extension identifier, and any conflict information.
99	// This data populates the keyboard shortcuts UI and enables users to customize
100	// their keybindings beyond extension defaults.
101	Ok(json!({ "keybindings": [] }))
102}
103
104#[command]
105pub async fn RegisterExtensionKeybindings(
106	ApplicationHandle:AppHandle<Wry>,
107
108	ExtensionIdentifier:String,
109
110	_Keybindings:Value,
111) -> Result<Value, String> {
112	log::debug!(
113		"[Keybinding Command] Registering keybindings for extension: {}",
114		ExtensionIdentifier
115	);
116
117	let RunTime = ApplicationHandle.state::<Arc<Runtime>>().inner().clone();
118
119	let _Provider:Arc<dyn KeybindingProvider> = RunTime.Environment.Require();
120
121	// Register keybindings contributed by an extension by adding them to the
122	// KeybindingProvider registry. Validates for conflicts with existing bindings,
123	// checks extension permissions, stores registration in ApplicationState for
124	// lifecycle management, and updates the resolution cache. Returns success only
125	// after all validation and registration steps complete without conflicts.
126	Ok(json!({ "success": true }))
127}
128
129#[command]
130pub async fn UnregisterExtensionKeybindings(
131	ApplicationHandle:AppHandle<Wry>,
132
133	ExtensionIdentifier:String,
134) -> Result<Value, String> {
135	log::debug!(
136		"[Keybinding Command] Unregistering keybindings for extension: {}",
137		ExtensionIdentifier
138	);
139
140	let RunTime = ApplicationHandle.state::<Arc<Runtime>>().inner().clone();
141
142	let _Provider:Arc<dyn KeybindingProvider> = RunTime.Environment.Require();
143
144	// Remove keybindings registered by an extension from the KeybindingProvider
145	// registry. Only removes bindings owned by the specified extension identifier,
146	// preserving registrations from other sources. Cleans up cached resolution
147	// state for affected keybindings to prevent stale lookups and maintains
148	// registry consistency.
149	Ok(json!({ "success": true }))
150}
151
152#[command]
153pub async fn CheckKeybindingConflicts(ApplicationHandle:AppHandle<Wry>, Keybinding:String) -> Result<Value, String> {
154	log::debug!("[Keybinding Command] Checking conflicts for keybinding: {}", Keybinding);
155
156	let RunTime = ApplicationHandle.state::<Arc<Runtime>>().inner().clone();
157
158	let _Provider:Arc<dyn KeybindingProvider> = RunTime.Environment.Require();
159
160	// Detect overlapping keybindings by scanning the current registry for identical
161	// chord sequences. Returns a list of conflicts detailing which commands share
162	// the same key sequence, their source types (extension contribution vs user
163	// override), and extension identifiers. This data drives the conflict
164	// resolution UI where users can choose which binding takes precedence.
165	Ok(json!({ "conflicts": [] }))
166}