Editor refactoring, merge undo and batch management

This commit is contained in:
Maxime Coste 2012-02-07 23:41:10 +00:00
parent 333e87dedd
commit 04a37d8895
5 changed files with 45 additions and 94 deletions

View File

@ -6,24 +6,9 @@
namespace Kakoune namespace Kakoune
{ {
namespace
{
struct scoped_undo_group
{
scoped_undo_group(Buffer& buffer)
: m_buffer(buffer) { m_buffer.begin_undo_group(); }
~scoped_undo_group() { m_buffer.end_undo_group(); }
private:
Buffer& m_buffer;
};
}
Editor::Editor(Buffer& buffer) Editor::Editor(Buffer& buffer)
: m_buffer(buffer), : m_buffer(buffer),
m_batch_level(0) m_edition_level(0)
{ {
m_selections.push_back(SelectionList()); m_selections.push_back(SelectionList());
selections().push_back(Selection(buffer.begin(), buffer.begin())); selections().push_back(Selection(buffer.begin(), buffer.begin()));
@ -31,69 +16,30 @@ Editor::Editor(Buffer& buffer)
void Editor::erase() void Editor::erase()
{ {
if (not is_in_batch()) scoped_edition edition(*this);
{
scoped_undo_group undo_group(m_buffer);
erase_noundo();
}
else
erase_noundo();
}
void Editor::erase_noundo()
{
check_invariant();
for (auto& sel : selections()) for (auto& sel : selections())
m_buffer.modify(Modification::make_erase(sel.begin(), sel.end())); m_buffer.modify(Modification::make_erase(sel.begin(), sel.end()));
} }
void Editor::insert(const String& string) void Editor::insert(const String& string)
{ {
if (not is_in_batch()) scoped_edition edition(*this);
{
scoped_undo_group undo_group(m_buffer);
insert_noundo(string);
}
else
insert_noundo(string);
}
void Editor::insert_noundo(const String& string)
{
for (auto& sel : selections()) for (auto& sel : selections())
m_buffer.modify(Modification::make_insert(sel.begin(), string)); m_buffer.modify(Modification::make_insert(sel.begin(), string));
} }
void Editor::append(const String& string) void Editor::append(const String& string)
{ {
if (not is_in_batch()) scoped_edition edition(*this);
{
scoped_undo_group undo_group(m_buffer);
append_noundo(string);
}
else
append_noundo(string);
}
void Editor::append_noundo(const String& string)
{
for (auto& sel : selections()) for (auto& sel : selections())
m_buffer.modify(Modification::make_insert(sel.end(), string)); m_buffer.modify(Modification::make_insert(sel.end(), string));
} }
void Editor::replace(const std::string& string) void Editor::replace(const std::string& string)
{ {
if (not is_in_batch()) scoped_edition edition(*this);
{ erase();
scoped_undo_group undo_group(m_buffer); insert(string);
erase_noundo();
insert_noundo(string);
}
else
{
erase_noundo();
insert_noundo(string);
}
} }
void Editor::push_selections() void Editor::push_selections()
@ -236,35 +182,30 @@ CandidateList Editor::complete_filterid(const std::string& prefix,
return m_filters.complete_id<str_to_str>(prefix, cursor_pos); return m_filters.complete_id<str_to_str>(prefix, cursor_pos);
} }
void Editor::begin_batch() void Editor::begin_edition()
{ {
++m_batch_level; ++m_edition_level;
if (m_batch_level == 1) if (m_edition_level == 1)
{
m_buffer.begin_undo_group(); m_buffer.begin_undo_group();
on_begin_batch();
}
} }
void Editor::end_batch() void Editor::end_edition()
{ {
assert(m_batch_level > 0); assert(m_edition_level > 0);
if (m_batch_level == 1) if (m_edition_level == 1)
{
on_end_batch();
m_buffer.end_undo_group(); m_buffer.end_undo_group();
}
--m_batch_level; --m_edition_level;
} }
IncrementalInserter::IncrementalInserter(Editor& editor, Mode mode) IncrementalInserter::IncrementalInserter(Editor& editor, Mode mode)
: m_editor(editor) : m_editor(editor), m_edition(editor)
{ {
m_editor.begin_batch(); m_editor.on_incremental_insertion_begin();
if (mode == Mode::Change) if (mode == Mode::Change)
editor.erase_noundo(); editor.erase();
for (auto& sel : m_editor.selections()) for (auto& sel : m_editor.selections())
{ {
@ -297,7 +238,7 @@ IncrementalInserter::IncrementalInserter(Editor& editor, Mode mode)
IncrementalInserter::~IncrementalInserter() IncrementalInserter::~IncrementalInserter()
{ {
move_cursors(BufferCoord(0, -1)); move_cursors(BufferCoord(0, -1));
m_editor.end_batch(); m_editor.on_incremental_insertion_end();
} }
void IncrementalInserter::apply(Modification&& modification) const void IncrementalInserter::apply(Modification&& modification) const

View File

@ -55,31 +55,40 @@ public:
CandidateList complete_filterid(const std::string& prefix, CandidateList complete_filterid(const std::string& prefix,
size_t cursor_pos = std::string::npos); size_t cursor_pos = std::string::npos);
void begin_batch(); bool is_editing() const { return m_edition_level!= 0; }
void end_batch();
bool is_in_batch() const { return m_batch_level != 0; }
private: private:
void erase_noundo(); friend class scoped_edition;
void insert_noundo(const String& string); void begin_edition();
void append_noundo(const String& string); void end_edition();
int m_edition_level;
SelectionList& selections() { return m_selections.back(); } SelectionList& selections() { return m_selections.back(); }
void check_invariant() const; void check_invariant() const;
friend class IncrementalInserter; friend class IncrementalInserter;
int m_batch_level; virtual void on_incremental_insertion_begin() {}
virtual void on_incremental_insertion_end() {}
virtual void on_begin_batch() {}
virtual void on_end_batch() {}
Buffer& m_buffer; Buffer& m_buffer;
std::vector<SelectionList> m_selections; std::vector<SelectionList> m_selections;
idvaluemap<std::string, FilterFunc> m_filters; idvaluemap<std::string, FilterFunc> m_filters;
}; };
struct scoped_edition
{
scoped_edition(Editor& editor)
: m_editor(editor)
{ m_editor.begin_edition(); }
~scoped_edition()
{ m_editor.end_edition(); }
private:
Editor& m_editor;
};
// An IncrementalInserter manage insert mode // An IncrementalInserter manage insert mode
class IncrementalInserter class IncrementalInserter
{ {
@ -109,6 +118,7 @@ private:
void apply(Modification&& modification) const; void apply(Modification&& modification) const;
Editor& m_editor; Editor& m_editor;
scoped_edition m_edition;
}; };
} }

View File

@ -1054,8 +1054,8 @@ void exec_keys(const KeyList& keys,
Editor& editor = context.has_window() ? static_cast<Editor&>(context.window()) Editor& editor = context.has_window() ? static_cast<Editor&>(context.window())
: static_cast<Editor&>(batch_editor); : static_cast<Editor&>(batch_editor);
editor.begin_batch();
auto end_batch = on_scope_end([&]() { editor.end_batch(); }); scoped_edition edition(editor);
int count = 0; int count = 0;
while(pos < keys.size()) while(pos < keys.size())

View File

@ -154,12 +154,12 @@ std::string Window::status_line() const
oss << " [+]"; oss << " [+]";
oss << " -- " << cursor.line+1 << "," << cursor.column+1 oss << " -- " << cursor.line+1 << "," << cursor.column+1
<< " -- " << selections().size() << " sel -- "; << " -- " << selections().size() << " sel -- ";
if (is_in_batch()) if (is_editing())
oss << "[Insert]"; oss << "[Insert]";
return oss.str(); return oss.str();
} }
void Window::on_end_batch() void Window::on_incremental_insertion_end()
{ {
push_selections(); push_selections();
hooks_manager().run_hook("InsertEnd", "", Context(*this)); hooks_manager().run_hook("InsertEnd", "", Context(*this));

View File

@ -50,7 +50,7 @@ private:
Window(Buffer& buffer); Window(Buffer& buffer);
Window(const Window&) = delete; Window(const Window&) = delete;
void on_end_batch(); void on_incremental_insertion_end();
void scroll_to_keep_cursor_visible_ifn(); void scroll_to_keep_cursor_visible_ifn();