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)
throw runtime_error("only a single key can be unmapped");
if (keymaps.is_mapped(key[0], keymap_mode) and
(parser.positional_count() < 4 or
(keymaps.get_mapping(key[0], keymap_mode).keys ==
parse_keys(parser[3]))))
if (not keymaps.is_mapped(key[0], keymap_mode))
return;
auto& mapping = keymaps.get_mapping(key[0], keymap_mode);
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);
}
};
@ -2653,8 +2658,12 @@ void enter_user_mode(Context& context, String mode_name, KeymapMode mode, bool l
InputHandler::ScopedForceNormal force_normal{context.input_handler(), {}};
ScopedEdition edition(context);
{
ScopedSetBool executing_mapping{mapping.is_executing};
for (auto& key : mapping.keys)
context.input_handler().handle_key(key);
}
if (lock)
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())
{
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);
}
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));
}
const KeymapManager::KeymapInfo&
KeymapManager::get_mapping(Key key, KeymapMode mode) const
KeymapManager::KeymapInfo&
KeymapManager::get_mapping(Key key, KeymapMode mode)
{
auto it = m_mapping.find(KeyAndMode{key, mode});
if (it != m_mapping.end())

View File

@ -6,6 +6,7 @@
#include "hash.hh"
#include "string.hh"
#include "hash_map.hh"
#include "utils.hh"
#include "vector.hh"
namespace Kakoune
@ -42,8 +43,9 @@ public:
{
KeyList keys;
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>;
UserModeList& user_modes() {

View File

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