From a5dd8a7935ccdc3859749d7757c6a4005b7b6a98 Mon Sep 17 00:00:00 2001 From: Frank LENORMAND Date: Sat, 11 Sep 2021 10:43:25 +0300 Subject: [PATCH] src: Allow `ga` to skip removed buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit prevents `ga` from returning a “no last buffer” error when the previously displayed buffer was removed. Since the jumps list keeps track of the order in which buffers were displayed already, handling arbitrary `delete-buffer`s as well, cycle through it to implement `ga` instead of storing a pointer. Note that this commit doesn't take into account buffer flags that might exclude some buffers from being cycled over by commands. Fixes #1840 --- src/context.cc | 32 +++++++++++++++++++++++--------- src/context.hh | 5 +++-- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/context.cc b/src/context.cc index 07259c97..efa91938 100644 --- a/src/context.cc +++ b/src/context.cc @@ -172,12 +172,6 @@ void Context::change_buffer(Buffer& buffer) if (has_buffer() and m_edition_level > 0) this->buffer().commit_undo_group(); - if (has_buffer()) - { - auto* current = &this->buffer(); - m_last_buffer = contains(BufferManager::instance(), current) ? current : nullptr; - } - if (has_client()) { client().info_hide(); @@ -197,8 +191,6 @@ void Context::change_buffer(Buffer& buffer) void Context::forget_buffer(Buffer& buffer) { m_jump_list.forget_buffer(buffer); - if (m_last_buffer.get() == &buffer) - m_last_buffer = nullptr; if (&this->buffer() != &buffer) return; @@ -206,7 +198,29 @@ void Context::forget_buffer(Buffer& buffer) if (is_editing() && has_input_handler()) input_handler().reset_normal_mode(); - change_buffer(m_last_buffer ? *m_last_buffer : BufferManager::instance().get_first_buffer()); + auto last_buffer = this->last_buffer(); + change_buffer(last_buffer ? *last_buffer : BufferManager::instance().get_first_buffer()); +} + +Buffer* Context::last_buffer() const +{ + const auto jump_list = m_jump_list.get_as_list(); + if (jump_list.empty()) + return nullptr; + + auto predicate = [this](const auto& sels) { + return &sels.buffer() != &this->buffer(); + }; + + auto next_buffer = find_if(jump_list.subrange(m_jump_list.current_index()-1), + predicate); + if (next_buffer != jump_list.end()) + return &next_buffer->buffer(); + + auto previous_buffer = find_if(jump_list.subrange(0, m_jump_list.current_index()) | reverse(), + predicate); + + return previous_buffer != jump_list.rend() ? &previous_buffer->buffer() : nullptr; } SelectionList& Context::selections() diff --git a/src/context.hh b/src/context.hh index 728c4cad..fd29b897 100644 --- a/src/context.hh +++ b/src/context.hh @@ -35,6 +35,8 @@ struct JumpList size_t current_index() const { return m_current; } + ConstArrayView get_as_list() const { return m_jumps; } + private: using Contents = Vector; Contents m_jumps; @@ -135,7 +137,7 @@ public: void repeat_last_select() { if (m_last_select) m_last_select(*this); } - Buffer* last_buffer() const { return m_last_buffer.get(); } + Buffer* last_buffer() const; private: void begin_edition(); void end_edition(); @@ -149,7 +151,6 @@ private: SafePtr m_input_handler; SafePtr m_window; SafePtr m_client; - SafePtr m_last_buffer; Optional m_selections;