From ea3e92aa5e68e73fa95196332b739891bbf3f24f Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Mon, 12 May 2014 23:25:15 +0100 Subject: [PATCH] SelectionList know its buffer and timestamp --- src/buffer.cc | 2 +- src/client.cc | 4 +- src/client_manager.cc | 6 +-- src/client_manager.hh | 3 +- src/commands.cc | 16 +++++--- src/context.cc | 10 ++--- src/context.hh | 3 +- src/dynamic_selection_list.cc | 25 ++---------- src/dynamic_selection_list.hh | 5 ++- src/input_handler.cc | 4 +- src/input_handler.hh | 2 +- src/normal.cc | 28 ++++++++------ src/selection.cc | 71 ++++++++++++++++++++++++++++++++++- src/selection.hh | 40 +++++++++----------- src/selectors.cc | 6 +-- src/selectors.hh | 4 +- src/window.cc | 8 ++-- 17 files changed, 150 insertions(+), 87 deletions(-) diff --git a/src/buffer.cc b/src/buffer.cc index f4b6782f..4e7c2606 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -706,7 +706,7 @@ void Buffer::on_option_changed(const Option& option) void Buffer::run_hook_in_own_context(const String& hook_name, const String& param) { - InputHandler hook_handler(*this, { Selection{} }); + InputHandler hook_handler({ *this, Selection{} }); m_hooks.run_hook(hook_name, param, hook_handler.context()); } diff --git a/src/client.cc b/src/client.cc index 5be59b99..dacaf607 100644 --- a/src/client.cc +++ b/src/client.cc @@ -18,7 +18,7 @@ Client::Client(std::unique_ptr&& ui, EnvVarMap env_vars, String name) : m_ui{std::move(ui)}, m_window{std::move(window)}, - m_input_handler{m_window->buffer(), std::move(selections), + m_input_handler{std::move(selections), std::move(name)}, m_env_vars(env_vars) { @@ -102,7 +102,7 @@ static void reload_buffer(Context& context, const String& filename) if (not buf) return; context.change_buffer(*buf); - context.selections() = SelectionList{buf->clamp(cursor_pos)}; + context.selections() = SelectionList{ *buf, buf->clamp(cursor_pos)}; context.window().set_position(view_pos); context.print_status({ "'" + buf->display_name() + "' reloaded", get_color("Information") }); diff --git a/src/client_manager.cc b/src/client_manager.cc index 6e3fd638..692a1a46 100644 --- a/src/client_manager.cc +++ b/src/client_manager.cc @@ -94,18 +94,18 @@ WindowAndSelections ClientManager::get_free_window(Buffer& buffer) w->forget_timestamp(); WindowAndSelections res = std::move(*it); m_free_windows.erase(it.base()-1); + res.selections.update(); return res; } } return WindowAndSelections{ std::unique_ptr{new Window{buffer}}, - DynamicSelectionList{buffer, - { Selection{ {}, {} } } } }; + SelectionList{ buffer, Selection{} } }; } void ClientManager::add_free_window(std::unique_ptr&& window, SelectionList selections) { Buffer& buffer = window->buffer(); - m_free_windows.push_back({ std::move(window), DynamicSelectionList{ buffer, std::move(selections) } }); + m_free_windows.push_back({ std::move(window), SelectionList{ std::move(selections) }, buffer.timestamp() }); } void ClientManager::ensure_no_client_uses_buffer(Buffer& buffer) diff --git a/src/client_manager.hh b/src/client_manager.hh index d3334486..410adab5 100644 --- a/src/client_manager.hh +++ b/src/client_manager.hh @@ -12,7 +12,8 @@ struct client_removed{}; struct WindowAndSelections { std::unique_ptr window; - DynamicSelectionList selections; + SelectionList selections; + size_t timestamp; }; class ClientManager : public Singleton diff --git a/src/commands.cc b/src/commands.cc index e3437dfa..4629c3d1 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -131,7 +131,8 @@ void edit(const ParametersParser& parser, Context& context) int column = param_count > 2 and not parser[2].empty() ? std::max(0, str_to_int(parser[2]) - 1) : 0; - context.selections() = context.buffer().clamp({ line, column }); + auto& buffer = context.buffer(); + context.selections() = { buffer, buffer.clamp({ line, column }) }; if (context.has_window()) context.window().center_line(context.selections().main().cursor().line); } @@ -962,7 +963,7 @@ void context_wrap(const ParametersParser& parser, Context& context, Func func) for (auto& name : names) { Buffer& buffer = BufferManager::instance().get_buffer(name); - InputHandler input_handler{buffer, ( Selection{} )}; + InputHandler input_handler{{ buffer, Selection{} }}; func(parser, input_handler.context()); } return; @@ -980,7 +981,7 @@ void context_wrap(const ParametersParser& parser, Context& context, Func func) if (parser.has_option("draft")) { - InputHandler input_handler(real_context->buffer(), real_context->selections(), real_context->name()); + InputHandler input_handler(real_context->selections(), real_context->name()); // We do not want this draft context to commit undo groups if the real one is // going to commit the whole thing later @@ -989,12 +990,17 @@ void context_wrap(const ParametersParser& parser, Context& context, Func func) if (parser.has_option("itersel")) { - DynamicSelectionList sels{real_context->buffer(), real_context->selections()}; + SelectionList sels{real_context->selections()}; ScopedEdition edition{input_handler.context()}; for (auto& sel : sels) { - input_handler.context().selections() = sel; + input_handler.context().selections() = SelectionList{ sels.buffer(), sel, sels.timestamp() }; + input_handler.context().selections().update(); + func(parser, input_handler.context()); + + if (&sels.buffer() != &input_handler.context().buffer()) + throw runtime_error("the buffer has changed while iterating on selections"); } } else diff --git a/src/context.cc b/src/context.cc index 00e3ff50..dac65284 100644 --- a/src/context.cc +++ b/src/context.cc @@ -10,10 +10,10 @@ namespace Kakoune Context::Context() = default; Context::~Context() = default; -Context::Context(InputHandler& input_handler, Buffer& buffer, - SelectionList selections, String name) +Context::Context(InputHandler& input_handler, SelectionList selections, + String name) : m_input_handler{&input_handler}, - m_selections{{buffer, std::move(selections)}}, + m_selections{std::move(selections)}, m_name(std::move(name)) {} @@ -110,7 +110,7 @@ void Context::push_jump() } m_jump_list.erase(std::remove(begin(m_jump_list), end(m_jump_list), jump), end(m_jump_list)); - m_jump_list.push_back({buffer(), jump}); + m_jump_list.push_back(jump); m_current_jump = m_jump_list.end(); } @@ -168,7 +168,7 @@ void Context::change_buffer(Buffer& buffer) if (has_client()) client().change_buffer(buffer); else - m_selections = DynamicSelectionList{ buffer }; + m_selections = DynamicSelectionList{ { buffer, Selection{} } }; if (has_input_handler()) input_handler().reset_normal_mode(); } diff --git a/src/context.hh b/src/context.hh index 60264aba..f612e36a 100644 --- a/src/context.hh +++ b/src/context.hh @@ -26,7 +26,8 @@ class Context { public: Context(); - Context(InputHandler& input_handler, Buffer& buffer, SelectionList selections, String name = ""); + Context(InputHandler& input_handler, SelectionList selections, + String name = ""); ~Context(); Context(const Context&) = delete; diff --git a/src/dynamic_selection_list.cc b/src/dynamic_selection_list.cc index 2792da30..4087bb0c 100644 --- a/src/dynamic_selection_list.cc +++ b/src/dynamic_selection_list.cc @@ -3,10 +3,9 @@ namespace Kakoune { -DynamicSelectionList::DynamicSelectionList(Buffer& buffer, - SelectionList selections) +DynamicSelectionList::DynamicSelectionList(SelectionList selections) : SelectionList(std::move(selections)), - BufferChangeListener_AutoRegister(buffer) + BufferChangeListener_AutoRegister(const_cast(buffer())) { check_invariant(); } @@ -18,32 +17,16 @@ DynamicSelectionList& DynamicSelectionList::operator=(SelectionList selections) return *this; } -void DynamicSelectionList::check_invariant() const -{ -#ifdef KAK_DEBUG - SelectionList::check_invariant(); - const Buffer& buffer = registry(); - for (size_t i = 0; i < size(); ++i) - { - auto& sel = (*this)[i]; - kak_assert(buffer.is_valid(sel.anchor())); - kak_assert(buffer.is_valid(sel.cursor())); - kak_assert(not buffer.is_end(sel.anchor())); - kak_assert(not buffer.is_end(sel.cursor())); - kak_assert(utf8::is_character_start(buffer.iterator_at(sel.anchor()))); - kak_assert(utf8::is_character_start(buffer.iterator_at(sel.cursor()))); - } -#endif -} - void DynamicSelectionList::on_insert(const Buffer& buffer, ByteCoord begin, ByteCoord end, bool at_end) { update_insert(begin, end, at_end); + set_timestamp(buffer.timestamp()); } void DynamicSelectionList::on_erase(const Buffer& buffer, ByteCoord begin, ByteCoord end, bool at_end) { update_erase(begin, end, at_end); + set_timestamp(buffer.timestamp()); } } diff --git a/src/dynamic_selection_list.hh b/src/dynamic_selection_list.hh index 2f408907..65f37915 100644 --- a/src/dynamic_selection_list.hh +++ b/src/dynamic_selection_list.hh @@ -13,10 +13,11 @@ public: using iterator = SelectionList::iterator; using const_iterator = SelectionList::const_iterator; - DynamicSelectionList(Buffer& buffer, SelectionList selections = { Selection{} }); + DynamicSelectionList(SelectionList selections); DynamicSelectionList& operator=(SelectionList selections); - void check_invariant() const; + + using SelectionList::buffer; private: void on_insert(const Buffer& buffer, ByteCoord begin, ByteCoord end, bool at_end) override; diff --git a/src/input_handler.cc b/src/input_handler.cc index f12a8854..62e3068f 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -875,9 +875,9 @@ void InputMode::reset_normal_mode() m_input_handler.reset_normal_mode(); } -InputHandler::InputHandler(Buffer& buffer, SelectionList selections, String name) +InputHandler::InputHandler(SelectionList selections, String name) : m_mode(new InputModes::Normal(*this)), - m_context(*this, buffer, std::move(selections), std::move(name)) + m_context(*this, std::move(selections), std::move(name)) { } diff --git a/src/input_handler.hh b/src/input_handler.hh index 0d9d34cc..80b8b43c 100644 --- a/src/input_handler.hh +++ b/src/input_handler.hh @@ -35,7 +35,7 @@ enum class InsertMode : unsigned; class InputHandler : public SafeCountable { public: - InputHandler(Buffer& buffer, SelectionList selections, String name = ""); + InputHandler(SelectionList selections, String name = ""); ~InputHandler(); // switch to insert mode diff --git a/src/normal.cc b/src/normal.cc index 45642b22..7ac51ad5 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -26,6 +26,7 @@ void erase(Buffer& buffer, SelectionList& selections) for (auto& sel : selections) { erase(buffer, sel); + selections.update(); avoid_eol(buffer, sel); } selections.check_invariant(); @@ -178,7 +179,7 @@ void select_coord(const Buffer& buffer, ByteCoord coord, SelectionList& selectio { coord = buffer.clamp(coord); if (mode == SelectMode::Replace) - selections = SelectionList { coord }; + selections = SelectionList{ buffer, coord }; else if (mode == SelectMode::Extend) { for (auto& sel : selections) @@ -598,7 +599,7 @@ void paste(Context& context, int) template void regex_prompt(Context& context, const String prompt, T func) { - DynamicSelectionList selections{context.buffer(), context.selections()}; + DynamicSelectionList selections{context.selections()}; context.input_handler().prompt(prompt, "", get_color("Prompt"), complete_nothing, [=](const String& str, PromptEvent event, Context& context) { try @@ -738,7 +739,7 @@ void split_lines(Context& context, int) { auto& selections = context.selections(); auto& buffer = context.buffer(); - SelectionList res; + SelectionList res(context.buffer()); for (auto& sel : selections) { if (sel.anchor().line == sel.cursor().line) @@ -760,7 +761,7 @@ void split_lines(Context& context, int) void join_select_spaces(Context& context, int) { auto& buffer = context.buffer(); - SelectionList selections; + SelectionList selections(buffer); for (auto& sel : context.selections()) { for (LineCount line = sel.min().line; line <= sel.max().line; ++line) @@ -783,8 +784,12 @@ void join_select_spaces(Context& context, int) void join(Context& context, int param) { - DynamicSelectionList sels{context.buffer(), context.selections()}; - auto restore_sels = on_scope_end([&]{ context.selections() = std::move(sels); }); + SelectionList sels{context.selections()}; + auto restore_sels = on_scope_end([&]{ + sels.update(); + context.selections() = std::move(sels); + }); + join_select_spaces(context, param); } @@ -796,7 +801,7 @@ void keep(Context& context, int) if (ex.empty()) return; const Buffer& buffer = context.buffer(); - SelectionList keep; + SelectionList keep(buffer); for (auto& sel : context.selections()) { if (boost::regex_search(buffer.iterator_at(sel.min()), @@ -818,7 +823,7 @@ void keep_pipe(Context& context, int) return; const Buffer& buffer = context.buffer(); auto& shell_manager = ShellManager::instance(); - SelectionList keep; + SelectionList keep(buffer); for (auto& sel : context.selections()) { int status = 0; @@ -839,7 +844,7 @@ void indent(Context& context, int) String indent = indent_width == 0 ? "\t" : String{' ', indent_width}; auto& buffer = context.buffer(); - SelectionList sels; + SelectionList sels(buffer); for (auto& sel : context.selections()) { for (auto line = sel.min().line; line < sel.max().line+1; ++line) @@ -864,7 +869,7 @@ void deindent(Context& context, int) indent_width = tabstop; auto& buffer = context.buffer(); - SelectionList sels; + SelectionList sels(buffer); for (auto& sel : context.selections()) { for (auto line = sel.min().line; line < sel.max().line+1; ++line) @@ -1235,7 +1240,7 @@ void spaces_to_tabs(Context& context, int ts) static SelectionList compute_modified_ranges(const Buffer& buffer, size_t timestamp) { - SelectionList ranges; + SelectionList ranges(buffer); for (auto& change : buffer.changes_since(timestamp)) { const ByteCoord& begin = change.begin; @@ -1264,6 +1269,7 @@ static SelectionList compute_modified_ranges(const Buffer& buffer, size_t timest if (ranges.empty()) return ranges; + ranges.set_timestamp(buffer.timestamp()); ranges.set_main_index(ranges.size() - 1); auto touches = [&](const Selection& lhs, const Selection& rhs) { diff --git a/src/selection.cc b/src/selection.cc index 0049689d..895c1f96 100644 --- a/src/selection.cc +++ b/src/selection.cc @@ -63,6 +63,7 @@ struct UpdateInsert coord.column = end.column + coord.column - begin.column; coord.line += end.line - begin.line; + kak_assert(coord.line >= 0 and coord.column >= 0); } }; @@ -78,7 +79,7 @@ struct UpdateErase kak_assert(end.line < coord.line); if (not assume_different_line and coord <= end) { - if (not at_end) + if (not at_end or begin == ByteCoord{0,0}) coord = begin; else coord = begin.column ? ByteCoord{begin.line, begin.column-1} @@ -94,11 +95,33 @@ struct UpdateErase else coord.line -= end.line - begin.line; } + kak_assert(coord.line >= 0 and coord.column >= 0); } }; } +SelectionList::SelectionList(const Buffer& buffer) + : m_buffer(&buffer), m_timestamp(buffer.timestamp()) +{ +} + +SelectionList::SelectionList(const Buffer& buffer, Selection s, size_t timestamp) + : m_buffer(&buffer), m_selections({ s }), m_timestamp(timestamp) +{} + +SelectionList::SelectionList(const Buffer& buffer, Selection s) + : SelectionList(buffer, s, buffer.timestamp()) +{} + +SelectionList::SelectionList(const Buffer& buffer, std::vector s, size_t timestamp) + : m_buffer(&buffer), m_selections(std::move(s)), m_timestamp(timestamp) +{} + +SelectionList::SelectionList(const Buffer& buffer, std::vector s) + : SelectionList(buffer, std::move(s), buffer.timestamp()) +{} + void SelectionList::update_insert(ByteCoord begin, ByteCoord end, bool at_end) { on_buffer_change(*this, begin, end, at_end, begin.line); @@ -109,12 +132,58 @@ void SelectionList::update_erase(ByteCoord begin, ByteCoord end, bool at_end) on_buffer_change(*this, begin, end, at_end, end.line); } +void SelectionList::update() +{ + for (auto& change : m_buffer->changes_since(m_timestamp)) + { + if (change.type == Buffer::Change::Insert) + update_insert(change.begin, change.end, change.at_end); + else + update_erase(change.begin, change.end, change.at_end); + } + m_timestamp = m_buffer->timestamp(); + + check_invariant(); +} + void SelectionList::check_invariant() const { +#ifdef KAK_DEBUG + auto& buffer = this->buffer(); kak_assert(size() > 0); kak_assert(m_main < size()); for (size_t i = 0; i+1 < size(); ++ i) kak_assert((*this)[i].min() <= (*this)[i+1].min()); + + for (size_t i = 0; i < size(); ++i) + { + auto& sel = (*this)[i]; + kak_assert(buffer.is_valid(sel.anchor())); + kak_assert(buffer.is_valid(sel.cursor())); + kak_assert(not buffer.is_end(sel.anchor())); + kak_assert(not buffer.is_end(sel.cursor())); + kak_assert(utf8::is_character_start(buffer.iterator_at(sel.anchor()))); + kak_assert(utf8::is_character_start(buffer.iterator_at(sel.cursor()))); + } +#endif +} + +void SelectionList::sort_and_merge_overlapping() +{ + if (size() == 1) + return; + + const auto& main = this->main(); + const auto main_begin = main.min(); + m_main = std::count_if(begin(), end(), [&](const Selection& sel) { + auto begin = sel.min(); + if (begin == main_begin) + return &sel < &main; + else + return begin < main_begin; + }); + std::stable_sort(begin(), end(), compare_selections); + merge_overlapping(overlaps); } } diff --git a/src/selection.hh b/src/selection.hh index 016ce5f5..9b3f747a 100644 --- a/src/selection.hh +++ b/src/selection.hh @@ -12,7 +12,7 @@ using CaptureList = std::vector; struct Selection { Selection() = default; - explicit Selection(ByteCoord pos) : Selection(pos,pos) {} + Selection(ByteCoord pos) : Selection(pos,pos) {} Selection(ByteCoord anchor, ByteCoord cursor, CaptureList captures = {}) : m_anchor{anchor}, m_cursor{cursor}, @@ -57,13 +57,17 @@ static bool compare_selections(const Selection& lhs, const Selection& rhs) struct SelectionList { - SelectionList() = default; - SelectionList(ByteCoord c) : m_selections{Selection{c,c}} {} - SelectionList(Selection s) : m_selections{s} {} + SelectionList(const Buffer& buffer); + SelectionList(const Buffer& buffer, Selection s); + SelectionList(const Buffer& buffer, Selection s, size_t timestamp); + SelectionList(const Buffer& buffer, std::vector s); + SelectionList(const Buffer& buffer, std::vector s, size_t timestamp); void update_insert(ByteCoord begin, ByteCoord end, bool at_end); void update_erase(ByteCoord begin, ByteCoord end, bool at_end); + void update(); + void check_invariant() const; const Selection& main() const { return (*this)[m_main]; } @@ -102,8 +106,8 @@ struct SelectionList size_t size() const { return m_selections.size(); } bool empty() const { return m_selections.empty(); } - bool operator==(const SelectionList& other) const { return m_selections == other.m_selections; } - bool operator!=(const SelectionList& other) const { return m_selections != other.m_selections; } + bool operator==(const SelectionList& other) const { return m_buffer == other.m_buffer and m_selections == other.m_selections; } + bool operator!=(const SelectionList& other) const { return !((*this) == other); } template void merge_overlapping(OverlapsFunc overlaps) @@ -129,27 +133,19 @@ struct SelectionList kak_assert(std::is_sorted(begin(), end(), compare_selections)); } - void sort_and_merge_overlapping() - { - if (size() == 1) - return; + void sort_and_merge_overlapping(); - const auto& main = this->main(); - const auto main_begin = main.min(); - m_main = std::count_if(begin(), end(), [&](const Selection& sel) { - auto begin = sel.min(); - if (begin == main_begin) - return &sel < &main; - else - return begin < main_begin; - }); - std::stable_sort(begin(), end(), compare_selections); - merge_overlapping(overlaps); - } + const Buffer& buffer() const { return *m_buffer; } + + size_t timestamp() const { return m_timestamp; } + void set_timestamp(size_t timestamp) { m_timestamp = timestamp; } private: size_t m_main = 0; std::vector m_selections; + + safe_ptr m_buffer; + size_t m_timestamp; }; } diff --git a/src/selectors.cc b/src/selectors.cc index 5d98be52..40db98c9 100644 --- a/src/selectors.cc +++ b/src/selectors.cc @@ -431,13 +431,13 @@ Selection trim_partial_lines(const Buffer& buffer, const Selection& selection) void select_whole_buffer(const Buffer& buffer, SelectionList& selections) { - selections = SelectionList{ Selection({0,0}, buffer.back_coord()) }; + selections = SelectionList{ buffer, Selection({0,0}, buffer.back_coord()) }; } void select_all_matches(const Buffer& buffer, SelectionList& selections, const Regex& regex) { - SelectionList result; + SelectionList result(buffer); for (auto& sel : selections) { auto sel_end = utf8::next(buffer.iterator_at(sel.max())); @@ -470,7 +470,7 @@ void select_all_matches(const Buffer& buffer, SelectionList& selections, void split_selections(const Buffer& buffer, SelectionList& selections, const Regex& regex) { - SelectionList result; + SelectionList result(buffer); for (auto& sel : selections) { auto begin = buffer.iterator_at(sel.min()); diff --git a/src/selectors.hh b/src/selectors.hh index b28febef..d98b73bf 100644 --- a/src/selectors.hh +++ b/src/selectors.hh @@ -16,7 +16,7 @@ inline void clear_selections(const Buffer& buffer, SelectionList& selections) avoid_eol(buffer, pos); sel.anchor() = pos; - selections = SelectionList{ std::move(sel) }; + selections = SelectionList{ buffer, std::move(sel) }; } inline void flip_selections(SelectionList& selections) @@ -31,7 +31,7 @@ inline void keep_selection(SelectionList& selections, int index) if (index < selections.size()) { size_t real_index = (index + selections.main_index() + 1) % selections.size(); - selections = SelectionList{ std::move(selections[real_index]) }; + selections = SelectionList{ selections.buffer(), std::move(selections[real_index]) }; } selections.check_invariant(); } diff --git a/src/window.cc b/src/window.cc index 90c4ded6..fa6c9af9 100644 --- a/src/window.cc +++ b/src/window.cc @@ -23,7 +23,7 @@ Window::Window(Buffer& buffer) m_options(buffer.options()), m_keymaps(buffer.keymaps()) { - InputHandler hook_handler{*m_buffer, { Selection{} } }; + InputHandler hook_handler{{ *m_buffer, Selection{} }}; hook_handler.context().set_window(*this); m_hooks.run_hook("WinCreate", buffer.name(), hook_handler.context()); m_options.register_watcher(*this); @@ -38,7 +38,7 @@ Window::Window(Buffer& buffer) Window::~Window() { - InputHandler hook_handler{*m_buffer, { Selection{} } }; + InputHandler hook_handler{{ *m_buffer, Selection{} }}; hook_handler.context().set_window(*this); m_hooks.run_hook("WinClose", buffer().name(), hook_handler.context()); m_options.unregister_watcher(*this); @@ -262,7 +262,7 @@ ByteCoord Window::offset_coord(ByteCoord coord, LineCount offset) lines.emplace_back(AtomList{ {buffer(), line, line+1} }); display_buffer.compute_range(); - InputHandler hook_handler{*m_buffer, { Selection{} } }; + InputHandler hook_handler{{ *m_buffer, Selection{} } }; hook_handler.context().set_window(*this); m_highlighters(hook_handler.context(), HighlightFlags::MoveOnly, display_buffer); m_builtin_highlighters(hook_handler.context(), HighlightFlags::MoveOnly, display_buffer); @@ -274,7 +274,7 @@ ByteCoord Window::offset_coord(ByteCoord coord, LineCount offset) void Window::on_option_changed(const Option& option) { String desc = option.name() + "=" + option.get_as_string(); - InputHandler hook_handler{*m_buffer, { Selection{} } }; + InputHandler hook_handler{{ *m_buffer, Selection{} }}; hook_handler.context().set_window(*this); m_hooks.run_hook("WinSetOption", desc, hook_handler.context());