From 94bbf47cd45e48b0f0f46971a82c6bc85965ac81 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 28 Jan 2013 13:48:34 +0100 Subject: [PATCH] InputHandler have it's own context --- src/client_manager.cc | 26 +++---- src/client_manager.hh | 7 +- src/commands.cc | 12 ++-- src/context.hh | 8 ++- src/input_handler.cc | 154 +++++++++++++++++++++--------------------- src/input_handler.hh | 6 +- 6 files changed, 110 insertions(+), 103 deletions(-) diff --git a/src/client_manager.cc b/src/client_manager.cc index f9a955e0..4b292f68 100644 --- a/src/client_manager.cc +++ b/src/client_manager.cc @@ -34,7 +34,7 @@ void ClientManager::create_client(std::unique_ptr&& ui, generate_name()}); InputHandler* input_handler = &m_clients.back()->input_handler; - Context* context = &m_clients.back()->context; + Context* context = &m_clients.back()->context(); try { @@ -50,10 +50,10 @@ void ClientManager::create_client(std::unique_ptr&& ui, return; } - context->ui().set_input_callback([input_handler, context, this]() { + context->ui().set_input_callback([context, this]() { try { - input_handler->handle_available_inputs(*context); + context->input_handler().handle_available_inputs(*context); context->window().forget_timestamp(); } catch (Kakoune::runtime_error& error) @@ -73,7 +73,7 @@ void ClientManager::remove_client_by_context(Context& context) { for (auto it = m_clients.begin(); it != m_clients.end(); ++it) { - if (&(*it)->context == &context) + if (&(*it)->context() == &context) { m_clients.erase(it); return; @@ -91,7 +91,7 @@ Window& ClientManager::get_unused_window_for_buffer(Buffer& buffer) auto it = std::find_if(m_clients.begin(), m_clients.end(), [&](const std::unique_ptr& client) - { return &client->context.window() == w.get(); }); + { return &client->context().window() == w.get(); }); if (it == m_clients.end()) { w->forget_timestamp(); @@ -106,9 +106,9 @@ void ClientManager::ensure_no_client_uses_buffer(Buffer& buffer) { for (auto& client : m_clients) { - client->context.forget_jumps_to_buffer(buffer); + client->context().forget_jumps_to_buffer(buffer); - if (&client->context.buffer() != &buffer) + if (&client->context().buffer() != &buffer) continue; // change client context to edit the first buffer which is not the @@ -119,7 +119,7 @@ void ClientManager::ensure_no_client_uses_buffer(Buffer& buffer) if (buf != &buffer) { Window& w = get_unused_window_for_buffer(*buf); - client->context.change_editor(w); + client->context().change_editor(w); break; } } @@ -134,12 +134,12 @@ void ClientManager::set_client_name(Context& context, String name) { auto it = find_if(m_clients, [&name](std::unique_ptr& client) { return client->name == name; }); - if (it != m_clients.end() and &(*it)->context != &context) + if (it != m_clients.end() and &(*it)->context() != &context) throw runtime_error("name not unique: " + name); for (auto& client : m_clients) { - if (&client->context == &context) + if (&client->context() == &context) { client->name = std::move(name); return; @@ -152,7 +152,7 @@ String ClientManager::get_client_name(const Context& context) { for (auto& client : m_clients) { - if (&client->context == &context) + if (&client->context() == &context) return client->name; } throw runtime_error("no client for current context"); @@ -163,7 +163,7 @@ Context& ClientManager::get_client_context(const String& name) auto it = find_if(m_clients, [&name](std::unique_ptr& client) { return client->name == name; }); if (it != m_clients.end()) - return (*it)->context; + return (*it)->context(); throw runtime_error("no client named: " + name); } @@ -171,7 +171,7 @@ void ClientManager::redraw_clients() const { for (auto& client : m_clients) { - Context& context = client->context; + Context& context = client->context(); if (context.window().timestamp() != context.buffer().timestamp()) { DisplayCoord dimensions = context.ui().dimensions(); diff --git a/src/client_manager.hh b/src/client_manager.hh index 6569d26b..e74110d1 100644 --- a/src/client_manager.hh +++ b/src/client_manager.hh @@ -35,14 +35,15 @@ private: Client(std::unique_ptr&& ui, Window& window, String name) : user_interface(std::move(ui)), - context(input_handler, window, *user_interface), - name(std::move(name)) {} + input_handler(*user_interface), + name(std::move(name)) { context().change_editor(window); } Client(Client&&) = delete; Client& operator=(Client&& other) = delete; + Context& context() { return input_handler.context(); } + std::unique_ptr user_interface; InputHandler input_handler; - Context context; String name; }; diff --git a/src/commands.cc b/src/commands.cc index 74deeb82..bd34db87 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -526,14 +526,14 @@ void exec_keys(const KeyList& keys, Context& context) RegisterRestorer quote('"', context); RegisterRestorer slash('/', context); - BatchUI batch_ui(keys); - InputHandler batch_input_handler; - scoped_edition edition(context.editor()); - Context new_context(batch_input_handler, context.editor(), batch_ui); - batch_input_handler.handle_available_inputs(new_context); - context.change_editor(new_context.editor()); + BatchUI batch_ui(keys); + InputHandler batch_input_handler(batch_ui); + batch_input_handler.context().change_editor(context.editor()); + + batch_input_handler.handle_available_inputs(batch_input_handler.context()); + context.change_editor(batch_input_handler.context().editor()); } template diff --git a/src/context.hh b/src/context.hh index 176df273..03f3efd2 100644 --- a/src/context.hh +++ b/src/context.hh @@ -2,12 +2,13 @@ #define context_hh_INCLUDED #include "window.hh" -#include "input_handler.hh" #include "user_interface.hh" namespace Kakoune { +class InputHandler; + // A Context is used to access non singleton objects for various services // in commands. // @@ -19,7 +20,8 @@ struct Context Context() {} explicit Context(Editor& editor) : m_editor(&editor) {} - + Context(InputHandler& input_handler, UserInterface& ui) + : m_input_handler(&input_handler), m_ui(&ui) {} Context(InputHandler& input_handler, Editor& editor, UserInterface& ui) : m_input_handler(&input_handler), m_editor(&editor), m_ui(&ui) {} @@ -165,7 +167,7 @@ struct Context int& numeric_param() { return m_numeric_param; } private: safe_ptr m_editor; - safe_ptr m_input_handler; + InputHandler* m_input_handler; safe_ptr m_ui; Insertion m_last_insert = {InsertMode::Insert, {}}; diff --git a/src/input_handler.cc b/src/input_handler.cc index dc9392c1..33e9018c 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -21,7 +21,8 @@ public: InputMode(const InputMode&) = delete; InputMode& operator=(const InputMode&) = delete; - virtual void on_key(const Key& key, Context& context) = 0; + virtual void on_key(const Key& key) = 0; + Context& context() const { return m_input_handler.context(); } protected: void reset_normal_mode(); private: @@ -41,7 +42,7 @@ public: { } - void on_key(const Key& key, Context& context) override + void on_key(const Key& key) override { if (key.modifiers == Key::Modifiers::None and isdigit(key.key)) m_count = m_count * 10 + key.key - '0'; @@ -50,8 +51,8 @@ public: auto it = keymap.find(key); if (it != keymap.end()) { - context.numeric_param() = m_count; - it->second(context); + context().numeric_param() = m_count; + it->second(context()); } m_count = 0; } @@ -125,17 +126,17 @@ private: class Menu : public InputMode { public: - Menu(Context& context, const memoryview& choices, + Menu(InputHandler& input_handler, const memoryview& choices, MenuCallback callback) - : InputMode(context.input_handler()), + : InputMode(input_handler), m_callback(callback), m_choices(choices.begin(), choices.end()), m_selected(m_choices.begin()) { - DisplayCoord menu_pos{ context.window().dimensions().line, 0_char }; - context.ui().menu_show(choices, menu_pos, MenuStyle::Prompt); + DisplayCoord menu_pos{ context().window().dimensions().line, 0_char }; + context().ui().menu_show(choices, menu_pos, MenuStyle::Prompt); } - void on_key(const Key& key, Context& context) override + void on_key(const Key& key) override { auto match_filter = [this](const String& str) { return boost::regex_match(str.begin(), str.end(), m_filter); @@ -143,11 +144,11 @@ public: if (key == Key(Key::Modifiers::Control, 'm')) { - context.ui().menu_hide(); - context.ui().print_status(""); + context().ui().menu_hide(); + context().ui().print_status(""); reset_normal_mode(); int selected = m_selected - m_choices.begin(); - m_callback(selected, MenuEvent::Validate, context); + m_callback(selected, MenuEvent::Validate, context()); return; } else if (key == Key::Escape or key == Key{ Key::Modifiers::Control, 'c' }) @@ -157,14 +158,14 @@ public: m_edit_filter = false; m_filter = boost::regex(".*"); m_filter_editor.reset(""); - context.ui().print_status(""); + context().ui().print_status(""); } else { - context.ui().menu_hide(); + context().ui().menu_hide(); reset_normal_mode(); int selected = m_selected - m_choices.begin(); - m_callback(selected, MenuEvent::Abort, context); + m_callback(selected, MenuEvent::Abort, context()); } } else if (key == Key::Down or @@ -175,7 +176,7 @@ public: auto it = std::find_if(m_selected+1, m_choices.end(), match_filter); if (it == m_choices.end()) it = std::find_if(m_choices.begin(), m_selected, match_filter); - select(it, context); + select(it); } else if (key == Key::Up or key == Key::BackTab or @@ -186,7 +187,7 @@ public: auto it = std::find_if(selected+1, m_choices.rend(), match_filter); if (it == m_choices.rend()) it = std::find_if(m_choices.rbegin(), selected, match_filter); - select(it.base()-1, context); + select(it.base()-1); } else if (key == '/' and not m_edit_filter) { @@ -201,11 +202,11 @@ public: auto it = std::find_if(m_selected, m_choices.end(), match_filter); if (it == m_choices.end()) it = std::find_if(m_choices.begin(), m_selected, match_filter); - select(it, context); + select(it); } if (m_edit_filter) - context.ui().print_status("/" + m_filter_editor.line(), + context().ui().print_status("/" + m_filter_editor.line(), m_filter_editor.cursor_pos() + 1); } @@ -216,12 +217,12 @@ private: const ChoiceList m_choices; ChoiceList::const_iterator m_selected; - void select(ChoiceList::const_iterator it, Context& context) + void select(ChoiceList::const_iterator it) { m_selected = it; int selected = m_selected - m_choices.begin(); - context.ui().menu_select(selected); - m_callback(selected, MenuEvent::Select, context); + context().ui().menu_select(selected); + m_callback(selected, MenuEvent::Select, context()); } boost::regex m_filter = boost::regex(".*"); @@ -250,23 +251,23 @@ String common_prefix(const memoryview& strings) class Prompt : public InputMode { public: - Prompt(Context& context, const String& prompt, + Prompt(InputHandler& input_handler, const String& prompt, Completer completer, PromptCallback callback) - : InputMode(context.input_handler()), m_prompt(prompt), + : InputMode(input_handler), m_prompt(prompt), m_completer(completer), m_callback(callback) { m_history_it = ms_history[m_prompt].end(); - context.ui().print_status(m_prompt, m_prompt.char_length()); + context().ui().print_status(m_prompt, m_prompt.char_length()); } - void on_key(const Key& key, Context& context) override + void on_key(const Key& key) override { std::vector& history = ms_history[m_prompt]; const String& line = m_line_editor.line(); if (m_insert_reg) { - String reg = RegisterManager::instance()[key.key].values(context)[0]; + String reg = RegisterManager::instance()[key.key].values(context())[0]; m_line_editor.insert(reg); m_insert_reg = false; } @@ -277,20 +278,20 @@ public: history.erase(it); history.push_back(line); - context.ui().print_status(""); - context.ui().menu_hide(); + context().ui().print_status(""); + context().ui().menu_hide(); reset_normal_mode(); // call callback after reset_normal_mode so that callback // may change the mode - m_callback(line, PromptEvent::Validate, context); + m_callback(line, PromptEvent::Validate, context()); return; } else if (key == Key::Escape or key == Key { Key::Modifiers::Control, 'c' }) { - context.ui().print_status(""); - context.ui().menu_hide(); + context().ui().print_status(""); + context().ui().menu_hide(); reset_normal_mode(); - m_callback(line, PromptEvent::Abort, context); + m_callback(line, PromptEvent::Abort, context()); return; } else if (key == Key{Key::Modifiers::Control, 'r'}) @@ -345,16 +346,16 @@ public: // first try, we need to ask our completer for completions if (m_current_completion == -1) { - m_completions = m_completer(context, line, + m_completions = m_completer(context(), line, line.byte_count_to(m_line_editor.cursor_pos())); if (candidates.empty()) return; - context.ui().menu_hide(); - DisplayCoord menu_pos{ context.window().dimensions().line, 0_char }; - context.ui().menu_show(candidates, menu_pos, MenuStyle::Prompt); + context().ui().menu_hide(); + DisplayCoord menu_pos{ context().window().dimensions().line, 0_char }; + context().ui().menu_show(candidates, menu_pos, MenuStyle::Prompt); - bool use_common_prefix = context.options()["complete_prefix"].as_int(); + bool use_common_prefix = context().options()["complete_prefix"].as_int(); String prefix = use_common_prefix ? common_prefix(candidates) : String(); if (m_completions.end - m_completions.start > prefix.length()) prefix = line.substr(m_completions.start, @@ -375,7 +376,7 @@ public: m_current_completion = candidates.size()-1; const String& completion = candidates[m_current_completion]; - context.ui().menu_select(m_current_completion); + context().ui().menu_select(m_current_completion); m_line_editor.insert_from(line.char_count_to(m_completions.start), completion); @@ -387,13 +388,13 @@ public: } else { - context.ui().menu_hide(); + context().ui().menu_hide(); m_current_completion = -1; m_line_editor.handle_key(key); } - context.ui().print_status(m_prompt + line, + context().ui().print_status(m_prompt + line, m_prompt.char_length() + m_line_editor.cursor_pos()); - m_callback(line, PromptEvent::Change, context); + m_callback(line, PromptEvent::Change, context()); } private: @@ -417,10 +418,10 @@ public: NextKey(InputHandler& input_handler, KeyCallback callback) : InputMode(input_handler), m_callback(callback) {} - void on_key(const Key& key, Context& context) override + void on_key(const Key& key) override { reset_normal_mode(); - m_callback(key, context); + m_callback(key, context()); } private: @@ -507,33 +508,33 @@ private: class Insert : public InputMode { public: - Insert(Context& context, InsertMode mode) - : InputMode(context.input_handler()), - m_inserter(context.editor(), mode), + Insert(InputHandler& input_handler, InsertMode mode) + : InputMode(input_handler), + m_inserter(context().editor(), mode), m_idle_timer{Clock::now() + idle_timeout, - [this, &context](Timer& timer) { - context.hooks().run_hook("InsertIdle", "", context); - m_completer.reset(context); - if (context.editor().selections().size() == 1) + [this](Timer& timer) { + context().hooks().run_hook("InsertIdle", "", context()); + m_completer.reset(context()); + if (context().editor().selections().size() == 1) { - BufferIterator prev = context.editor().selections().back().last(); + BufferIterator prev = context().editor().selections().back().last(); if (not prev.is_begin() && is_word(*utf8::previous(prev))) - m_completer.select(context, 0); + m_completer.select(context(), 0); } }} { - context.last_insert().first = mode; - context.last_insert().second.clear(); - context.hooks().run_hook("InsertBegin", "", context); + context().last_insert().first = mode; + context().last_insert().second.clear(); + context().hooks().run_hook("InsertBegin", "", context()); } - void on_key(const Key& key, Context& context) override + void on_key(const Key& key) override { - context.last_insert().second.push_back(key); + context().last_insert().second.push_back(key); if (m_insert_reg) { if (key.modifiers == Key::Modifiers::None) - m_inserter.insert(RegisterManager::instance()[key.key].values(context)); + m_inserter.insert(RegisterManager::instance()[key.key].values(context())); m_insert_reg = false; return; } @@ -541,8 +542,8 @@ public: bool moved = false; if (key == Key::Escape or key == Key{ Key::Modifiers::Control, 'c' }) { - context.hooks().run_hook("InsertEnd", "", context); - m_completer.reset(context); + context().hooks().run_hook("InsertEnd", "", context()); + m_completer.reset(context()); reset_normal_mode(); } else if (key == Key::Backspace) @@ -577,19 +578,19 @@ public: m_inserter.insert(String() + '\t'); else if ( key == Key{ Key::Modifiers::Control, 'n' }) { - m_completer.select(context, 1); + m_completer.select(context(), 1); update_completions = false; } else if ( key == Key{ Key::Modifiers::Control, 'p' }) { - m_completer.select(context, -1); + m_completer.select(context(), -1); update_completions = false; } if (update_completions) m_idle_timer.set_next_date(Clock::now() + idle_timeout); if (moved) - context.hooks().run_hook("InsertMove", "", context); + context().hooks().run_hook("InsertMove", "", context()); } private: bool m_insert_reg = false; @@ -607,8 +608,8 @@ void InputMode::reset_normal_mode() } -InputHandler::InputHandler() - : m_mode(new InputModes::Normal(*this)) +InputHandler::InputHandler(UserInterface& ui) + : m_context(*this, ui), m_mode(new InputModes::Normal(*this)) { } @@ -618,14 +619,14 @@ InputHandler::~InputHandler() void InputHandler::insert(Context& context, InsertMode mode) { - assert(&context.input_handler() == this); + assert(&context == &m_context); m_mode_trash.emplace_back(std::move(m_mode)); - m_mode.reset(new InputModes::Insert(context, mode)); + m_mode.reset(new InputModes::Insert(*this, mode)); } void InputHandler::repeat_last_insert(Context& context) { - assert(&context.input_handler() == this); + assert(&context == &m_context); Context::Insertion& last_insert = context.last_insert(); if (last_insert.second.empty()) return; @@ -635,26 +636,26 @@ void InputHandler::repeat_last_insert(Context& context) // context.last_insert will be refilled by the new Insert // this is very inefficient. m_mode_trash.emplace_back(std::move(m_mode)); - m_mode.reset(new InputModes::Insert(context, last_insert.first)); + m_mode.reset(new InputModes::Insert(*this, last_insert.first)); for (auto& key : keys) - m_mode->on_key(key, context); + m_mode->on_key(key); assert(dynamic_cast(m_mode.get()) != nullptr); } void InputHandler::prompt(const String& prompt, Completer completer, PromptCallback callback, Context& context) { - assert(&context.input_handler() == this); + assert(&context == &m_context); m_mode_trash.emplace_back(std::move(m_mode)); - m_mode.reset(new InputModes::Prompt(context, prompt, completer, callback)); + m_mode.reset(new InputModes::Prompt(*this, prompt, completer, callback)); } void InputHandler::menu(const memoryview& choices, MenuCallback callback, Context& context) { - assert(&context.input_handler() == this); + assert(&context == &m_context); m_mode_trash.emplace_back(std::move(m_mode)); - m_mode.reset(new InputModes::Menu(context, choices, callback)); + m_mode.reset(new InputModes::Menu(*this, choices, callback)); } void InputHandler::on_next_key(KeyCallback callback) @@ -670,12 +671,13 @@ bool is_valid(const Key& key) void InputHandler::handle_available_inputs(Context& context) { + assert(&context == &m_context); m_mode_trash.clear(); while (context.ui().is_key_available()) { Key key = context.ui().get_key(); if (is_valid(key)) - m_mode->on_key(key, context); + m_mode->on_key(key); m_mode_trash.clear(); } } diff --git a/src/input_handler.hh b/src/input_handler.hh index 9baa56ce..6a9536c0 100644 --- a/src/input_handler.hh +++ b/src/input_handler.hh @@ -5,12 +5,12 @@ #include "completion.hh" #include "utils.hh" #include "string.hh" +#include "context.hh" namespace Kakoune { class Editor; -class Context; enum class MenuEvent { @@ -35,7 +35,7 @@ enum class InsertMode : unsigned; class InputHandler : public SafeCountable { public: - InputHandler(); + InputHandler(UserInterface& ui); ~InputHandler(); // switch to insert mode @@ -65,7 +65,9 @@ public: // user interface void handle_available_inputs(Context& context); + Context& context() { return m_context; } private: + Context m_context; friend class InputMode; std::unique_ptr m_mode; std::vector> m_mode_trash;