Iterate in reversed order on selections when modifing buffer
This way, update only needs to be called once everything is done as we always modify after the next selection to be used.
This commit is contained in:
parent
c3f4ef9ba2
commit
4e280977a2
|
@ -24,20 +24,6 @@ inline CharCount char_length(const Buffer& buffer, const Selection& range)
|
|||
utf8::next(buffer.iterator_at(range.max())));
|
||||
}
|
||||
|
||||
inline void avoid_eol(const Buffer& buffer, ByteCoord& coord)
|
||||
{
|
||||
const auto column = coord.column;
|
||||
const auto& line = buffer[coord.line];
|
||||
if (column != 0 and column == line.length() - 1)
|
||||
coord.column = line.byte_count_to(line.char_length() - 2);
|
||||
}
|
||||
|
||||
inline void avoid_eol(const Buffer& buffer, Selection& sel)
|
||||
{
|
||||
avoid_eol(buffer, sel.anchor());
|
||||
avoid_eol(buffer, sel.cursor());
|
||||
}
|
||||
|
||||
CharCount get_column(const Buffer& buffer,
|
||||
CharCount tabstop, ByteCoord coord);
|
||||
|
||||
|
|
|
@ -667,7 +667,7 @@ public:
|
|||
}
|
||||
else if (key == Key::Backspace)
|
||||
{
|
||||
for (auto& sel : context().selections())
|
||||
for (auto& sel : reversed(context().selections()))
|
||||
{
|
||||
if (sel.cursor() == ByteCoord{0,0})
|
||||
continue;
|
||||
|
@ -677,7 +677,7 @@ public:
|
|||
}
|
||||
else if (key == Key::Erase)
|
||||
{
|
||||
for (auto& sel : context().selections())
|
||||
for (auto& sel : reversed(context().selections()))
|
||||
{
|
||||
auto pos = buffer.iterator_at(sel.cursor());
|
||||
buffer.erase(pos, utf8::next(pos));
|
||||
|
@ -761,11 +761,12 @@ private:
|
|||
auto& selections = context().selections();
|
||||
for (size_t i = 0; i < selections.size(); ++i)
|
||||
{
|
||||
size_t index = std::min(i, strings.size()-1);
|
||||
buffer.insert(buffer.iterator_at(selections[i].cursor()),
|
||||
strings[index]);
|
||||
selections.update();
|
||||
size_t index = selections.size() - 1 - i;
|
||||
const String& str = strings[std::min(index, strings.size()-1)];
|
||||
buffer.insert(buffer.iterator_at(selections[index].cursor()),
|
||||
str);
|
||||
}
|
||||
selections.update();
|
||||
}
|
||||
|
||||
void insert(Codepoint key)
|
||||
|
@ -773,11 +774,9 @@ private:
|
|||
auto str = codepoint_to_str(key);
|
||||
auto& buffer = context().buffer();
|
||||
auto& selections = context().selections();
|
||||
for (auto& sel : selections)
|
||||
{
|
||||
for (auto& sel : reversed(selections))
|
||||
buffer.insert(buffer.iterator_at(sel.cursor()), str);
|
||||
selections.update();
|
||||
}
|
||||
selections.update();
|
||||
context().hooks().run_hook("InsertChar", str, context());
|
||||
}
|
||||
|
||||
|
@ -786,7 +785,7 @@ private:
|
|||
SelectionList& selections = context().selections();
|
||||
Buffer& buffer = context().buffer();
|
||||
|
||||
for (auto& sel : selections)
|
||||
for (auto& sel : reversed(selections))
|
||||
{
|
||||
ByteCoord anchor, cursor;
|
||||
switch (mode)
|
||||
|
@ -835,10 +834,10 @@ private:
|
|||
if (buffer.is_end(cursor))
|
||||
cursor = buffer.char_prev(cursor);
|
||||
|
||||
selections.update();
|
||||
sel.anchor() = anchor;
|
||||
sel.cursor() = cursor;
|
||||
}
|
||||
selections.update();
|
||||
if (mode == InsertMode::OpenLineBelow or mode == InsertMode::OpenLineAbove)
|
||||
{
|
||||
insert('\n');
|
||||
|
@ -859,12 +858,13 @@ private:
|
|||
|
||||
void on_disabled() override
|
||||
{
|
||||
for (auto& sel : context().selections())
|
||||
auto& selections = context().selections();
|
||||
for (auto& sel : selections)
|
||||
{
|
||||
if (m_insert_mode == InsertMode::Append and sel.cursor().column > 0)
|
||||
sel.cursor() = context().buffer().char_prev(sel.cursor());
|
||||
avoid_eol(context().buffer(), sel);
|
||||
}
|
||||
selections.avoid_eol();
|
||||
}
|
||||
|
||||
enum class Mode { Default, Complete, InsertReg };
|
||||
|
|
|
@ -23,13 +23,12 @@ namespace Kakoune
|
|||
|
||||
void erase(Buffer& buffer, SelectionList& selections)
|
||||
{
|
||||
for (auto& sel : selections)
|
||||
for (auto& sel : reversed(selections))
|
||||
{
|
||||
erase(buffer, sel);
|
||||
selections.update();
|
||||
avoid_eol(buffer, sel);
|
||||
}
|
||||
selections.check_invariant();
|
||||
selections.update();
|
||||
selections.avoid_eol();
|
||||
buffer.check_invariant();
|
||||
}
|
||||
|
||||
|
@ -66,20 +65,24 @@ BufferIterator prepare_insert(Buffer& buffer, const Selection& sel)
|
|||
template<InsertMode mode>
|
||||
void insert(Buffer& buffer, SelectionList& selections, const String& str)
|
||||
{
|
||||
for (auto& sel : selections)
|
||||
for (auto& sel : reversed(selections))
|
||||
{
|
||||
auto pos = prepare_insert<mode>(buffer, sel);
|
||||
pos = buffer.insert(pos, str);
|
||||
selections.update();
|
||||
if (mode == InsertMode::Replace and pos != buffer.end())
|
||||
if (mode == InsertMode::Replace)
|
||||
{
|
||||
if (pos == buffer.end())
|
||||
--pos;
|
||||
sel.anchor() = pos.coord();
|
||||
sel.cursor() = str.empty() ?
|
||||
pos.coord() : (pos + str.byte_count_to(str.char_length() - 1)).coord();
|
||||
}
|
||||
avoid_eol(buffer, sel);
|
||||
}
|
||||
selections.check_invariant();
|
||||
if (mode == InsertMode::Replace)
|
||||
selections.set_timestamp(buffer.timestamp());
|
||||
else
|
||||
selections.update();
|
||||
selections.avoid_eol();
|
||||
buffer.check_invariant();
|
||||
}
|
||||
|
||||
|
@ -90,20 +93,25 @@ void insert(Buffer& buffer, SelectionList& selections, memoryview<String> string
|
|||
return;
|
||||
for (size_t i = 0; i < selections.size(); ++i)
|
||||
{
|
||||
auto& sel = selections[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(i, strings.size()-1)];
|
||||
const String& str = strings[std::min(index, strings.size()-1)];
|
||||
pos = buffer.insert(pos, str);
|
||||
selections.update();
|
||||
if (mode == InsertMode::Replace and pos != buffer.end())
|
||||
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();
|
||||
}
|
||||
avoid_eol(buffer, sel);
|
||||
}
|
||||
selections.check_invariant();
|
||||
if (mode == InsertMode::Replace)
|
||||
selections.set_timestamp(buffer.timestamp());
|
||||
else
|
||||
selections.update();
|
||||
selections.avoid_eol();
|
||||
buffer.check_invariant();
|
||||
}
|
||||
|
||||
|
@ -1352,9 +1360,9 @@ void move(Context& context, int count)
|
|||
: context.buffer().offset_coord(sel.cursor(), offset);
|
||||
|
||||
sel.anchor() = mode == SelectMode::Extend ? sel.anchor() : cursor;
|
||||
sel.cursor() = cursor;
|
||||
avoid_eol(context.buffer(), sel);
|
||||
sel.cursor() = cursor;
|
||||
}
|
||||
selections.avoid_eol();
|
||||
selections.sort_and_merge_overlapping();
|
||||
}
|
||||
|
||||
|
|
|
@ -188,5 +188,31 @@ void SelectionList::sort_and_merge_overlapping()
|
|||
std::stable_sort(begin(), end(), compare_selections);
|
||||
merge_overlapping(overlaps);
|
||||
}
|
||||
namespace
|
||||
{
|
||||
|
||||
inline void _avoid_eol(const Buffer& buffer, ByteCoord& coord)
|
||||
{
|
||||
const auto column = coord.column;
|
||||
const auto& line = buffer[coord.line];
|
||||
if (column != 0 and column == line.length() - 1)
|
||||
coord.column = line.byte_count_to(line.char_length() - 2);
|
||||
}
|
||||
|
||||
|
||||
inline void _avoid_eol(const Buffer& buffer, Selection& sel)
|
||||
{
|
||||
_avoid_eol(buffer, sel.anchor());
|
||||
_avoid_eol(buffer, sel.cursor());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SelectionList::avoid_eol()
|
||||
{
|
||||
update();
|
||||
for (auto& sel : m_selections)
|
||||
_avoid_eol(buffer(), sel);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -73,6 +73,8 @@ struct SelectionList
|
|||
|
||||
void rotate_main(int count) { m_main = (m_main + count) % size(); }
|
||||
|
||||
void avoid_eol();
|
||||
|
||||
void push_back(const Selection& sel) { m_selections.push_back(sel); }
|
||||
void push_back(Selection&& sel) { m_selections.push_back(std::move(sel)); }
|
||||
|
||||
|
@ -92,6 +94,10 @@ struct SelectionList
|
|||
iterator begin() { return m_selections.begin(); }
|
||||
iterator end() { return m_selections.end(); }
|
||||
|
||||
using reverse_iterator = std::vector<Selection>::reverse_iterator;
|
||||
reverse_iterator rbegin() { return m_selections.rbegin(); }
|
||||
reverse_iterator rend() { return m_selections.rend(); }
|
||||
|
||||
using const_iterator = std::vector<Selection>::const_iterator;
|
||||
const_iterator begin() const { return m_selections.begin(); }
|
||||
const_iterator end() const { return m_selections.end(); }
|
||||
|
|
|
@ -13,8 +13,8 @@ inline void clear_selections(const Buffer& buffer, SelectionList& selections)
|
|||
{
|
||||
auto& sel = selections.main();
|
||||
auto& pos = sel.cursor();
|
||||
avoid_eol(buffer, pos);
|
||||
sel.anchor() = pos;
|
||||
selections.avoid_eol();
|
||||
|
||||
selections = SelectionList{ buffer, std::move(sel) };
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user