Skip to main content

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