From 4e280977a2fcd7ca423b5909b435b896b256cdaf Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Wed, 14 May 2014 20:56:27 +0100 Subject: [PATCH] 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. --- src/buffer_utils.hh | 14 -------------- src/input_handler.cc | 28 ++++++++++++++-------------- src/normal.cc | 42 +++++++++++++++++++++++++----------------- src/selection.cc | 26 ++++++++++++++++++++++++++ src/selection.hh | 6 ++++++ src/selectors.hh | 2 +- 6 files changed, 72 insertions(+), 46 deletions(-) diff --git a/src/buffer_utils.hh b/src/buffer_utils.hh index bd617595..f47c2c26 100644 --- a/src/buffer_utils.hh +++ b/src/buffer_utils.hh @@ -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); diff --git a/src/input_handler.cc b/src/input_handler.cc index 08cd7f44..459f6751 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -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 }; diff --git a/src/normal.cc b/src/normal.cc index a8386b32..ff38c29d 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -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 void insert(Buffer& buffer, SelectionList& selections, const String& str) { - for (auto& sel : selections) + for (auto& sel : reversed(selections)) { auto pos = prepare_insert(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 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(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(); } diff --git a/src/selection.cc b/src/selection.cc index 746253f9..1e8356ab 100644 --- a/src/selection.cc +++ b/src/selection.cc @@ -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); +} } diff --git a/src/selection.hh b/src/selection.hh index f8727b90..5f0ce459 100644 --- a/src/selection.hh +++ b/src/selection.hh @@ -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::reverse_iterator; + reverse_iterator rbegin() { return m_selections.rbegin(); } + reverse_iterator rend() { return m_selections.rend(); } + using const_iterator = std::vector::const_iterator; const_iterator begin() const { return m_selections.begin(); } const_iterator end() const { return m_selections.end(); } diff --git a/src/selectors.hh b/src/selectors.hh index d98b73bf..d5b0523d 100644 --- a/src/selectors.hh +++ b/src/selectors.hh @@ -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) }; }