Return an optional selection in most selectors, fail rather than keep current
Instead of returning the current selection when a selector fails, return an empty Optional<Selection>. That means object selections will now remove the selections that dont match the object.
This commit is contained in:
parent
6759511b9e
commit
ddc5e958e6
|
@ -40,33 +40,49 @@ void select(Context& context, T func)
|
||||||
if (mode == SelectMode::Append)
|
if (mode == SelectMode::Append)
|
||||||
{
|
{
|
||||||
auto& sel = selections.main();
|
auto& sel = selections.main();
|
||||||
auto res = func(buffer, sel);
|
if (auto res = func(buffer, sel))
|
||||||
if (res.captures().empty())
|
{
|
||||||
res.captures() = sel.captures();
|
if (res->captures().empty())
|
||||||
selections.push_back(res);
|
res->captures() = sel.captures();
|
||||||
|
selections.push_back(std::move(*res));
|
||||||
selections.set_main_index(selections.size() - 1);
|
selections.set_main_index(selections.size() - 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (auto& sel : selections)
|
Vector<int> to_remove;
|
||||||
|
for (int i = 0; i < (int)selections.size(); ++i)
|
||||||
{
|
{
|
||||||
|
auto& sel = selections[i];
|
||||||
auto res = func(buffer, sel);
|
auto res = func(buffer, sel);
|
||||||
|
if (not res)
|
||||||
|
{
|
||||||
|
to_remove.push_back(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == SelectMode::Extend)
|
if (mode == SelectMode::Extend)
|
||||||
sel.merge_with(res);
|
sel.merge_with(*res);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sel.anchor() = res.anchor();
|
sel.anchor() = res->anchor();
|
||||||
sel.cursor() = res.cursor();
|
sel.cursor() = res->cursor();
|
||||||
}
|
}
|
||||||
if (not res.captures().empty())
|
if (not res->captures().empty())
|
||||||
sel.captures() = std::move(res.captures());
|
sel.captures() = std::move(res->captures());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (to_remove.size() == selections.size())
|
||||||
|
throw runtime_error{"no selections remaining"};
|
||||||
|
for (auto& i : to_remove | reverse())
|
||||||
|
selections.remove(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
selections.sort_and_merge_overlapping();
|
selections.sort_and_merge_overlapping();
|
||||||
selections.check_invariant();
|
selections.check_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<SelectMode mode, Selection (*func)(const Buffer&, const Selection&)>
|
template<SelectMode mode, Optional<Selection> (*func)(const Buffer&, const Selection&)>
|
||||||
void select(Context& context, NormalParams)
|
void select(Context& context, NormalParams)
|
||||||
{
|
{
|
||||||
select<mode>(context, func);
|
select<mode>(context, func);
|
||||||
|
@ -1053,7 +1069,7 @@ void select_object(Context& context, NormalParams params)
|
||||||
static constexpr struct ObjectType
|
static constexpr struct ObjectType
|
||||||
{
|
{
|
||||||
Codepoint key;
|
Codepoint key;
|
||||||
Selection (*func)(const Buffer&, const Selection&, int, ObjectFlags);
|
Optional<Selection> (*func)(const Buffer&, const Selection&, int, ObjectFlags);
|
||||||
} selectors[] = {
|
} selectors[] = {
|
||||||
{ 'w', select_word<Word> },
|
{ 'w', select_word<Word> },
|
||||||
{ 'W', select_word<WORD> },
|
{ 'W', select_word<WORD> },
|
||||||
|
|
141
src/selectors.cc
141
src/selectors.cc
|
@ -37,17 +37,18 @@ Selection utf8_range(const Utf8Iterator& first, const Utf8Iterator& last)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<WordType word_type>
|
template<WordType word_type>
|
||||||
Selection select_to_next_word(const Buffer& buffer, const Selection& selection)
|
Optional<Selection>
|
||||||
|
select_to_next_word(const Buffer& buffer, const Selection& selection)
|
||||||
{
|
{
|
||||||
Utf8Iterator begin{buffer.iterator_at(selection.cursor()), buffer};
|
Utf8Iterator begin{buffer.iterator_at(selection.cursor()), buffer};
|
||||||
if (begin+1 == buffer.end())
|
if (begin+1 == buffer.end())
|
||||||
return selection;
|
return {};
|
||||||
if (categorize<word_type>(*begin) != categorize<word_type>(*(begin+1)))
|
if (categorize<word_type>(*begin) != categorize<word_type>(*(begin+1)))
|
||||||
++begin;
|
++begin;
|
||||||
|
|
||||||
if (not skip_while(begin, buffer.end(),
|
if (not skip_while(begin, buffer.end(),
|
||||||
[](Codepoint c) { return is_eol(c); }))
|
[](Codepoint c) { return is_eol(c); }))
|
||||||
return selection;
|
return {};
|
||||||
Utf8Iterator end = begin+1;
|
Utf8Iterator end = begin+1;
|
||||||
|
|
||||||
if (word_type == Word and is_punctuation(*begin))
|
if (word_type == Word and is_punctuation(*begin))
|
||||||
|
@ -59,21 +60,21 @@ Selection select_to_next_word(const Buffer& buffer, const Selection& selection)
|
||||||
|
|
||||||
return utf8_range(begin, end-1);
|
return utf8_range(begin, end-1);
|
||||||
}
|
}
|
||||||
template Selection select_to_next_word<WordType::Word>(const Buffer&, const Selection&);
|
template Optional<Selection> select_to_next_word<WordType::Word>(const Buffer&, const Selection&);
|
||||||
template Selection select_to_next_word<WordType::WORD>(const Buffer&, const Selection&);
|
template Optional<Selection> select_to_next_word<WordType::WORD>(const Buffer&, const Selection&);
|
||||||
|
|
||||||
template<WordType word_type>
|
template<WordType word_type>
|
||||||
Selection select_to_next_word_end(const Buffer& buffer, const Selection& selection)
|
Optional<Selection> select_to_next_word_end(const Buffer& buffer, const Selection& selection)
|
||||||
{
|
{
|
||||||
Utf8Iterator begin{buffer.iterator_at(selection.cursor()), buffer};
|
Utf8Iterator begin{buffer.iterator_at(selection.cursor()), buffer};
|
||||||
if (begin+1 == buffer.end())
|
if (begin+1 == buffer.end())
|
||||||
return selection;
|
return {};
|
||||||
if (categorize<word_type>(*begin) != categorize<word_type>(*(begin+1)))
|
if (categorize<word_type>(*begin) != categorize<word_type>(*(begin+1)))
|
||||||
++begin;
|
++begin;
|
||||||
|
|
||||||
if (not skip_while(begin, buffer.end(),
|
if (not skip_while(begin, buffer.end(),
|
||||||
[](Codepoint c) { return is_eol(c); }))
|
[](Codepoint c) { return is_eol(c); }))
|
||||||
return selection;
|
return {};
|
||||||
Utf8Iterator end = begin;
|
Utf8Iterator end = begin;
|
||||||
skip_while(end, buffer.end(), is_horizontal_blank);
|
skip_while(end, buffer.end(), is_horizontal_blank);
|
||||||
|
|
||||||
|
@ -84,15 +85,16 @@ Selection select_to_next_word_end(const Buffer& buffer, const Selection& selecti
|
||||||
|
|
||||||
return utf8_range(begin, end-1);
|
return utf8_range(begin, end-1);
|
||||||
}
|
}
|
||||||
template Selection select_to_next_word_end<WordType::Word>(const Buffer&, const Selection&);
|
template Optional<Selection> select_to_next_word_end<WordType::Word>(const Buffer&, const Selection&);
|
||||||
template Selection select_to_next_word_end<WordType::WORD>(const Buffer&, const Selection&);
|
template Optional<Selection> select_to_next_word_end<WordType::WORD>(const Buffer&, const Selection&);
|
||||||
|
|
||||||
template<WordType word_type>
|
template<WordType word_type>
|
||||||
Selection select_to_previous_word(const Buffer& buffer, const Selection& selection)
|
Optional<Selection>
|
||||||
|
select_to_previous_word(const Buffer& buffer, const Selection& selection)
|
||||||
{
|
{
|
||||||
Utf8Iterator begin{buffer.iterator_at(selection.cursor()), buffer};
|
Utf8Iterator begin{buffer.iterator_at(selection.cursor()), buffer};
|
||||||
if (begin == buffer.begin())
|
if (begin == buffer.begin())
|
||||||
return selection;
|
return {};
|
||||||
if (categorize<word_type>(*begin) != categorize<word_type>(*(begin-1)))
|
if (categorize<word_type>(*begin) != categorize<word_type>(*(begin-1)))
|
||||||
--begin;
|
--begin;
|
||||||
|
|
||||||
|
@ -108,11 +110,12 @@ Selection select_to_previous_word(const Buffer& buffer, const Selection& selecti
|
||||||
|
|
||||||
return utf8_range(begin, with_end ? end : end+1);
|
return utf8_range(begin, with_end ? end : end+1);
|
||||||
}
|
}
|
||||||
template Selection select_to_previous_word<WordType::Word>(const Buffer&, const Selection&);
|
template Optional<Selection> select_to_previous_word<WordType::Word>(const Buffer&, const Selection&);
|
||||||
template Selection select_to_previous_word<WordType::WORD>(const Buffer&, const Selection&);
|
template Optional<Selection> select_to_previous_word<WordType::WORD>(const Buffer&, const Selection&);
|
||||||
|
|
||||||
template<WordType word_type>
|
template<WordType word_type>
|
||||||
Selection select_word(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_word(const Buffer& buffer, const Selection& selection,
|
||||||
int count, ObjectFlags flags)
|
int count, ObjectFlags flags)
|
||||||
{
|
{
|
||||||
Utf8Iterator first{buffer.iterator_at(selection.cursor()), buffer};
|
Utf8Iterator first{buffer.iterator_at(selection.cursor()), buffer};
|
||||||
|
@ -120,7 +123,7 @@ Selection select_word(const Buffer& buffer, const Selection& selection,
|
||||||
((flags & ObjectFlags::Inner) or
|
((flags & ObjectFlags::Inner) or
|
||||||
not skip_while(first, buffer.end(), [](Codepoint c)
|
not skip_while(first, buffer.end(), [](Codepoint c)
|
||||||
{ return not is_word<word_type>(c); })))
|
{ return not is_word<word_type>(c); })))
|
||||||
return selection;
|
return {};
|
||||||
|
|
||||||
Utf8Iterator last = first;
|
Utf8Iterator last = first;
|
||||||
if (flags & ObjectFlags::ToBegin)
|
if (flags & ObjectFlags::ToBegin)
|
||||||
|
@ -139,10 +142,11 @@ Selection select_word(const Buffer& buffer, const Selection& selection,
|
||||||
return (flags & ObjectFlags::ToEnd) ? utf8_range(first, last)
|
return (flags & ObjectFlags::ToEnd) ? utf8_range(first, last)
|
||||||
: utf8_range(last, first);
|
: utf8_range(last, first);
|
||||||
}
|
}
|
||||||
template Selection select_word<WordType::Word>(const Buffer&, const Selection&, int, ObjectFlags);
|
template Optional<Selection> select_word<WordType::Word>(const Buffer&, const Selection&, int, ObjectFlags);
|
||||||
template Selection select_word<WordType::WORD>(const Buffer&, const Selection&, int, ObjectFlags);
|
template Optional<Selection> select_word<WordType::WORD>(const Buffer&, const Selection&, int, ObjectFlags);
|
||||||
|
|
||||||
Selection select_line(const Buffer& buffer, const Selection& selection)
|
Optional<Selection>
|
||||||
|
select_line(const Buffer& buffer, const Selection& selection)
|
||||||
{
|
{
|
||||||
Utf8Iterator first{buffer.iterator_at(selection.cursor()), buffer};
|
Utf8Iterator first{buffer.iterator_at(selection.cursor()), buffer};
|
||||||
if (*first == '\n' and first + 1 != buffer.end())
|
if (*first == '\n' and first + 1 != buffer.end())
|
||||||
|
@ -158,7 +162,8 @@ Selection select_line(const Buffer& buffer, const Selection& selection)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool only_move>
|
template<bool only_move>
|
||||||
Selection select_to_line_end(const Buffer& buffer, const Selection& selection)
|
Optional<Selection>
|
||||||
|
select_to_line_end(const Buffer& buffer, const Selection& selection)
|
||||||
{
|
{
|
||||||
BufferCoord begin = selection.cursor();
|
BufferCoord begin = selection.cursor();
|
||||||
LineCount line = begin.line;
|
LineCount line = begin.line;
|
||||||
|
@ -168,20 +173,22 @@ Selection select_to_line_end(const Buffer& buffer, const Selection& selection)
|
||||||
end = begin;
|
end = begin;
|
||||||
return target_eol({only_move ? end : begin, end});
|
return target_eol({only_move ? end : begin, end});
|
||||||
}
|
}
|
||||||
template Selection select_to_line_end<false>(const Buffer&, const Selection&);
|
template Optional<Selection> select_to_line_end<false>(const Buffer&, const Selection&);
|
||||||
template Selection select_to_line_end<true>(const Buffer&, const Selection&);
|
template Optional<Selection> select_to_line_end<true>(const Buffer&, const Selection&);
|
||||||
|
|
||||||
template<bool only_move>
|
template<bool only_move>
|
||||||
Selection select_to_line_begin(const Buffer& buffer, const Selection& selection)
|
Optional<Selection>
|
||||||
|
select_to_line_begin(const Buffer& buffer, const Selection& selection)
|
||||||
{
|
{
|
||||||
BufferCoord begin = selection.cursor();
|
BufferCoord begin = selection.cursor();
|
||||||
BufferCoord end = begin.line;
|
BufferCoord end = begin.line;
|
||||||
return {only_move ? end : begin, end};
|
return Selection{only_move ? end : begin, end};
|
||||||
}
|
}
|
||||||
template Selection select_to_line_begin<false>(const Buffer&, const Selection&);
|
template Optional<Selection> select_to_line_begin<false>(const Buffer&, const Selection&);
|
||||||
template Selection select_to_line_begin<true>(const Buffer&, const Selection&);
|
template Optional<Selection> select_to_line_begin<true>(const Buffer&, const Selection&);
|
||||||
|
|
||||||
Selection select_to_first_non_blank(const Buffer& buffer, const Selection& selection)
|
Optional<Selection>
|
||||||
|
select_to_first_non_blank(const Buffer& buffer, const Selection& selection)
|
||||||
{
|
{
|
||||||
auto it = buffer.iterator_at(selection.cursor().line);
|
auto it = buffer.iterator_at(selection.cursor().line);
|
||||||
skip_while(it, buffer.iterator_at(selection.cursor().line+1),
|
skip_while(it, buffer.iterator_at(selection.cursor().line+1),
|
||||||
|
@ -189,7 +196,8 @@ Selection select_to_first_non_blank(const Buffer& buffer, const Selection& selec
|
||||||
return {it.coord()};
|
return {it.coord()};
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_matching(const Buffer& buffer, const Selection& selection)
|
Optional<Selection>
|
||||||
|
select_matching(const Buffer& buffer, const Selection& selection)
|
||||||
{
|
{
|
||||||
Vector<Codepoint> matching_pairs = { '(', ')', '{', '}', '[', ']', '<', '>' };
|
Vector<Codepoint> matching_pairs = { '(', ')', '{', '}', '[', ']', '<', '>' };
|
||||||
Utf8Iterator it{buffer.iterator_at(selection.cursor()), buffer};
|
Utf8Iterator it{buffer.iterator_at(selection.cursor()), buffer};
|
||||||
|
@ -202,7 +210,7 @@ Selection select_matching(const Buffer& buffer, const Selection& selection)
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
if (match == matching_pairs.end())
|
if (match == matching_pairs.end())
|
||||||
return selection;
|
return {};
|
||||||
|
|
||||||
Utf8Iterator begin = it;
|
Utf8Iterator begin = it;
|
||||||
|
|
||||||
|
@ -236,7 +244,7 @@ Selection select_matching(const Buffer& buffer, const Selection& selection)
|
||||||
--it;
|
--it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return selection;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Iterator, typename Container>
|
template<typename Iterator, typename Container>
|
||||||
|
@ -333,7 +341,8 @@ find_surrounding(const Container& container, Iterator pos,
|
||||||
opening, closing, flags, init_level);
|
opening, closing, flags, init_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_surrounding(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_surrounding(const Buffer& buffer, const Selection& selection,
|
||||||
StringView opening, StringView closing, int level,
|
StringView opening, StringView closing, int level,
|
||||||
ObjectFlags flags)
|
ObjectFlags flags)
|
||||||
{
|
{
|
||||||
|
@ -344,7 +353,7 @@ Selection select_surrounding(const Buffer& buffer, const Selection& selection,
|
||||||
if (auto res = find_surrounding(buffer, buffer.iterator_at(pos),
|
if (auto res = find_surrounding(buffer, buffer.iterator_at(pos),
|
||||||
opening, closing, flags, level))
|
opening, closing, flags, level))
|
||||||
return utf8_range(res->first, res->second);
|
return utf8_range(res->first, res->second);
|
||||||
return selection;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto c = buffer.byte_at(pos);
|
auto c = buffer.byte_at(pos);
|
||||||
|
@ -355,21 +364,22 @@ Selection select_surrounding(const Buffer& buffer, const Selection& selection,
|
||||||
auto res = find_surrounding(buffer, buffer.iterator_at(pos),
|
auto res = find_surrounding(buffer, buffer.iterator_at(pos),
|
||||||
opening, closing, flags, level);
|
opening, closing, flags, level);
|
||||||
if (not res)
|
if (not res)
|
||||||
return selection;
|
return {};
|
||||||
|
|
||||||
Selection sel = utf8_range(res->first, res->second);
|
Selection sel = utf8_range(res->first, res->second);
|
||||||
|
|
||||||
if (flags == (ObjectFlags::ToBegin | ObjectFlags::ToEnd) and
|
if (flags != (ObjectFlags::ToBegin | ObjectFlags::ToEnd) or
|
||||||
sel.min() == selection.min() and sel.max() == selection.max())
|
sel.min() != selection.min() or sel.max() != selection.max())
|
||||||
{
|
return sel;
|
||||||
|
|
||||||
if (auto res_parent = find_surrounding(buffer, buffer.iterator_at(pos),
|
if (auto res_parent = find_surrounding(buffer, buffer.iterator_at(pos),
|
||||||
opening, closing, flags, level+1))
|
opening, closing, flags, level+1))
|
||||||
return utf8_range(res_parent->first, res_parent->second);
|
return utf8_range(res_parent->first, res_parent->second);
|
||||||
}
|
return {};
|
||||||
return sel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_to(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_to(const Buffer& buffer, const Selection& selection,
|
||||||
Codepoint c, int count, bool inclusive)
|
Codepoint c, int count, bool inclusive)
|
||||||
{
|
{
|
||||||
Utf8Iterator begin{buffer.iterator_at(selection.cursor()), buffer};
|
Utf8Iterator begin{buffer.iterator_at(selection.cursor()), buffer};
|
||||||
|
@ -379,14 +389,15 @@ Selection select_to(const Buffer& buffer, const Selection& selection,
|
||||||
++end;
|
++end;
|
||||||
skip_while(end, buffer.end(), [c](Codepoint cur) { return cur != c; });
|
skip_while(end, buffer.end(), [c](Codepoint cur) { return cur != c; });
|
||||||
if (end == buffer.end())
|
if (end == buffer.end())
|
||||||
return selection;
|
return {};
|
||||||
}
|
}
|
||||||
while (--count > 0);
|
while (--count > 0);
|
||||||
|
|
||||||
return utf8_range(begin, inclusive ? end : end-1);
|
return utf8_range(begin, inclusive ? end : end-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_to_reverse(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_to_reverse(const Buffer& buffer, const Selection& selection,
|
||||||
Codepoint c, int count, bool inclusive)
|
Codepoint c, int count, bool inclusive)
|
||||||
{
|
{
|
||||||
Utf8Iterator begin{buffer.iterator_at(selection.cursor()), buffer};
|
Utf8Iterator begin{buffer.iterator_at(selection.cursor()), buffer};
|
||||||
|
@ -396,14 +407,16 @@ Selection select_to_reverse(const Buffer& buffer, const Selection& selection,
|
||||||
--end;
|
--end;
|
||||||
if (skip_while_reverse(end, buffer.begin(),
|
if (skip_while_reverse(end, buffer.begin(),
|
||||||
[c](Codepoint cur) { return cur != c; }))
|
[c](Codepoint cur) { return cur != c; }))
|
||||||
return selection;
|
return {};
|
||||||
}
|
}
|
||||||
while (--count > 0);
|
while (--count > 0);
|
||||||
|
|
||||||
return utf8_range(begin, inclusive ? end : end+1);
|
return utf8_range(begin, inclusive ? end : end+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_number(const Buffer& buffer, const Selection& selection, int count, ObjectFlags flags)
|
Optional<Selection>
|
||||||
|
select_number(const Buffer& buffer, const Selection& selection,
|
||||||
|
int count, ObjectFlags flags)
|
||||||
{
|
{
|
||||||
auto is_number = [&](char c) {
|
auto is_number = [&](char c) {
|
||||||
return (c >= '0' and c <= '9') or
|
return (c >= '0' and c <= '9') or
|
||||||
|
@ -414,7 +427,7 @@ Selection select_number(const Buffer& buffer, const Selection& selection, int co
|
||||||
BufferIterator last = first;
|
BufferIterator last = first;
|
||||||
|
|
||||||
if (not is_number(*first) and *first != '-')
|
if (not is_number(*first) and *first != '-')
|
||||||
return selection;
|
return {};
|
||||||
|
|
||||||
if (flags & ObjectFlags::ToBegin)
|
if (flags & ObjectFlags::ToBegin)
|
||||||
{
|
{
|
||||||
|
@ -437,7 +450,9 @@ Selection select_number(const Buffer& buffer, const Selection& selection, int co
|
||||||
: Selection{last.coord(), first.coord()};
|
: Selection{last.coord(), first.coord()};
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_sentence(const Buffer& buffer, const Selection& selection, int count, ObjectFlags flags)
|
Optional<Selection>
|
||||||
|
select_sentence(const Buffer& buffer, const Selection& selection,
|
||||||
|
int count, ObjectFlags flags)
|
||||||
{
|
{
|
||||||
auto is_end_of_sentence = [](char c) {
|
auto is_end_of_sentence = [](char c) {
|
||||||
return c == '.' or c == ';' or c == '!' or c == '?';
|
return c == '.' or c == ';' or c == '!' or c == '?';
|
||||||
|
@ -502,7 +517,9 @@ Selection select_sentence(const Buffer& buffer, const Selection& selection, int
|
||||||
: Selection{last.coord(), first.coord()};
|
: Selection{last.coord(), first.coord()};
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_paragraph(const Buffer& buffer, const Selection& selection, int count, ObjectFlags flags)
|
Optional<Selection>
|
||||||
|
select_paragraph(const Buffer& buffer, const Selection& selection,
|
||||||
|
int count, ObjectFlags flags)
|
||||||
{
|
{
|
||||||
BufferIterator first = buffer.iterator_at(selection.cursor());
|
BufferIterator first = buffer.iterator_at(selection.cursor());
|
||||||
|
|
||||||
|
@ -555,7 +572,9 @@ Selection select_paragraph(const Buffer& buffer, const Selection& selection, int
|
||||||
: Selection{last.coord(), first.coord()};
|
: Selection{last.coord(), first.coord()};
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_whitespaces(const Buffer& buffer, const Selection& selection, int count, ObjectFlags flags)
|
Optional<Selection>
|
||||||
|
select_whitespaces(const Buffer& buffer, const Selection& selection,
|
||||||
|
int count, ObjectFlags flags)
|
||||||
{
|
{
|
||||||
auto is_whitespace = [&](char c) {
|
auto is_whitespace = [&](char c) {
|
||||||
return c == ' ' or c == '\t' or
|
return c == ' ' or c == '\t' or
|
||||||
|
@ -563,6 +582,10 @@ Selection select_whitespaces(const Buffer& buffer, const Selection& selection, i
|
||||||
};
|
};
|
||||||
BufferIterator first = buffer.iterator_at(selection.cursor());
|
BufferIterator first = buffer.iterator_at(selection.cursor());
|
||||||
BufferIterator last = first;
|
BufferIterator last = first;
|
||||||
|
|
||||||
|
if (not is_whitespace(*first))
|
||||||
|
return {};
|
||||||
|
|
||||||
if (flags & ObjectFlags::ToBegin)
|
if (flags & ObjectFlags::ToBegin)
|
||||||
{
|
{
|
||||||
if (is_whitespace(*first))
|
if (is_whitespace(*first))
|
||||||
|
@ -584,7 +607,9 @@ Selection select_whitespaces(const Buffer& buffer, const Selection& selection, i
|
||||||
: Selection{last.coord(), first.coord()};
|
: Selection{last.coord(), first.coord()};
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_indent(const Buffer& buffer, const Selection& selection, int count, ObjectFlags flags)
|
Optional<Selection>
|
||||||
|
select_indent(const Buffer& buffer, const Selection& selection,
|
||||||
|
int count, ObjectFlags flags)
|
||||||
{
|
{
|
||||||
auto get_indent = [](StringView str, int tabstop) {
|
auto get_indent = [](StringView str, int tabstop) {
|
||||||
CharCount indent = 0;
|
CharCount indent = 0;
|
||||||
|
@ -641,7 +666,8 @@ Selection select_indent(const Buffer& buffer, const Selection& selection, int co
|
||||||
return Selection{begin_line, {end_line, buffer[end_line].length() - 1}};
|
return Selection{begin_line, {end_line, buffer[end_line].length() - 1}};
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_argument(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_argument(const Buffer& buffer, const Selection& selection,
|
||||||
int level, ObjectFlags flags)
|
int level, ObjectFlags flags)
|
||||||
{
|
{
|
||||||
enum Class { None, Opening, Closing, Delimiter };
|
enum Class { None, Opening, Closing, Delimiter };
|
||||||
|
@ -724,11 +750,13 @@ Selection select_argument(const Buffer& buffer, const Selection& selection,
|
||||||
--end;
|
--end;
|
||||||
|
|
||||||
if (flags & ObjectFlags::ToBegin and not (flags & ObjectFlags::ToEnd))
|
if (flags & ObjectFlags::ToBegin and not (flags & ObjectFlags::ToEnd))
|
||||||
return {pos.coord(), begin.coord()};
|
return Selection{pos.coord(), begin.coord()};
|
||||||
return {(flags & ObjectFlags::ToBegin ? begin : pos).coord(), end.coord()};
|
return Selection{(flags & ObjectFlags::ToBegin ? begin : pos).coord(),
|
||||||
|
end.coord()};
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection select_lines(const Buffer& buffer, const Selection& selection)
|
Optional<Selection>
|
||||||
|
select_lines(const Buffer& buffer, const Selection& selection)
|
||||||
{
|
{
|
||||||
BufferCoord anchor = selection.anchor();
|
BufferCoord anchor = selection.anchor();
|
||||||
BufferCoord cursor = selection.cursor();
|
BufferCoord cursor = selection.cursor();
|
||||||
|
@ -741,7 +769,8 @@ Selection select_lines(const Buffer& buffer, const Selection& selection)
|
||||||
return target_eol({anchor, cursor});
|
return target_eol({anchor, cursor});
|
||||||
}
|
}
|
||||||
|
|
||||||
Selection trim_partial_lines(const Buffer& buffer, const Selection& selection)
|
Optional<Selection>
|
||||||
|
trim_partial_lines(const Buffer& buffer, const Selection& selection)
|
||||||
{
|
{
|
||||||
BufferCoord anchor = selection.anchor();
|
BufferCoord anchor = selection.anchor();
|
||||||
BufferCoord cursor = selection.cursor();
|
BufferCoord cursor = selection.cursor();
|
||||||
|
@ -753,14 +782,14 @@ Selection trim_partial_lines(const Buffer& buffer, const Selection& selection)
|
||||||
if (to_line_end.column != buffer[to_line_end.line].length()-1)
|
if (to_line_end.column != buffer[to_line_end.line].length()-1)
|
||||||
{
|
{
|
||||||
if (to_line_end.line == 0)
|
if (to_line_end.line == 0)
|
||||||
return selection;
|
return {};
|
||||||
|
|
||||||
auto prev_line = to_line_end.line-1;
|
auto prev_line = to_line_end.line-1;
|
||||||
to_line_end = BufferCoord{ prev_line, buffer[prev_line].length()-1 };
|
to_line_end = BufferCoord{ prev_line, buffer[prev_line].length()-1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to_line_start > to_line_end)
|
if (to_line_start > to_line_end)
|
||||||
return selection;
|
return {};
|
||||||
|
|
||||||
return target_eol({anchor, cursor});
|
return target_eol({anchor, cursor});
|
||||||
}
|
}
|
||||||
|
@ -772,7 +801,7 @@ void select_buffer(SelectionList& selections)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Direction direction>
|
template<Direction direction>
|
||||||
bool find_match_in_buffer(const Buffer& buffer, const BufferIterator pos,
|
static bool find_match_in_buffer(const Buffer& buffer, const BufferIterator pos,
|
||||||
MatchResults<BufferIterator>& matches,
|
MatchResults<BufferIterator>& matches,
|
||||||
const Regex& ex, bool& wrapped)
|
const Regex& ex, bool& wrapped)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,29 +18,40 @@ inline Selection keep_direction(Selection res, const Selection& ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<WordType word_type>
|
template<WordType word_type>
|
||||||
Selection select_to_next_word(const Buffer& buffer, const Selection& selection);
|
Optional<Selection>
|
||||||
|
select_to_next_word(const Buffer& buffer, const Selection& selection);
|
||||||
|
|
||||||
template<WordType word_type>
|
template<WordType word_type>
|
||||||
Selection select_to_next_word_end(const Buffer& buffer, const Selection& selection);
|
Optional<Selection>
|
||||||
|
select_to_next_word_end(const Buffer& buffer, const Selection& selection);
|
||||||
|
|
||||||
template<WordType word_type>
|
template<WordType word_type>
|
||||||
Selection select_to_previous_word(const Buffer& buffer, const Selection& selection);
|
Optional<Selection>
|
||||||
|
select_to_previous_word(const Buffer& buffer, const Selection& selection);
|
||||||
|
|
||||||
Selection select_line(const Buffer& buffer, const Selection& selection);
|
Optional<Selection>
|
||||||
Selection select_matching(const Buffer& buffer, const Selection& selection);
|
select_line(const Buffer& buffer, const Selection& selection);
|
||||||
|
|
||||||
Selection select_to(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_matching(const Buffer& buffer, const Selection& selection);
|
||||||
|
|
||||||
|
Optional<Selection>
|
||||||
|
select_to(const Buffer& buffer, const Selection& selection,
|
||||||
Codepoint c, int count, bool inclusive);
|
Codepoint c, int count, bool inclusive);
|
||||||
Selection select_to_reverse(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_to_reverse(const Buffer& buffer, const Selection& selection,
|
||||||
Codepoint c, int count, bool inclusive);
|
Codepoint c, int count, bool inclusive);
|
||||||
|
|
||||||
template<bool only_move>
|
template<bool only_move>
|
||||||
Selection select_to_line_end(const Buffer& buffer, const Selection& selection);
|
Optional<Selection>
|
||||||
|
select_to_line_end(const Buffer& buffer, const Selection& selection);
|
||||||
|
|
||||||
template<bool only_move>
|
template<bool only_move>
|
||||||
Selection select_to_line_begin(const Buffer& buffer, const Selection& selection);
|
Optional<Selection>
|
||||||
|
select_to_line_begin(const Buffer& buffer, const Selection& selection);
|
||||||
|
|
||||||
Selection select_to_first_non_blank(const Buffer& buffer, const Selection& selection);
|
Optional<Selection>
|
||||||
|
select_to_first_non_blank(const Buffer& buffer, const Selection& selection);
|
||||||
|
|
||||||
enum class ObjectFlags
|
enum class ObjectFlags
|
||||||
{
|
{
|
||||||
|
@ -52,47 +63,53 @@ enum class ObjectFlags
|
||||||
template<> struct WithBitOps<ObjectFlags> : std::true_type {};
|
template<> struct WithBitOps<ObjectFlags> : std::true_type {};
|
||||||
|
|
||||||
template<WordType word_type>
|
template<WordType word_type>
|
||||||
Selection select_word(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_word(const Buffer& buffer, const Selection& selection,
|
||||||
int count, ObjectFlags flags);
|
int count, ObjectFlags flags);
|
||||||
|
|
||||||
Selection select_number(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_number(const Buffer& buffer, const Selection& selection,
|
||||||
int count, ObjectFlags flags);
|
int count, ObjectFlags flags);
|
||||||
|
|
||||||
Selection select_sentence(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_sentence(const Buffer& buffer, const Selection& selection,
|
||||||
int count, ObjectFlags flags);
|
int count, ObjectFlags flags);
|
||||||
|
|
||||||
Selection select_paragraph(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_paragraph(const Buffer& buffer, const Selection& selection,
|
||||||
int count, ObjectFlags flags);
|
int count, ObjectFlags flags);
|
||||||
|
|
||||||
Selection select_whitespaces(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_whitespaces(const Buffer& buffer, const Selection& selection,
|
||||||
int count, ObjectFlags flags);
|
int count, ObjectFlags flags);
|
||||||
|
|
||||||
Selection select_indent(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_indent(const Buffer& buffer, const Selection& selection,
|
||||||
int count, ObjectFlags flags);
|
int count, ObjectFlags flags);
|
||||||
|
|
||||||
Selection select_argument(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_argument(const Buffer& buffer, const Selection& selection,
|
||||||
int level, ObjectFlags flags);
|
int level, ObjectFlags flags);
|
||||||
|
|
||||||
Selection select_lines(const Buffer& buffer, const Selection& selection);
|
Optional<Selection>
|
||||||
|
select_lines(const Buffer& buffer, const Selection& selection);
|
||||||
|
|
||||||
Selection trim_partial_lines(const Buffer& buffer, const Selection& selection);
|
Optional<Selection>
|
||||||
|
trim_partial_lines(const Buffer& buffer, const Selection& selection);
|
||||||
|
|
||||||
void select_buffer(SelectionList& selections);
|
void select_buffer(SelectionList& selections);
|
||||||
|
|
||||||
enum Direction { Forward, Backward };
|
enum Direction { Forward, Backward };
|
||||||
|
|
||||||
template<Direction direction>
|
template<Direction direction>
|
||||||
bool find_match_in_buffer(const Buffer& buffer, const BufferIterator pos,
|
Selection find_next_match(const Buffer& buffer, const Selection& sel,
|
||||||
MatchResults<BufferIterator>& matches,
|
const Regex& regex, bool& wrapped);
|
||||||
const Regex& ex, bool& wrapped);
|
|
||||||
|
|
||||||
template<Direction direction>
|
|
||||||
Selection find_next_match(const Buffer& buffer, const Selection& sel, const Regex& regex, bool& wrapped);
|
|
||||||
|
|
||||||
void select_all_matches(SelectionList& selections, const Regex& regex, int capture = 0);
|
void select_all_matches(SelectionList& selections, const Regex& regex, int capture = 0);
|
||||||
void split_selections(SelectionList& selections, const Regex& separator_regex, int capture = 0);
|
void split_selections(SelectionList& selections, const Regex& separator_regex, int capture = 0);
|
||||||
|
|
||||||
Selection select_surrounding(const Buffer& buffer, const Selection& selection,
|
Optional<Selection>
|
||||||
|
select_surrounding(const Buffer& buffer, const Selection& selection,
|
||||||
StringView opening, StringView closing, int level,
|
StringView opening, StringView closing, int level,
|
||||||
ObjectFlags flags);
|
ObjectFlags flags);
|
||||||
|
|
||||||
|
|
1
test/unit/object/drop-non-whitespace/cmd
Normal file
1
test/unit/object/drop-non-whitespace/cmd
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<a-a>
|
3
test/unit/object/drop-non-whitespace/in
Normal file
3
test/unit/object/drop-non-whitespace/in
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
wo%(r)d
|
||||||
|
foo %( ) bar
|
||||||
|
baz%( )qux
|
1
test/unit/object/drop-non-whitespace/selections
Normal file
1
test/unit/object/drop-non-whitespace/selections
Normal file
|
@ -0,0 +1 @@
|
||||||
|
:
|
Loading…
Reference in New Issue
Block a user