diff --git a/src/client_manager.cc b/src/client_manager.cc index 07322fed..c2a7dcce 100644 --- a/src/client_manager.cc +++ b/src/client_manager.cc @@ -67,6 +67,8 @@ void ClientManager::ensure_no_client_uses_buffer(Buffer& buffer) { for (auto& client : m_clients) { + client.context->forget_jumps_to_buffer(buffer); + if (&client.context->buffer() != &buffer) continue; diff --git a/src/commands.cc b/src/commands.cc index 55fcf2ff..899b4fd4 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -283,6 +283,9 @@ void edit(const CommandParameters& params, Context& context) BufferManager::instance().set_last_used_buffer(*buffer); + if (buffer != &context.buffer() or param_count > 1) + context.push_jump(); + if (buffer != &context.buffer()) { auto& manager = ClientManager::instance(); @@ -385,6 +388,7 @@ void show_buffer(const 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)); } diff --git a/src/context.hh b/src/context.hh index 0568c6c4..844b4d04 100644 --- a/src/context.hh +++ b/src/context.hh @@ -100,6 +100,62 @@ struct Context using Insertion = std::pair>; Insertion& last_insert() { return m_last_insert; } + using Jump = std::pair, BufferCoord>; + void push_jump() + { + Jump jump{safe_ptr{&buffer()}, + editor().selections().back().last().coord()}; + if (m_current_jump != m_jump_list.end()) + { + m_jump_list.erase(m_current_jump+1, m_jump_list.end()); + if (*m_current_jump == jump) + return; + } + + m_jump_list.push_back(jump); + m_current_jump = m_jump_list.end(); + } + + Jump jump_forward() + { + if (m_current_jump != m_jump_list.end() and + m_current_jump + 1 != m_jump_list.end()) + return *++m_current_jump; + throw runtime_error("no next jump"); + } + + Jump jump_backward() + { + if (m_current_jump != m_jump_list.begin()) + { + if (m_current_jump == m_jump_list.end()) + { + push_jump(); + --m_current_jump; + } + return *--m_current_jump; + } + throw runtime_error("no previous jump"); + } + + void forget_jumps_to_buffer(Buffer& buffer) + { + for (auto it = m_jump_list.begin(); it != m_jump_list.end();) + { + if (it->first == &buffer) + { + if (it < m_current_jump) + --m_current_jump; + else if (it == m_current_jump) + m_current_jump = m_jump_list.end(); + + it = m_jump_list.erase(it); + } + else + ++it; + } + } + int& numeric_param() { return m_numeric_param; } private: safe_ptr m_editor; @@ -108,6 +164,10 @@ private: Insertion m_last_insert = {InsertMode::Insert, {}}; int m_numeric_param = 0; + + using JumpList = std::vector; + JumpList m_jump_list; + JumpList::iterator m_current_jump = m_jump_list.begin(); }; } diff --git a/src/main.cc b/src/main.cc index 95ef2f63..9f2136dc 100644 --- a/src/main.cc +++ b/src/main.cc @@ -59,6 +59,7 @@ void do_go(Context& context) BufferIterator target = context.editor().buffer().iterator_at_line_begin(count-1); + context.push_jump(); context.editor().select(target); if (context.has_window()) context.window().center_selection(); @@ -73,6 +74,7 @@ void do_go(Context& context) { case 'g': case 't': + context.push_jump(); editor.select(editor.buffer().begin()); break; case 'l': @@ -85,6 +87,7 @@ void do_go(Context& context) break; case 'b': { + context.push_jump(); const Buffer& buf = editor.buffer(); editor.select(buf.iterator_at_line_begin(buf.line_count() - 1)); break; @@ -329,6 +332,32 @@ void select_to_next_char(Context& context) }); } +void jump_forward(Context& context) +{ + auto jump = context.jump_forward(); + + BufferManager::instance().set_last_used_buffer(*jump.first); + if (jump.first != &context.buffer()) + { + auto& manager = ClientManager::instance(); + context.change_editor(manager.get_unused_window_for_buffer(*jump.first)); + } + context.editor().select(jump.first->iterator_at(jump.second)); +} + +void jump_backward(Context& context) +{ + auto jump = context.jump_backward(); + + BufferManager::instance().set_last_used_buffer(*jump.first); + if (jump.first != &context.buffer()) + { + auto& manager = ClientManager::instance(); + context.change_editor(manager.get_unused_window_for_buffer(*jump.first)); + } + context.editor().select(jump.first->iterator_at(jump.second)); +} + String runtime_directory() { char buffer[2048]; @@ -448,6 +477,9 @@ std::unordered_map> keymap = { { Key::Modifiers::None, Key::PageUp }, do_scroll }, { { Key::Modifiers::None, Key::PageDown }, do_scroll }, + + { { Key::Modifiers::Control, 'i' }, jump_forward }, + { { Key::Modifiers::Control, 'o' }, jump_backward }, }; }