From 0942cd5084b08ff2154725faa06e800b8536922c Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Wed, 8 Nov 2017 14:39:52 +0800 Subject: [PATCH] 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 will get their keys recorded as well). Fixes #1680 --- src/input_handler.cc | 25 ++++++++++++++----- src/input_handler.hh | 9 +++++-- .../1680-crash-with-dot-and-alt-semicolon/cmd | 1 + .../1680-crash-with-dot-and-alt-semicolon/in | 1 + .../1680-crash-with-dot-and-alt-semicolon/out | 1 + 5 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 test/regression/1680-crash-with-dot-and-alt-semicolon/cmd create mode 100644 test/regression/1680-crash-with-dot-and-alt-semicolon/in create mode 100644 test/regression/1680-crash-with-dot-and-alt-semicolon/out diff --git a/src/input_handler.cc b/src/input_handler.cc index 15261c4f..efffcc30 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -1059,6 +1059,7 @@ public: context().hooks().run_hook("InsertIdle", "", context()); }} { + last_insert().recording.set(); last_insert().mode = mode; last_insert().keys.clear(); last_insert().disable_hooks = context().hooks_disabled(); @@ -1084,6 +1085,8 @@ public: if (not temporary) { + last_insert().recording.unset(); + auto& selections = context().selections(); if (m_restore_cursor) { @@ -1100,7 +1103,6 @@ public: void on_key(Key key) override { auto& buffer = context().buffer(); - last_insert().keys.push_back(key); const bool transient = context().flags() & Context::Flags::Transient; bool update_completions = true; @@ -1441,18 +1443,23 @@ void InputHandler::repeat_last_insert() if (m_last_insert.keys.empty()) return; - if (dynamic_cast(¤t_mode()) == nullptr) + if (dynamic_cast(¤t_mode()) == nullptr or + m_last_insert.recording) throw runtime_error{"repeating last insert not available in this context"}; Vector keys; swap(keys, m_last_insert.keys); ScopedSetBool disable_hooks(context().hooks_disabled(), 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)); 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); + } kak_assert(dynamic_cast(¤t_mode()) != nullptr); } @@ -1526,6 +1533,12 @@ void InputHandler::handle_key(Key key) ++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(); KeymapManager& keymaps = m_context.keymaps(); if (keymaps.is_mapped(key, keymap_mode) and @@ -1533,10 +1546,10 @@ void InputHandler::handle_key(Key key) { ScopedSetBool disable_history{context().history_disabled()}; for (auto& k : keymaps.get_mapping(key, keymap_mode).keys) - current_mode().handle_key(k); + process_key(k); } else - current_mode().handle_key(key); + process_key(key); // do not record the key that made us enter or leave recording mode, // and the ones that are triggered recursively by previous keys. diff --git a/src/input_handler.hh b/src/input_handler.hh index 9b23308c..663fd81b 100644 --- a/src/input_handler.hh +++ b/src/input_handler.hh @@ -116,8 +116,13 @@ private: void push_mode(InputMode* new_mode); void pop_mode(InputMode* current_mode); - struct Insertion{ InsertMode mode; Vector keys; bool disable_hooks; int count; }; - Insertion m_last_insert = { InsertMode::Insert, {}, false, 1 }; + struct Insertion{ + NestedBool recording; + InsertMode mode; + Vector keys; + bool disable_hooks; + int count; + } m_last_insert = { {}, InsertMode::Insert, {}, false, 1 }; char m_recording_reg = 0; String m_recorded_keys; diff --git a/test/regression/1680-crash-with-dot-and-alt-semicolon/cmd b/test/regression/1680-crash-with-dot-and-alt-semicolon/cmd new file mode 100644 index 00000000..c6ff4769 --- /dev/null +++ b/test/regression/1680-crash-with-dot-and-alt-semicolon/cmd @@ -0,0 +1 @@ +afoo:w. diff --git a/test/regression/1680-crash-with-dot-and-alt-semicolon/in b/test/regression/1680-crash-with-dot-and-alt-semicolon/in new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/regression/1680-crash-with-dot-and-alt-semicolon/in @@ -0,0 +1 @@ + diff --git a/test/regression/1680-crash-with-dot-and-alt-semicolon/out b/test/regression/1680-crash-with-dot-and-alt-semicolon/out new file mode 100644 index 00000000..55b5f1fc --- /dev/null +++ b/test/regression/1680-crash-with-dot-and-alt-semicolon/out @@ -0,0 +1 @@ +foofoo