Move LineRangeSet to line_modification.hh
This commit is contained in:
parent
7dbca46bf0
commit
72bdd7900f
|
@ -4,6 +4,7 @@
|
|||
#include "face.hh"
|
||||
#include "hash.hh"
|
||||
#include "coord.hh"
|
||||
#include "range.hh"
|
||||
#include "string.hh"
|
||||
#include "vector.hh"
|
||||
#include "hash_map.hh"
|
||||
|
@ -12,18 +13,7 @@ namespace Kakoune
|
|||
{
|
||||
|
||||
class Buffer;
|
||||
struct BufferRange{ BufferCoord begin, end; };
|
||||
|
||||
inline bool operator==(const BufferRange& lhs, const BufferRange& rhs)
|
||||
{
|
||||
return lhs.begin == rhs.begin and lhs.end == rhs.end;
|
||||
}
|
||||
|
||||
inline
|
||||
size_t hash_value(const BufferRange& range)
|
||||
{
|
||||
return hash_values(range.begin, range.end);
|
||||
}
|
||||
using BufferRange = Range<BufferCoord>;
|
||||
|
||||
class BufferIterator;
|
||||
// Return a buffer iterator to the coord, tolerating one past end of line coords
|
||||
|
|
|
@ -1638,21 +1638,6 @@ struct RegexMatch
|
|||
};
|
||||
|
||||
using RegexMatchList = Vector<RegexMatch, MemoryDomain::Regions>;
|
||||
struct LineRange
|
||||
{
|
||||
LineCount begin;
|
||||
LineCount end;
|
||||
|
||||
friend bool operator==(LineRange lhs, LineRange rhs)
|
||||
{
|
||||
return lhs.begin == rhs.begin and lhs.end == rhs.end;
|
||||
}
|
||||
friend bool operator!=(LineRange lhs, LineRange rhs)
|
||||
{
|
||||
return not (lhs == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
void append_matches(const Buffer& buffer, LineCount line, RegexMatchList& matches, const Regex& regex, bool capture)
|
||||
{
|
||||
auto l = buffer[line];
|
||||
|
@ -1772,123 +1757,6 @@ struct RegionMatches : UseMemoryDomain<MemoryDomain::Highlight>
|
|||
}
|
||||
};
|
||||
|
||||
struct LineRangeSet : private Vector<LineRange, MemoryDomain::Highlight>
|
||||
{
|
||||
using Base = Vector<LineRange, MemoryDomain::Highlight>;
|
||||
using Base::operator[];
|
||||
using Base::begin;
|
||||
using Base::end;
|
||||
|
||||
ConstArrayView<LineRange> view() const { return {data(), data() + size()}; }
|
||||
|
||||
void reset(LineRange range) { Base::operator=({range}); }
|
||||
|
||||
void update(ConstArrayView<LineModification> modifs)
|
||||
{
|
||||
if (modifs.empty())
|
||||
return;
|
||||
|
||||
for (auto it = begin(); it != end(); ++it)
|
||||
{
|
||||
auto modif_beg = std::lower_bound(modifs.begin(), modifs.end(), it->begin,
|
||||
[](const LineModification& c, const LineCount& l)
|
||||
{ return c.old_line + c.num_removed < l; });
|
||||
auto modif_end = std::upper_bound(modifs.begin(), modifs.end(), it->end,
|
||||
[](const LineCount& l, const LineModification& c)
|
||||
{ return l < c.old_line; });
|
||||
|
||||
if (modif_beg == modifs.end())
|
||||
{
|
||||
const auto diff = (modif_beg-1)->diff();
|
||||
it->begin += diff;
|
||||
it->end += diff;
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto diff = modif_beg->new_line - modif_beg->old_line;
|
||||
it->begin += diff;
|
||||
it->end += diff;
|
||||
|
||||
while (modif_beg != modif_end)
|
||||
{
|
||||
auto& m = *modif_beg++;
|
||||
if (m.num_removed > 0)
|
||||
{
|
||||
if (m.new_line < it->begin)
|
||||
it->begin = std::max(m.new_line, it->begin - m.num_removed);
|
||||
it->end = std::max(m.new_line, std::max(it->begin, it->end - m.num_removed));
|
||||
}
|
||||
if (m.num_added > 0)
|
||||
{
|
||||
if (it->begin >= m.new_line)
|
||||
it->begin += m.num_added;
|
||||
else
|
||||
{
|
||||
it = insert(it, {it->begin, m.new_line}) + 1;
|
||||
it->begin = m.new_line + m.num_added;
|
||||
}
|
||||
it->end += m.num_added;
|
||||
}
|
||||
}
|
||||
};
|
||||
erase(std::remove_if(begin(), end(), [](auto& r) { return r.begin >= r.end; }), end());
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
void add_range(LineRange range, Func&& func)
|
||||
{
|
||||
auto it = std::lower_bound(begin(), end(), range.begin,
|
||||
[](LineRange range, LineCount line) { return range.end < line; });
|
||||
if (it == end() or it->begin > range.end)
|
||||
func(range);
|
||||
else
|
||||
{
|
||||
auto pos = range.begin;
|
||||
while (it != end() and it->begin <= range.end)
|
||||
{
|
||||
if (pos < it->begin)
|
||||
func({pos, it->begin});
|
||||
|
||||
range = LineRange{std::min(range.begin, it->begin), std::max(range.end, it->end)};
|
||||
pos = it->end;
|
||||
it = erase(it);
|
||||
}
|
||||
if (pos < range.end)
|
||||
func({pos, range.end});
|
||||
}
|
||||
insert(it, range);
|
||||
}
|
||||
|
||||
void remove_range(LineRange range)
|
||||
{
|
||||
auto inside = [](LineCount line, LineRange range) {
|
||||
return range.begin <= line and line < range.end;
|
||||
};
|
||||
|
||||
auto it = std::lower_bound(begin(), end(), range.begin,
|
||||
[](LineRange range, LineCount line) { return range.end < line; });
|
||||
if (it == end() or it->begin > range.end)
|
||||
return;
|
||||
else while (it != end() and it->begin <= range.end)
|
||||
{
|
||||
if (it->begin < range.begin and range.end <= it->end)
|
||||
{
|
||||
it = insert(it, {it->begin, range.begin}) + 1;
|
||||
it->begin = range.end;
|
||||
}
|
||||
if (inside(it->begin, range))
|
||||
it->begin = range.end;
|
||||
if (inside(it->end, range))
|
||||
it->end = range.begin;
|
||||
|
||||
if (it->end <= it->begin)
|
||||
it = erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct RegionsHighlighter : public Highlighter
|
||||
{
|
||||
public:
|
||||
|
@ -2387,68 +2255,4 @@ void register_highlighters()
|
|||
"Define the default region of a regions highlighter" } });
|
||||
}
|
||||
|
||||
UnitTest test_line_range_set{[]{
|
||||
auto expect = [](ConstArrayView<LineRange> ranges) {
|
||||
return [it = ranges.begin(), end = ranges.end()](LineRange r) mutable {
|
||||
kak_assert(it != end);
|
||||
kak_assert(r == *it++);
|
||||
};
|
||||
};
|
||||
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 5}, expect({{0, 5}}));
|
||||
ranges.add_range({10, 15}, expect({{10, 15}}));
|
||||
ranges.add_range({5, 10}, expect({{5, 10}}));
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 15}}));
|
||||
ranges.add_range({5, 10}, expect({}));
|
||||
ranges.remove_range({3, 8});
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 3}, {8, 15}}));
|
||||
}
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 7}, expect({{0, 7}}));
|
||||
ranges.add_range({9, 15}, expect({{9, 15}}));
|
||||
ranges.add_range({5, 10}, expect({{7, 9}}));
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 15}}));
|
||||
}
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 7}, expect({{0, 7}}));
|
||||
ranges.add_range({11, 15}, expect({{11, 15}}));
|
||||
ranges.add_range({5, 10}, expect({{7, 10}}));
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 10}, {11, 15}}));
|
||||
ranges.remove_range({8, 13});
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 8}, {13, 15}}));
|
||||
}
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 5}, expect({{0, 5}}));
|
||||
ranges.add_range({10, 15}, expect({{10, 15}}));
|
||||
ranges.update(ConstArrayView<LineModification>{{3, 3, 3, 1}, {11, 9, 2, 4}});
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 3}, {8, 9}, {13, 15}}));
|
||||
}
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 5}, expect({{0, 5}}));
|
||||
ranges.update(ConstArrayView<LineModification>{{2, 2, 2, 0}});
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 3}}));
|
||||
}
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 5}, expect({{0, 5}}));
|
||||
ranges.update(ConstArrayView<LineModification>{{2, 2, 0, 2}});
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 2}, {4, 7}}));
|
||||
}
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 1}, expect({{0, 1}}));
|
||||
ranges.add_range({5, 10}, expect({{5, 10}}));
|
||||
ranges.add_range({15, 20}, expect({{15, 20}}));
|
||||
ranges.add_range({25, 30}, expect({{25, 30}}));
|
||||
ranges.update(ConstArrayView<LineModification>{{2, 2, 3, 0}});
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 1}, {2, 7}, {12, 17}, {22, 27}}));
|
||||
}
|
||||
}};
|
||||
|
||||
}
|
||||
|
|
|
@ -94,6 +94,111 @@ bool operator==(const LineModification& lhs, const LineModification& rhs)
|
|||
std::tie(rhs.old_line, rhs.new_line, rhs.num_removed, rhs.num_added);
|
||||
}
|
||||
|
||||
void LineRangeSet::update(ConstArrayView<LineModification> modifs)
|
||||
{
|
||||
if (modifs.empty())
|
||||
return;
|
||||
|
||||
for (auto it = begin(); it != end(); ++it)
|
||||
{
|
||||
auto modif_beg = std::lower_bound(modifs.begin(), modifs.end(), it->begin,
|
||||
[](const LineModification& c, const LineCount& l)
|
||||
{ return c.old_line + c.num_removed < l; });
|
||||
auto modif_end = std::upper_bound(modifs.begin(), modifs.end(), it->end,
|
||||
[](const LineCount& l, const LineModification& c)
|
||||
{ return l < c.old_line; });
|
||||
|
||||
if (modif_beg == modifs.end())
|
||||
{
|
||||
const auto diff = (modif_beg-1)->diff();
|
||||
it->begin += diff;
|
||||
it->end += diff;
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto diff = modif_beg->new_line - modif_beg->old_line;
|
||||
it->begin += diff;
|
||||
it->end += diff;
|
||||
|
||||
while (modif_beg != modif_end)
|
||||
{
|
||||
auto& m = *modif_beg++;
|
||||
if (m.num_removed > 0)
|
||||
{
|
||||
if (m.new_line < it->begin)
|
||||
it->begin = std::max(m.new_line, it->begin - m.num_removed);
|
||||
it->end = std::max(m.new_line, std::max(it->begin, it->end - m.num_removed));
|
||||
}
|
||||
if (m.num_added > 0)
|
||||
{
|
||||
if (it->begin >= m.new_line)
|
||||
it->begin += m.num_added;
|
||||
else
|
||||
{
|
||||
it = insert(it, {it->begin, m.new_line}) + 1;
|
||||
it->begin = m.new_line + m.num_added;
|
||||
}
|
||||
it->end += m.num_added;
|
||||
}
|
||||
}
|
||||
};
|
||||
erase(std::remove_if(begin(), end(), [](auto& r) { return r.begin >= r.end; }), end());
|
||||
}
|
||||
|
||||
void LineRangeSet::add_range(LineRange range, std::function<void (LineRange)> on_new_range)
|
||||
{
|
||||
auto it = std::lower_bound(begin(), end(), range.begin,
|
||||
[](LineRange range, LineCount line) { return range.end < line; });
|
||||
if (it == end() or it->begin > range.end)
|
||||
on_new_range(range);
|
||||
else
|
||||
{
|
||||
auto pos = range.begin;
|
||||
while (it != end() and it->begin <= range.end)
|
||||
{
|
||||
if (pos < it->begin)
|
||||
on_new_range({pos, it->begin});
|
||||
|
||||
range = LineRange{std::min(range.begin, it->begin), std::max(range.end, it->end)};
|
||||
pos = it->end;
|
||||
it = erase(it);
|
||||
}
|
||||
if (pos < range.end)
|
||||
on_new_range({pos, range.end});
|
||||
}
|
||||
insert(it, range);
|
||||
}
|
||||
|
||||
void LineRangeSet::remove_range(LineRange range)
|
||||
{
|
||||
auto inside = [](LineCount line, LineRange range) {
|
||||
return range.begin <= line and line < range.end;
|
||||
};
|
||||
|
||||
auto it = std::lower_bound(begin(), end(), range.begin,
|
||||
[](LineRange range, LineCount line) { return range.end < line; });
|
||||
if (it == end() or it->begin > range.end)
|
||||
return;
|
||||
else while (it != end() and it->begin <= range.end)
|
||||
{
|
||||
if (it->begin < range.begin and range.end <= it->end)
|
||||
{
|
||||
it = insert(it, {it->begin, range.begin}) + 1;
|
||||
it->begin = range.end;
|
||||
}
|
||||
if (inside(it->begin, range))
|
||||
it->begin = range.end;
|
||||
if (inside(it->end, range))
|
||||
it->end = range.begin;
|
||||
|
||||
if (it->end <= it->begin)
|
||||
it = erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UnitTest test_line_modifications{[]()
|
||||
{
|
||||
{
|
||||
|
@ -155,4 +260,68 @@ UnitTest test_line_modifications{[]()
|
|||
}
|
||||
}};
|
||||
|
||||
UnitTest test_line_range_set{[]{
|
||||
auto expect = [](ConstArrayView<LineRange> ranges) {
|
||||
return [it = ranges.begin(), end = ranges.end()](LineRange r) mutable {
|
||||
kak_assert(it != end);
|
||||
kak_assert(r == *it++);
|
||||
};
|
||||
};
|
||||
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 5}, expect({{0, 5}}));
|
||||
ranges.add_range({10, 15}, expect({{10, 15}}));
|
||||
ranges.add_range({5, 10}, expect({{5, 10}}));
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 15}}));
|
||||
ranges.add_range({5, 10}, expect({}));
|
||||
ranges.remove_range({3, 8});
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 3}, {8, 15}}));
|
||||
}
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 7}, expect({{0, 7}}));
|
||||
ranges.add_range({9, 15}, expect({{9, 15}}));
|
||||
ranges.add_range({5, 10}, expect({{7, 9}}));
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 15}}));
|
||||
}
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 7}, expect({{0, 7}}));
|
||||
ranges.add_range({11, 15}, expect({{11, 15}}));
|
||||
ranges.add_range({5, 10}, expect({{7, 10}}));
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 10}, {11, 15}}));
|
||||
ranges.remove_range({8, 13});
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 8}, {13, 15}}));
|
||||
}
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 5}, expect({{0, 5}}));
|
||||
ranges.add_range({10, 15}, expect({{10, 15}}));
|
||||
ranges.update(ConstArrayView<LineModification>{{3, 3, 3, 1}, {11, 9, 2, 4}});
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 3}, {8, 9}, {13, 15}}));
|
||||
}
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 5}, expect({{0, 5}}));
|
||||
ranges.update(ConstArrayView<LineModification>{{2, 2, 2, 0}});
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 3}}));
|
||||
}
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 5}, expect({{0, 5}}));
|
||||
ranges.update(ConstArrayView<LineModification>{{2, 2, 0, 2}});
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 2}, {4, 7}}));
|
||||
}
|
||||
{
|
||||
LineRangeSet ranges;
|
||||
ranges.add_range({0, 1}, expect({{0, 1}}));
|
||||
ranges.add_range({5, 10}, expect({{5, 10}}));
|
||||
ranges.add_range({15, 20}, expect({{15, 20}}));
|
||||
ranges.add_range({25, 30}, expect({{25, 30}}));
|
||||
ranges.update(ConstArrayView<LineModification>{{2, 2, 3, 0}});
|
||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 1}, {2, 7}, {12, 17}, {22, 27}}));
|
||||
}
|
||||
}};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#ifndef line_change_watcher_hh_INCLUDED
|
||||
#define line_change_watcher_hh_INCLUDED
|
||||
|
||||
#include "array_view.hh"
|
||||
#include "units.hh"
|
||||
#include "utils.hh"
|
||||
#include "range.hh"
|
||||
#include "vector.hh"
|
||||
|
||||
namespace Kakoune
|
||||
|
@ -22,6 +24,25 @@ struct LineModification
|
|||
|
||||
Vector<LineModification> compute_line_modifications(const Buffer& buffer, size_t timestamp);
|
||||
|
||||
using LineRange = Range<LineCount>;
|
||||
|
||||
struct LineRangeSet : private Vector<LineRange, MemoryDomain::Highlight>
|
||||
{
|
||||
using Base = Vector<LineRange, MemoryDomain::Highlight>;
|
||||
using Base::operator[];
|
||||
using Base::begin;
|
||||
using Base::end;
|
||||
|
||||
ConstArrayView<LineRange> view() const { return {data(), data() + size()}; }
|
||||
|
||||
void reset(LineRange range) { Base::operator=({range}); }
|
||||
|
||||
void update(ConstArrayView<LineModification> modifs);
|
||||
void add_range(LineRange range, std::function<void (LineRange)> on_new_range);
|
||||
void remove_range(LineRange range);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // line_change_watcher_hh_INCLUDED
|
||||
|
|
31
src/range.hh
Normal file
31
src/range.hh
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef range_hh_INCLUDED
|
||||
#define range_hh_INCLUDED
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
struct Range
|
||||
{
|
||||
T begin;
|
||||
T end;
|
||||
|
||||
friend bool operator==(const Range& lhs, const Range& rhs)
|
||||
{
|
||||
return lhs.begin == rhs.begin and lhs.end == rhs.end;
|
||||
}
|
||||
|
||||
friend bool operator!=(const Range& lhs, const Range& rhs)
|
||||
{
|
||||
return not (lhs == rhs);
|
||||
}
|
||||
|
||||
friend size_t hash_value(const Range& range)
|
||||
{
|
||||
return hash_values(range.begin, range.end);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // range_hh_INCLUDED
|
Loading…
Reference in New Issue
Block a user