Move template selectors to the header

This commit is contained in:
Maxime Coste 2013-12-14 14:49:10 +00:00
parent 93b561983a
commit 0c4d523b22
4 changed files with 175 additions and 206 deletions

View File

@ -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());

View File

@ -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,

View File

@ -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

View File

@ -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