diff --git a/docs/changelog.md b/docs/changelog.md index 059be861c..f084e6f57 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -32,6 +32,7 @@ As features stabilize some brief notes about them will accumulate here. #### Changed * Debian packages now register wezterm as an alternative for `x-terminal-emulator`. Thanks to [@xpufx](https://github.com/xpufx)! [#1883](https://github.com/wez/wezterm/pull/1883) * Windows: wezterm will now read the default environment variables from the `HKLM\System\CurrentControlSet\Control\Session Manager\Environment` and `HKCU\Environment` and apply those to the base environment prior to applying `set_environment_variables`. [#1848](https://github.com/wez/wezterm/issues/1848) +* [Key Table](config/key-tables.md) lookups will now keep searching the activation stack until a matching assignment is found, allowing for layered key tables. [#993](https://github.com/wez/wezterm/issues/993) #### Fixed * Flush after replying to XTGETTCAP and DECRQM. [#1850](https://github.com/wez/wezterm/issues/1850) [#1950](https://github.com/wez/wezterm/issues/1950) diff --git a/docs/config/key-tables.md b/docs/config/key-tables.md index 3f592eef4..8b5b409e2 100644 --- a/docs/config/key-tables.md +++ b/docs/config/key-tables.md @@ -119,5 +119,14 @@ The stack is also cleared when the configuration is reloaded, so if you're working on a complex key table setup and get stuck, you may be able to unstick yourself by re-saving your wezterm configuration to trigger a reload. +*Since: nightly builds only* +When resolving a key assignment, the top of stack is first searched for a match, +and if one is not found, the next entry on the stack is searched and so on until a match is found. + +In previous releases, only a single lookup was performed on the top of the stack. + +The new behavior allows key table activations to effectively layer over the top +of previously activated key assignments, making it a bit easier to compose key +assignments. diff --git a/wezterm-gui/src/termwindow/keyevent.rs b/wezterm-gui/src/termwindow/keyevent.rs index 931a6947b..4d5e0fa5b 100644 --- a/wezterm-gui/src/termwindow/keyevent.rs +++ b/wezterm-gui/src/termwindow/keyevent.rs @@ -1,5 +1,7 @@ +use crate::termwindow::InputMap; use ::window::{DeadKeyStatus, KeyCode, KeyEvent, Modifiers, RawKeyEvent, WindowOps}; use anyhow::Context; +use config::keyassignment::KeyTableEntry; use mux::pane::Pane; use smol::Timer; use std::rc::Rc; @@ -67,6 +69,24 @@ impl KeyTableState { self.stack.last().map(|entry| entry.name.as_str()) } + pub fn lookup_key( + &mut self, + input_map: &InputMap, + key: &KeyCode, + mods: Modifiers, + ) -> Option<(KeyTableEntry, Option<&str>)> { + while self.process_expiration() {} + for entry in self.stack.iter().rev() { + let name = entry.name.as_str(); + if let Some(entry) = input_map.lookup_key(key, mods, Some(name)) { + return Some((entry, Some(name))); + } + } + input_map + .lookup_key(key, mods, None) + .map(|entry| (entry, None)) + } + pub fn did_process_key(&mut self) { let should_pop = self .stack @@ -160,15 +180,15 @@ impl super::TermWindow { } if is_down { - let current_table = self.key_table_state.current_table(); - if let Some(entry) = - self.input_map - .lookup_key(&keycode, raw_modifiers | leader_mod, current_table) - { + if let Some((entry, table_name)) = self.key_table_state.lookup_key( + &self.input_map, + &keycode, + raw_modifiers | leader_mod, + ) { if self.config.debug_key_events { log::info!( "{}{:?} {:?} -> perform {:?}", - match current_table { + match table_name { Some(name) => format!("table:{} ", name), None => String::new(), },