Make find_surrounding more reusable and add unit tests
This commit is contained in:
parent
4f07632ac0
commit
04119d6207
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "optional.hh"
|
#include "optional.hh"
|
||||||
#include "string.hh"
|
#include "string.hh"
|
||||||
|
#include "unit_tests.hh"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -73,20 +74,22 @@ Selection select_matching(const Buffer& buffer, const Selection& selection)
|
||||||
return selection;
|
return selection;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Optional<Selection> find_surrounding(const Buffer& buffer,
|
template<typename Iterator>
|
||||||
ByteCoord coord,
|
Optional<std::pair<Iterator, Iterator>>
|
||||||
MatchingPair matching,
|
find_surrounding(Iterator begin, Iterator end,
|
||||||
ObjectFlags flags, int init_level)
|
Iterator pos, MatchingPair matching,
|
||||||
|
ObjectFlags flags, int init_level)
|
||||||
{
|
{
|
||||||
|
using Utf8It = utf8::iterator<Iterator>;
|
||||||
|
|
||||||
const bool to_begin = flags & ObjectFlags::ToBegin;
|
const bool to_begin = flags & ObjectFlags::ToBegin;
|
||||||
const bool to_end = flags & ObjectFlags::ToEnd;
|
const bool to_end = flags & ObjectFlags::ToEnd;
|
||||||
const bool nestable = matching.opening != matching.closing;
|
const bool nestable = matching.opening != matching.closing;
|
||||||
auto pos = buffer.iterator_at(coord);
|
Utf8It first{pos, begin, end};
|
||||||
Utf8Iterator first{pos, buffer};
|
|
||||||
if (to_begin)
|
if (to_begin)
|
||||||
{
|
{
|
||||||
int level = nestable ? init_level : 0;
|
int level = nestable ? init_level : 0;
|
||||||
while (first != buffer.begin())
|
while (first != begin)
|
||||||
{
|
{
|
||||||
if (nestable and first != pos and *first == matching.closing)
|
if (nestable and first != pos and *first == matching.closing)
|
||||||
++level;
|
++level;
|
||||||
|
@ -100,14 +103,14 @@ static Optional<Selection> find_surrounding(const Buffer& buffer,
|
||||||
--first;
|
--first;
|
||||||
}
|
}
|
||||||
if (level != 0 or *first != matching.opening)
|
if (level != 0 or *first != matching.opening)
|
||||||
return Optional<Selection>{};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Utf8Iterator last{pos, buffer};
|
Utf8It last{pos, begin, end};
|
||||||
if (to_end)
|
if (to_end)
|
||||||
{
|
{
|
||||||
int level = nestable ? init_level : 0;
|
int level = nestable ? init_level : 0;
|
||||||
while (last != buffer.end())
|
while (last != end)
|
||||||
{
|
{
|
||||||
if (nestable and last != pos and *last == matching.opening)
|
if (nestable and last != pos and *last == matching.opening)
|
||||||
++level;
|
++level;
|
||||||
|
@ -120,8 +123,8 @@ static Optional<Selection> find_surrounding(const Buffer& buffer,
|
||||||
}
|
}
|
||||||
++last;
|
++last;
|
||||||
}
|
}
|
||||||
if (level != 0 or last == buffer.end())
|
if (level != 0 or last == end)
|
||||||
return Optional<Selection>{};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & ObjectFlags::Inner)
|
if (flags & ObjectFlags::Inner)
|
||||||
|
@ -131,7 +134,17 @@ static Optional<Selection> find_surrounding(const Buffer& buffer,
|
||||||
if (to_end and first != last)
|
if (to_end and first != last)
|
||||||
--last;
|
--last;
|
||||||
}
|
}
|
||||||
return to_end ? utf8_range(first, last) : utf8_range(last, first);
|
return to_end ? std::pair<Iterator, Iterator>{first.base(), last.base()}
|
||||||
|
: std::pair<Iterator, Iterator>{last.base(), first.base()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container, typename Iterator>
|
||||||
|
Optional<std::pair<Iterator, Iterator>>
|
||||||
|
find_surrounding(const Container& container, Iterator pos,
|
||||||
|
MatchingPair matching, ObjectFlags flags, int init_level)
|
||||||
|
{
|
||||||
|
return find_surrounding(begin(container), end(container), pos,
|
||||||
|
matching, flags, init_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_surrounding(const Buffer& buffer, const Selection& selection,
|
Selection select_surrounding(const Buffer& buffer, const Selection& selection,
|
||||||
|
@ -142,8 +155,9 @@ Selection select_surrounding(const Buffer& buffer, const Selection& selection,
|
||||||
auto pos = selection.cursor();
|
auto pos = selection.cursor();
|
||||||
if (not nestable or flags & ObjectFlags::Inner)
|
if (not nestable or flags & ObjectFlags::Inner)
|
||||||
{
|
{
|
||||||
if (auto res = find_surrounding(buffer, pos, matching, flags, level))
|
if (auto res = find_surrounding(buffer, buffer.iterator_at(pos),
|
||||||
return *res;
|
matching, flags, level))
|
||||||
|
return utf8_range(res->first, res->second);
|
||||||
return selection;
|
return selection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,17 +166,22 @@ Selection select_surrounding(const Buffer& buffer, const Selection& selection,
|
||||||
(flags == ObjectFlags::ToEnd and c == matching.closing))
|
(flags == ObjectFlags::ToEnd and c == matching.closing))
|
||||||
++level;
|
++level;
|
||||||
|
|
||||||
auto res = find_surrounding(buffer, pos, matching, flags, level);
|
auto res = find_surrounding(buffer, buffer.iterator_at(pos),
|
||||||
|
matching, flags, level);
|
||||||
if (not res)
|
if (not res)
|
||||||
return selection;
|
return selection;
|
||||||
|
|
||||||
|
Selection sel = utf8_range(res->first, res->second);
|
||||||
|
|
||||||
if (flags == (ObjectFlags::ToBegin | ObjectFlags::ToEnd) and
|
if (flags == (ObjectFlags::ToBegin | ObjectFlags::ToEnd) and
|
||||||
res->min() == selection.min() and res->max() == selection.max())
|
sel.min() == selection.min() and sel.max() == selection.max())
|
||||||
{
|
{
|
||||||
if (auto res_parent = find_surrounding(buffer, pos, matching, flags, level+1))
|
if (auto res_parent = find_surrounding(buffer.begin(), buffer.end(),
|
||||||
return Selection{*res_parent};
|
buffer.iterator_at(pos),
|
||||||
|
matching, flags, level+1))
|
||||||
|
return utf8_range(res_parent->first, res_parent->second);
|
||||||
}
|
}
|
||||||
return *res;
|
return sel;
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_to(const Buffer& buffer, const Selection& selection,
|
Selection select_to(const Buffer& buffer, const Selection& selection,
|
||||||
|
@ -642,4 +661,21 @@ void split_selections(SelectionList& selections, const Regex& regex, unsigned ca
|
||||||
selections = std::move(result);
|
selections = std::move(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnitTest test_find_surrounding{[]()
|
||||||
|
{
|
||||||
|
StringView s("[salut { toi[] }]");
|
||||||
|
{
|
||||||
|
auto res = find_surrounding(s, s.begin() + 10, { '{', '}' },
|
||||||
|
ObjectFlags::ToBegin | ObjectFlags::ToEnd, 0);
|
||||||
|
|
||||||
|
kak_assert(res and StringView{res->first COMMA res->second+1} == "{ toi[] }");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto res = find_surrounding(s, s.begin() + 10, { '[', ']' },
|
||||||
|
ObjectFlags::ToBegin | ObjectFlags::ToEnd | ObjectFlags::Inner, 0);
|
||||||
|
|
||||||
|
kak_assert(res and StringView{res->first COMMA res->second+1} == "salut { toi[] }");
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,11 @@ void skip_while_reverse(Iterator& it, const BeginIterator& begin, T condition)
|
||||||
|
|
||||||
using Utf8Iterator = utf8::iterator<BufferIterator, utf8::InvalidPolicy::Pass>;
|
using Utf8Iterator = utf8::iterator<BufferIterator, utf8::InvalidPolicy::Pass>;
|
||||||
|
|
||||||
|
inline Selection utf8_range(const BufferIterator& first, const BufferIterator& last)
|
||||||
|
{
|
||||||
|
return {first.coord(), last.coord()};
|
||||||
|
}
|
||||||
|
|
||||||
inline Selection utf8_range(const Utf8Iterator& first, const Utf8Iterator& last)
|
inline Selection utf8_range(const Utf8Iterator& first, const Utf8Iterator& last)
|
||||||
{
|
{
|
||||||
return {first.base().coord(), last.base().coord()};
|
return {first.base().coord(), last.base().coord()};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user