diff --git a/src/client.cc b/src/client.cc deleted file mode 100644 index bfa0099a..00000000 --- a/src/client.cc +++ /dev/null @@ -1,35 +0,0 @@ -#include "client.hh" - -#include "window.hh" - -namespace Kakoune -{ - -Client* current_client = nullptr; - -void draw_editor_ifn(Editor& editor) -{ - Window* window = dynamic_cast(&editor); - if (current_client and window) - current_client->draw_window(*window); -} - -String prompt(const String& text, const Context& context, Completer completer) -{ - assert(current_client); - return current_client->prompt(text, context, completer); -} - -Key get_key() -{ - assert(current_client); - return current_client->get_key(); -} - -void print_status(const String& status) -{ - assert(current_client); - return current_client->print_status(status); -} - -} diff --git a/src/client.hh b/src/client.hh index 3ec36620..84adab4f 100644 --- a/src/client.hh +++ b/src/client.hh @@ -3,6 +3,7 @@ #include "keys.hh" #include "completion.hh" +#include "utils.hh" namespace Kakoune { @@ -12,26 +13,20 @@ class Window; class String; class Context; -class Client +class Client : public SafeCountable { public: virtual ~Client() {} virtual void draw_window(Window& window) = 0; virtual void print_status(const String& status) = 0; - virtual String prompt(const String& prompt, const Context& context, Completer completer) = 0; + virtual String prompt(const String& prompt, const Context& context, + Completer completer = complete_nothing) = 0; virtual Key get_key() = 0; }; struct prompt_aborted {}; -extern Client* current_client; - -void draw_editor_ifn(Editor& editor); -String prompt(const String& text, const Context& context, Completer completer = complete_nothing); -Key get_key(); -void print_status(const String& status); - } #endif // client_hh_INCLUDED diff --git a/src/commands.cc b/src/commands.cc index faf399c9..596519ae 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -214,7 +214,7 @@ private: std::unordered_map m_options; }; -Buffer* open_or_create(const String& filename) +Buffer* open_or_create(const String& filename, Context& context) { Buffer* buffer = NULL; try @@ -223,7 +223,7 @@ Buffer* open_or_create(const String& filename) } catch (file_not_found& what) { - print_status("new file " + filename); + context.print_status("new file " + filename); buffer = new Buffer(filename, Buffer::Type::NewFile); } return buffer; @@ -248,7 +248,7 @@ void edit(const CommandParameters& params, Context& context) if (parser.has_option("scratch")) buffer = new Buffer(filename, Buffer::Type::Scratch); else - buffer = open_or_create(filename); + buffer = open_or_create(filename, context); } Window& window = *buffer->get_or_create_window(); @@ -262,7 +262,7 @@ void edit(const CommandParameters& params, Context& context) window.select(window.buffer().iterator_at({line, column})); } - context = Context(window); + context.change_editor(window); } void write_buffer(const CommandParameters& params, Context& context) @@ -344,7 +344,7 @@ void show_buffer(const CommandParameters& params, Context& context) if (not buffer) throw runtime_error("buffer " + buffer_name + " does not exists"); - context = Context(*buffer->get_or_create_window()); + context.change_editor(*buffer->get_or_create_window()); } void delete_buffer(const CommandParameters& params, Context& context) @@ -374,7 +374,7 @@ void delete_buffer(const CommandParameters& params, Context& context) { if (buf != buffer) { - context = Context(*buf->get_or_create_window()); + context.change_editor(*buf->get_or_create_window()); break; } } @@ -554,7 +554,7 @@ void echo_message(const CommandParameters& params, Context& context) String message; for (auto& param : params) message += param + " "; - print_status(message); + context.print_status(message); } void exec_commands_in_file(const CommandParameters& params, @@ -626,16 +626,10 @@ private: class BatchClient : public Client { public: - BatchClient(const KeyList& keys) + BatchClient(const KeyList& keys, Client* previous_client) : m_keys(keys), m_pos(0) { - m_previous_client = current_client; - current_client = this; - } - - ~BatchClient() - { - current_client = m_previous_client; + m_previous_client = previous_client; } String prompt(const String&, const Context&, Completer) @@ -679,7 +673,8 @@ private: void exec_keys(const KeyList& keys, Context& context) { - BatchClient batch_client(keys); + BatchClient batch_client(keys, context.has_client() ? &context.client() + : nullptr); RegisterRestorer quote('"', context); RegisterRestorer slash('/', context); @@ -687,7 +682,8 @@ void exec_keys(const KeyList& keys, Context& context) scoped_edition edition(context.editor()); int count = 0; - Context new_context(context); + Context new_context(batch_client); + new_context.change_editor(context.window()); while (batch_client.has_key_left()) { Key key = batch_client.get_key(); @@ -738,7 +734,8 @@ void menu(const CommandParameters& params, Context& context) } oss << "(empty cancels): "; - String choice = prompt(oss.str(), context, complete_nothing); + String choice = context.client().prompt(oss.str(), context, + complete_nothing); int i = str_to_int(choice); if (i > 0 and i < (count / 2) + 1) diff --git a/src/context.hh b/src/context.hh index cc4e4fe6..f7bb5282 100644 --- a/src/context.hh +++ b/src/context.hh @@ -2,22 +2,26 @@ #define context_hh_INCLUDED #include "window.hh" +#include "client.hh" namespace Kakoune { -class Buffer; - struct Context { Context() {} Context(Editor& editor) : m_editor(&editor) {} + Context(Client& client) + : m_client(&client) {} + // to allow func(Context(Editor(...))) Context(Editor&& editor) : m_editor(&editor) {} + Context& operator=(const Context&) = delete; + Buffer& buffer() const { if (not has_buffer()) @@ -42,6 +46,21 @@ struct Context } bool has_window() const { return m_editor and dynamic_cast(m_editor.get()); } + Client& client() const + { + if (not has_client()) + throw runtime_error("no client in context"); + return *m_client; + } + bool has_client() const { return m_client; } + + void change_editor(Editor& editor) + { + if (has_client() and not dynamic_cast(&editor)) + throw logic_error(); + m_editor.reset(&editor); + } + OptionManager& option_manager() const { if (has_window()) @@ -51,11 +70,24 @@ struct Context return GlobalOptionManager::instance(); } + void draw_ifn() const + { + if (has_client()) + client().draw_window(window()); + } + + void print_status(const String& status) const + { + if (has_client()) + client().print_status(status); + } + int numeric_param() const { return m_numeric_param; } void numeric_param(int param) { m_numeric_param = param; } public: safe_ptr m_editor; + safe_ptr m_client; int m_numeric_param = 0; }; diff --git a/src/main.cc b/src/main.cc index 68e32262..b9fbecdb 100644 --- a/src/main.cc +++ b/src/main.cc @@ -97,12 +97,12 @@ void do_insert(Context& context) last_insert_sequence.mode = mode; last_insert_sequence.keys.clear(); IncrementalInserter inserter(context.editor(), mode); - draw_editor_ifn(context.editor()); + context.draw_ifn(); insert_sequence(inserter, context, - [&]() { Key key = get_key(); + [&]() { Key key = context.client().get_key(); last_insert_sequence.keys.push_back(key); return key; }, - [&]() { draw_editor_ifn(context.editor()); }); + [&]() { context.draw_ifn(); }); } void do_repeat_insert(Context& context) @@ -131,7 +131,7 @@ void do_go(Context& context) } else { - Key key = get_key(); + Key key = context.client().get_key(); if (key.modifiers != Key::Modifiers::None) return; @@ -168,10 +168,10 @@ void do_command(Context& context) { try { - auto cmdline = prompt(":", context, - std::bind(&CommandManager::complete, - &CommandManager::instance(), - _1, _2, _3)); + auto cmdline = context.client().prompt( + ":", context, std::bind(&CommandManager::complete, + &CommandManager::instance(), + _1, _2, _3)); CommandManager::instance().execute(cmdline, context); } @@ -182,7 +182,7 @@ void do_pipe(Context& context) { try { - auto cmdline = prompt("|", context, complete_nothing); + auto cmdline = context.client().prompt("|", context, complete_nothing); Editor& editor = context.editor(); std::vector strings; @@ -199,7 +199,7 @@ void do_search(Context& context) { try { - String ex = prompt("/", context); + String ex = context.client().prompt("/", context); if (ex.empty()) ex = RegisterManager::instance()['/'].values(context)[0]; else @@ -217,7 +217,7 @@ void do_search_next(Context& context) if (not ex.empty()) context.editor().select(std::bind(select_next_match, _1, ex), append); else - print_status("no search pattern"); + context.print_status("no search pattern"); } void do_yank(Context& context) @@ -274,7 +274,7 @@ void do_select_regex(Context& context) { try { - String ex = prompt("select: ", context); + String ex = context.client().prompt("select: ", context); context.editor().multi_select(std::bind(select_all_matches, _1, ex)); } catch (prompt_aborted&) {} @@ -284,7 +284,7 @@ void do_split_regex(Context& context) { try { - String ex = prompt("split: ", context); + String ex = context.client().prompt("split: ", context); context.editor().multi_select(std::bind(split_selection, _1, ex)); } catch (prompt_aborted&) {} @@ -321,7 +321,7 @@ void do_select_object(Context& context) { { Key::Modifiers::None, 'W' }, std::bind(select_whole_word, _1, inner) }, }; - Key key = get_key(); + Key key = context.client().get_key(); auto it = key_to_selector.find(key); if (it != key_to_selector.end()) context.editor().select(it->second); @@ -357,10 +357,10 @@ std::unordered_map> keymap = { { Key::Modifiers::None, 'K' }, [](Context& context) { context.editor().move_selections(BufferCoord(-std::max(context.numeric_param(),1), 0), true); } }, { { Key::Modifiers::None, 'L' }, [](Context& context) { context.editor().move_selections(BufferCoord(0, std::max(context.numeric_param(),1)), true); } }, - { { Key::Modifiers::None, 't' }, [](Context& context) { context.editor().select(std::bind(select_to, _1, get_key().key, context.numeric_param(), false)); } }, - { { Key::Modifiers::None, 'f' }, [](Context& context) { context.editor().select(std::bind(select_to, _1, get_key().key, context.numeric_param(), true)); } }, - { { Key::Modifiers::None, 'T' }, [](Context& context) { context.editor().select(std::bind(select_to, _1, get_key().key, context.numeric_param(), false), true); } }, - { { Key::Modifiers::None, 'F' }, [](Context& context) { context.editor().select(std::bind(select_to, _1, get_key().key, context.numeric_param(), true), true); } }, + { { Key::Modifiers::None, 't' }, [](Context& context) { context.editor().select(std::bind(select_to, _1, context.client().get_key().key, context.numeric_param(), false)); } }, + { { Key::Modifiers::None, 'f' }, [](Context& context) { context.editor().select(std::bind(select_to, _1, context.client().get_key().key, context.numeric_param(), true)); } }, + { { Key::Modifiers::None, 'T' }, [](Context& context) { context.editor().select(std::bind(select_to, _1, context.client().get_key().key, context.numeric_param(), false), true); } }, + { { Key::Modifiers::None, 'F' }, [](Context& context) { context.editor().select(std::bind(select_to, _1, context.client().get_key().key, context.numeric_param(), true), true); } }, { { Key::Modifiers::None, 'd' }, do_erase }, { { Key::Modifiers::None, 'c' }, do_change }, @@ -410,16 +410,16 @@ std::unordered_map> keymap = { { Key::Modifiers::None, 'n' }, do_search_next }, { { Key::Modifiers::None, 'N' }, do_search_next }, - { { Key::Modifiers::None, 'u' }, repeated([](Context& context) { if (not context.editor().undo()) { print_status("nothing left to undo"); } }) }, - { { Key::Modifiers::None, 'U' }, repeated([](Context& context) { if (not context.editor().redo()) { print_status("nothing left to redo"); } }) }, + { { Key::Modifiers::None, 'u' }, repeated([](Context& context) { if (not context.editor().undo()) { context.print_status("nothing left to undo"); } }) }, + { { Key::Modifiers::None, 'U' }, repeated([](Context& context) { if (not context.editor().redo()) { context.print_status("nothing left to redo"); } }) }, { { Key::Modifiers::Alt, 'i' }, do_select_object }, { { Key::Modifiers::Alt, 'a' }, do_select_object }, - { { Key::Modifiers::Alt, 't' }, [](Context& context) { context.editor().select(std::bind(select_to_reverse, _1, get_key().key, context.numeric_param(), false)); } }, - { { Key::Modifiers::Alt, 'f' }, [](Context& context) { context.editor().select(std::bind(select_to_reverse, _1, get_key().key, context.numeric_param(), true)); } }, - { { Key::Modifiers::Alt, 'T' }, [](Context& context) { context.editor().select(std::bind(select_to_reverse, _1, get_key().key, context.numeric_param(), false), true); } }, - { { Key::Modifiers::Alt, 'F' }, [](Context& context) { context.editor().select(std::bind(select_to_reverse, _1, get_key().key, context.numeric_param(), true), true); } }, + { { Key::Modifiers::Alt, 't' }, [](Context& context) { context.editor().select(std::bind(select_to_reverse, _1, context.client().get_key().key, context.numeric_param(), false)); } }, + { { Key::Modifiers::Alt, 'f' }, [](Context& context) { context.editor().select(std::bind(select_to_reverse, _1, context.client().get_key().key, context.numeric_param(), true)); } }, + { { Key::Modifiers::Alt, 'T' }, [](Context& context) { context.editor().select(std::bind(select_to_reverse, _1, context.client().get_key().key, context.numeric_param(), false), true); } }, + { { Key::Modifiers::Alt, 'F' }, [](Context& context) { context.editor().select(std::bind(select_to_reverse, _1, context.client().get_key().key, context.numeric_param(), true), true); } }, { { Key::Modifiers::Alt, 'w' }, repeated([](Context& context) { context.editor().select(select_to_next_word); }) }, { { Key::Modifiers::Alt, 'e' }, repeated([](Context& context) { context.editor().select(select_to_next_word_end); }) }, @@ -480,8 +480,7 @@ int main(int argc, char* argv[]) try { NCursesClient client; - current_client = &client; - Context context; + Context context(client); try { @@ -489,7 +488,7 @@ int main(int argc, char* argv[]) } catch (Kakoune::runtime_error& error) { - print_status(error.description()); + context.print_status(error.description()); } @@ -506,16 +505,16 @@ int main(int argc, char* argv[]) else { auto buffer = new Buffer("*scratch*", Buffer::Type::Scratch); - context = Context(*buffer->get_or_create_window()); + context.change_editor(*buffer->get_or_create_window()); } - current_client->draw_window(context.window()); + context.draw_ifn(); int count = 0; while(not quit_requested) { try { - Key key = get_key(); + Key key = context.client().get_key(); if (key.modifiers == Key::Modifiers::None and isdigit(key.key)) count = count * 10 + key.key - '0'; else @@ -525,14 +524,14 @@ int main(int argc, char* argv[]) { context.numeric_param(count); it->second(context); - current_client->draw_window(context.window()); + context.draw_ifn(); } count = 0; } } catch (Kakoune::runtime_error& error) { - print_status(error.description()); + context.print_status(error.description()); } } }