diff --git a/src/buffer.cc b/src/buffer.cc index 2e248a3c..e2d01201 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -786,8 +786,7 @@ void Buffer::on_option_changed(const Option& option) void Buffer::run_hook_in_own_context(const String& hook_name, const String& param) { - Editor hook_editor{*this}; - InputHandler hook_handler(hook_editor); + InputHandler hook_handler(*this, SelectionList{ {} }); m_hooks.run_hook(hook_name, param, hook_handler.context()); } diff --git a/src/buffer.hh b/src/buffer.hh index 81b1bab4..13b958c5 100644 --- a/src/buffer.hh +++ b/src/buffer.hh @@ -268,13 +268,13 @@ struct BufferListenerRegisterFuncs class BufferChangeListener_AutoRegister : public BufferChangeListener, public AutoRegister + BufferListenerRegisterFuncs, Buffer> { public: - BufferChangeListener_AutoRegister(const Buffer& buffer) + BufferChangeListener_AutoRegister(Buffer& buffer) : AutoRegister(buffer) {} - const Buffer& buffer() const { return registry(); } + Buffer& buffer() const { return registry(); } }; } diff --git a/src/client.cc b/src/client.cc index a03c2e29..95802181 100644 --- a/src/client.cc +++ b/src/client.cc @@ -2,7 +2,6 @@ #include "color_registry.hh" #include "context.hh" -#include "editor.hh" #include "buffer_manager.hh" #include "user_interface.hh" #include "file.hh" @@ -13,10 +12,14 @@ namespace Kakoune { -Client::Client(std::unique_ptr&& ui, Editor& editor, String name) - : m_input_handler(editor, std::move(name)), m_ui(std::move(ui)) +Client::Client(std::unique_ptr&& ui, + std::unique_ptr&& window, + SelectionList selections, String name) + : m_ui{std::move(ui)}, m_window{std::move(window)}, + m_input_handler{m_window->buffer(), std::move(selections), std::move(name)} { context().set_client(*this); + context().set_window(*m_window); } Client::~Client() @@ -58,6 +61,15 @@ DisplayLine Client::generate_mode_line() const return { oss.str(), get_color("StatusLine") }; } +void Client::change_buffer(Buffer& buffer) +{ + ClientManager::instance().add_free_window(std::move(m_window), std::move(context().selections())); + std::tie(m_window, context().m_selections) = ClientManager::instance().get_free_window(buffer); + context().set_window(*m_window); + m_window->set_dimensions(ui().dimensions()); + m_window->hooks().run_hook("WinDisplay", buffer.name(), context()); +} + void Client::redraw_ifn() { if (context().window().timestamp() != context().buffer().timestamp()) @@ -80,10 +92,9 @@ static void reload_buffer(Context& context, const String& filename) Buffer* buf = create_buffer_from_file(filename); if (not buf) return; - Window& win = ClientManager::instance().get_unused_window_for_buffer(*buf); - win.selections() = SelectionList{cursor_pos}; - win.set_position(view_pos); - context.change_editor(win); + context.change_buffer(*buf); + context.selections() = SelectionList{cursor_pos}; + context.window().set_position(view_pos); context.print_status({ "'" + buf->display_name() + "' reloaded", get_color("Information") }); } diff --git a/src/client.hh b/src/client.hh index 89fb46bc..ac191542 100644 --- a/src/client.hh +++ b/src/client.hh @@ -1,7 +1,6 @@ #ifndef client_hh_INCLUDED #define client_hh_INCLUDED -#include "editor.hh" #include "string.hh" #include "utils.hh" #include "display_buffer.hh" @@ -11,11 +10,14 @@ namespace Kakoune { class UserInterface; +class Window; class Client : public SafeCountable { public: - Client(std::unique_ptr&& ui, Editor& editor, String name); + Client(std::unique_ptr&& ui, + std::unique_ptr&& window, + SelectionList selections, String name); ~Client(); // handle all the keys currently available in the user interface @@ -26,18 +28,22 @@ public: void redraw_ifn(); UserInterface& ui() const { return *m_ui; } + Window& window() const { return *m_window; } void check_buffer_fs_timestamp(); Context& context() { return m_input_handler.context(); } const Context& context() const { return m_input_handler.context(); } -private: - InputHandler m_input_handler; + void change_buffer(Buffer& buffer); +private: DisplayLine generate_mode_line() const; std::unique_ptr m_ui; + std::unique_ptr m_window; + + InputHandler m_input_handler; DisplayLine m_status_line; }; diff --git a/src/client_manager.cc b/src/client_manager.cc index 657e6d93..e5a3018b 100644 --- a/src/client_manager.cc +++ b/src/client_manager.cc @@ -28,8 +28,9 @@ Client* ClientManager::create_client(std::unique_ptr&& ui, const String& init_commands) { Buffer& buffer = **BufferManager::instance().begin(); - Client* client = new Client{std::move(ui), get_unused_window_for_buffer(buffer), - generate_name()}; + WindowAndSelections ws = get_free_window(buffer); + Client* client = new Client{std::move(ui), std::move(std::get<0>(ws)), + std::move(std::get<1>(ws)), generate_name()}; m_clients.emplace_back(client); try { @@ -80,24 +81,27 @@ void ClientManager::remove_client(Client& client) kak_assert(false); } -Window& ClientManager::get_unused_window_for_buffer(Buffer& buffer) +WindowAndSelections ClientManager::get_free_window(Buffer& buffer) { - for (auto& w : m_windows) + for (auto it = m_free_windows.begin(), end = m_free_windows.end(); + it != end; ++it) { - if (&w->buffer() != &buffer) - continue; - - auto it = std::find_if(m_clients.begin(), m_clients.end(), - [&](const std::unique_ptr& client) - { return &client->context().window() == w.get(); }); - if (it == m_clients.end()) + auto& w = std::get<0>(*it); + if (&w->buffer() == &buffer) { w->forget_timestamp(); - return *w; + WindowAndSelections res = std::move(*it); + m_free_windows.erase(it); + return res; } } - m_windows.emplace_back(new Window(buffer)); - return *m_windows.back(); + return WindowAndSelections{ std::unique_ptr{new Window{buffer}}, DynamicSelectionList{buffer, { Selection{ {}, {} } } } }; +} + +void ClientManager::add_free_window(std::unique_ptr&& window, SelectionList selections) +{ + Buffer& buffer = window->buffer(); + m_free_windows.emplace_back(std::move(window), DynamicSelectionList{ buffer, std::move(selections) }); } void ClientManager::ensure_no_client_uses_buffer(Buffer& buffer) @@ -120,16 +124,15 @@ 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_buffer(*buf); break; } } } - auto end = std::remove_if(m_windows.begin(), m_windows.end(), - [&buffer](const std::unique_ptr& w) - { return &w->buffer() == &buffer; }); - m_windows.erase(end, m_windows.end()); + auto end = std::remove_if(m_free_windows.begin(), m_free_windows.end(), + [&buffer](const WindowAndSelections& ws) + { return &std::get<0>(ws)->buffer() == &buffer; }); + m_free_windows.erase(end, m_free_windows.end()); } bool ClientManager::validate_client_name(const String& name) const diff --git a/src/client_manager.hh b/src/client_manager.hh index 2e6638e7..9c32404a 100644 --- a/src/client_manager.hh +++ b/src/client_manager.hh @@ -8,6 +8,9 @@ namespace Kakoune struct client_removed{}; +using WindowAndSelections = std::tuple, + DynamicSelectionList>; + class ClientManager : public Singleton { public: @@ -20,9 +23,11 @@ public: bool empty() const { return m_clients.empty(); } size_t count() const { return m_clients.size(); } - Window& get_unused_window_for_buffer(Buffer& buffer); void ensure_no_client_uses_buffer(Buffer& buffer); + WindowAndSelections get_free_window(Buffer& buffer); + void add_free_window(std::unique_ptr&& window, SelectionList selections); + void redraw_clients() const; Client* get_client_ifp(const String& name); @@ -34,7 +39,7 @@ private: String generate_name() const; std::vector> m_clients; - std::vector> m_windows; + std::vector m_free_windows; }; } diff --git a/src/commands.cc b/src/commands.cc index 21dce82f..d538ebf8 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -116,10 +116,7 @@ void edit(CommandParameters params, Context& context) context.push_jump(); if (buffer != &context.buffer()) - { - auto& manager = ClientManager::instance(); - context.change_editor(manager.get_unused_window_for_buffer(*buffer)); - } + context.change_buffer(*buffer); if (param_count > 1 and not parser[1].empty()) { @@ -210,8 +207,7 @@ void show_buffer(CommandParameters params, Context& context) if (&buffer != &context.buffer()) { context.push_jump(); - auto& manager = ClientManager::instance(); - context.change_editor(manager.get_unused_window_for_buffer(buffer)); + context.change_buffer(buffer); } } @@ -568,9 +564,7 @@ void context_wrap(CommandParameters params, Context& context, Func func) if (parser.has_option("draft")) { - InputHandler input_handler(real_context->editor(), real_context->name()); - DynamicSelectionList sels{real_context->buffer(), real_context->selections()}; - auto restore_sels = on_scope_end([&]{ real_context->selections() = std::move(sels); }); + InputHandler input_handler(real_context->buffer(), 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 @@ -579,6 +573,7 @@ void context_wrap(CommandParameters params, Context& context, Func func) if (parser.has_option("itersel")) { + DynamicSelectionList sels{real_context->buffer(), real_context->selections()}; for (auto& sel : sels) { input_handler.context().selections() = sel; diff --git a/src/context.cc b/src/context.cc index a638a927..d4ad1616 100644 --- a/src/context.cc +++ b/src/context.cc @@ -8,41 +8,24 @@ namespace Kakoune { Context::Context() = default; - -Context::Context(InputHandler& input_handler, Editor& editor, String name) - : m_input_handler(&input_handler), m_editor(&editor), - m_name(std::move(name)) {} - -Context::Context(Editor& editor, String name) - : m_editor(&editor), - m_name(std::move(name)) {} - Context::~Context() = default; +Context::Context(InputHandler& input_handler, Buffer& buffer, SelectionList selections, String name) + : m_input_handler{&input_handler}, m_selections{{buffer, std::move(selections)}}, + m_name(std::move(name)) {} + Buffer& Context::buffer() const { if (not has_buffer()) throw runtime_error("no buffer in context"); - return m_editor->buffer(); -} - -Editor& Context::editor() const -{ - if (not has_editor()) - throw runtime_error("no editor in context"); - return *m_editor.get(); + return (*m_selections).registry(); } Window& Context::window() const { if (not has_window()) throw runtime_error("no window in context"); - return *dynamic_cast(m_editor.get()); -} - -bool Context::has_window() const -{ - return (bool)m_editor and dynamic_cast(m_editor.get()); + return *m_window; } InputHandler& Context::input_handler() const @@ -99,6 +82,12 @@ void Context::set_client(Client& client) m_client.reset(&client); } +void Context::set_window(Window& window) +{ + kak_assert(&window.buffer() == &buffer()); + m_window.reset(&window); +} + void Context::print_status(DisplayLine status) const { if (has_client()) @@ -111,14 +100,14 @@ void Context::push_jump() if (m_current_jump != m_jump_list.end()) { auto begin = m_current_jump; - if (&editor().buffer() != &begin->buffer() or + if (&buffer() != &begin->buffer() or (const SelectionList&)(*begin) != jump) ++begin; m_jump_list.erase(begin, m_jump_list.end()); } m_jump_list.erase(std::remove(begin(m_jump_list), end(m_jump_list), jump), end(m_jump_list)); - m_jump_list.push_back({editor().buffer(), jump}); + m_jump_list.push_back({buffer(), jump}); m_current_jump = m_jump_list.end(); } @@ -168,27 +157,29 @@ void Context::forget_jumps_to_buffer(Buffer& buffer) } } -void Context::change_editor(Editor& editor) +void Context::change_buffer(Buffer& buffer) { - m_editor.reset(&editor); - if (has_window()) - { - if (has_ui()) - window().set_dimensions(ui().dimensions()); - window().hooks().run_hook("WinDisplay", buffer().name(), *this); - } + m_window.reset(); + if (has_client()) + client().change_buffer(buffer); + else + m_selections = DynamicSelectionList{ buffer }; if (has_input_handler()) input_handler().reset_normal_mode(); } SelectionList& Context::selections() { - return editor().selections(); + if (not m_selections) + throw runtime_error("no selections in context"); + return *m_selections; } const SelectionList& Context::selections() const { - return editor().selections(); + if (not m_selections) + throw runtime_error("no selections in context"); + return *m_selections; } std::vector Context::selections_content() const diff --git a/src/context.hh b/src/context.hh index 54c79490..60d76c71 100644 --- a/src/context.hh +++ b/src/context.hh @@ -3,6 +3,8 @@ #include "dynamic_selection_list.hh" +#include + namespace Kakoune { @@ -25,21 +27,17 @@ class Context { public: Context(); - Context(InputHandler& input_handler, Editor& editor, String name = ""); - Context(Editor& editor, String name = ""); + Context(InputHandler& input_handler, Buffer& buffer, SelectionList selections, String name = ""); ~Context(); Context(const Context&) = delete; Context& operator=(const Context&) = delete; Buffer& buffer() const; - bool has_buffer() const { return (bool)m_editor; } - - Editor& editor() const; - bool has_editor() const { return (bool)m_editor; } + bool has_buffer() const { return m_selections; } Window& window() const; - bool has_window() const; + bool has_window() const { return (bool)m_window; } Client& client() const; bool has_client() const { return (bool)m_client; } @@ -54,9 +52,10 @@ public: const SelectionList& selections() const; std::vector selections_content() const; - void change_editor(Editor& editor); + void change_buffer(Buffer& buffer); void set_client(Client& client); + void set_window(Window& window); OptionManager& options() const; HookManager& hooks() const; @@ -81,10 +80,13 @@ private: friend struct ScopedEdition; - safe_ptr m_editor; safe_ptr m_input_handler; + safe_ptr m_window; safe_ptr m_client; + friend class Client; + boost::optional m_selections; + String m_name; using JumpList = std::vector; diff --git a/src/debug.cc b/src/debug.cc index 7b97b2f0..61bc7116 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -1,8 +1,8 @@ #include "debug.hh" #include "assert.hh" +#include "buffer.hh" #include "buffer_manager.hh" -#include "editor.hh" namespace Kakoune { diff --git a/src/dynamic_selection_list.cc b/src/dynamic_selection_list.cc index 92a95d1c..35ac26a3 100644 --- a/src/dynamic_selection_list.cc +++ b/src/dynamic_selection_list.cc @@ -3,7 +3,7 @@ namespace Kakoune { -DynamicSelectionList::DynamicSelectionList(const Buffer& buffer, +DynamicSelectionList::DynamicSelectionList(Buffer& buffer, SelectionList selections) : SelectionList(std::move(selections)), BufferChangeListener_AutoRegister(buffer) diff --git a/src/dynamic_selection_list.hh b/src/dynamic_selection_list.hh index fc90dcfd..54cd2d5b 100644 --- a/src/dynamic_selection_list.hh +++ b/src/dynamic_selection_list.hh @@ -13,7 +13,7 @@ public: using iterator = SelectionList::iterator; using const_iterator = SelectionList::const_iterator; - DynamicSelectionList(const Buffer& buffer, SelectionList selections = {}); + DynamicSelectionList(Buffer& buffer, SelectionList selections = {}); DynamicSelectionList& operator=(SelectionList selections); void check_invariant() const; diff --git a/src/editor.hh b/src/editor.hh deleted file mode 100644 index 11f3ecee..00000000 --- a/src/editor.hh +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef editor_hh_INCLUDED -#define editor_hh_INCLUDED - -#include "buffer.hh" -#include "dynamic_selection_list.hh" -#include "memoryview.hh" - -namespace Kakoune -{ - -// An Editor is a to be removed class from the past -class Editor : public SafeCountable -{ -public: - Editor(Buffer& buffer) - : m_buffer(&buffer), - m_selections(buffer, {BufferCoord{}}) - {} - - virtual ~Editor() {} - - Buffer& buffer() const { return *m_buffer; } - - const SelectionList& selections() const { return m_selections; } - SelectionList& selections() { return m_selections; } - -private: - safe_ptr m_buffer; - DynamicSelectionList m_selections; -}; - -} - -#endif // editor_hh_INCLUDED - diff --git a/src/input_handler.cc b/src/input_handler.cc index 03c9f497..c68c0c76 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -995,7 +995,7 @@ private: template void move(Type offset) { - auto& selections = context().editor().selections(); + auto& selections = context().selections(); for (auto& sel : selections) { auto last = context().has_window() ? context().window().offset_coord(sel.last(), offset) @@ -1125,9 +1125,9 @@ void InputMode::reset_normal_mode() m_input_handler.reset_normal_mode(); } -InputHandler::InputHandler(Editor& editor, String name) +InputHandler::InputHandler(Buffer& buffer, SelectionList selections, String name) : m_mode(new InputModes::Normal(*this)), - m_context(*this, editor, std::move(name)) + m_context(*this, buffer, std::move(selections), std::move(name)) { } diff --git a/src/input_handler.hh b/src/input_handler.hh index 93e0ae94..461470e0 100644 --- a/src/input_handler.hh +++ b/src/input_handler.hh @@ -37,7 +37,7 @@ enum class InsertMode : unsigned; class InputHandler : public SafeCountable { public: - InputHandler(Editor& editor, String name = ""); + InputHandler(Buffer& buffer, SelectionList selections, String name = ""); ~InputHandler(); // switch to insert mode diff --git a/src/normal.cc b/src/normal.cc index 175173c0..e612f6f7 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -285,8 +285,7 @@ void goto_commands(Context& context, int line) if (it->get() == &buffer and ++it == buffer_manager.end()) break; context.push_jump(); - auto& client_manager = ClientManager::instance(); - context.change_editor(client_manager.get_unused_window_for_buffer(**it)); + context.change_buffer(**it); break; } case 'f': @@ -894,7 +893,7 @@ void scroll(Context& context, int) auto cursor_pos = utf8::advance(buffer.iterator_at(position.line), buffer.iterator_at(position.line+1), position.column); - select_coord(buffer, cursor_pos.coord(), window.selections()); + select_coord(buffer, cursor_pos.coord(), context.selections()); window.set_position(position); } @@ -985,10 +984,7 @@ void jump(Context& context, int) Buffer& buffer = const_cast(jump.buffer()); BufferManager::instance().set_last_used_buffer(buffer); if (&buffer != &context.buffer()) - { - auto& manager = ClientManager::instance(); - context.change_editor(manager.get_unused_window_for_buffer(buffer)); - } + context.change_buffer(buffer); context.selections() = jump; } diff --git a/src/selectors.hh b/src/selectors.hh index da9b195f..0cfa7a68 100644 --- a/src/selectors.hh +++ b/src/selectors.hh @@ -3,7 +3,6 @@ #include "selection.hh" #include "unicode.hh" -#include "editor.hh" #include "utf8_iterator.hh" namespace Kakoune diff --git a/src/unit_tests.cc b/src/unit_tests.cc index 8bd0c5fc..3b2b2960 100644 --- a/src/unit_tests.cc +++ b/src/unit_tests.cc @@ -1,6 +1,5 @@ #include "assert.hh" #include "buffer.hh" -#include "editor.hh" #include "keys.hh" #include "selectors.hh" diff --git a/src/utils.hh b/src/utils.hh index a08e7707..0cbf4c91 100644 --- a/src/utils.hh +++ b/src/utils.hh @@ -109,7 +109,7 @@ public: return *this; } - void reset(T* ptr) + void reset(T* ptr = nullptr) { *this = safe_ptr(ptr); } diff --git a/src/window.cc b/src/window.cc index b7e4b0c8..c982bd82 100644 --- a/src/window.cc +++ b/src/window.cc @@ -18,12 +18,13 @@ void expand_tabulations(const Context& context, DisplayBuffer& display_buffer); void expand_unprintable(const Context& context, DisplayBuffer& display_buffer); Window::Window(Buffer& buffer) - : Editor(buffer), + : m_buffer(&buffer), m_hooks(buffer.hooks()), m_options(buffer.options()), m_keymaps(buffer.keymaps()) { - InputHandler hook_handler{*this}; + InputHandler hook_handler{*m_buffer, SelectionList{ {} } }; + hook_handler.context().set_window(*this); m_hooks.run_hook("WinCreate", buffer.name(), hook_handler.context()); m_options.register_watcher(*this); @@ -37,7 +38,8 @@ Window::Window(Buffer& buffer) Window::~Window() { - InputHandler hook_handler{*this}; + InputHandler hook_handler{*m_buffer, SelectionList{ {} } }; + hook_handler.context().set_window(*this); m_hooks.run_hook("WinClose", buffer().name(), hook_handler.context()); m_options.unregister_watcher(*this); } @@ -66,7 +68,7 @@ void Window::scroll(CharCount offset) void Window::update_display_buffer(const Context& context) { kak_assert(&buffer() == &context.buffer()); - scroll_to_keep_selection_visible_ifn(context.selections().main()); + scroll_to_keep_selection_visible_ifn(context); DisplayBuffer::LineList& lines = m_display_buffer.lines(); lines.clear(); @@ -143,8 +145,9 @@ static CharCount adapt_view_pos(const DisplayBuffer& display_buffer, return view_pos; } -void Window::scroll_to_keep_selection_visible_ifn(const Range& selection) +void Window::scroll_to_keep_selection_visible_ifn(const Context& context) { + auto& selection = context.selections().main(); const auto& first = selection.first(); const auto& last = selection.last(); @@ -163,8 +166,8 @@ void Window::scroll_to_keep_selection_visible_ifn(const Range& selection) lines.emplace_back(AtomList{ {buffer(), last.line, last.line+1} }); display_buffer.compute_range(); - m_highlighters(*this, display_buffer); - m_builtin_highlighters(*this, display_buffer); + m_highlighters(context, display_buffer); + m_builtin_highlighters(context, display_buffer); // now we can compute where the cursor is in display columns // (this is only valid if highlighting one line and multiple lines put @@ -245,9 +248,10 @@ BufferCoord Window::offset_coord(BufferCoord coord, LineCount offset) lines.emplace_back(AtomList{ {buffer(), line, line+1} }); display_buffer.compute_range(); - Context context(*this); - m_highlighters(*this, display_buffer); - m_builtin_highlighters(*this, display_buffer); + InputHandler hook_handler{*m_buffer, SelectionList{ {} } }; + hook_handler.context().set_window(*this); + m_highlighters(hook_handler.context(), display_buffer); + m_builtin_highlighters(hook_handler.context(), display_buffer); CharCount column = find_display_column(lines[0], buffer(), coord); return find_buffer_coord(lines[1], buffer(), column); @@ -256,7 +260,8 @@ BufferCoord Window::offset_coord(BufferCoord coord, LineCount offset) void Window::on_option_changed(const Option& option) { String desc = option.name() + "=" + option.get_as_string(); - InputHandler hook_handler{*this}; + InputHandler hook_handler{*m_buffer, SelectionList{ {} } }; + hook_handler.context().set_window(*this); m_hooks.run_hook("WinSetOption", desc, hook_handler.context()); // an highlighter might depend on the option, so we need to redraw diff --git a/src/window.hh b/src/window.hh index 33fed537..3b8928db 100644 --- a/src/window.hh +++ b/src/window.hh @@ -3,9 +3,8 @@ #include "completion.hh" #include "display_buffer.hh" -#include "editor.hh" -#include "highlighter.hh" #include "highlighter.hh" +#include "selection.hh" #include "hook_manager.hh" #include "option_manager.hh" #include "keymap_manager.hh" @@ -13,13 +12,8 @@ namespace Kakoune { -// A Window is an editing view onto a Buffer -// -// The Window class is an interactive Editor adding display functionalities -// to the editing ones already provided by the Editor class. -// Display can be customized through the use of highlighters handled by -// the window's HighlighterGroup -class Window : public Editor, public OptionManagerWatcher +// A Window is a view onto a Buffer +class Window : public SafeCountable, public OptionManagerWatcher { public: Window(Buffer& buffer); @@ -50,6 +44,8 @@ public: KeymapManager& keymaps() { return m_keymaps; } const KeymapManager& keymaps() const { return m_keymaps; } + Buffer& buffer() const { return *m_buffer; } + size_t timestamp() const { return m_timestamp; } void forget_timestamp() { m_timestamp = -1; } @@ -59,8 +55,9 @@ private: Window(const Window&) = delete; void on_option_changed(const Option& option) override; + void scroll_to_keep_selection_visible_ifn(const Context& context); - void scroll_to_keep_selection_visible_ifn(const Range& selection); + safe_ptr m_buffer; DisplayCoord m_position; DisplayCoord m_dimensions;