Store buffer undo/redo information in a tree instead of a vector
This commit is contained in:
parent
003cb8dfea
commit
2296b43299
|
@ -59,15 +59,17 @@ static void apply_options(OptionManager& options, const ParsedLines& parsed_line
|
||||||
options.get_local_option("BOM").set(parsed_lines.bom);
|
options.get_local_option("BOM").set(parsed_lines.bom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Buffer::HistoryNode::HistoryNode(HistoryNode* parent) : parent(parent) {}
|
||||||
|
|
||||||
Buffer::Buffer(String name, Flags flags, StringView data,
|
Buffer::Buffer(String name, Flags flags, StringView data,
|
||||||
timespec fs_timestamp)
|
timespec fs_timestamp)
|
||||||
: Scope(GlobalScope::instance()),
|
: Scope{GlobalScope::instance()},
|
||||||
m_name((flags & Flags::File) ? real_path(parse_filename(name)) : std::move(name)),
|
m_name{(flags & Flags::File) ? real_path(parse_filename(name)) : std::move(name)},
|
||||||
m_display_name((flags & Flags::File) ? compact_path(m_name) : m_name),
|
m_display_name{(flags & Flags::File) ? compact_path(m_name) : m_name},
|
||||||
m_flags(flags | Flags::NoUndo),
|
m_flags{flags | Flags::NoUndo},
|
||||||
m_history(), m_history_cursor(m_history.begin()),
|
m_history{nullptr}, m_history_cursor{&m_history},
|
||||||
m_last_save_undo_index(0),
|
m_last_save_history_cursor{&m_history},
|
||||||
m_fs_timestamp(fs_timestamp)
|
m_fs_timestamp{fs_timestamp}
|
||||||
{
|
{
|
||||||
ParsedLines parsed_lines = parse_lines(data);
|
ParsedLines parsed_lines = parse_lines(data);
|
||||||
|
|
||||||
|
@ -285,7 +287,7 @@ void Buffer::reload(StringView data, timespec fs_timestamp)
|
||||||
|
|
||||||
apply_options(options(), parsed_lines);
|
apply_options(options(), parsed_lines);
|
||||||
|
|
||||||
m_last_save_undo_index = m_history_cursor - m_history.begin();
|
m_last_save_history_cursor = m_history_cursor;
|
||||||
m_fs_timestamp = fs_timestamp;
|
m_fs_timestamp = fs_timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,41 +299,40 @@ void Buffer::commit_undo_group()
|
||||||
if (m_current_undo_group.empty())
|
if (m_current_undo_group.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_history.erase(m_history_cursor, m_history.end());
|
auto* node = new HistoryNode{m_history_cursor.get()};
|
||||||
|
node->undo_group = std::move(m_current_undo_group);
|
||||||
m_history.push_back(std::move(m_current_undo_group));
|
|
||||||
m_current_undo_group.clear();
|
m_current_undo_group.clear();
|
||||||
m_history_cursor = m_history.end();
|
|
||||||
|
|
||||||
if (m_history.size() < m_last_save_undo_index)
|
m_history_cursor->childs.emplace_back(node);
|
||||||
m_last_save_undo_index = -1;
|
m_history_cursor->redo_child = node;
|
||||||
|
m_history_cursor = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::undo()
|
bool Buffer::undo()
|
||||||
{
|
{
|
||||||
commit_undo_group();
|
commit_undo_group();
|
||||||
|
|
||||||
if (m_history_cursor == m_history.begin())
|
if (not m_history_cursor->parent)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
--m_history_cursor;
|
for (const Modification& modification : m_history_cursor->undo_group | reverse())
|
||||||
|
|
||||||
for (const Modification& modification : *m_history_cursor | reverse())
|
|
||||||
apply_modification(modification.inverse());
|
apply_modification(modification.inverse());
|
||||||
|
|
||||||
|
m_history_cursor = m_history_cursor->parent;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::redo()
|
bool Buffer::redo()
|
||||||
{
|
{
|
||||||
if (m_history_cursor == m_history.end())
|
if (not m_history_cursor->redo_child)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
kak_assert(m_current_undo_group.empty());
|
kak_assert(m_current_undo_group.empty());
|
||||||
|
|
||||||
for (const Modification& modification : *m_history_cursor)
|
m_history_cursor = m_history_cursor->redo_child.get();
|
||||||
apply_modification(modification);
|
|
||||||
|
|
||||||
++m_history_cursor;
|
for (const Modification& modification : m_history_cursor->undo_group)
|
||||||
|
apply_modification(modification);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,8 +506,7 @@ ByteCoord Buffer::replace(ByteCoord begin, ByteCoord end, StringView content)
|
||||||
|
|
||||||
bool Buffer::is_modified() const
|
bool Buffer::is_modified() const
|
||||||
{
|
{
|
||||||
size_t history_cursor_index = m_history_cursor - m_history.begin();
|
return m_history_cursor != m_last_save_history_cursor
|
||||||
return m_last_save_undo_index != history_cursor_index
|
|
||||||
or not m_current_undo_group.empty();
|
or not m_current_undo_group.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,9 +516,7 @@ void Buffer::notify_saved()
|
||||||
commit_undo_group();
|
commit_undo_group();
|
||||||
|
|
||||||
m_flags &= ~Flags::New;
|
m_flags &= ~Flags::New;
|
||||||
size_t history_cursor_index = m_history_cursor - m_history.begin();
|
m_last_save_history_cursor = m_history_cursor;
|
||||||
if (m_last_save_undo_index != history_cursor_index)
|
|
||||||
m_last_save_undo_index = history_cursor_index;
|
|
||||||
m_fs_timestamp = get_fs_timestamp(m_name);
|
m_fs_timestamp = get_fs_timestamp(m_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,9 +623,9 @@ void Buffer::run_hook_in_own_context(StringView hook_name, StringView param)
|
||||||
|
|
||||||
ByteCoord Buffer::last_modification_coord() const
|
ByteCoord Buffer::last_modification_coord() const
|
||||||
{
|
{
|
||||||
if (m_history.empty())
|
if (m_history_cursor.get() == &m_history)
|
||||||
return {};
|
return {};
|
||||||
return m_history.back().back().coord;
|
return m_history_cursor->undo_group.back().coord;
|
||||||
}
|
}
|
||||||
|
|
||||||
String Buffer::debug_description() const
|
String Buffer::debug_description() const
|
||||||
|
@ -636,10 +634,14 @@ String Buffer::debug_description() const
|
||||||
for (auto& line : m_lines)
|
for (auto& line : m_lines)
|
||||||
content_size += (int)line->strview().length();
|
content_size += (int)line->strview().length();
|
||||||
|
|
||||||
size_t additional_size = 0;
|
static size_t (*count_mem)(const HistoryNode&) = [](const HistoryNode& node) {
|
||||||
for (auto& undo_group : m_history)
|
size_t size = node.undo_group.size() * sizeof(Modification);
|
||||||
additional_size += undo_group.size() * sizeof(Modification);
|
for (auto& child : node.childs)
|
||||||
additional_size += m_changes.size() * sizeof(Change);
|
size += count_mem(*child);
|
||||||
|
return size;
|
||||||
|
};
|
||||||
|
const size_t additional_size = count_mem(m_history) +
|
||||||
|
m_changes.size() * sizeof(Change);
|
||||||
|
|
||||||
return format("{}\nFlags: {}{}{}{}\nUsed mem: content={} additional={}\n",
|
return format("{}\nFlags: {}{}{}{}\nUsed mem: content={} additional={}\n",
|
||||||
display_name(),
|
display_name(),
|
||||||
|
|
|
@ -241,13 +241,21 @@ private:
|
||||||
Flags m_flags;
|
Flags m_flags;
|
||||||
|
|
||||||
using UndoGroup = Vector<Modification, MemoryDomain::BufferMeta>;
|
using UndoGroup = Vector<Modification, MemoryDomain::BufferMeta>;
|
||||||
using History = Vector<UndoGroup, MemoryDomain::BufferMeta>;
|
|
||||||
|
|
||||||
History m_history;
|
struct HistoryNode : SafeCountable
|
||||||
History::iterator m_history_cursor;
|
{
|
||||||
UndoGroup m_current_undo_group;
|
HistoryNode(HistoryNode* parent);
|
||||||
|
|
||||||
size_t m_last_save_undo_index;
|
SafePtr<HistoryNode> parent;
|
||||||
|
UndoGroup undo_group;
|
||||||
|
Vector<std::unique_ptr<HistoryNode>> childs;
|
||||||
|
SafePtr<HistoryNode> redo_child;
|
||||||
|
};
|
||||||
|
|
||||||
|
HistoryNode m_history;
|
||||||
|
SafePtr<HistoryNode> m_history_cursor;
|
||||||
|
SafePtr<HistoryNode> m_last_save_history_cursor;
|
||||||
|
UndoGroup m_current_undo_group;
|
||||||
|
|
||||||
Vector<Change, MemoryDomain::BufferMeta> m_changes;
|
Vector<Change, MemoryDomain::BufferMeta> m_changes;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user