1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
#include "selection.hh"
#include "utf8.hh"
namespace Kakoune
{
void Range::merge_with(const Range& range)
{
m_last = range.m_last;
if (m_first < m_last)
m_first = std::min(m_first, range.m_first);
if (m_first > m_last)
m_first = std::max(m_first, range.m_first);
}
BufferIterator Range::begin() const
{
return std::min(m_first, m_last);
}
BufferIterator Range::end() const
{
return utf8::next(std::max(m_first, m_last));
}
String Range::content() const
{
return m_first.buffer().string(begin(), end());
}
void Range::check_invariant() const
{
#ifdef KAK_DEBUG
kak_assert(m_first.is_valid());
kak_assert(m_last.is_valid());
kak_assert(utf8::is_character_start(m_first));
kak_assert(utf8::is_character_start(m_last));
#endif
}
namespace
{
template<template <bool, bool> class UpdateFunc>
void on_buffer_change(SelectionList& sels, const BufferCoord& begin, const BufferCoord& end, LineCount end_line)
{
auto update_beg = std::lower_bound(sels.begin(), sels.end(), begin,
[](const Selection& s, const BufferCoord& c) { return std::max(s.first(), s.last()).coord() < c; });
auto update_only_line_beg = std::upper_bound(sels.begin(), sels.end(), end_line,
[](LineCount l, const Selection& s) { return l < std::min(s.first(), s.last()).line(); });
if (update_beg != update_only_line_beg)
{
// for the first one, we are not sure if min < begin
UpdateFunc<false, false>{}(update_beg->first(), begin, end);
UpdateFunc<false, false>{}(update_beg->last(), begin, end);
}
for (auto it = update_beg+1; it < update_only_line_beg; ++it)
{
UpdateFunc<false, true>{}(it->first(), begin, end);
UpdateFunc<false, true>{}(it->last(), begin, end);
}
if (end.line > begin.line)
{
for (auto it = update_only_line_beg; it != sels.end(); ++it)
{
UpdateFunc<true, true>{}(it->first(), begin, end);
UpdateFunc<true, true>{}(it->last(), begin, end);
}
}
}
template<bool assume_different_line, bool assume_greater_than_begin>
struct UpdateInsert
{
void operator()(BufferIterator& it,
const BufferCoord& begin, const BufferCoord& end) const
{
BufferCoord coord = it.coord();
if (assume_different_line)
kak_assert(begin.line < coord.line);
if (not assume_greater_than_begin and coord < begin)
return;
if (not assume_different_line and begin.line == coord.line)
coord.column = end.column + coord.column - begin.column;
coord.line += end.line - begin.line;
it = coord;
}
};
template<bool assume_different_line, bool assume_greater_than_begin>
struct UpdateErase
{
void operator()(BufferIterator& it,
const BufferCoord& begin, const BufferCoord& end) const
{
BufferCoord coord = it.coord();
if (not assume_greater_than_begin and coord < begin)
return;
if (assume_different_line)
kak_assert(end.line < coord.line);
if (not assume_different_line and coord <= end)
coord = it.buffer().clamp(begin);
else
{
if (not assume_different_line and end.line == coord.line)
{
coord.line = begin.line;
coord.column = begin.column + coord.column - end.column;
}
else
coord.line -= end.line - begin.line;
}
it = coord;
}
};
}
void SelectionList::update_insert(const BufferCoord& begin, const BufferCoord& end)
{
on_buffer_change<UpdateInsert>(*this, begin, end, begin.line);
}
void SelectionList::update_erase(const BufferCoord& begin, const BufferCoord& end)
{
on_buffer_change<UpdateErase>(*this, begin, end, end.line);
}
void SelectionList::check_invariant() const
{
#ifdef KAK_DEBUG
for (size_t i = 0; i < size(); ++i)
{
auto& sel = (*this)[i];
sel.check_invariant();
if (i+1 < size())
kak_assert(sel.begin() <= (*this)[i+1].begin());
}
#endif
}
}
|