summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2016-03-22 22:54:29 +0000
committerMaxime Coste <frrrwww@gmail.com>2016-03-22 22:54:29 +0000
commit5bf92430064a5136dba51402bd852398cee7e994 (patch)
treea146fff9cb74b25a7e00a90eaa2c4afe3d451001
parentc1c17db5e9a3bc62f2023bbf355b9031837ee7f4 (diff)
User mappings and :exec are always executed in normal mode
Fix #551
-rw-r--r--src/commands.cc4
-rw-r--r--src/input_handler.cc29
-rw-r--r--src/input_handler.hh11
-rw-r--r--src/normal.cc3
4 files changed, 46 insertions, 1 deletions
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 <switches> <keys>: execute given keys as if entered by user",
+ "exec <switches> <keys>: 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<InputMode>& 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);