InputHandler: handle of last insert keys happening in nested modes
Move recording of keys to the input handler itself instead of the Insert mode so that eventual nested modes (potentially introduced by <a-;> will get their keys recorded as well). Fixes #1680
This commit is contained in:
parent
04993de687
commit
0942cd5084
|
@ -1059,6 +1059,7 @@ public:
|
||||||
context().hooks().run_hook("InsertIdle", "", context());
|
context().hooks().run_hook("InsertIdle", "", context());
|
||||||
}}
|
}}
|
||||||
{
|
{
|
||||||
|
last_insert().recording.set();
|
||||||
last_insert().mode = mode;
|
last_insert().mode = mode;
|
||||||
last_insert().keys.clear();
|
last_insert().keys.clear();
|
||||||
last_insert().disable_hooks = context().hooks_disabled();
|
last_insert().disable_hooks = context().hooks_disabled();
|
||||||
|
@ -1084,6 +1085,8 @@ public:
|
||||||
|
|
||||||
if (not temporary)
|
if (not temporary)
|
||||||
{
|
{
|
||||||
|
last_insert().recording.unset();
|
||||||
|
|
||||||
auto& selections = context().selections();
|
auto& selections = context().selections();
|
||||||
if (m_restore_cursor)
|
if (m_restore_cursor)
|
||||||
{
|
{
|
||||||
|
@ -1100,7 +1103,6 @@ public:
|
||||||
void on_key(Key key) override
|
void on_key(Key key) override
|
||||||
{
|
{
|
||||||
auto& buffer = context().buffer();
|
auto& buffer = context().buffer();
|
||||||
last_insert().keys.push_back(key);
|
|
||||||
|
|
||||||
const bool transient = context().flags() & Context::Flags::Transient;
|
const bool transient = context().flags() & Context::Flags::Transient;
|
||||||
bool update_completions = true;
|
bool update_completions = true;
|
||||||
|
@ -1441,18 +1443,23 @@ void InputHandler::repeat_last_insert()
|
||||||
if (m_last_insert.keys.empty())
|
if (m_last_insert.keys.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (dynamic_cast<InputModes::Normal*>(¤t_mode()) == nullptr)
|
if (dynamic_cast<InputModes::Normal*>(¤t_mode()) == nullptr or
|
||||||
|
m_last_insert.recording)
|
||||||
throw runtime_error{"repeating last insert not available in this context"};
|
throw runtime_error{"repeating last insert not available in this context"};
|
||||||
|
|
||||||
Vector<Key> keys;
|
Vector<Key> keys;
|
||||||
swap(keys, m_last_insert.keys);
|
swap(keys, m_last_insert.keys);
|
||||||
ScopedSetBool disable_hooks(context().hooks_disabled(),
|
ScopedSetBool disable_hooks(context().hooks_disabled(),
|
||||||
m_last_insert.disable_hooks);
|
m_last_insert.disable_hooks);
|
||||||
// context.last_insert will be refilled by the new Insert
|
|
||||||
// this is very inefficient.
|
|
||||||
push_mode(new InputModes::Insert(*this, m_last_insert.mode, m_last_insert.count));
|
push_mode(new InputModes::Insert(*this, m_last_insert.mode, m_last_insert.count));
|
||||||
for (auto& key : keys)
|
for (auto& key : keys)
|
||||||
|
{
|
||||||
|
// refill last_insert, this is very inefficient, but necesary at the moment
|
||||||
|
// to properly handle insert completion
|
||||||
|
m_last_insert.keys.push_back(key);
|
||||||
current_mode().handle_key(key);
|
current_mode().handle_key(key);
|
||||||
|
}
|
||||||
kak_assert(dynamic_cast<InputModes::Normal*>(¤t_mode()) != nullptr);
|
kak_assert(dynamic_cast<InputModes::Normal*>(¤t_mode()) != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1526,6 +1533,12 @@ void InputHandler::handle_key(Key key)
|
||||||
++m_handle_key_level;
|
++m_handle_key_level;
|
||||||
auto dec = on_scope_end([this]{ --m_handle_key_level; });
|
auto dec = on_scope_end([this]{ --m_handle_key_level; });
|
||||||
|
|
||||||
|
auto process_key = [&](Key key) {
|
||||||
|
if (m_last_insert.recording)
|
||||||
|
m_last_insert.keys.push_back(key);
|
||||||
|
current_mode().handle_key(key);
|
||||||
|
};
|
||||||
|
|
||||||
auto keymap_mode = current_mode().keymap_mode();
|
auto keymap_mode = current_mode().keymap_mode();
|
||||||
KeymapManager& keymaps = m_context.keymaps();
|
KeymapManager& keymaps = m_context.keymaps();
|
||||||
if (keymaps.is_mapped(key, keymap_mode) and
|
if (keymaps.is_mapped(key, keymap_mode) and
|
||||||
|
@ -1533,10 +1546,10 @@ void InputHandler::handle_key(Key key)
|
||||||
{
|
{
|
||||||
ScopedSetBool disable_history{context().history_disabled()};
|
ScopedSetBool disable_history{context().history_disabled()};
|
||||||
for (auto& k : keymaps.get_mapping(key, keymap_mode).keys)
|
for (auto& k : keymaps.get_mapping(key, keymap_mode).keys)
|
||||||
current_mode().handle_key(k);
|
process_key(k);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
current_mode().handle_key(key);
|
process_key(key);
|
||||||
|
|
||||||
// do not record the key that made us enter or leave recording mode,
|
// do not record the key that made us enter or leave recording mode,
|
||||||
// and the ones that are triggered recursively by previous keys.
|
// and the ones that are triggered recursively by previous keys.
|
||||||
|
|
|
@ -116,8 +116,13 @@ private:
|
||||||
void push_mode(InputMode* new_mode);
|
void push_mode(InputMode* new_mode);
|
||||||
void pop_mode(InputMode* current_mode);
|
void pop_mode(InputMode* current_mode);
|
||||||
|
|
||||||
struct Insertion{ InsertMode mode; Vector<Key> keys; bool disable_hooks; int count; };
|
struct Insertion{
|
||||||
Insertion m_last_insert = { InsertMode::Insert, {}, false, 1 };
|
NestedBool recording;
|
||||||
|
InsertMode mode;
|
||||||
|
Vector<Key> keys;
|
||||||
|
bool disable_hooks;
|
||||||
|
int count;
|
||||||
|
} m_last_insert = { {}, InsertMode::Insert, {}, false, 1 };
|
||||||
|
|
||||||
char m_recording_reg = 0;
|
char m_recording_reg = 0;
|
||||||
String m_recorded_keys;
|
String m_recorded_keys;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
afoo<a-;>:w<ret><esc>.
|
1
test/regression/1680-crash-with-dot-and-alt-semicolon/in
Normal file
1
test/regression/1680-crash-with-dot-and-alt-semicolon/in
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
foofoo
|
Loading…
Reference in New Issue
Block a user