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())));
|
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 get_column(const Buffer& buffer,
|
||||||
CharCount tabstop, ByteCoord coord);
|
CharCount tabstop, ByteCoord coord);
|
||||||
|
|
||||||
|
|
|
@ -667,7 +667,7 @@ public:
|
||||||
}
|
}
|
||||||
else if (key == Key::Backspace)
|
else if (key == Key::Backspace)
|
||||||
{
|
{
|
||||||
for (auto& sel : context().selections())
|
for (auto& sel : reversed(context().selections()))
|
||||||
{
|
{
|
||||||
if (sel.cursor() == ByteCoord{0,0})
|
if (sel.cursor() == ByteCoord{0,0})
|
||||||
continue;
|
continue;
|
||||||
|
@ -677,7 +677,7 @@ public:
|
||||||
}
|
}
|
||||||
else if (key == Key::Erase)
|
else if (key == Key::Erase)
|
||||||
{
|
{
|
||||||
for (auto& sel : context().selections())
|
for (auto& sel : reversed(context().selections()))
|
||||||
{
|
{
|
||||||
auto pos = buffer.iterator_at(sel.cursor());
|
auto pos = buffer.iterator_at(sel.cursor());
|
||||||
buffer.erase(pos, utf8::next(pos));
|
buffer.erase(pos, utf8::next(pos));
|
||||||
|
@ -761,11 +761,12 @@ private:
|
||||||
auto& selections = context().selections();
|
auto& selections = context().selections();
|
||||||
for (size_t i = 0; i < selections.size(); ++i)
|
for (size_t i = 0; i < selections.size(); ++i)
|
||||||
{
|
{
|
||||||
size_t index = std::min(i, strings.size()-1);
|
size_t index = selections.size() - 1 - i;
|
||||||
buffer.insert(buffer.iterator_at(selections[i].cursor()),
|
const String& str = strings[std::min(index, strings.size()-1)];
|
||||||
strings[index]);
|
buffer.insert(buffer.iterator_at(selections[index].cursor()),
|
||||||
selections.update();
|
str);
|
||||||
}
|
}
|
||||||
|
selections.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(Codepoint key)
|
void insert(Codepoint key)
|
||||||
|
@ -773,11 +774,9 @@ private:
|
||||||
auto str = codepoint_to_str(key);
|
auto str = codepoint_to_str(key);
|
||||||
auto& buffer = context().buffer();
|
auto& buffer = context().buffer();
|
||||||
auto& selections = context().selections();
|
auto& selections = context().selections();
|
||||||
for (auto& sel : selections)
|
for (auto& sel : reversed(selections))
|
||||||
{
|
|
||||||
buffer.insert(buffer.iterator_at(sel.cursor()), str);
|
buffer.insert(buffer.iterator_at(sel.cursor()), str);
|
||||||
selections.update();
|
selections.update();
|
||||||
}
|
|
||||||
context().hooks().run_hook("InsertChar", str, context());
|
context().hooks().run_hook("InsertChar", str, context());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,7 +785,7 @@ private:
|
||||||
SelectionList& selections = context().selections();
|
SelectionList& selections = context().selections();
|
||||||
Buffer& buffer = context().buffer();
|
Buffer& buffer = context().buffer();
|
||||||
|
|
||||||
for (auto& sel : selections)
|
for (auto& sel : reversed(selections))
|
||||||
{
|
{
|
||||||
ByteCoord anchor, cursor;
|
ByteCoord anchor, cursor;
|
||||||
switch (mode)
|
switch (mode)
|
||||||
|
@ -835,10 +834,10 @@ private:
|
||||||
if (buffer.is_end(cursor))
|
if (buffer.is_end(cursor))
|
||||||
cursor = buffer.char_prev(cursor);
|
cursor = buffer.char_prev(cursor);
|
||||||
|
|
||||||
selections.update();
|
|
||||||
sel.anchor() = anchor;
|
sel.anchor() = anchor;
|
||||||
sel.cursor() = cursor;
|
sel.cursor() = cursor;
|
||||||
}
|
}
|
||||||
|
selections.update();
|
||||||
if (mode == InsertMode::OpenLineBelow or mode == InsertMode::OpenLineAbove)
|
if (mode == InsertMode::OpenLineBelow or mode == InsertMode::OpenLineAbove)
|
||||||
{
|
{
|
||||||
insert('\n');
|
insert('\n');
|
||||||
|
@ -859,12 +858,13 @@ private:
|
||||||
|
|
||||||
void on_disabled() override
|
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)
|
if (m_insert_mode == InsertMode::Append and sel.cursor().column > 0)
|
||||||
sel.cursor() = context().buffer().char_prev(sel.cursor());
|
sel.cursor() = context().buffer().char_prev(sel.cursor());
|
||||||
avoid_eol(context().buffer(), sel);
|
|
||||||
}
|
}
|
||||||
|
selections.avoid_eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Mode { Default, Complete, InsertReg };
|
enum class Mode { Default, Complete, InsertReg };
|
||||||
|
|
|
@ -23,13 +23,12 @@ namespace Kakoune
|
||||||
|
|
||||||
void erase(Buffer& buffer, SelectionList& selections)
|
void erase(Buffer& buffer, SelectionList& selections)
|
||||||
{
|
{
|
||||||
for (auto& sel : selections)
|
for (auto& sel : reversed(selections))
|
||||||
{
|
{
|
||||||
erase(buffer, sel);
|
erase(buffer, sel);
|
||||||
selections.update();
|
|
||||||
avoid_eol(buffer, sel);
|
|
||||||
}
|
}
|
||||||
selections.check_invariant();
|
selections.update();
|
||||||
|
selections.avoid_eol();
|
||||||
buffer.check_invariant();
|
buffer.check_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,20 +65,24 @@ BufferIterator prepare_insert(Buffer& buffer, const Selection& sel)
|
||||||
template<InsertMode mode>
|
template<InsertMode mode>
|
||||||
void insert(Buffer& buffer, SelectionList& selections, const String& str)
|
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);
|
auto pos = prepare_insert<mode>(buffer, sel);
|
||||||
pos = buffer.insert(pos, str);
|
pos = buffer.insert(pos, str);
|
||||||
selections.update();
|
if (mode == InsertMode::Replace)
|
||||||
if (mode == InsertMode::Replace and pos != buffer.end())
|
|
||||||
{
|
{
|
||||||
|
if (pos == buffer.end())
|
||||||
|
--pos;
|
||||||
sel.anchor() = pos.coord();
|
sel.anchor() = pos.coord();
|
||||||
sel.cursor() = str.empty() ?
|
sel.cursor() = str.empty() ?
|
||||||
pos.coord() : (pos + str.byte_count_to(str.char_length() - 1)).coord();
|
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();
|
buffer.check_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,20 +93,25 @@ void insert(Buffer& buffer, SelectionList& selections, memoryview<String> string
|
||||||
return;
|
return;
|
||||||
for (size_t i = 0; i < selections.size(); ++i)
|
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);
|
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);
|
pos = buffer.insert(pos, str);
|
||||||
selections.update();
|
if (mode == InsertMode::Replace)
|
||||||
if (mode == InsertMode::Replace and pos != buffer.end())
|
|
||||||
{
|
{
|
||||||
|
if (pos == buffer.end())
|
||||||
|
--pos;
|
||||||
sel.anchor() = pos.coord();
|
sel.anchor() = pos.coord();
|
||||||
sel.cursor() = (str.empty() ?
|
sel.cursor() = (str.empty() ?
|
||||||
pos : pos + str.byte_count_to(str.char_length() - 1)).coord();
|
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();
|
buffer.check_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1352,9 +1360,9 @@ void move(Context& context, int count)
|
||||||
: context.buffer().offset_coord(sel.cursor(), offset);
|
: context.buffer().offset_coord(sel.cursor(), offset);
|
||||||
|
|
||||||
sel.anchor() = mode == SelectMode::Extend ? sel.anchor() : cursor;
|
sel.anchor() = mode == SelectMode::Extend ? sel.anchor() : cursor;
|
||||||
sel.cursor() = cursor;
|
sel.cursor() = cursor;
|
||||||
avoid_eol(context.buffer(), sel);
|
|
||||||
}
|
}
|
||||||
|
selections.avoid_eol();
|
||||||
selections.sort_and_merge_overlapping();
|
selections.sort_and_merge_overlapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -188,5 +188,31 @@ void SelectionList::sort_and_merge_overlapping()
|
||||||
std::stable_sort(begin(), end(), compare_selections);
|
std::stable_sort(begin(), end(), compare_selections);
|
||||||
merge_overlapping(overlaps);
|
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 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(const Selection& sel) { m_selections.push_back(sel); }
|
||||||
void push_back(Selection&& sel) { m_selections.push_back(std::move(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 begin() { return m_selections.begin(); }
|
||||||
iterator end() { return m_selections.end(); }
|
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;
|
using const_iterator = std::vector<Selection>::const_iterator;
|
||||||
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(); }
|
||||||
|
|
|
@ -13,8 +13,8 @@ inline void clear_selections(const Buffer& buffer, SelectionList& selections)
|
||||||
{
|
{
|
||||||
auto& sel = selections.main();
|
auto& sel = selections.main();
|
||||||
auto& pos = sel.cursor();
|
auto& pos = sel.cursor();
|
||||||
avoid_eol(buffer, pos);
|
|
||||||
sel.anchor() = pos;
|
sel.anchor() = pos;
|
||||||
|
selections.avoid_eol();
|
||||||
|
|
||||||
selections = SelectionList{ buffer, std::move(sel) };
|
selections = SelectionList{ buffer, std::move(sel) };
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user