diff --git a/src/normal.cc b/src/normal.cc index e66045a3..fb295f4d 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -1734,11 +1734,22 @@ SelectionList read_selections_from_register(char reg, Context& context) const auto desc = content[0] | split('@') | static_gather(); Buffer& buffer = BufferManager::instance().get_buffer(desc[0]); const size_t timestamp = str_to_int(desc[1]); - const size_t main = str_to_int(desc[2]); + size_t main = str_to_int(desc[2]); + + if (timestamp > buffer.timestamp()) + throw runtime_error{"register '{}' refers to an invalid timestamp"}; auto sels = content | skip(1) | transform(selection_from_string) | gather>(); + sort_selections(sels, main); + merge_overlapping_selections(sels, main); + if (timestamp < buffer.timestamp()) + update_selections(sels, main, buffer, timestamp); + else + clamp_selections(sels, buffer); - return {SelectionList::UnsortedTag{}, buffer, std::move(sels), timestamp, main}; + SelectionList res{buffer, std::move(sels)}; + res.set_main_index(main); + return res; } enum class CombineOp @@ -2012,9 +2023,7 @@ void move_cursor(Context& context, NormalParams params) sel.anchor() = mode == SelectMode::Extend ? sel.anchor() : cursor; sel.cursor() = cursor; } - selections.sort(); - - selections.merge_overlapping(); + selections.sort_and_merge_overlapping(); } void select_whole_buffer(Context& context, NormalParams) diff --git a/src/selection.cc b/src/selection.cc index 02358fea..c8ab543b 100644 --- a/src/selection.cc +++ b/src/selection.cc @@ -212,6 +212,12 @@ static void clamp(Selection& sel, const Buffer& buffer) sel.cursor() = buffer.clamp(sel.cursor()); } +void clamp_selections(Vector& selections, const Buffer& buffer) +{ + for (auto& sel : selections) + clamp(sel, buffer); +} + void update_selections(Vector& selections, size_t& main, Buffer& buffer, size_t timestamp) { if (timestamp == buffer.timestamp()) @@ -286,30 +292,41 @@ void SelectionList::check_invariant() const #endif } -void SelectionList::sort() +void sort_selections(Vector& selections, size_t& main_index) { - if (size() == 1) + if (selections.size() == 1) return; - const auto& main = this->main(); + const auto& main = selections[main_index]; const auto main_begin = main.min(); - m_main = std::count_if(begin(), end(), [&](const Selection& sel) { - auto begin = sel.min(); - if (begin == main_begin) - return &sel < &main; - else - return begin < main_begin; - }); - std::stable_sort(begin(), end(), compare_selections); + main_index = std::count_if(selections.begin(), selections.end(), + [&](const Selection& sel) { + auto begin = sel.min(); + if (begin == main_begin) + return &sel < &main; + else + return begin < main_begin; + }); + std::stable_sort(selections.begin(), selections.end(), compare_selections); +} + +void merge_overlapping_selections(Vector& selections, size_t& main_index) +{ + if (selections.size() == 1) + return; + + selections.erase(Kakoune::merge_overlapping(selections.begin(), selections.end(), + main_index, overlaps), selections.end()); +} + +void SelectionList::sort() +{ + sort_selections(m_selections, m_main); } void SelectionList::merge_overlapping() { - if (size() == 1) - return; - - m_selections.erase(Kakoune::merge_overlapping(begin(), end(), - m_main, overlaps), end()); + merge_overlapping_selections(m_selections, m_main); } void SelectionList::merge_consecutive() diff --git a/src/selection.hh b/src/selection.hh index 1ab93aa5..510f999b 100644 --- a/src/selection.hh +++ b/src/selection.hh @@ -65,6 +65,10 @@ inline bool overlaps(const Selection& lhs, const Selection& rhs) void update_selections(Vector& selections, size_t& main, Buffer& buffer, size_t timestamp); +void sort_selections(Vector& selections, size_t& main); +void merge_overlapping_selections(Vector& selections, size_t& main); +void clamp_selections(Vector& sel, const Buffer& buffer); + enum class InsertMode : unsigned { Insert, diff --git a/test/regression/2078-assert-on-restoring-invalid-selections/cmd b/test/regression/2078-assert-on-restoring-invalid-selections/cmd new file mode 100644 index 00000000..685aa86d --- /dev/null +++ b/test/regression/2078-assert-on-restoring-invalid-selections/cmd @@ -0,0 +1 @@ +ifooibar:set-register ^ %@1@0 100.100,100.100z diff --git a/test/regression/2078-assert-on-restoring-invalid-selections/in b/test/regression/2078-assert-on-restoring-invalid-selections/in new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/test/regression/2078-assert-on-restoring-invalid-selections/in @@ -0,0 +1 @@ + diff --git a/test/regression/2078-assert-on-restoring-invalid-selections/state b/test/regression/2078-assert-on-restoring-invalid-selections/state new file mode 100644 index 00000000..e1245693 --- /dev/null +++ b/test/regression/2078-assert-on-restoring-invalid-selections/state @@ -0,0 +1 @@ +1.7,1.7