From 5bf92430064a5136dba51402bd852398cee7e994 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 22 Mar 2016 22:54:29 +0000 Subject: [PATCH] User mappings and :exec are always executed in normal mode Fix #551 --- src/commands.cc | 4 +++- src/input_handler.cc | 29 +++++++++++++++++++++++++++++ src/input_handler.hh | 11 +++++++++++ src/normal.cc | 3 +++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/commands.cc b/src/commands.cc index 8eb676ba..d92f3ee9 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -1405,7 +1405,7 @@ void context_wrap(const ParametersParser& parser, Context& context, Func func) const CommandDesc exec_string_cmd = { "exec", nullptr, - "exec : execute given keys as if entered by user", + "exec : execute given keys in normal mode as if entered by user", context_wrap_params, CommandFlags::None, CommandHelper{}, @@ -1420,6 +1420,8 @@ const CommandDesc exec_string_cmd = { keys.insert(keys.end(), param_keys.begin(), param_keys.end()); } + InputHandler::ScopedForceNormal force_normal{context.input_handler()}; + ScopedEdition edition(context); for (auto& key : keys) context.input_handler().handle_key(key); diff --git a/src/input_handler.cc b/src/input_handler.cc index 0dbd5ddc..874601c2 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -1325,6 +1325,35 @@ void InputHandler::on_next_key(KeymapMode keymap_mode, KeyCallback callback) push_mode(new InputModes::NextKey(*this, keymap_mode, callback)); } +InputHandler::ScopedForceNormal::ScopedForceNormal(InputHandler& handler) + : m_handler(handler), m_mode(nullptr) +{ + if (handler.m_mode_stack.size() == 1) + return; + + handler.push_mode(new InputModes::Normal(handler)); + m_mode = handler.m_mode_stack.back().get(); +} + +InputHandler::ScopedForceNormal::~ScopedForceNormal() +{ + if (not m_mode) + return; + + kak_assert(m_handler.m_mode_stack.size() > 1); + + if (m_mode == m_handler.m_mode_stack.back().get()) + m_handler.pop_mode(m_mode); + else + { + auto it = find_if(m_handler.m_mode_stack, + [this](const RefPtr& m) + { return m.get() == m_mode; }); + kak_assert(it != m_handler.m_mode_stack.end()); + m_handler.m_mode_stack.erase(it); + } +} + static bool is_valid(Key key) { return key != Key::Invalid and diff --git a/src/input_handler.hh b/src/input_handler.hh index 8719ca15..41397b28 100644 --- a/src/input_handler.hh +++ b/src/input_handler.hh @@ -82,6 +82,17 @@ public: DisplayLine mode_line() const; + // Force an input handler into normal mode temporarily + struct ScopedForceNormal + { + ScopedForceNormal(InputHandler& handler); + ~ScopedForceNormal(); + + private: + InputHandler& m_handler; + InputMode* m_mode; + }; + private: Context m_context; diff --git a/src/normal.cc b/src/normal.cc index 5f5fb177..ab08da9b 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -1456,6 +1456,9 @@ void exec_user_mappings(Context& context, NormalParams params) auto mapping = context.keymaps().get_mapping(key, KeymapMode::User); ScopedSetBool disable_keymaps(context.keymaps_disabled()); + + InputHandler::ScopedForceNormal force_normal{context.input_handler()}; + ScopedEdition edition(context); for (auto& key : mapping) context.input_handler().handle_key(key);