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}