diff options
| author | Maxime Coste <frrrwww@gmail.com> | 2011-09-06 18:49:32 +0000 |
|---|---|---|
| committer | Maxime Coste <frrrwww@gmail.com> | 2011-09-06 18:49:32 +0000 |
| commit | 1e87fe17c6941ffc257a6afc22e6bf1f15342d19 (patch) | |
| tree | 4572bcceae30022da09efee9cff2e22b3a0a918b /src/buffer.cc | |
| parent | f58cbf0b98f6fc36e1746107a5095d55eb1ffc94 (diff) | |
Buffer: Undo/Redo implementation
Currently only a linear undo, i.e. if you undo and then make some new
changes, previous undoed changes are lost. Final undo system should
support an undo tree, with timestamped modifications.
Diffstat (limited to 'src/buffer.cc')
| -rw-r--r-- | src/buffer.cc | 88 |
1 files changed, 87 insertions, 1 deletions
diff --git a/src/buffer.cc b/src/buffer.cc index ef8e0e1e..5e42a295 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -127,11 +127,23 @@ Buffer::Buffer(const std::string& name, const BufferString& initial_content) void Buffer::erase(const BufferIterator& begin, const BufferIterator& end) { + append_modification(Modification(Modification::Erase, begin, string(begin, end))); + do_erase(begin, end); +} + +void Buffer::insert(const BufferIterator& position, const BufferString& string) +{ + append_modification(Modification(Modification::Insert, position, string)); + do_insert(position, string); +} + +void Buffer::do_erase(const BufferIterator& begin, const BufferIterator& end) +{ m_content.erase(begin.m_position, end - begin); compute_lines(); } -void Buffer::insert(const BufferIterator& position, const BufferString& string) +void Buffer::do_insert(const BufferIterator& position, const BufferString& string) { m_content.insert(position.m_position, string); compute_lines(); @@ -223,4 +235,78 @@ BufferChar Buffer::at(BufferPos position) const return m_content[position]; } +void Buffer::begin_undo_group() +{ + assert(m_current_undo_group.empty()); + m_history.erase(m_history_cursor, m_history.end()); + m_history_cursor = m_history.end(); +} + +void Buffer::end_undo_group() +{ + m_history.push_back(m_current_undo_group); + m_history_cursor = m_history.end(); + + m_current_undo_group.clear(); +} + +Buffer::Modification Buffer::Modification::inverse() const +{ + Modification::Type inverse_type; + switch (type) + { + case Modification::Insert: inverse_type = Erase; break; + case Modification::Erase: inverse_type = Insert; break; + default: assert(false); + } + return Modification(inverse_type, position, content); +} + +bool Buffer::undo() +{ + if (m_history_cursor == m_history.begin()) + return false; + + --m_history_cursor; + + for (const Modification& modification : reversed(*m_history_cursor)) + replay_modification(modification.inverse()); +} + +bool Buffer::redo() +{ + if (m_history_cursor == m_history.end()) + return false; + + for (const Modification& modification : *m_history_cursor) + replay_modification(modification); + + ++m_history_cursor; +} + +void Buffer::replay_modification(const Modification& modification) +{ + switch (modification.type) + { + case Modification::Insert: + do_insert(modification.position, modification.content); + break; + case Modification::Erase: + { + BufferIterator begin = modification.position; + BufferIterator end = begin + modification.content.size(); + assert(string(begin, end) == modification.content); + do_erase(begin, end); + break; + } + default: + assert(false); + } +} + +void Buffer::append_modification(Modification&& modification) +{ + m_current_undo_group.push_back(modification); +} + } |
