par_term_config/config/keybindings_methods.rs
1//! Keybinding management methods for `Config`.
2//!
3//! Covers:
4//! - Merging default keybindings and status-bar widgets into user config
5//! - Generating / synchronising snippet and action keybindings
6
7use super::config_struct::Config;
8
9impl Config {
10 /// Merge default keybindings into the user's config.
11 /// Only adds keybindings for actions that don't already exist in the user's config.
12 /// This ensures new features with default keybindings are available to existing users.
13 pub(crate) fn merge_default_keybindings(&mut self) {
14 let default_keybindings = crate::defaults::keybindings();
15
16 // Get the set of actions already configured by the user (owned strings to avoid borrow issues)
17 let existing_actions: std::collections::HashSet<String> = self
18 .keybindings
19 .iter()
20 .map(|kb| kb.action.clone())
21 .collect();
22
23 // Add any default keybindings whose actions are not already configured
24 let mut added_count = 0;
25 for default_kb in default_keybindings {
26 if !existing_actions.contains(&default_kb.action) {
27 log::info!(
28 "Adding new default keybinding: {} -> {}",
29 default_kb.key,
30 default_kb.action
31 );
32 self.keybindings.push(default_kb);
33 added_count += 1;
34 }
35 }
36
37 if added_count > 0 {
38 log::info!(
39 "Merged {} new default keybinding(s) into user config",
40 added_count
41 );
42 }
43 }
44
45 /// Merge default status bar widgets into the user's config.
46 /// Only adds widgets whose `WidgetId` doesn't already exist in the user's widget list.
47 /// This ensures new built-in widgets are available to existing users.
48 pub(crate) fn merge_default_widgets(&mut self) {
49 let default_widgets = crate::status_bar::default_widgets();
50
51 let existing_ids: std::collections::HashSet<crate::status_bar::WidgetId> = self
52 .status_bar
53 .status_bar_widgets
54 .iter()
55 .map(|w| w.id.clone())
56 .collect();
57
58 let mut added_count = 0;
59 for default_widget in default_widgets {
60 if !existing_ids.contains(&default_widget.id) {
61 log::info!(
62 "Adding new default status bar widget: {:?}",
63 default_widget.id
64 );
65 self.status_bar.status_bar_widgets.push(default_widget);
66 added_count += 1;
67 }
68 }
69
70 if added_count > 0 {
71 log::info!(
72 "Merged {} new default status bar widget(s) into user config",
73 added_count
74 );
75 }
76 }
77
78 /// Generate keybindings for snippets and actions that have keybindings configured.
79 ///
80 /// This method adds or updates keybindings for snippets and actions in the keybindings list,
81 /// using the format `snippet:<id>` for snippets and `action:<id>` for actions.
82 /// If a keybinding for a snippet/action already exists, it will be updated with the new key.
83 pub fn generate_snippet_action_keybindings(&mut self) {
84 use crate::config::KeyBinding;
85
86 // Track actions we've seen to remove stale keybindings later
87 let mut seen_actions = std::collections::HashSet::new();
88 let mut added_count = 0;
89 let mut updated_count = 0;
90
91 // Generate keybindings for snippets
92 for snippet in &self.snippets {
93 if let Some(key) = &snippet.keybinding {
94 let action = format!("snippet:{}", snippet.id);
95 seen_actions.insert(action.clone());
96
97 if !key.is_empty() && snippet.enabled && snippet.keybinding_enabled {
98 // Check if this action already has a keybinding
99 if let Some(existing) =
100 self.keybindings.iter_mut().find(|kb| kb.action == action)
101 {
102 // Update existing keybinding if the key changed
103 if existing.key != *key {
104 log::info!(
105 "Updating keybinding for snippet '{}': {} -> {} (was: {})",
106 snippet.title,
107 key,
108 action,
109 existing.key
110 );
111 existing.key = key.clone();
112 updated_count += 1;
113 }
114 } else {
115 // Add new keybinding
116 log::info!(
117 "Adding keybinding for snippet '{}': {} -> {} (enabled={}, keybinding_enabled={})",
118 snippet.title,
119 key,
120 action,
121 snippet.enabled,
122 snippet.keybinding_enabled
123 );
124 self.keybindings.push(KeyBinding {
125 key: key.clone(),
126 action,
127 });
128 added_count += 1;
129 }
130 } else if !key.is_empty() {
131 log::info!(
132 "Skipping keybinding for snippet '{}': {} (enabled={}, keybinding_enabled={})",
133 snippet.title,
134 key,
135 snippet.enabled,
136 snippet.keybinding_enabled
137 );
138 }
139 }
140 }
141
142 // Generate keybindings for actions
143 for action_config in &self.actions {
144 if let Some(key) = action_config.keybinding() {
145 let action = format!("action:{}", action_config.id());
146 seen_actions.insert(action.clone());
147
148 if !key.is_empty() && action_config.keybinding_enabled() {
149 // Check if this action already has a keybinding
150 if let Some(existing) =
151 self.keybindings.iter_mut().find(|kb| kb.action == action)
152 {
153 // Update existing keybinding if the key changed
154 if existing.key != key {
155 log::info!(
156 "Updating keybinding for action '{}': {} -> {} (was: {})",
157 action_config.title(),
158 key,
159 action,
160 existing.key
161 );
162 existing.key = key.to_string();
163 updated_count += 1;
164 }
165 } else {
166 // Add new keybinding
167 log::info!(
168 "Adding keybinding for action '{}': {} -> {} (keybinding_enabled={})",
169 action_config.title(),
170 key,
171 action,
172 action_config.keybinding_enabled()
173 );
174 self.keybindings.push(KeyBinding {
175 key: key.to_string(),
176 action,
177 });
178 added_count += 1;
179 }
180 } else if !key.is_empty() {
181 log::info!(
182 "Skipping keybinding for action '{}': {} (keybinding_enabled={})",
183 action_config.title(),
184 key,
185 action_config.keybinding_enabled()
186 );
187 }
188 }
189 }
190
191 // Remove stale keybindings for snippets that no longer have keybindings or are disabled
192 let original_len = self.keybindings.len();
193 self.keybindings.retain(|kb| {
194 // Keep if it's not a snippet/action keybinding
195 if !kb.action.starts_with("snippet:") && !kb.action.starts_with("action:") {
196 return true;
197 }
198 // Keep if we saw it during our scan
199 seen_actions.contains(&kb.action)
200 });
201 let removed_count = original_len - self.keybindings.len();
202
203 if added_count > 0 || updated_count > 0 || removed_count > 0 {
204 log::info!(
205 "Snippet/Action keybindings: {} added, {} updated, {} removed",
206 added_count,
207 updated_count,
208 removed_count
209 );
210 }
211 }
212}