unmap: fail if the mapping is currently executing

When unmapping a key sequence that is currently executing, we continue
executing freed memory which can have weird effects.  Let's instead
throw an error if that happens. In future we can support unmap in
this scenario.

Closes #4896
This commit is contained in:
Johannes Altmanninger 2023-05-14 12:59:18 +02:00
parent cfa658b899
commit e49c0fb040
9 changed files with 29 additions and 10 deletions

View File

@ -1933,10 +1933,15 @@ const CommandDesc unmap_key_cmd = {
if (key.size() != 1) if (key.size() != 1)
throw runtime_error("only a single key can be unmapped"); throw runtime_error("only a single key can be unmapped");
if (keymaps.is_mapped(key[0], keymap_mode) and if (not keymaps.is_mapped(key[0], keymap_mode))
(parser.positional_count() < 4 or return;
(keymaps.get_mapping(key[0], keymap_mode).keys == auto& mapping = keymaps.get_mapping(key[0], keymap_mode);
parse_keys(parser[3]))))
if (mapping.is_executing)
throw runtime_error("cannot unmap key that is currently executing");
if (parser.positional_count() < 4 or
(mapping.keys == parse_keys(parser[3])))
keymaps.unmap_key(key[0], keymap_mode); keymaps.unmap_key(key[0], keymap_mode);
} }
}; };
@ -2653,8 +2658,12 @@ void enter_user_mode(Context& context, String mode_name, KeymapMode mode, bool l
InputHandler::ScopedForceNormal force_normal{context.input_handler(), {}}; InputHandler::ScopedForceNormal force_normal{context.input_handler(), {}};
ScopedEdition edition(context); ScopedEdition edition(context);
for (auto& key : mapping.keys)
context.input_handler().handle_key(key); {
ScopedSetBool executing_mapping{mapping.is_executing};
for (auto& key : mapping.keys)
context.input_handler().handle_key(key);
}
if (lock) if (lock)
enter_user_mode(context, std::move(mode_name), mode, true); enter_user_mode(context, std::move(mode_name), mode, true);

View File

@ -1773,7 +1773,10 @@ void InputHandler::handle_key(Key key)
if (keymaps.is_mapped(key, keymap_mode) and not m_context.keymaps_disabled()) if (keymaps.is_mapped(key, keymap_mode) and not m_context.keymaps_disabled())
{ {
ScopedSetBool disable_history{context().history_disabled()}; ScopedSetBool disable_history{context().history_disabled()};
for (auto& k : keymaps.get_mapping(key, keymap_mode).keys)
auto& mapping = keymaps.get_mapping(key, keymap_mode);
ScopedSetBool executing_mapping{mapping.is_executing};
for (auto& k : mapping.keys)
process_key(k); process_key(k);
} }
else else

View File

@ -40,8 +40,8 @@ bool KeymapManager::is_mapped(Key key, KeymapMode mode) const
(m_parent and m_parent->is_mapped(key, mode)); (m_parent and m_parent->is_mapped(key, mode));
} }
const KeymapManager::KeymapInfo& KeymapManager::KeymapInfo&
KeymapManager::get_mapping(Key key, KeymapMode mode) const KeymapManager::get_mapping(Key key, KeymapMode mode)
{ {
auto it = m_mapping.find(KeyAndMode{key, mode}); auto it = m_mapping.find(KeyAndMode{key, mode});
if (it != m_mapping.end()) if (it != m_mapping.end())

View File

@ -6,6 +6,7 @@
#include "hash.hh" #include "hash.hh"
#include "string.hh" #include "string.hh"
#include "hash_map.hh" #include "hash_map.hh"
#include "utils.hh"
#include "vector.hh" #include "vector.hh"
namespace Kakoune namespace Kakoune
@ -42,8 +43,9 @@ public:
{ {
KeyList keys; KeyList keys;
String docstring; String docstring;
NestedBool is_executing{};
}; };
const KeymapInfo& get_mapping(Key key, KeymapMode mode) const; KeymapInfo& get_mapping(Key key, KeymapMode mode);
using UserModeList = Vector<String>; using UserModeList = Vector<String>;
UserModeList& user_modes() { UserModeList& user_modes() {

View File

@ -2033,6 +2033,7 @@ void exec_user_mappings(Context& context, NormalParams params)
ScopedEdition edition(context); ScopedEdition edition(context);
ScopedSelectionEdition selection_edition{context}; ScopedSelectionEdition selection_edition{context};
ScopedSetBool executing_mapping{mapping.is_executing};
for (auto& key : mapping.keys) for (auto& key : mapping.keys)
context.input_handler().handle_key(key); context.input_handler().handle_key(key);
}, "user mapping", }, "user mapping",

View File

@ -0,0 +1 @@
<space>u

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
123

View File

@ -0,0 +1 @@
map global user u %{i123<esc>:unmap global user u<ret>i456<esc>}