summaryrefslogtreecommitdiff
path: root/src/buffer.cc
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2011-09-06 18:49:32 +0000
committerMaxime Coste <frrrwww@gmail.com>2011-09-06 18:49:32 +0000
commit1e87fe17c6941ffc257a6afc22e6bf1f15342d19 (patch)
tree4572bcceae30022da09efee9cff2e22b3a0a918b /src/buffer.cc
parentf58cbf0b98f6fc36e1746107a5095d55eb1ffc94 (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.cc88
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);
+}
+
}