From 4db89382f657cff9092fdfec671fc440a44af841 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Wed, 21 May 2025 00:51:48 +0000 Subject: Fix hint binding IPC overrides This fixes an issue where changes made to the bindings of a hint through IPC were completely ignored, since the hint key bindings were only generated on config load without regeneration on IPC config override. While it would be possible to just filter out remove hint key bindings based on their action and then repopulate them on IPC config reload, this solution would be quite hacky. To have a better distinction between traditional and hint key bindings, the two have been entirely separated and hint bindings are just converted to key bindings on demand. This allows easily replacing the entire hint array without any post-processing, making it simpler to maintain for future changes. Closes #8568. --- CHANGELOG.md | 1 + alacritty/src/config/mod.rs | 5 +--- alacritty/src/config/ui_config.rs | 54 ++++++++++++++++++++++----------------- alacritty/src/input/keyboard.rs | 32 +++++++++++++++++++---- 4 files changed, 60 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cb79b0c..bc0b7df1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Notable changes to the `alacritty_terminal` crate are documented in its - Modifier keys clearing selection with kitty keyboard protocol enabled - `glyph_offset.y` not applied to strikeout - `Enter`,`Tab`, `Backspace` not disambiguated with `shift` in kitty keyboard's disambiguate mode +- Hint bindings not respecting IPC overrides ## 0.15.1 diff --git a/alacritty/src/config/mod.rs b/alacritty/src/config/mod.rs index ba9d674d..c5b5d72d 100644 --- a/alacritty/src/config/mod.rs +++ b/alacritty/src/config/mod.rs @@ -31,7 +31,7 @@ use crate::cli::Options; #[cfg(test)] pub use crate::config::bindings::Binding; pub use crate::config::bindings::{ - Action, BindingKey, BindingMode, MouseAction, SearchAction, ViAction, + Action, BindingKey, BindingMode, KeyBinding, MouseAction, SearchAction, ViAction, }; pub use crate::config::ui_config::UiConfig; use crate::logging::LOG_TARGET_CONFIG; @@ -162,9 +162,6 @@ pub fn reload(config_path: &Path, options: &mut Options) -> Result { fn after_loading(config: &mut UiConfig, options: &mut Options) { // Override config with CLI options. options.override_config(config); - - // Create key bindings for regex hints. - config.generate_hint_bindings(); } /// Load configuration file and log errors. diff --git a/alacritty/src/config/ui_config.rs b/alacritty/src/config/ui_config.rs index 960bdbbc..a02a6215 100644 --- a/alacritty/src/config/ui_config.rs +++ b/alacritty/src/config/ui_config.rs @@ -1,4 +1,4 @@ -use std::cell::RefCell; +use std::cell::{OnceCell, RefCell}; use std::collections::HashMap; use std::error::Error; use std::fmt::{self, Formatter}; @@ -133,26 +133,6 @@ impl UiConfig { PtyOptions { working_directory, shell, drain_on_exit: false, env: HashMap::new() } } - /// Generate key bindings for all keyboard hints. - pub fn generate_hint_bindings(&mut self) { - for hint in &self.hints.enabled { - let binding = match &hint.binding { - Some(binding) => binding, - None => continue, - }; - - let binding = KeyBinding { - trigger: binding.key.clone(), - mods: binding.mods.0, - mode: binding.mode.mode, - notmode: binding.mode.not_mode, - action: Action::Hint(hint.clone()), - }; - - self.keyboard.bindings.0.push(binding); - } - } - #[inline] pub fn window_opacity(&self) -> f32 { self.window.opacity.as_f32() @@ -286,6 +266,7 @@ impl Default for Hints { location: KeyLocation::Standard, }, mods: ModsWrapper(ModifiersState::SHIFT | ModifiersState::CONTROL), + cache: Default::default(), mode: Default::default(), }), })], @@ -381,7 +362,7 @@ pub struct Hint { pub mouse: Option, /// Binding required to search for this hint. - binding: Option, + pub binding: Option, } #[derive(Default, Clone, Debug, PartialEq, Eq)] @@ -460,7 +441,7 @@ impl<'de> Deserialize<'de> for HintContent { } /// Binding for triggering a keyboard hint. -#[derive(Deserialize, Clone, Debug, PartialEq, Eq)] +#[derive(Deserialize, Clone, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct HintBinding { pub key: BindingKey, @@ -468,6 +449,33 @@ pub struct HintBinding { pub mods: ModsWrapper, #[serde(default)] pub mode: ModeWrapper, + + /// Cache for on-demand [`HintBinding`] to [`KeyBinding`] conversion. + #[serde(skip)] + cache: OnceCell, +} + +impl HintBinding { + /// Get the key binding for a hint. + pub fn key_binding(&self, hint: &Rc) -> &KeyBinding { + self.cache.get_or_init(|| KeyBinding { + trigger: self.key.clone(), + mods: self.mods.0, + mode: self.mode.mode, + notmode: self.mode.not_mode, + action: Action::Hint(hint.clone()), + }) + } +} + +impl fmt::Debug for HintBinding { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("HintBinding") + .field("key", &self.key) + .field("mods", &self.mods) + .field("mode", &self.mode) + .finish_non_exhaustive() + } } /// Hint mouse highlighting. diff --git a/alacritty/src/input/keyboard.rs b/alacritty/src/input/keyboard.rs index 113472c4..24d1abad 100644 --- a/alacritty/src/input/keyboard.rs +++ b/alacritty/src/input/keyboard.rs @@ -11,7 +11,7 @@ use alacritty_terminal::event::EventListener; use alacritty_terminal::term::TermMode; use winit::platform::modifier_supplement::KeyEventExtModifierSupplement; -use crate::config::{Action, BindingKey, BindingMode}; +use crate::config::{Action, BindingKey, BindingMode, KeyBinding}; use crate::event::TYPING_SEARCH_DELAY; use crate::input::{ActionContext, Execute, Processor}; use crate::scheduler::{TimerId, Topic}; @@ -203,9 +203,8 @@ impl> Processor { key.logical_key.clone() }; - for i in 0..self.ctx.config().key_bindings().len() { - let binding = &self.ctx.config().key_bindings()[i]; - + // Get the action of a key binding. + let mut binding_action = |binding: &KeyBinding| { let key = match (&binding.trigger, &logical_key) { (BindingKey::Scancode(_), _) => BindingKey::Scancode(key.physical_key), (_, code) => { @@ -218,7 +217,30 @@ impl> Processor { *suppress_chars.get_or_insert(true) &= binding.action != Action::ReceiveChar; // Binding was triggered; run the action. - binding.action.clone().execute(&mut self.ctx); + Some(binding.action.clone()) + } else { + None + } + }; + + // Trigger matching key bindings. + for i in 0..self.ctx.config().key_bindings().len() { + let binding = &self.ctx.config().key_bindings()[i]; + if let Some(action) = binding_action(binding) { + action.execute(&mut self.ctx); + } + } + + // Trigger key bindings for hints. + for i in 0..self.ctx.config().hints.enabled.len() { + let hint = &self.ctx.config().hints.enabled[i]; + let binding = match hint.binding.as_ref() { + Some(binding) => binding.key_binding(hint), + None => continue, + }; + + if let Some(action) = binding_action(binding) { + action.execute(&mut self.ctx); } } -- cgit