Add backward search support (bound to alt-/)

This commit is contained in:
Maxime Coste 2013-01-08 18:46:45 +01:00
parent f77509d498
commit bba7152063
3 changed files with 56 additions and 24 deletions

View File

@ -133,7 +133,7 @@ void do_pipe(Context& context)
}, context);
}
template<SelectMode mode>
template<SelectMode mode, bool forward>
void do_search(Context& context)
{
SelectionList selections = context.editor().selections();
@ -158,7 +158,7 @@ void do_search(Context& context)
else if (not context.options()["incsearch"].as_int())
return;
context.editor().select(std::bind(select_next_match, _1, ex), mode);
context.editor().select(std::bind(select_next_match<forward>, _1, ex), mode);
}
catch (runtime_error&)
{
@ -172,7 +172,7 @@ void do_search(Context& context)
}, context);
}
template<SelectMode mode>
template<SelectMode mode, bool forward>
void do_search_next(Context& context)
{
const String& ex = RegisterManager::instance()['/'].values(context)[0];
@ -182,7 +182,7 @@ void do_search_next(Context& context)
context.push_jump();
int count = context.numeric_param();
do {
context.editor().select(std::bind(select_next_match, _1, ex), mode);
context.editor().select(std::bind(select_next_match<forward>, _1, ex), mode);
} while (--count > 0);
}
else
@ -526,11 +526,14 @@ std::unordered_map<Key, std::function<void (Context& context)>> keymap =
{ { Key::Modifiers::None, 'm' }, [](Context& context) { context.editor().select(select_matching); } },
{ { Key::Modifiers::None, 'M' }, [](Context& context) { context.editor().select(select_matching, SelectMode::Extend); } },
{ { Key::Modifiers::None, '/' }, do_search<SelectMode::Replace> },
{ { Key::Modifiers::None, '?' }, do_search<SelectMode::Extend> },
{ { Key::Modifiers::None, 'n' }, do_search_next<SelectMode::Replace> },
{ { Key::Modifiers::Alt, 'n' }, do_search_next<SelectMode::ReplaceLast> },
{ { Key::Modifiers::None, 'N' }, do_search_next<SelectMode::Append> },
{ { Key::Modifiers::None, '/' }, do_search<SelectMode::Replace, true> },
{ { Key::Modifiers::None, '?' }, do_search<SelectMode::Extend, true> },
{ { Key::Modifiers::Alt, '/' }, do_search<SelectMode::Replace, false> },
{ { Key::Modifiers::Alt, '?' }, do_search<SelectMode::Extend, false> },
{ { Key::Modifiers::None, 'n' }, do_search_next<SelectMode::Replace, true> },
{ { Key::Modifiers::Alt, 'n' }, do_search_next<SelectMode::ReplaceLast, true> },
{ { Key::Modifiers::None, 'N' }, do_search_next<SelectMode::Append, true> },
{ { Key::Modifiers::None, 'u' }, repeated([](Context& context) { if (not context.editor().undo()) { context.print_status("nothing left to undo"); } }) },
{ { Key::Modifiers::None, 'U' }, repeated([](Context& context) { if (not context.editor().redo()) { context.print_status("nothing left to redo"); } }) },

View File

@ -385,6 +385,39 @@ Selection select_whole_buffer(const Selection& selection)
return Selection(buffer.begin(), utf8::previous(buffer.end()));
}
using MatchResults = boost::match_results<BufferIterator>;
static bool find_last_match(BufferIterator begin, const BufferIterator& end,
MatchResults& res, const Regex& regex)
{
MatchResults matches;
while (boost::regex_search(begin, end, matches, regex))
{
if (begin == matches[0].second)
break;
begin = matches[0].second;
res.swap(matches);
}
return not res.empty();
}
template<bool forward>
bool find_match_in_buffer(const BufferIterator pos, MatchResults& matches,
const Regex& ex)
{
auto bufbeg = pos.buffer().begin();
auto bufend = pos.buffer().end();
if (forward)
return (boost::regex_search(pos, bufend, matches, ex) or
boost::regex_search(bufbeg, pos, matches, ex));
else
return (find_last_match(bufbeg, pos, matches, ex) or
find_last_match(pos, bufend, matches, ex));
}
template<bool forward>
Selection select_next_match(const Selection& selection, const String& regex)
{
try
@ -395,19 +428,10 @@ Selection select_next_match(const Selection& selection, const String& regex)
BufferIterator end = begin;
CaptureList captures;
Regex ex(regex.begin(), regex.end());
boost::match_results<BufferIterator> matches;
Regex ex{regex.begin(), regex.end()};
MatchResults matches;
if (boost::regex_search(utf8::next(begin), begin.buffer().end(),
matches, ex))
{
begin = matches[0].first;
end = matches[0].second;
for (auto& match : matches)
captures.push_back(String(match.first, match.second));
}
else if (boost::regex_search(begin.buffer().begin(), utf8::next(begin),
matches, ex))
if (find_match_in_buffer<forward>(utf8::next(begin), matches, ex))
{
begin = matches[0].first;
end = matches[0].second;
@ -420,13 +444,18 @@ Selection select_next_match(const Selection& selection, const String& regex)
if (begin == end)
++end;
return Selection(begin, utf8::previous(end), std::move(captures));
end = utf8::previous(end);
if (not forward)
std::swap(begin, end);
return Selection{begin, end, std::move(captures)};
}
catch (boost::regex_error& err)
{
throw runtime_error(String("regex error: ") + err.what());
}
}
template Selection select_next_match<true>(const Selection&, const String&);
template Selection select_next_match<false>(const Selection&, const String&);
SelectionList select_all_matches(const Selection& selection, const String& regex)
{

View File

@ -30,8 +30,8 @@ Selection select_whole_word(const Selection& selection, bool inner);
Selection select_whole_lines(const Selection& selection);
Selection select_whole_buffer(const Selection& selection);
Selection select_next_match(const Selection& selection,
const String& regex);
template<bool forward>
Selection select_next_match(const Selection& selection, const String& regex);
SelectionList select_all_matches(const Selection& selection,
const String& regex);