Skip to content

fix(keybindings): preserve plugin bindings when switching keybinding maps (#2307)#2335

Merged
sinelaw merged 1 commit into
masterfrom
claude/upbeat-maxwell-mk5zax
Jun 21, 2026
Merged

fix(keybindings): preserve plugin bindings when switching keybinding maps (#2307)#2335
sinelaw merged 1 commit into
masterfrom
claude/upbeat-maxwell-mk5zax

Conversation

@sinelaw

@sinelaw sinelaw commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes #2307. Switching the active keybinding map and back dropped every plugin-contributed binding (the Keybinding Editor reported 866 → 547, losing all 391 plugin bindings) until the next restart.

Root cause

Plugin bindings — modes registered at runtime via defineMode — live only in the KeybindingResolver (plugin_defaults, plugin_chord_defaults, inheriting_modes). They are not part of Config. Every config-triggered rebuild replaced the live resolver with a fresh KeybindingResolver::new(&config), which starts those fields empty, so the entire plugin layer silently vanished.

Switching keybinding maps is the user-visible trigger, but the same latent loss affected saving settings, editing keybindings, theme/toggle reloads, and external config reloads — all six call sites did *self.keybindings.write().unwrap() = KeybindingResolver::new(&self.config).

Fix

Add KeybindingResolver::reload_from_config, which rebuilds the config-derived keymap + custom bindings exactly as new does, then carries the runtime plugin state across untouched. Route all six rebuild sites through it.

Testing

  • E2E reproducer (test_switch_keybinding_map_preserves_plugin_bindings): registers a plugin mode binding, drives the real SwitchKeybindingMap action to emacs and back to default, and asserts the binding still resolves. Fails before the fix (left: None), passes after.
  • Resolver unit test (test_reload_from_config_preserves_plugin_state): single keys, chords, and inheriting-modes membership all survive reload_from_config.
  • Full keybinding_editor e2e module: 53 passed.
  • cargo fmt --check, cargo clippy -p fresh-editor --all-targets clean for the touched code.

https://claude.ai/code/session_01LnBJS6kx9TmSAnwsbz3Dnt


Generated by Claude Code

…er (#2307)

Plugin-contributed bindings (modes registered at runtime via defineMode)
live only in the KeybindingResolver — its plugin_defaults,
plugin_chord_defaults, and inheriting_modes fields — and are not
represented in Config. Every config-triggered rebuild replaced the live
resolver with a fresh `KeybindingResolver::new(&config)`, which starts
those fields empty, so all plugin bindings silently vanished until the
next restart.

Switching the active keybinding map and back is the user-visible trigger
(#2307): the editor reported 866 -> 547 bindings, dropping all 391
plugin-contributed entries. The same latent loss affected saving
settings, editing keybindings, theme/toggle reloads, and external config
reloads.

Add `KeybindingResolver::reload_from_config`, which rebuilds the
config-derived keymap and custom bindings exactly as `new` does but
carries the runtime plugin state across untouched. Route all six rebuild
sites through it instead of overwriting the resolver.

Covered by an e2e test that drives the real SwitchKeybindingMap action
round-trip and a resolver unit test for the reload contract (single
keys, chords, and inheriting-modes membership all survive).
@sinelaw sinelaw force-pushed the claude/upbeat-maxwell-mk5zax branch from ac4459c to 16589f2 Compare June 21, 2026 19:39
@sinelaw sinelaw merged commit 4b6e1d2 into master Jun 21, 2026
8 checks passed
@sinelaw sinelaw deleted the claude/upbeat-maxwell-mk5zax branch June 21, 2026 20:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Keybinding Editor: switching keybinding map and back hides all plugin bindings (count drops 866 → 547) until restart

2 participants