Move insert/erase methods from normal.cc to member functions in SelectionList

It does look like the Editor class is attempting a sneaky comeback...
This commit is contained in:
Maxime Coste 2014-05-25 20:28:32 +01:00
parent 0a060b62a2
commit b2621ca140
6 changed files with 136 additions and 144 deletions

View File

@ -22,86 +22,6 @@
namespace Kakoune namespace Kakoune
{ {
void erase(Buffer& buffer, SelectionList& selections)
{
for (auto& sel : reversed(selections))
{
erase(buffer, sel);
}
selections.update();
selections.avoid_eol();
buffer.check_invariant();
}
template<InsertMode mode>
BufferIterator prepare_insert(Buffer& buffer, const Selection& sel)
{
switch (mode)
{
case InsertMode::Insert:
return buffer.iterator_at(sel.min());
case InsertMode::Replace:
return Kakoune::erase(buffer, sel);
case InsertMode::Append:
{
// special case for end of lines, append to current line instead
auto pos = buffer.iterator_at(sel.max());
return *pos == '\n' ? pos : utf8::next(pos);
}
case InsertMode::InsertAtLineBegin:
return buffer.iterator_at(sel.min().line);
case InsertMode::AppendAtLineEnd:
return buffer.iterator_at({sel.max().line, buffer[sel.max().line].length() - 1});
case InsertMode::InsertAtNextLineBegin:
return buffer.iterator_at(sel.max().line+1);
case InsertMode::OpenLineBelow:
return buffer.insert(buffer.iterator_at(sel.max().line + 1), "\n");
case InsertMode::OpenLineAbove:
return buffer.insert(buffer.iterator_at(sel.min().line), "\n");
}
kak_assert(false);
return {};
}
template<InsertMode mode>
void insert(Buffer& buffer, SelectionList& selections, memoryview<String> strings)
{
if (strings.empty())
return;
selections.update();
for (size_t i = 0; i < selections.size(); ++i)
{
size_t index = selections.size() - 1 - i;
auto& sel = selections[index];
auto pos = prepare_insert<mode>(buffer, sel);
const String& str = strings[std::min(index, strings.size()-1)];
pos = buffer.insert(pos, str);
if (mode == InsertMode::Replace)
{
if (pos == buffer.end())
--pos;
sel.anchor() = pos.coord();
sel.cursor() = (str.empty() ?
pos : pos + str.byte_count_to(str.char_length() - 1)).coord();
// update following selections
auto changes = compute_modifications(buffer, selections.timestamp());
for (size_t j = index+1; j < selections.size(); ++j)
{
auto& sel = selections[j];
sel.anchor() = update_pos(changes, sel.anchor());
sel.cursor() = update_pos(changes, sel.cursor());
}
selections.update_timestamp();
}
}
selections.update();
selections.avoid_eol();
selections.check_invariant();
buffer.check_invariant();
}
using namespace std::placeholders; using namespace std::placeholders;
enum class SelectMode enum class SelectMode
@ -172,7 +92,7 @@ constexpr Select<mode, T> make_select(T func)
} }
template<SelectMode mode = SelectMode::Replace> template<SelectMode mode = SelectMode::Replace>
void select_coord(const Buffer& buffer, ByteCoord coord, SelectionList& selections) void select_coord(Buffer& buffer, ByteCoord coord, SelectionList& selections)
{ {
coord = buffer.clamp(coord); coord = buffer.clamp(coord);
if (mode == SelectMode::Replace) if (mode == SelectMode::Replace)
@ -405,7 +325,7 @@ void replace_with_char(Context& context, int)
CharCount count = char_length(buffer, sel); CharCount count = char_length(buffer, sel);
strings.emplace_back(key.key, count); strings.emplace_back(key.key, count);
} }
insert<InsertMode::Replace>(buffer, selections, strings); selections.insert(strings, InsertMode::Replace);
}, "replace with char", "enter char to replace with\n"); }, "replace with char", "enter char to replace with\n");
} }
@ -428,7 +348,7 @@ void for_each_char(Context& context, int)
for (auto& c : sel) for (auto& c : sel)
c = func(c); c = func(c);
} }
insert<InsertMode::Replace>(context.buffer(), context.selections(), sels); context.selections().insert(sels, InsertMode::Replace);
} }
void command(Context& context, int) void command(Context& context, int)
@ -493,7 +413,7 @@ void pipe(Context& context, int)
strings.push_back(str); strings.push_back(str);
} }
ScopedEdition edition(context); ScopedEdition edition(context);
insert<mode>(buffer, selections, strings); selections.insert(strings, mode);
}); });
} }
@ -543,7 +463,7 @@ void erase_selections(Context& context, int)
{ {
RegisterManager::instance()['"'] = context.selections_content(); RegisterManager::instance()['"'] = context.selections_content();
ScopedEdition edition(context); ScopedEdition edition(context);
erase(context.buffer(), context.selections()); context.selections().erase();
} }
void cat_erase_selections(Context& context, int) void cat_erase_selections(Context& context, int)
@ -553,7 +473,7 @@ void cat_erase_selections(Context& context, int)
for (auto& sel : sels) for (auto& sel : sels)
str += sel; str += sel;
RegisterManager::instance()['"'] = memoryview<String>(str); RegisterManager::instance()['"'] = memoryview<String>(str);
erase(context.buffer(), context.selections()); context.selections().erase();
} }
@ -587,10 +507,8 @@ void paste(Context& context, int)
} }
} }
ScopedEdition edition(context); ScopedEdition edition(context);
if (linewise) context.selections().insert(strings,
insert<adapt_for_linewise(mode)>(context.buffer(), context.selections(), strings); linewise ? adapt_for_linewise(mode) : mode);
else
insert<mode>(context.buffer(), context.selections(), strings);
} }
template<typename T> template<typename T>
@ -717,7 +635,7 @@ void select_regex(Context& context, int)
else else
RegisterManager::instance()['/'] = String{ex.str()}; RegisterManager::instance()['/'] = String{ex.str()};
if (not ex.empty() and not ex.str().empty()) if (not ex.empty() and not ex.str().empty())
select_all_matches(context.buffer(), context.selections(), ex); select_all_matches(context.selections(), ex);
}); });
} }
@ -729,7 +647,7 @@ void split_regex(Context& context, int)
else else
RegisterManager::instance()['/'] = String{ex.str()}; RegisterManager::instance()['/'] = String{ex.str()};
if (not ex.empty() and not ex.str().empty()) if (not ex.empty() and not ex.str().empty())
split_selections(context.buffer(), context.selections(), ex); split_selections(context.selections(), ex);
}); });
} }
@ -775,7 +693,7 @@ void join_select_spaces(Context& context, int)
return; return;
context.selections() = selections; context.selections() = selections;
ScopedEdition edition(context); ScopedEdition edition(context);
insert<InsertMode::Replace>(buffer, context.selections(), " "_str); context.selections().insert(" "_str, InsertMode::Replace);
} }
void join(Context& context, int param) void join(Context& context, int param)
@ -853,7 +771,7 @@ void indent(Context& context, int)
{ {
ScopedEdition edition(context); ScopedEdition edition(context);
SelectionList selections{buffer, std::move(sels)}; SelectionList selections{buffer, std::move(sels)};
insert<InsertMode::Insert>(buffer, selections, indent); selections.insert(indent, InsertMode::Insert);
} }
} }
@ -898,7 +816,7 @@ void deindent(Context& context, int)
{ {
ScopedEdition edition(context); ScopedEdition edition(context);
SelectionList selections{context.buffer(), std::move(sels)}; SelectionList selections{context.buffer(), std::move(sels)};
erase(context.buffer(), selections); selections.erase();
} }
} }
@ -1008,7 +926,7 @@ void rotate_selections_content(Context& context, int group)
std::rotate(it, end-count, end); std::rotate(it, end-count, end);
it = end; it = end;
} }
insert<InsertMode::Replace>(context.buffer(), context.selections(), strings); context.selections().insert(strings, InsertMode::Replace);
context.selections().rotate_main(count); context.selections().rotate_main(count);
} }
@ -1236,7 +1154,7 @@ void spaces_to_tabs(Context& context, int ts)
} }
} }
static boost::optional<SelectionList> compute_modified_ranges(const Buffer& buffer, size_t timestamp) static boost::optional<SelectionList> compute_modified_ranges(Buffer& buffer, size_t timestamp)
{ {
std::vector<Selection> ranges; std::vector<Selection> ranges;
for (auto& change : buffer.changes_since(timestamp)) for (auto& change : buffer.changes_since(timestamp))
@ -1402,12 +1320,12 @@ KeyMap keymap =
{ '.', repeat_last_insert }, { '.', repeat_last_insert },
{ '%', [](Context& context, int) { select_whole_buffer(context.buffer(), context.selections()); } }, { '%', [](Context& context, int) { select_whole_buffer(context.selections()); } },
{ ':', command }, { ':', command },
{ '|', pipe<InsertMode::Replace> }, { '|', pipe<InsertMode::Replace> },
{ alt('|'), pipe<InsertMode::Append> }, { alt('|'), pipe<InsertMode::Append> },
{ ' ', [](Context& context, int count) { if (count == 0) clear_selections(context.buffer(), context.selections()); { ' ', [](Context& context, int count) { if (count == 0) clear_selections(context.selections());
else keep_selection(context.selections(), count-1); } }, else keep_selection(context.selections(), count-1); } },
{ alt(' '), [](Context& context, int count) { if (count == 0) flip_selections(context.selections()); { alt(' '), [](Context& context, int count) { if (count == 0) flip_selections(context.selections());
else remove_selection(context.selections(), count-1); } }, else remove_selection(context.selections(), count-1); } },

View File

@ -11,18 +11,6 @@ namespace Kakoune
class Context; class Context;
enum class InsertMode : unsigned
{
Insert,
Append,
Replace,
InsertAtLineBegin,
InsertAtNextLineBegin,
AppendAtLineEnd,
OpenLineBelow,
OpenLineAbove
};
using KeyMap = std::unordered_map<Key, std::function<void (Context& context, int param)>>; using KeyMap = std::unordered_map<Key, std::function<void (Context& context, int param)>>;
extern KeyMap keymap; extern KeyMap keymap;

View File

@ -2,6 +2,7 @@
#include "utf8.hh" #include "utf8.hh"
#include "modification.hh" #include "modification.hh"
#include "buffer_utils.hh"
namespace Kakoune namespace Kakoune
{ {
@ -102,24 +103,24 @@ struct UpdateErase
} }
SelectionList::SelectionList(const Buffer& buffer, Selection s, size_t timestamp) SelectionList::SelectionList(Buffer& buffer, Selection s, size_t timestamp)
: m_buffer(&buffer), m_selections({ s }), m_timestamp(timestamp) : m_buffer(&buffer), m_selections({ s }), m_timestamp(timestamp)
{ {
check_invariant(); check_invariant();
} }
SelectionList::SelectionList(const Buffer& buffer, Selection s) SelectionList::SelectionList(Buffer& buffer, Selection s)
: SelectionList(buffer, s, buffer.timestamp()) : SelectionList(buffer, s, buffer.timestamp())
{} {}
SelectionList::SelectionList(const Buffer& buffer, std::vector<Selection> s, size_t timestamp) SelectionList::SelectionList(Buffer& buffer, std::vector<Selection> s, size_t timestamp)
: m_buffer(&buffer), m_selections(std::move(s)), m_timestamp(timestamp) : m_buffer(&buffer), m_selections(std::move(s)), m_timestamp(timestamp)
{ {
kak_assert(size() > 0); kak_assert(size() > 0);
check_invariant(); check_invariant();
} }
SelectionList::SelectionList(const Buffer& buffer, std::vector<Selection> s) SelectionList::SelectionList(Buffer& buffer, std::vector<Selection> s)
: SelectionList(buffer, std::move(s), buffer.timestamp()) : SelectionList(buffer, std::move(s), buffer.timestamp())
{} {}
@ -221,4 +222,83 @@ void SelectionList::avoid_eol()
_avoid_eol(buffer(), sel); _avoid_eol(buffer(), sel);
} }
void SelectionList::erase()
{
for (auto& sel : reversed(m_selections))
{
Kakoune::erase(*m_buffer, sel);
}
update();
avoid_eol();
m_buffer->check_invariant();
}
BufferIterator prepare_insert(Buffer& buffer, const Selection& sel, InsertMode mode)
{
switch (mode)
{
case InsertMode::Insert:
return buffer.iterator_at(sel.min());
case InsertMode::Replace:
return erase(buffer, sel);
case InsertMode::Append:
{
// special case for end of lines, append to current line instead
auto pos = buffer.iterator_at(sel.max());
return *pos == '\n' ? pos : utf8::next(pos);
}
case InsertMode::InsertAtLineBegin:
return buffer.iterator_at(sel.min().line);
case InsertMode::AppendAtLineEnd:
return buffer.iterator_at({sel.max().line, buffer[sel.max().line].length() - 1});
case InsertMode::InsertAtNextLineBegin:
return buffer.iterator_at(sel.max().line+1);
case InsertMode::OpenLineBelow:
return buffer.insert(buffer.iterator_at(sel.max().line + 1), "\n");
case InsertMode::OpenLineAbove:
return buffer.insert(buffer.iterator_at(sel.min().line), "\n");
}
kak_assert(false);
return {};
}
void SelectionList::insert(memoryview<String> strings, InsertMode mode)
{
if (strings.empty())
return;
update();
for (size_t i = 0; i < m_selections.size(); ++i)
{
size_t index = m_selections.size() - 1 - i;
auto& sel = m_selections[index];
auto pos = prepare_insert(*m_buffer, sel, mode);
const String& str = strings[std::min(index, strings.size()-1)];
pos = m_buffer->insert(pos, str);
if (mode == InsertMode::Replace)
{
if (pos == m_buffer->end())
--pos;
sel.anchor() = pos.coord();
sel.cursor() = (str.empty() ?
pos : pos + str.byte_count_to(str.char_length() - 1)).coord();
// update following selections
auto changes = compute_modifications(*m_buffer, timestamp());
for (size_t j = index+1; j < m_selections.size(); ++j)
{
auto& sel = m_selections[j];
sel.anchor() = update_pos(changes, sel.anchor());
sel.cursor() = update_pos(changes, sel.cursor());
}
update_timestamp();
}
}
update();
avoid_eol();
check_invariant();
m_buffer->check_invariant();
}
} }

View File

@ -55,12 +55,24 @@ static bool compare_selections(const Selection& lhs, const Selection& rhs)
return lhs.min() < rhs.min(); return lhs.min() < rhs.min();
} }
enum class InsertMode : unsigned
{
Insert,
Append,
Replace,
InsertAtLineBegin,
InsertAtNextLineBegin,
AppendAtLineEnd,
OpenLineBelow,
OpenLineAbove
};
struct SelectionList struct SelectionList
{ {
SelectionList(const Buffer& buffer, Selection s); SelectionList(Buffer& buffer, Selection s);
SelectionList(const Buffer& buffer, Selection s, size_t timestamp); SelectionList(Buffer& buffer, Selection s, size_t timestamp);
SelectionList(const Buffer& buffer, std::vector<Selection> s); SelectionList(Buffer& buffer, std::vector<Selection> s);
SelectionList(const Buffer& buffer, std::vector<Selection> s, size_t timestamp); SelectionList(Buffer& buffer, std::vector<Selection> s, size_t timestamp);
void update(); void update();
@ -103,17 +115,7 @@ struct SelectionList
const_iterator begin() const { return m_selections.begin(); } const_iterator begin() const { return m_selections.begin(); }
const_iterator end() const { return m_selections.end(); } const_iterator end() const { return m_selections.end(); }
template<typename... Args> void remove(size_t index) { m_selections.erase(begin() + index); }
iterator insert(Args... args)
{
return m_selections.insert(std::forward<Args>(args)...);
}
template<typename... Args>
iterator erase(Args... args)
{
return m_selections.erase(std::forward<Args>(args)...);
}
size_t size() const { return m_selections.size(); } size_t size() const { return m_selections.size(); }
@ -140,22 +142,25 @@ struct SelectionList
(*this)[i] = std::move((*this)[j]); (*this)[i] = std::move((*this)[j]);
} }
} }
erase(begin() + i + 1, end()); m_selections.erase(begin() + i + 1, end());
kak_assert(std::is_sorted(begin(), end(), compare_selections)); kak_assert(std::is_sorted(begin(), end(), compare_selections));
} }
void sort_and_merge_overlapping(); void sort_and_merge_overlapping();
const Buffer& buffer() const { return *m_buffer; } Buffer& buffer() const { return *m_buffer; }
size_t timestamp() const { return m_timestamp; } size_t timestamp() const { return m_timestamp; }
void update_timestamp() { m_timestamp = m_buffer->timestamp(); } void update_timestamp() { m_timestamp = m_buffer->timestamp(); }
void insert(memoryview<String> strings, InsertMode mode);
void erase();
private: private:
size_t m_main = 0; size_t m_main = 0;
std::vector<Selection> m_selections; std::vector<Selection> m_selections;
safe_ptr<const Buffer> m_buffer; safe_ptr<Buffer> m_buffer;
size_t m_timestamp; size_t m_timestamp;
}; };

View File

@ -429,15 +429,16 @@ Selection trim_partial_lines(const Buffer& buffer, const Selection& selection)
return Selection(first.coord(), last.coord()); return Selection(first.coord(), last.coord());
} }
void select_whole_buffer(const Buffer& buffer, SelectionList& selections) void select_whole_buffer(SelectionList& selections)
{ {
auto& buffer = selections.buffer();
selections = SelectionList{ buffer, Selection({0,0}, buffer.back_coord()) }; selections = SelectionList{ buffer, Selection({0,0}, buffer.back_coord()) };
} }
void select_all_matches(const Buffer& buffer, SelectionList& selections, void select_all_matches(SelectionList& selections, const Regex& regex)
const Regex& regex)
{ {
std::vector<Selection> result; std::vector<Selection> result;
auto& buffer = selections.buffer();
for (auto& sel : selections) for (auto& sel : selections)
{ {
auto sel_end = utf8::next(buffer.iterator_at(sel.max())); auto sel_end = utf8::next(buffer.iterator_at(sel.max()));
@ -466,10 +467,10 @@ void select_all_matches(const Buffer& buffer, SelectionList& selections,
selections = std::move(result); selections = std::move(result);
} }
void split_selections(const Buffer& buffer, SelectionList& selections, void split_selections(SelectionList& selections, const Regex& regex)
const Regex& regex)
{ {
std::vector<Selection> result; std::vector<Selection> result;
auto& buffer = selections.buffer();
for (auto& sel : selections) for (auto& sel : selections)
{ {
auto begin = buffer.iterator_at(sel.min()); auto begin = buffer.iterator_at(sel.min());

View File

@ -9,14 +9,14 @@
namespace Kakoune namespace Kakoune
{ {
inline void clear_selections(const Buffer& buffer, SelectionList& selections) inline void clear_selections(SelectionList& selections)
{ {
auto& sel = selections.main(); auto& sel = selections.main();
auto& pos = sel.cursor(); auto& pos = sel.cursor();
sel.anchor() = pos; sel.anchor() = pos;
selections.avoid_eol(); selections.avoid_eol();
selections = SelectionList{ buffer, std::move(sel) }; selections = SelectionList{ selections.buffer(), std::move(sel) };
} }
inline void flip_selections(SelectionList& selections) inline void flip_selections(SelectionList& selections)
@ -41,7 +41,7 @@ inline void remove_selection(SelectionList& selections, int index)
if (selections.size() > 1 and index < selections.size()) if (selections.size() > 1 and index < selections.size())
{ {
size_t real_index = (index + selections.main_index() + 1) % selections.size(); size_t real_index = (index + selections.main_index() + 1) % selections.size();
selections.erase(selections.begin() + real_index); selections.remove(real_index);
size_t main_index = selections.main_index(); size_t main_index = selections.main_index();
if (real_index <= main_index) if (real_index <= main_index)
selections.set_main_index((main_index > 0 ? main_index selections.set_main_index((main_index > 0 ? main_index
@ -207,7 +207,7 @@ Selection select_whole_paragraph(const Buffer& buffer, const Selection& selectio
Selection select_whole_indent(const Buffer& buffer, const Selection& selection, Selection select_whole_indent(const Buffer& buffer, const Selection& selection,
ObjectFlags flags); ObjectFlags flags);
Selection select_whole_lines(const Buffer& buffer, const Selection& selection); Selection select_whole_lines(const Buffer& buffer, const Selection& selection);
void select_whole_buffer(const Buffer& buffer, SelectionList& selections); void select_whole_buffer(SelectionList& selections);
Selection trim_partial_lines(const Buffer& buffer, const Selection& selection); Selection trim_partial_lines(const Buffer& buffer, const Selection& selection);
enum Direction { Forward, Backward }; enum Direction { Forward, Backward };
@ -266,10 +266,10 @@ Selection find_next_match(const Buffer& buffer, const Selection& sel, const Rege
return {begin.coord(), end.coord(), std::move(captures)}; return {begin.coord(), end.coord(), std::move(captures)};
} }
void select_all_matches(const Buffer& buffer, SelectionList& selections, void select_all_matches(SelectionList& selections,
const Regex& regex); const Regex& regex);
void split_selections(const Buffer& buffer, SelectionList& selections, void split_selections(SelectionList& selections,
const Regex& separator_regex); const Regex& separator_regex);
using CodepointPair = std::pair<Codepoint, Codepoint>; using CodepointPair = std::pair<Codepoint, Codepoint>;