Add backward search support (bound to alt-/)
This commit is contained in:
parent
f77509d498
commit
bba7152063
21
src/main.cc
21
src/main.cc
|
@ -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"); } }) },
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user