mirror of
https://github.com/mawww/kakoune.git
synced 2024-12-18 17:02:06 +03:00
Make use of custom regex backward searching support for reverse search
This commit is contained in:
parent
785cd34b4b
commit
1c95074657
@ -687,7 +687,7 @@ void paste_all(Context& context, NormalParams params)
|
|||||||
selections = std::move(result);
|
selections = std::move(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<MatchDirection direction = MatchDirection::Forward, typename T>
|
||||||
void regex_prompt(Context& context, String prompt, String default_regex, T func)
|
void regex_prompt(Context& context, String prompt, String default_regex, T func)
|
||||||
{
|
{
|
||||||
DisplayCoord position = context.has_window() ? context.window().position() : DisplayCoord{};
|
DisplayCoord position = context.has_window() ? context.window().position() : DisplayCoord{};
|
||||||
@ -719,7 +719,7 @@ void regex_prompt(Context& context, String prompt, String default_regex, T func)
|
|||||||
context.push_jump();
|
context.push_jump();
|
||||||
|
|
||||||
if (not str.empty() or event == PromptEvent::Validate)
|
if (not str.empty() or event == PromptEvent::Validate)
|
||||||
func(str.empty() ? Regex{default_regex} : Regex{str}, event, context);
|
func(Regex{str.empty() ? default_regex : str, RegexCompileFlags::None, direction}, event, context);
|
||||||
}
|
}
|
||||||
catch (regex_error& err)
|
catch (regex_error& err)
|
||||||
{
|
{
|
||||||
@ -739,12 +739,12 @@ void regex_prompt(Context& context, String prompt, String default_regex, T func)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<SelectMode mode, Direction direction>
|
template<SelectMode mode, MatchDirection direction>
|
||||||
void search(Context& context, NormalParams params)
|
void search(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
constexpr StringView prompt = mode == SelectMode::Extend ?
|
constexpr StringView prompt = mode == SelectMode::Extend ?
|
||||||
(direction == Forward ? "search (extend):" : "reverse search (extend):")
|
(direction == MatchDirection::Forward ? "search (extend):" : "reverse search (extend):")
|
||||||
: (direction == Forward ? "search:" : "reverse search:");
|
: (direction == MatchDirection::Forward ? "search:" : "reverse search:");
|
||||||
|
|
||||||
const char reg = to_lower(params.reg ? params.reg : '/');
|
const char reg = to_lower(params.reg ? params.reg : '/');
|
||||||
const int count = params.count;
|
const int count = params.count;
|
||||||
@ -753,7 +753,7 @@ void search(Context& context, NormalParams params)
|
|||||||
Vector<String> saved_reg{reg_content.begin(), reg_content.end()};
|
Vector<String> saved_reg{reg_content.begin(), reg_content.end()};
|
||||||
const int main_index = std::min(context.selections().main_index(), saved_reg.size()-1);
|
const int main_index = std::min(context.selections().main_index(), saved_reg.size()-1);
|
||||||
|
|
||||||
regex_prompt(context, prompt.str(), saved_reg[main_index],
|
regex_prompt<direction>(context, prompt.str(), saved_reg[main_index],
|
||||||
[reg, count, saved_reg, main_index]
|
[reg, count, saved_reg, main_index]
|
||||||
(Regex regex, PromptEvent event, Context& context) {
|
(Regex regex, PromptEvent event, Context& context) {
|
||||||
if (event == PromptEvent::Abort)
|
if (event == PromptEvent::Abort)
|
||||||
@ -782,14 +782,14 @@ void search(Context& context, NormalParams params)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<SelectMode mode, Direction direction>
|
template<SelectMode mode, MatchDirection direction>
|
||||||
void search_next(Context& context, NormalParams params)
|
void search_next(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
const char reg = to_lower(params.reg ? params.reg : '/');
|
const char reg = to_lower(params.reg ? params.reg : '/');
|
||||||
StringView str = context.main_sel_register_value(reg);
|
StringView str = context.main_sel_register_value(reg);
|
||||||
if (not str.empty())
|
if (not str.empty())
|
||||||
{
|
{
|
||||||
Regex regex{str};
|
Regex regex{str, RegexCompileFlags::None, direction};
|
||||||
auto& selections = context.selections();
|
auto& selections = context.selections();
|
||||||
bool main_wrapped = false;
|
bool main_wrapped = false;
|
||||||
do {
|
do {
|
||||||
@ -1223,6 +1223,8 @@ void select_object(Context& context, NormalParams params)
|
|||||||
{{'c'}, "custom object desc"}}));
|
{{'c'}, "custom object desc"}}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Direction { Forward, Backward };
|
||||||
|
|
||||||
template<Direction direction, bool half = false>
|
template<Direction direction, bool half = false>
|
||||||
void scroll(Context& context, NormalParams params)
|
void scroll(Context& context, NormalParams params)
|
||||||
{
|
{
|
||||||
@ -2050,14 +2052,14 @@ static const HashMap<Key, NormalCmd, MemoryDomain::Undefined, KeymapBackend> key
|
|||||||
{ {'m'}, {"select to matching character", select<SelectMode::Replace, select_matching>} },
|
{ {'m'}, {"select to matching character", select<SelectMode::Replace, select_matching>} },
|
||||||
{ {'M'}, {"extend to matching character", select<SelectMode::Extend, select_matching>} },
|
{ {'M'}, {"extend to matching character", select<SelectMode::Extend, select_matching>} },
|
||||||
|
|
||||||
{ {'/'}, {"select next given regex match", search<SelectMode::Replace, Forward>} },
|
{ {'/'}, {"select next given regex match", search<SelectMode::Replace, MatchDirection::Forward>} },
|
||||||
{ {'?'}, {"extend with next given regex match", search<SelectMode::Extend, Forward>} },
|
{ {'?'}, {"extend with next given regex match", search<SelectMode::Extend, MatchDirection::Forward>} },
|
||||||
{ {alt('/')}, {"select previous given regex match", search<SelectMode::Replace, Backward>} },
|
{ {alt('/')}, {"select previous given regex match", search<SelectMode::Replace, MatchDirection::Backward>} },
|
||||||
{ {alt('?')}, {"extend with previous given regex match", search<SelectMode::Extend, Backward>} },
|
{ {alt('?')}, {"extend with previous given regex match", search<SelectMode::Extend, MatchDirection::Backward>} },
|
||||||
{ {'n'}, {"select next current search pattern match", search_next<SelectMode::Replace, Forward>} },
|
{ {'n'}, {"select next current search pattern match", search_next<SelectMode::Replace, MatchDirection::Forward>} },
|
||||||
{ {'N'}, {"extend with next current search pattern match", search_next<SelectMode::Append, Forward>} },
|
{ {'N'}, {"extend with next current search pattern match", search_next<SelectMode::Append, MatchDirection::Forward>} },
|
||||||
{ {alt('n')}, {"select previous current search pattern match", search_next<SelectMode::Replace, Backward>} },
|
{ {alt('n')}, {"select previous current search pattern match", search_next<SelectMode::Replace, MatchDirection::Backward>} },
|
||||||
{ {alt('N')}, {"extend with previous current search pattern match", search_next<SelectMode::Append, Backward>} },
|
{ {alt('N')}, {"extend with previous current search pattern match", search_next<SelectMode::Append, MatchDirection::Backward>} },
|
||||||
{ {'*'}, {"set search pattern to main selection content", use_selection_as_search_pattern<true>} },
|
{ {'*'}, {"set search pattern to main selection content", use_selection_as_search_pattern<true>} },
|
||||||
{ {alt('*')}, {"set search pattern to main selection content, do not detect words", use_selection_as_search_pattern<false>} },
|
{ {alt('*')}, {"set search pattern to main selection content, do not detect words", use_selection_as_search_pattern<false>} },
|
||||||
|
|
||||||
|
13
src/regex.cc
13
src/regex.cc
@ -50,13 +50,18 @@ void regex_mismatch(const Regex& re)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Regex::Regex(StringView re, RegexCompileFlags flags) try
|
Regex::Regex(StringView re, RegexCompileFlags flags, MatchDirection direction)
|
||||||
: m_impl{new CompiledRegex{compile_regex(re, flags)}},
|
: m_impl{new CompiledRegex{compile_regex(re, flags, direction)}},
|
||||||
m_str{re.str()}
|
m_str{re.str()}
|
||||||
|
{
|
||||||
#ifdef REGEX_CHECK_WITH_BOOST
|
#ifdef REGEX_CHECK_WITH_BOOST
|
||||||
, m_boost_impl{Utf8It{re.begin(), re}, Utf8It{re.end(), re}, convert_flags(flags)}
|
if (direction == MatchDirection::Forward) try
|
||||||
|
{
|
||||||
|
m_boost_impl.assign({Utf8It{re.begin(), re}, Utf8It{re.end(), re}, convert_flags(flags)});
|
||||||
|
}
|
||||||
|
catch (std::runtime_error& err) { throw regex_error(err.what()); }
|
||||||
#endif
|
#endif
|
||||||
{} catch (std::runtime_error& err) { throw regex_error(err.what()); }
|
}
|
||||||
|
|
||||||
String option_to_string(const Regex& re)
|
String option_to_string(const Regex& re)
|
||||||
{
|
{
|
||||||
|
26
src/regex.hh
26
src/regex.hh
@ -22,7 +22,8 @@ class Regex
|
|||||||
public:
|
public:
|
||||||
Regex() = default;
|
Regex() = default;
|
||||||
|
|
||||||
explicit Regex(StringView re, RegexCompileFlags flags = RegexCompileFlags::None);
|
explicit Regex(StringView re, RegexCompileFlags flags = RegexCompileFlags::None,
|
||||||
|
MatchDirection direction = MatchDirection::Forward);
|
||||||
bool empty() const { return m_str.empty(); }
|
bool empty() const { return m_str.empty(); }
|
||||||
bool operator==(const Regex& other) const { return m_str == other.m_str; }
|
bool operator==(const Regex& other) const { return m_str == other.m_str; }
|
||||||
bool operator!=(const Regex& other) const { return m_str != other.m_str; }
|
bool operator!=(const Regex& other) const { return m_str != other.m_str; }
|
||||||
@ -225,24 +226,27 @@ bool regex_search(It begin, It end, const Regex& re,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename It>
|
template<typename It, MatchDirection direction = MatchDirection::Forward>
|
||||||
bool regex_search(It begin, It end, MatchResults<It>& res, const Regex& re,
|
bool regex_search(It begin, It end, MatchResults<It>& res, const Regex& re,
|
||||||
RegexExecFlags flags = RegexExecFlags::None)
|
RegexExecFlags flags = RegexExecFlags::None)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Vector<It> captures;
|
Vector<It> captures;
|
||||||
const bool matched = regex_search(begin, end, captures, *re.impl(), flags);
|
const bool matched = regex_search<It, direction>(begin, end, captures, *re.impl(), flags);
|
||||||
|
|
||||||
#ifdef REGEX_CHECK_WITH_BOOST
|
#ifdef REGEX_CHECK_WITH_BOOST
|
||||||
auto first = (flags & RegexExecFlags::PrevAvailable) ? begin-1 : begin;
|
if (direction == MatchDirection::Forward)
|
||||||
boost::match_results<RegexUtf8It<It>> boost_res;
|
{
|
||||||
if (not re.boost_impl().empty() and
|
auto first = (flags & RegexExecFlags::PrevAvailable) ? begin-1 : begin;
|
||||||
matched != boost::regex_search<RegexUtf8It<It>>({begin, first, end}, {end, first, end},
|
boost::match_results<RegexUtf8It<It>> boost_res;
|
||||||
boost_res, re.boost_impl(), convert_flags(flags)))
|
if (not re.boost_impl().empty() and
|
||||||
regex_mismatch(re);
|
matched != boost::regex_search<RegexUtf8It<It>>({begin, first, end}, {end, first, end},
|
||||||
if (not re.boost_impl().empty() and matched)
|
boost_res, re.boost_impl(), convert_flags(flags)))
|
||||||
check_captures(re, boost_res, captures);
|
regex_mismatch(re);
|
||||||
|
if (not re.boost_impl().empty() and matched)
|
||||||
|
check_captures(re, boost_res, captures);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
res = matched ? MatchResults<It>{std::move(captures)} : MatchResults<It>{};
|
res = matched ? MatchResults<It>{std::move(captures)} : MatchResults<It>{};
|
||||||
|
@ -861,36 +861,25 @@ static bool find_prev(const Buffer& buffer, const BufferIterator& pos,
|
|||||||
MatchResults<BufferIterator>& matches,
|
MatchResults<BufferIterator>& matches,
|
||||||
const Regex& ex, bool& wrapped)
|
const Regex& ex, bool& wrapped)
|
||||||
{
|
{
|
||||||
auto find_last_match = [&](const BufferIterator& pos) {
|
if (pos != buffer.begin() and
|
||||||
MatchResults<BufferIterator> m;
|
regex_search<BufferIterator, MatchDirection::Backward>(
|
||||||
const bool is_pos_eol = is_eol(buffer, pos.coord());
|
buffer.begin(), pos, matches, ex,
|
||||||
const bool is_pos_eow = is_eow(buffer, pos.coord());
|
match_flags(buffer, buffer.begin(), pos)))
|
||||||
auto begin = buffer.begin();
|
|
||||||
while (begin != pos and
|
|
||||||
regex_search(begin, pos, m, ex,
|
|
||||||
match_flags(is_bol(begin.coord()), is_pos_eol,
|
|
||||||
is_bow(buffer, begin.coord()), is_pos_eow)))
|
|
||||||
{
|
|
||||||
begin = utf8::next(m[0].first, pos);
|
|
||||||
if (matches.empty() or m[0].second > matches[0].second)
|
|
||||||
matches.swap(m);
|
|
||||||
}
|
|
||||||
return not matches.empty();
|
|
||||||
};
|
|
||||||
if (find_last_match(pos))
|
|
||||||
return true;
|
return true;
|
||||||
wrapped = true;
|
wrapped = true;
|
||||||
return find_last_match(buffer.end());
|
return regex_search<BufferIterator, MatchDirection::Backward>(
|
||||||
|
buffer.begin(), buffer.end(), matches, ex,
|
||||||
|
match_flags(buffer, buffer.begin(), buffer.end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<Direction direction>
|
template<MatchDirection direction>
|
||||||
Selection find_next_match(const Context& context, const Selection& sel, const Regex& regex, bool& wrapped)
|
Selection find_next_match(const Context& context, const Selection& sel, const Regex& regex, bool& wrapped)
|
||||||
{
|
{
|
||||||
auto& buffer = context.buffer();
|
auto& buffer = context.buffer();
|
||||||
MatchResults<BufferIterator> matches;
|
MatchResults<BufferIterator> matches;
|
||||||
auto pos = buffer.iterator_at(direction == Backward ? sel.min() : sel.max());
|
auto pos = buffer.iterator_at(direction == MatchDirection::Backward ? sel.min() : sel.max());
|
||||||
wrapped = false;
|
wrapped = false;
|
||||||
const bool found = (direction == Forward) ?
|
const bool found = (direction == MatchDirection::Forward) ?
|
||||||
find_next(buffer, utf8::next(pos, buffer.end()), matches, regex, wrapped)
|
find_next(buffer, utf8::next(pos, buffer.end()), matches, regex, wrapped)
|
||||||
: find_prev(buffer, pos, matches, regex, wrapped);
|
: find_prev(buffer, pos, matches, regex, wrapped);
|
||||||
|
|
||||||
@ -903,13 +892,13 @@ Selection find_next_match(const Context& context, const Selection& sel, const Re
|
|||||||
|
|
||||||
auto begin = matches[0].first, end = matches[0].second;
|
auto begin = matches[0].first, end = matches[0].second;
|
||||||
end = (begin == end) ? end : utf8::previous(end, begin);
|
end = (begin == end) ? end : utf8::previous(end, begin);
|
||||||
if (direction == Backward)
|
if (direction == MatchDirection::Backward)
|
||||||
std::swap(begin, end);
|
std::swap(begin, end);
|
||||||
|
|
||||||
return {begin.coord(), end.coord(), std::move(captures)};
|
return {begin.coord(), end.coord(), std::move(captures)};
|
||||||
}
|
}
|
||||||
template Selection find_next_match<Forward>(const Context&, const Selection&, const Regex&, bool&);
|
template Selection find_next_match<MatchDirection::Forward>(const Context&, const Selection&, const Regex&, bool&);
|
||||||
template Selection find_next_match<Backward>(const Context&, const Selection&, const Regex&, bool&);
|
template Selection find_next_match<MatchDirection::Backward>(const Context&, const Selection&, const Regex&, bool&);
|
||||||
|
|
||||||
using RegexIt = RegexIterator<BufferIterator>;
|
using RegexIt = RegexIterator<BufferIterator>;
|
||||||
|
|
||||||
|
@ -98,9 +98,9 @@ trim_partial_lines(const Context& context, const Selection& selection);
|
|||||||
|
|
||||||
void select_buffer(SelectionList& selections);
|
void select_buffer(SelectionList& selections);
|
||||||
|
|
||||||
enum Direction { Forward, Backward };
|
enum class MatchDirection;
|
||||||
|
|
||||||
template<Direction direction>
|
template<MatchDirection direction>
|
||||||
Selection find_next_match(const Context& context, const Selection& sel,
|
Selection find_next_match(const Context& context, const Selection& sel,
|
||||||
const Regex& regex, bool& wrapped);
|
const Regex& regex, bool& wrapped);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user