diff options
| author | Johannes Altmanninger <aclopte@gmail.com> | 2023-06-24 19:49:02 +0200 |
|---|---|---|
| committer | Johannes Altmanninger <aclopte@gmail.com> | 2023-07-03 19:03:11 +0200 |
| commit | 42be0057a68f30b439ccb52159fa756e82b61c98 (patch) | |
| tree | b619672f6cd1bd3cf13374de75dd574629ee1144 /src/keymap_manager.cc | |
| parent | 661d1a090572323627ccdb16aeba4e6adf4ca59a (diff) | |
map: fail if key is currently executing
If during execution of a mapping, that same mapping is replaced,
there is undefined behavior because we destroy a mapping that we are
still iterating over.
I have been using this mapping inside my kakrc to re-source the kakrc.
map global user s %{:source "%val{config}/kakrc"<ret>} -docstring 'source "%val{config}/kakrc"'
Now <space>s happens to not trigger undefined behavior because the
mapping stays the same.
However it triggers an assertion added by Commit e49c0fb04 (unmap:
fail if the mapping is currently executing, 2023-05-14), specifically
the destructor of ScopedSetBool that guards mapping execution.
Fix these by banning map of a key that is executing, just like we
did for unmap.
Alternative solution: we could allow mapping (and even unmapping)
keys at any time and keep them alive by moving them into a trash can,
like we do for clients and others.
Diffstat (limited to 'src/keymap_manager.cc')
| -rw-r--r-- | src/keymap_manager.cc | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/src/keymap_manager.cc b/src/keymap_manager.cc index 81efe7ed..26579bf7 100644 --- a/src/keymap_manager.cc +++ b/src/keymap_manager.cc @@ -13,6 +13,9 @@ namespace Kakoune void KeymapManager::map_key(Key key, KeymapMode mode, KeyList mapping, String docstring) { + if (auto it = m_mapping.find(KeyAndMode{key, mode}); it != m_mapping.end()) + if (it->value.is_executing) + throw runtime_error("cannot map key that is currently executing"); m_mapping[KeyAndMode{key, mode}] = {std::move(mapping), std::move(docstring)}; } |
