12310418b0
Commitse49c0fb04
(unmap: fail if the mapping is currently executing, 2023-05-14)42be0057a
(map: fail if key is currently executing, 2023-06-24) fixed potential use-after-free issues. By doing so, it broke configurations that in practice have not triggered any crashes [1] [2]. For example with, set -remove global autocomplete insert hook global InsertCompletionShow .* %{ map window insert <esc> <c-o> } hook global InsertCompletionHide .* %{ unmap window insert <esc> <c-o> } The execution of the <esc> mapping triggers InsertCompletionHide fails at unmapping. This seems legit and I don't see an obvious alternative way to write it (InsertIdle would not be correct though it would work in practice). Fix the regression by allowing map and unmap again while keeping the mappings alive until they have finished executing. Applying map/unmap immediately seems like the most obvious semantics. Alternatively, we could apply them in between key presses. [1]: <https://github.com/kak-lsp/kak-lsp/issues/689> [2]: <https://github.com/alexherbo2/auto-pairs.kak/issues/60>
79 lines
1.7 KiB
C++
79 lines
1.7 KiB
C++
#ifndef keymap_manager_hh_INCLUDED
|
|
#define keymap_manager_hh_INCLUDED
|
|
|
|
#include "array_view.hh"
|
|
#include "keys.hh"
|
|
#include "hash.hh"
|
|
#include "string.hh"
|
|
#include "hash_map.hh"
|
|
#include "utils.hh"
|
|
#include "vector.hh"
|
|
|
|
namespace Kakoune
|
|
{
|
|
|
|
enum class KeymapMode : char
|
|
{
|
|
None,
|
|
Normal,
|
|
Insert,
|
|
Prompt,
|
|
Menu,
|
|
Goto,
|
|
View,
|
|
User,
|
|
Object,
|
|
FirstUserMode,
|
|
};
|
|
|
|
class KeymapManager
|
|
{
|
|
public:
|
|
KeymapManager(KeymapManager& parent) : m_parent(&parent) {}
|
|
|
|
using KeyList = Vector<Key, MemoryDomain::Mapping>;
|
|
void map_key(Key key, KeymapMode mode, KeyList mapping, String docstring);
|
|
void unmap_key(Key key, KeymapMode mode);
|
|
void unmap_keys(KeymapMode mode);
|
|
|
|
bool is_mapped(Key key, KeymapMode mode) const;
|
|
KeyList get_mapped_keys(KeymapMode mode) const;
|
|
|
|
auto get_mapping_keys(Key key, KeymapMode mode) {
|
|
return get_mapping(key, mode).keys;
|
|
}
|
|
|
|
const String& get_mapping_docstring(Key key, KeymapMode mode) { return get_mapping(key, mode).docstring; }
|
|
|
|
using UserModeList = Vector<String>;
|
|
UserModeList& user_modes() {
|
|
if (m_parent)
|
|
return m_parent->user_modes();
|
|
return m_user_modes;
|
|
}
|
|
void add_user_mode(String user_mode_name);
|
|
|
|
private:
|
|
struct KeymapInfo
|
|
{
|
|
KeyList keys;
|
|
String docstring;
|
|
};
|
|
const KeymapInfo& get_mapping(Key key, KeymapMode mode) const;
|
|
|
|
KeymapManager()
|
|
: m_parent(nullptr) {}
|
|
// the only one allowed to construct a root map manager
|
|
friend class Scope;
|
|
|
|
KeymapManager* m_parent;
|
|
using KeyAndMode = std::pair<Key, KeymapMode>;
|
|
HashMap<KeyAndMode, KeymapInfo, MemoryDomain::Mapping> m_mapping;
|
|
|
|
UserModeList m_user_modes;
|
|
};
|
|
|
|
}
|
|
|
|
#endif // keymap_manager_hh_INCLUDED
|