Tolerate restoring invalid coordinates from register

Clamp those selection after updating them to the current timestamp

Fixes #2078
This commit is contained in:
Maxime Coste 2018-06-03 21:08:45 +10:00
parent ed123a2cc9
commit 124a5d4905
6 changed files with 54 additions and 21 deletions

View File

@ -1734,11 +1734,22 @@ SelectionList read_selections_from_register(char reg, Context& context)
const auto desc = content[0] | split<StringView>('@') | static_gather<error, 3>(); const auto desc = content[0] | split<StringView>('@') | static_gather<error, 3>();
Buffer& buffer = BufferManager::instance().get_buffer(desc[0]); Buffer& buffer = BufferManager::instance().get_buffer(desc[0]);
const size_t timestamp = str_to_int(desc[1]); 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<Vector<Selection>>(); auto sels = content | skip(1) | transform(selection_from_string) | gather<Vector<Selection>>();
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 enum class CombineOp
@ -2012,9 +2023,7 @@ void move_cursor(Context& context, NormalParams params)
sel.anchor() = mode == SelectMode::Extend ? sel.anchor() : cursor; sel.anchor() = mode == SelectMode::Extend ? sel.anchor() : cursor;
sel.cursor() = cursor; sel.cursor() = cursor;
} }
selections.sort(); selections.sort_and_merge_overlapping();
selections.merge_overlapping();
} }
void select_whole_buffer(Context& context, NormalParams) void select_whole_buffer(Context& context, NormalParams)

View File

@ -212,6 +212,12 @@ static void clamp(Selection& sel, const Buffer& buffer)
sel.cursor() = buffer.clamp(sel.cursor()); sel.cursor() = buffer.clamp(sel.cursor());
} }
void clamp_selections(Vector<Selection>& selections, const Buffer& buffer)
{
for (auto& sel : selections)
clamp(sel, buffer);
}
void update_selections(Vector<Selection>& selections, size_t& main, Buffer& buffer, size_t timestamp) void update_selections(Vector<Selection>& selections, size_t& main, Buffer& buffer, size_t timestamp)
{ {
if (timestamp == buffer.timestamp()) if (timestamp == buffer.timestamp())
@ -286,30 +292,41 @@ void SelectionList::check_invariant() const
#endif #endif
} }
void SelectionList::sort() void sort_selections(Vector<Selection>& selections, size_t& main_index)
{ {
if (size() == 1) if (selections.size() == 1)
return; return;
const auto& main = this->main(); const auto& main = selections[main_index];
const auto main_begin = main.min(); const auto main_begin = main.min();
m_main = std::count_if(begin(), end(), [&](const Selection& sel) { main_index = std::count_if(selections.begin(), selections.end(),
[&](const Selection& sel) {
auto begin = sel.min(); auto begin = sel.min();
if (begin == main_begin) if (begin == main_begin)
return &sel < &main; return &sel < &main;
else else
return begin < main_begin; return begin < main_begin;
}); });
std::stable_sort(begin(), end(), compare_selections); std::stable_sort(selections.begin(), selections.end(), compare_selections);
}
void merge_overlapping_selections(Vector<Selection>& 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() void SelectionList::merge_overlapping()
{ {
if (size() == 1) merge_overlapping_selections(m_selections, m_main);
return;
m_selections.erase(Kakoune::merge_overlapping(begin(), end(),
m_main, overlaps), end());
} }
void SelectionList::merge_consecutive() void SelectionList::merge_consecutive()

View File

@ -65,6 +65,10 @@ inline bool overlaps(const Selection& lhs, const Selection& rhs)
void update_selections(Vector<Selection>& selections, size_t& main, void update_selections(Vector<Selection>& selections, size_t& main,
Buffer& buffer, size_t timestamp); Buffer& buffer, size_t timestamp);
void sort_selections(Vector<Selection>& selections, size_t& main);
void merge_overlapping_selections(Vector<Selection>& selections, size_t& main);
void clamp_selections(Vector<Selection>& sel, const Buffer& buffer);
enum class InsertMode : unsigned enum class InsertMode : unsigned
{ {
Insert, Insert,

View File

@ -0,0 +1 @@
ifoo<esc>ibar<esc>:set-register ^ <c-r>%@1@0 100.100,100.100<ret>z

View File

@ -0,0 +1 @@
1.7,1.7