Tolerate restoring invalid coordinates from register
Clamp those selection after updating them to the current timestamp Fixes #2078
This commit is contained in:
parent
ed123a2cc9
commit
124a5d4905
|
@ -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)
|
||||||
|
|
|
@ -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(),
|
||||||
auto begin = sel.min();
|
[&](const Selection& sel) {
|
||||||
if (begin == main_begin)
|
auto begin = sel.min();
|
||||||
return &sel < &main;
|
if (begin == main_begin)
|
||||||
else
|
return &sel < &main;
|
||||||
return begin < main_begin;
|
else
|
||||||
});
|
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()
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
ifoo<esc>ibar<esc>:set-register ^ <c-r>%@1@0 100.100,100.100<ret>z
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
1.7,1.7
|
Loading…
Reference in New Issue
Block a user