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
{
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;
enum class SelectMode
@ -172,7 +92,7 @@ constexpr Select<mode, T> make_select(T func)
}
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);
if (mode == SelectMode::Replace)
@ -405,7 +325,7 @@ void replace_with_char(Context& context, int)
CharCount count = char_length(buffer, sel);
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");
}
@ -428,7 +348,7 @@ void for_each_char(Context& context, int)
for (auto& c : sel)
c = func(c);
}
insert<InsertMode::Replace>(context.buffer(), context.selections(), sels);
context.selections().insert(sels, InsertMode::Replace);
}
void command(Context& context, int)
@ -493,7 +413,7 @@ void pipe(Context& context, int)
strings.push_back(str);
}
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();
ScopedEdition edition(context);
erase(context.buffer(), context.selections());
context.selections().erase();
}
void cat_erase_selections(Context& context, int)
@ -553,7 +473,7 @@ void cat_erase_selections(Context& context, int)
for (auto& sel : sels)
str += sel;
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);
if (linewise)
insert<adapt_for_linewise(mode)>(context.buffer(), context.selections(), strings);
else
insert<mode>(context.buffer(), context.selections(), strings);
context.selections().insert(strings,
linewise ? adapt_for_linewise(mode) : mode);
}
template<typename T>
@ -717,7 +635,7 @@ void select_regex(Context& context, int)
else
RegisterManager::instance()['/'] = String{ex.str()};
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
RegisterManager::instance()['/'] = String{ex.str()};
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;
context.selections() = selections;
ScopedEdition edition(context);
insert<InsertMode::Replace>(buffer, context.selections(), " "_str);
context.selections().insert(" "_str, InsertMode::Replace);
}
void join(Context& context, int param)
@ -853,7 +771,7 @@ void indent(Context& context, int)
{
ScopedEdition edition(context);
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);
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);
it = end;
}
insert<InsertMode::Replace>(context.buffer(), context.selections(), strings);
context.selections().insert(strings, InsertMode::Replace);
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;
for (auto& change : buffer.changes_since(timestamp))
@ -1402,12 +1320,12 @@ KeyMap keymap =
{ '.', repeat_last_insert },
{ '%', [](Context& context, int) { select_whole_buffer(context.buffer(), context.selections()); } },
{ '%', [](Context& context, int) { select_whole_buffer(context.selections()); } },
{ ':', command },
{ '|', pipe<InsertMode::Replace> },
{ 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); } },
{ alt(' '), [](Context& context, int count) { if (count == 0) flip_selections(context.selections());
else remove_selection(context.selections(), count-1); } },

View File

@ -11,18 +11,6 @@ namespace Kakoune
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)>>;
extern KeyMap keymap;

View File

@ -2,6 +2,7 @@
#include "utf8.hh"
#include "modification.hh"
#include "buffer_utils.hh"
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)
{
check_invariant();
}
SelectionList::SelectionList(const Buffer& buffer, Selection s)
SelectionList::SelectionList(Buffer& buffer, Selection s)
: 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)
{
kak_assert(size() > 0);
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())
{}
@ -221,4 +222,83 @@ void SelectionList::avoid_eol()
_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();
}
enum class InsertMode : unsigned
{
Insert,
Append,
Replace,
InsertAtLineBegin,
InsertAtNextLineBegin,
AppendAtLineEnd,
OpenLineBelow,
OpenLineAbove
};
struct SelectionList
{
SelectionList(const Buffer& buffer, Selection s);
SelectionList(const Buffer& buffer, Selection s, size_t timestamp);
SelectionList(const Buffer& buffer, std::vector<Selection> s);
SelectionList(const Buffer& buffer, std::vector<Selection> s, size_t timestamp);
SelectionList(Buffer& buffer, Selection s);
SelectionList(Buffer& buffer, Selection s, size_t timestamp);
SelectionList(Buffer& buffer, std::vector<Selection> s);
SelectionList(Buffer& buffer, std::vector<Selection> s, size_t timestamp);
void update();
@ -103,17 +115,7 @@ struct SelectionList
const_iterator begin() const { return m_selections.begin(); }
const_iterator end() const { return m_selections.end(); }
template<typename... Args>
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)...);
}
void remove(size_t index) { m_selections.erase(begin() + index); }
size_t size() const { return m_selections.size(); }
@ -140,22 +142,25 @@ struct SelectionList
(*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));
}
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; }
void update_timestamp() { m_timestamp = m_buffer->timestamp(); }
void insert(memoryview<String> strings, InsertMode mode);
void erase();
private:
size_t m_main = 0;
std::vector<Selection> m_selections;
safe_ptr<const Buffer> m_buffer;
safe_ptr<Buffer> m_buffer;
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());
}
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()) };
}
void select_all_matches(const Buffer& buffer, SelectionList& selections,
const Regex& regex)
void select_all_matches(SelectionList& selections, const Regex& regex)
{
std::vector<Selection> result;
auto& buffer = selections.buffer();
for (auto& sel : selections)
{
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);
}
void split_selections(const Buffer& buffer, SelectionList& selections,
const Regex& regex)
void split_selections(SelectionList& selections, const Regex& regex)
{
std::vector<Selection> result;
auto& buffer = selections.buffer();
for (auto& sel : selections)
{
auto begin = buffer.iterator_at(sel.min());

View File

@ -9,14 +9,14 @@
namespace Kakoune
{
inline void clear_selections(const Buffer& buffer, SelectionList& selections)
inline void clear_selections(SelectionList& selections)
{
auto& sel = selections.main();
auto& pos = sel.cursor();
sel.anchor() = pos;
selections.avoid_eol();
selections = SelectionList{ buffer, std::move(sel) };
selections = SelectionList{ selections.buffer(), std::move(sel) };
}
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())
{
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();
if (real_index <= 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,
ObjectFlags flags);
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);
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)};
}
void select_all_matches(const Buffer& buffer, SelectionList& selections,
void select_all_matches(SelectionList& selections,
const Regex& regex);
void split_selections(const Buffer& buffer, SelectionList& selections,
void split_selections(SelectionList& selections,
const Regex& separator_regex);
using CodepointPair = std::pair<Codepoint, Codepoint>;