Move template selectors to the header
This commit is contained in:
parent
93b561983a
commit
0c4d523b22
192
src/selectors.cc
192
src/selectors.cc
|
@ -1,7 +1,6 @@
|
||||||
#include "selectors.hh"
|
#include "selectors.hh"
|
||||||
|
|
||||||
#include "string.hh"
|
#include "string.hh"
|
||||||
#include "utf8_iterator.hh"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -10,153 +9,6 @@
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
using Utf8Iterator = utf8::utf8_iterator<BufferIterator, utf8::InvalidBytePolicy::Pass>;
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
template<WordType word_type = Word>
|
|
||||||
bool is_word(Codepoint c)
|
|
||||||
{
|
|
||||||
return Kakoune::is_word(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
bool is_word<WORD>(Codepoint c)
|
|
||||||
{
|
|
||||||
return !is_blank(c) and !is_eol(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_punctuation(Codepoint c)
|
|
||||||
{
|
|
||||||
return not (is_word(c) or is_blank(c) or is_eol(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class CharCategories
|
|
||||||
{
|
|
||||||
Blank,
|
|
||||||
EndOfLine,
|
|
||||||
Word,
|
|
||||||
Punctuation,
|
|
||||||
};
|
|
||||||
|
|
||||||
template<WordType word_type = Word>
|
|
||||||
CharCategories categorize(Codepoint c)
|
|
||||||
{
|
|
||||||
if (is_word(c))
|
|
||||||
return CharCategories::Word;
|
|
||||||
if (is_eol(c))
|
|
||||||
return CharCategories::EndOfLine;
|
|
||||||
if (is_blank(c))
|
|
||||||
return CharCategories::Blank;
|
|
||||||
return word_type == WORD ? CharCategories::Word
|
|
||||||
: CharCategories::Punctuation;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Iterator, typename EndIterator, typename T>
|
|
||||||
void skip_while(Iterator& it, const EndIterator& end, T condition)
|
|
||||||
{
|
|
||||||
while (it != end and condition(*it))
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Iterator, typename BeginIterator, typename T>
|
|
||||||
void skip_while_reverse(Iterator& it, const BeginIterator& begin, T condition)
|
|
||||||
{
|
|
||||||
while (it != begin and condition(*it))
|
|
||||||
--it;
|
|
||||||
}
|
|
||||||
|
|
||||||
Range utf8_range(const Utf8Iterator& first, const Utf8Iterator& last)
|
|
||||||
{
|
|
||||||
return {first.base().coord(), last.base().coord()};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef boost::regex_iterator<BufferIterator> RegexIterator;
|
|
||||||
|
|
||||||
template<WordType word_type>
|
|
||||||
Selection select_to_next_word(const Buffer& buffer, const Selection& selection)
|
|
||||||
{
|
|
||||||
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
|
||||||
if (begin+1 == buffer.end())
|
|
||||||
return selection;
|
|
||||||
if (categorize<word_type>(*begin) != categorize<word_type>(*(begin+1)))
|
|
||||||
++begin;
|
|
||||||
|
|
||||||
skip_while(begin, buffer.end(), is_eol);
|
|
||||||
if (begin == buffer.end())
|
|
||||||
return selection;
|
|
||||||
Utf8Iterator end = begin+1;
|
|
||||||
|
|
||||||
if (word_type == Word and is_punctuation(*begin))
|
|
||||||
skip_while(end, buffer.end(), is_punctuation);
|
|
||||||
else if (is_word<word_type>(*begin))
|
|
||||||
skip_while(end, buffer.end(), is_word<word_type>);
|
|
||||||
|
|
||||||
skip_while(end, buffer.end(), is_blank);
|
|
||||||
|
|
||||||
return utf8_range(begin, end-1);
|
|
||||||
}
|
|
||||||
template Selection select_to_next_word<Word>(const Buffer&, const Selection&);
|
|
||||||
template Selection select_to_next_word<WORD>(const Buffer&, const Selection&);
|
|
||||||
|
|
||||||
template<WordType word_type>
|
|
||||||
Selection select_to_next_word_end(const Buffer& buffer, const Selection& selection)
|
|
||||||
{
|
|
||||||
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
|
||||||
if (begin+1 == buffer.end())
|
|
||||||
return selection;
|
|
||||||
if (categorize<word_type>(*begin) != categorize<word_type>(*(begin+1)))
|
|
||||||
++begin;
|
|
||||||
|
|
||||||
skip_while(begin, buffer.end(), is_eol);
|
|
||||||
if (begin == buffer.end())
|
|
||||||
return selection;
|
|
||||||
Utf8Iterator end = begin;
|
|
||||||
skip_while(end, buffer.end(), is_blank);
|
|
||||||
|
|
||||||
if (word_type == Word and is_punctuation(*end))
|
|
||||||
skip_while(end, buffer.end(), is_punctuation);
|
|
||||||
else if (is_word<word_type>(*end))
|
|
||||||
skip_while(end, buffer.end(), is_word<word_type>);
|
|
||||||
|
|
||||||
return utf8_range(begin, end-1);
|
|
||||||
}
|
|
||||||
template Selection select_to_next_word_end<Word>(const Buffer&, const Selection&);
|
|
||||||
template Selection select_to_next_word_end<WORD>(const Buffer&, const Selection&);
|
|
||||||
|
|
||||||
template<WordType word_type>
|
|
||||||
Selection select_to_previous_word(const Buffer& buffer, const Selection& selection)
|
|
||||||
{
|
|
||||||
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
|
||||||
if (begin == buffer.begin())
|
|
||||||
return selection;
|
|
||||||
if (categorize<word_type>(*begin) != categorize<word_type>(*(begin-1)))
|
|
||||||
--begin;
|
|
||||||
|
|
||||||
skip_while_reverse(begin, buffer.begin(), is_eol);
|
|
||||||
Utf8Iterator end = begin;
|
|
||||||
skip_while_reverse(end, buffer.begin(), is_blank);
|
|
||||||
|
|
||||||
bool with_end = false;
|
|
||||||
if (word_type == Word and is_punctuation(*end))
|
|
||||||
{
|
|
||||||
skip_while_reverse(end, buffer.begin(), is_punctuation);
|
|
||||||
with_end = is_punctuation(*end);
|
|
||||||
}
|
|
||||||
else if (is_word<word_type>(*end))
|
|
||||||
{
|
|
||||||
skip_while_reverse(end, buffer.begin(), is_word<word_type>);
|
|
||||||
with_end = is_word<word_type>(*end);
|
|
||||||
}
|
|
||||||
|
|
||||||
return utf8_range(begin, with_end ? end : end+1);
|
|
||||||
}
|
|
||||||
template Selection select_to_previous_word<Word>(const Buffer&, const Selection&);
|
|
||||||
template Selection select_to_previous_word<WORD>(const Buffer&, const Selection&);
|
|
||||||
|
|
||||||
Selection select_line(const Buffer& buffer, const Selection& selection)
|
Selection select_line(const Buffer& buffer, const Selection& selection)
|
||||||
{
|
{
|
||||||
Utf8Iterator first = buffer.iterator_at(selection.last());
|
Utf8Iterator first = buffer.iterator_at(selection.last());
|
||||||
|
@ -366,50 +218,6 @@ Selection select_to_eol_reverse(const Buffer& buffer, const Selection& selection
|
||||||
return utf8_range(begin, end == buffer.begin() ? end : end+1);
|
return utf8_range(begin, end == buffer.begin() ? end : end+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<WordType word_type>
|
|
||||||
Selection select_whole_word(const Buffer& buffer, const Selection& selection, ObjectFlags flags)
|
|
||||||
{
|
|
||||||
Utf8Iterator first = buffer.iterator_at(selection.last());
|
|
||||||
Utf8Iterator last = first;
|
|
||||||
if (is_word<word_type>(*first))
|
|
||||||
{
|
|
||||||
if (flags & ObjectFlags::ToBegin)
|
|
||||||
{
|
|
||||||
skip_while_reverse(first, buffer.begin(), is_word<word_type>);
|
|
||||||
if (not is_word<word_type>(*first))
|
|
||||||
++first;
|
|
||||||
}
|
|
||||||
if (flags & ObjectFlags::ToEnd)
|
|
||||||
{
|
|
||||||
skip_while(last, buffer.end(), is_word<word_type>);
|
|
||||||
if (not (flags & ObjectFlags::Inner))
|
|
||||||
skip_while(last, buffer.end(), is_blank);
|
|
||||||
--last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (not (flags & ObjectFlags::Inner))
|
|
||||||
{
|
|
||||||
if (flags & ObjectFlags::ToBegin)
|
|
||||||
{
|
|
||||||
skip_while_reverse(first, buffer.begin(), is_blank);
|
|
||||||
if (not is_word<word_type>(*first))
|
|
||||||
return selection;
|
|
||||||
skip_while_reverse(first, buffer.begin(), is_word<word_type>);
|
|
||||||
if (not is_word<word_type>(*first))
|
|
||||||
++first;
|
|
||||||
}
|
|
||||||
if (flags & ObjectFlags::ToEnd)
|
|
||||||
{
|
|
||||||
skip_while(last, buffer.end(), is_blank);
|
|
||||||
--last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (flags & ObjectFlags::ToEnd) ? utf8_range(first, last)
|
|
||||||
: utf8_range(last, first);
|
|
||||||
}
|
|
||||||
template Selection select_whole_word<Word>(const Buffer&, const Selection&, ObjectFlags);
|
|
||||||
template Selection select_whole_word<WORD>(const Buffer&, const Selection&, ObjectFlags);
|
|
||||||
|
|
||||||
Selection select_whole_sentence(const Buffer& buffer, const Selection& selection, ObjectFlags flags)
|
Selection select_whole_sentence(const Buffer& buffer, const Selection& selection, ObjectFlags flags)
|
||||||
{
|
{
|
||||||
BufferIterator first = buffer.iterator_at(selection.last());
|
BufferIterator first = buffer.iterator_at(selection.last());
|
||||||
|
|
130
src/selectors.hh
130
src/selectors.hh
|
@ -4,6 +4,7 @@
|
||||||
#include "selection.hh"
|
#include "selection.hh"
|
||||||
#include "unicode.hh"
|
#include "unicode.hh"
|
||||||
#include "editor.hh"
|
#include "editor.hh"
|
||||||
|
#include "utf8_iterator.hh"
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
@ -49,17 +50,89 @@ inline void remove_selection(const Buffer&, SelectionList& selections, int index
|
||||||
selections.check_invariant();
|
selections.check_invariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum WordType { Word, WORD };
|
using Utf8Iterator = utf8::utf8_iterator<BufferIterator, utf8::InvalidBytePolicy::Pass>;
|
||||||
|
|
||||||
|
inline Range utf8_range(const Utf8Iterator& first, const Utf8Iterator& last)
|
||||||
|
{
|
||||||
|
return {first.base().coord(), last.base().coord()};
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef boost::regex_iterator<BufferIterator> RegexIterator;
|
||||||
|
|
||||||
template<WordType word_type>
|
template<WordType word_type>
|
||||||
Selection select_to_next_word(const Buffer& buffer,
|
Selection select_to_next_word(const Buffer& buffer, const Selection& selection)
|
||||||
const Selection& selection);
|
{
|
||||||
|
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
||||||
|
if (begin+1 == buffer.end())
|
||||||
|
return selection;
|
||||||
|
if (categorize<word_type>(*begin) != categorize<word_type>(*(begin+1)))
|
||||||
|
++begin;
|
||||||
|
|
||||||
|
skip_while(begin, buffer.end(), is_eol);
|
||||||
|
if (begin == buffer.end())
|
||||||
|
return selection;
|
||||||
|
Utf8Iterator end = begin+1;
|
||||||
|
|
||||||
|
if (word_type == Word and is_punctuation(*begin))
|
||||||
|
skip_while(end, buffer.end(), is_punctuation);
|
||||||
|
else if (is_word<word_type>(*begin))
|
||||||
|
skip_while(end, buffer.end(), is_word<word_type>);
|
||||||
|
|
||||||
|
skip_while(end, buffer.end(), is_blank);
|
||||||
|
|
||||||
|
return utf8_range(begin, end-1);
|
||||||
|
}
|
||||||
|
|
||||||
template<WordType word_type>
|
template<WordType word_type>
|
||||||
Selection select_to_next_word_end(const Buffer& buffer,
|
Selection select_to_next_word_end(const Buffer& buffer, const Selection& selection)
|
||||||
const Selection& selection);
|
{
|
||||||
|
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
||||||
|
if (begin+1 == buffer.end())
|
||||||
|
return selection;
|
||||||
|
if (categorize<word_type>(*begin) != categorize<word_type>(*(begin+1)))
|
||||||
|
++begin;
|
||||||
|
|
||||||
|
skip_while(begin, buffer.end(), is_eol);
|
||||||
|
if (begin == buffer.end())
|
||||||
|
return selection;
|
||||||
|
Utf8Iterator end = begin;
|
||||||
|
skip_while(end, buffer.end(), is_blank);
|
||||||
|
|
||||||
|
if (word_type == Word and is_punctuation(*end))
|
||||||
|
skip_while(end, buffer.end(), is_punctuation);
|
||||||
|
else if (is_word<word_type>(*end))
|
||||||
|
skip_while(end, buffer.end(), is_word<word_type>);
|
||||||
|
|
||||||
|
return utf8_range(begin, end-1);
|
||||||
|
}
|
||||||
|
|
||||||
template<WordType word_type>
|
template<WordType word_type>
|
||||||
Selection select_to_previous_word(const Buffer& buffer,
|
Selection select_to_previous_word(const Buffer& buffer, const Selection& selection)
|
||||||
const Selection& selection);
|
{
|
||||||
|
Utf8Iterator begin = buffer.iterator_at(selection.last());
|
||||||
|
if (begin == buffer.begin())
|
||||||
|
return selection;
|
||||||
|
if (categorize<word_type>(*begin) != categorize<word_type>(*(begin-1)))
|
||||||
|
--begin;
|
||||||
|
|
||||||
|
skip_while_reverse(begin, buffer.begin(), is_eol);
|
||||||
|
Utf8Iterator end = begin;
|
||||||
|
skip_while_reverse(end, buffer.begin(), is_blank);
|
||||||
|
|
||||||
|
bool with_end = false;
|
||||||
|
if (word_type == Word and is_punctuation(*end))
|
||||||
|
{
|
||||||
|
skip_while_reverse(end, buffer.begin(), is_punctuation);
|
||||||
|
with_end = is_punctuation(*end);
|
||||||
|
}
|
||||||
|
else if (is_word<word_type>(*end))
|
||||||
|
{
|
||||||
|
skip_while_reverse(end, buffer.begin(), is_word<word_type>);
|
||||||
|
with_end = is_word<word_type>(*end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return utf8_range(begin, with_end ? end : end+1);
|
||||||
|
}
|
||||||
|
|
||||||
Selection select_line(const Buffer& buffer,
|
Selection select_line(const Buffer& buffer,
|
||||||
const Selection& selection);
|
const Selection& selection);
|
||||||
|
@ -86,8 +159,47 @@ constexpr ObjectFlags operator|(ObjectFlags lhs, ObjectFlags rhs)
|
||||||
{ return (ObjectFlags)((int)lhs | (int) rhs); }
|
{ return (ObjectFlags)((int)lhs | (int) rhs); }
|
||||||
|
|
||||||
template<WordType word_type>
|
template<WordType word_type>
|
||||||
Selection select_whole_word(const Buffer& buffer, const Selection& selection,
|
Selection select_whole_word(const Buffer& buffer, const Selection& selection, ObjectFlags flags)
|
||||||
ObjectFlags flags);
|
{
|
||||||
|
Utf8Iterator first = buffer.iterator_at(selection.last());
|
||||||
|
Utf8Iterator last = first;
|
||||||
|
if (is_word<word_type>(*first))
|
||||||
|
{
|
||||||
|
if (flags & ObjectFlags::ToBegin)
|
||||||
|
{
|
||||||
|
skip_while_reverse(first, buffer.begin(), is_word<word_type>);
|
||||||
|
if (not is_word<word_type>(*first))
|
||||||
|
++first;
|
||||||
|
}
|
||||||
|
if (flags & ObjectFlags::ToEnd)
|
||||||
|
{
|
||||||
|
skip_while(last, buffer.end(), is_word<word_type>);
|
||||||
|
if (not (flags & ObjectFlags::Inner))
|
||||||
|
skip_while(last, buffer.end(), is_blank);
|
||||||
|
--last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (not (flags & ObjectFlags::Inner))
|
||||||
|
{
|
||||||
|
if (flags & ObjectFlags::ToBegin)
|
||||||
|
{
|
||||||
|
skip_while_reverse(first, buffer.begin(), is_blank);
|
||||||
|
if (not is_word<word_type>(*first))
|
||||||
|
return selection;
|
||||||
|
skip_while_reverse(first, buffer.begin(), is_word<word_type>);
|
||||||
|
if (not is_word<word_type>(*first))
|
||||||
|
++first;
|
||||||
|
}
|
||||||
|
if (flags & ObjectFlags::ToEnd)
|
||||||
|
{
|
||||||
|
skip_while(last, buffer.end(), is_blank);
|
||||||
|
--last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (flags & ObjectFlags::ToEnd) ? utf8_range(first, last)
|
||||||
|
: utf8_range(last, first);
|
||||||
|
}
|
||||||
|
|
||||||
Selection select_whole_sentence(const Buffer& buffer, const Selection& selection,
|
Selection select_whole_sentence(const Buffer& buffer, const Selection& selection,
|
||||||
ObjectFlags flags);
|
ObjectFlags flags);
|
||||||
Selection select_whole_paragraph(const Buffer& buffer, const Selection& selection,
|
Selection select_whole_paragraph(const Buffer& buffer, const Selection& selection,
|
||||||
|
|
|
@ -9,11 +9,6 @@ namespace Kakoune
|
||||||
|
|
||||||
using Codepoint = uint32_t;
|
using Codepoint = uint32_t;
|
||||||
|
|
||||||
inline bool is_word(Codepoint c)
|
|
||||||
{
|
|
||||||
return c == '_' or isalnum(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool is_eol(Codepoint c)
|
inline bool is_eol(Codepoint c)
|
||||||
{
|
{
|
||||||
return c == '\n';
|
return c == '\n';
|
||||||
|
@ -29,6 +24,46 @@ inline bool is_horizontal_blank(Codepoint c)
|
||||||
return c == ' ' or c == '\t';
|
return c == ' ' or c == '\t';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum WordType { Word, WORD };
|
||||||
|
|
||||||
|
template<WordType word_type = Word>
|
||||||
|
inline bool is_word(Codepoint c)
|
||||||
|
{
|
||||||
|
return c == '_' or isalnum(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool is_word<WORD>(Codepoint c)
|
||||||
|
{
|
||||||
|
return !is_blank(c) and !is_eol(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_punctuation(Codepoint c)
|
||||||
|
{
|
||||||
|
return not (is_word(c) or is_blank(c) or is_eol(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class CharCategories
|
||||||
|
{
|
||||||
|
Blank,
|
||||||
|
EndOfLine,
|
||||||
|
Word,
|
||||||
|
Punctuation,
|
||||||
|
};
|
||||||
|
|
||||||
|
template<WordType word_type = Word>
|
||||||
|
inline CharCategories categorize(Codepoint c)
|
||||||
|
{
|
||||||
|
if (is_word(c))
|
||||||
|
return CharCategories::Word;
|
||||||
|
if (is_eol(c))
|
||||||
|
return CharCategories::EndOfLine;
|
||||||
|
if (is_blank(c))
|
||||||
|
return CharCategories::Blank;
|
||||||
|
return word_type == WORD ? CharCategories::Word
|
||||||
|
: CharCategories::Punctuation;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // unicode_hh_INCLUDED
|
#endif // unicode_hh_INCLUDED
|
||||||
|
|
14
src/utils.hh
14
src/utils.hh
|
@ -189,6 +189,20 @@ bool contains(const std::unordered_set<T1>& container, const T2& value)
|
||||||
return container.find(value) != container.end();
|
return container.find(value) != container.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Iterator, typename EndIterator, typename T>
|
||||||
|
void skip_while(Iterator& it, const EndIterator& end, T condition)
|
||||||
|
{
|
||||||
|
while (it != end and condition(*it))
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Iterator, typename BeginIterator, typename T>
|
||||||
|
void skip_while_reverse(Iterator& it, const BeginIterator& begin, T condition)
|
||||||
|
{
|
||||||
|
while (it != begin and condition(*it))
|
||||||
|
--it;
|
||||||
|
}
|
||||||
|
|
||||||
// *** On scope end ***
|
// *** On scope end ***
|
||||||
//
|
//
|
||||||
// on_scope_end provides a way to register some code to be
|
// on_scope_end provides a way to register some code to be
|
||||||
|
|
Loading…
Reference in New Issue
Block a user