refactor regex based selectors, move regex construction out of them

This commit is contained in:
Maxime Coste 2013-04-05 19:28:08 +02:00
parent e3f097ad40
commit 1ab8120147
4 changed files with 118 additions and 131 deletions

View File

@ -116,7 +116,7 @@ void do_replace_with_char(Context& context)
Editor& editor = context.editor(); Editor& editor = context.editor();
SelectionList sels = editor.selections(); SelectionList sels = editor.selections();
auto restore_sels = on_scope_end([&]{ editor.select(std::move(sels)); }); auto restore_sels = on_scope_end([&]{ editor.select(std::move(sels)); });
editor.multi_select(std::bind(select_all_matches, _1, ".")); editor.multi_select(std::bind(select_all_matches, _1, Regex{"."}));
editor.insert(codepoint_to_str(key.key), InsertMode::Replace); editor.insert(codepoint_to_str(key.key), InsertMode::Replace);
}); });
} }
@ -184,20 +184,25 @@ void do_search(Context& context)
if (event == PromptEvent::Abort) if (event == PromptEvent::Abort)
return; return;
String ex = str; Regex ex{str};
if (event == PromptEvent::Validate) if (event == PromptEvent::Validate)
{ {
if (ex.empty()) if (str.empty())
ex = RegisterManager::instance()['/'].values(context)[0]; ex = Regex{RegisterManager::instance()['/'].values(context)[0]};
else else
RegisterManager::instance()['/'] = ex; RegisterManager::instance()['/'] = str;
context.push_jump(); context.push_jump();
} }
else if (ex.empty() or not context.options()["incsearch"].get<bool>()) else if (str.empty() or not context.options()["incsearch"].get<bool>())
return; return;
context.editor().select(std::bind(select_next_match<forward>, _1, ex), mode); context.editor().select(std::bind(select_next_match<forward>, _1, ex), mode);
} }
catch (boost::regex_error& err)
{
if (event == PromptEvent::Validate)
throw runtime_error("regex error: "_str + err.what());
}
catch (runtime_error&) catch (runtime_error&)
{ {
context.editor().select(selections); context.editor().select(selections);
@ -206,16 +211,18 @@ void do_search(Context& context)
if (event == PromptEvent::Validate) if (event == PromptEvent::Validate)
throw; throw;
} }
}); });
} }
template<SelectMode mode, bool forward> template<SelectMode mode, bool forward>
void do_search_next(Context& context) void do_search_next(Context& context)
{ {
const String& ex = RegisterManager::instance()['/'].values(context)[0]; const String& str = RegisterManager::instance()['/'].values(context)[0];
if (not ex.empty()) if (not str.empty())
{ {
try
{
Regex ex{str};
if (mode == SelectMode::Replace) if (mode == SelectMode::Replace)
context.push_jump(); context.push_jump();
int count = context.numeric_param(); int count = context.numeric_param();
@ -223,8 +230,13 @@ void do_search_next(Context& context)
context.editor().select(std::bind(select_next_match<forward>, _1, ex), mode); context.editor().select(std::bind(select_next_match<forward>, _1, ex), mode);
} while (--count > 0); } while (--count > 0);
} }
catch (boost::regex_error& err)
{
throw runtime_error("regex error: "_str + err.what());
}
}
else else
context.print_status({ "no search pattern", get_color("Error") }); throw runtime_error("no search pattern");
} }
template<bool smart> template<bool smart>
@ -318,7 +330,16 @@ void regex_prompt(Context& context, const String prompt, T on_validate)
context.input_handler().prompt(prompt, get_color("Prompt"), complete_nothing, context.input_handler().prompt(prompt, get_color("Prompt"), complete_nothing,
[=](const String& str, PromptEvent event, Context& context) { [=](const String& str, PromptEvent event, Context& context) {
if (event == PromptEvent::Validate) if (event == PromptEvent::Validate)
on_validate(str, context); {
try
{
on_validate(Regex{str}, context);
}
catch (boost::regex_error& err)
{
throw runtime_error("regex error: "_str + err.what());
}
}
else if (event == PromptEvent::Change) else if (event == PromptEvent::Change)
{ {
const bool ok = Regex{str, boost::regex_constants::no_except}.status() == 0; const bool ok = Regex{str, boost::regex_constants::no_except}.status() == 0;
@ -329,12 +350,11 @@ void regex_prompt(Context& context, const String prompt, T on_validate)
void do_select_regex(Context& context) void do_select_regex(Context& context)
{ {
regex_prompt(context, "select: ", [](const String& str, Context& context) { regex_prompt(context, "select: ", [](Regex ex, Context& context) {
String ex = str;
if (ex.empty()) if (ex.empty())
ex = RegisterManager::instance()['/'].values(context)[0]; ex = Regex{RegisterManager::instance()['/'].values(context)[0]};
else else
RegisterManager::instance()['/'] = ex; RegisterManager::instance()['/'] = String{ex.str()};
if (not ex.empty()) if (not ex.empty())
context.editor().multi_select(std::bind(select_all_matches, _1, ex)); context.editor().multi_select(std::bind(select_all_matches, _1, ex));
}); });
@ -342,12 +362,11 @@ void do_select_regex(Context& context)
void do_split_regex(Context& context) void do_split_regex(Context& context)
{ {
regex_prompt(context, "split: ", [](const String& str, Context& context) { regex_prompt(context, "split: ", [](Regex ex, Context& context) {
String ex = str;
if (ex.empty()) if (ex.empty())
ex = RegisterManager::instance()['/'].values(context)[0]; ex = Regex{RegisterManager::instance()['/'].values(context)[0]};
else else
RegisterManager::instance()['/'] = ex; RegisterManager::instance()['/'] = String{ex.str()};
if (not ex.empty()) if (not ex.empty())
context.editor().multi_select(std::bind(split_selection, _1, ex)); context.editor().multi_select(std::bind(split_selection, _1, ex));
}); });
@ -355,7 +374,7 @@ void do_split_regex(Context& context)
void do_split_lines(Context& context) void do_split_lines(Context& context)
{ {
context.editor().multi_select(std::bind(split_selection, _1, "^")); context.editor().multi_select(std::bind(split_selection, _1, Regex{"^"}));
} }
void do_join(Context& context) void do_join(Context& context)
@ -367,7 +386,7 @@ void do_join(Context& context)
editor.select(select_to_eol, SelectMode::Extend); editor.select(select_to_eol, SelectMode::Extend);
editor.multi_select([](const Selection& sel) editor.multi_select([](const Selection& sel)
{ {
SelectionList res = select_all_matches(sel, "\n\\h*"); SelectionList res = select_all_matches(sel, Regex{"\n\\h*"});
// remove last end of line if selected // remove last end of line if selected
assert(std::is_sorted(res.begin(), res.end(), assert(std::is_sorted(res.begin(), res.end(),
[](const Selection& lhs, const Selection& rhs) [](const Selection& lhs, const Selection& rhs)
@ -383,26 +402,18 @@ template<bool matching>
void do_keep(Context& context) void do_keep(Context& context)
{ {
constexpr const char* prompt = matching ? "keep matching: " : "keep not matching: "; constexpr const char* prompt = matching ? "keep matching: " : "keep not matching: ";
regex_prompt(context, prompt, [](const String& str, Context& context) { regex_prompt(context, prompt, [](const Regex& ex, Context& context) {
try
{
Regex re(str);
Editor& editor = context.editor(); Editor& editor = context.editor();
SelectionList sels = editor.selections(); SelectionList sels = editor.selections();
SelectionList keep; SelectionList keep;
for (auto& sel : sels) for (auto& sel : sels)
{ {
if (boost::regex_search(sel.begin(), sel.end(), re) == matching) if (boost::regex_search(sel.begin(), sel.end(), ex) == matching)
keep.push_back(sel); keep.push_back(sel);
} }
if (keep.empty()) if (keep.empty())
throw runtime_error("no selections remaining"); throw runtime_error("no selections remaining");
editor.select(std::move(keep)); editor.select(std::move(keep));
}
catch (boost::regex_error& error)
{
throw runtime_error("regex_error: "_str + error.what());
}
}); });
} }
@ -415,7 +426,7 @@ void do_indent(Context& context)
DynamicSelectionList sels{editor.buffer(), editor.selections()}; DynamicSelectionList sels{editor.buffer(), editor.selections()};
auto restore_sels = on_scope_end([&]{ editor.select((SelectionList)std::move(sels)); }); auto restore_sels = on_scope_end([&]{ editor.select((SelectionList)std::move(sels)); });
editor.select(select_whole_lines); editor.select(select_whole_lines);
editor.multi_select(std::bind(select_all_matches, _1, "^[^\n]")); editor.multi_select(std::bind(select_all_matches, _1, Regex{"^[^\n]"}));
editor.insert(indent, InsertMode::Insert); editor.insert(indent, InsertMode::Insert);
} }
@ -427,7 +438,7 @@ void do_deindent(Context& context)
auto restore_sels = on_scope_end([&]{ editor.select((SelectionList)std::move(sels)); }); auto restore_sels = on_scope_end([&]{ editor.select((SelectionList)std::move(sels)); });
editor.select(select_whole_lines); editor.select(select_whole_lines);
editor.multi_select(std::bind(select_all_matches, _1, editor.multi_select(std::bind(select_all_matches, _1,
"^\\h{1," + int_to_str(width) + "}")); Regex{"^\\h{1," + int_to_str(width) + "}"}));
editor.erase(); editor.erase();
} }

View File

@ -419,20 +419,17 @@ bool find_match_in_buffer(const BufferIterator pos, MatchResults& matches,
template<bool forward> template<bool forward>
Selection select_next_match(const Selection& selection, const String& regex) Selection select_next_match(const Selection& selection, const Regex& regex)
{ {
try
{
// regex matching do not use Utf8Iterator as boost::regex handle utf8 // regex matching do not use Utf8Iterator as boost::regex handle utf8
// decoding itself // decoding itself
BufferIterator begin = selection.last(); BufferIterator begin = selection.last();
BufferIterator end = begin; BufferIterator end = begin;
CaptureList captures; CaptureList captures;
Regex ex{regex.begin(), regex.end()};
MatchResults matches; MatchResults matches;
if (find_match_in_buffer<forward>(utf8::next(begin), matches, ex)) if (find_match_in_buffer<forward>(utf8::next(begin), matches, regex))
{ {
begin = matches[0].first; begin = matches[0].first;
end = matches[0].second; end = matches[0].second;
@ -440,7 +437,7 @@ Selection select_next_match(const Selection& selection, const String& regex)
captures.push_back(String(match.first, match.second)); captures.push_back(String(match.first, match.second));
} }
else else
throw runtime_error("'" + regex + "': no matches found"); throw runtime_error("'" + regex.str() + "': no matches found");
if (begin == end) if (begin == end)
++end; ++end;
@ -449,21 +446,13 @@ Selection select_next_match(const Selection& selection, const String& regex)
if (not forward) if (not forward)
std::swap(begin, end); std::swap(begin, end);
return Selection{begin, end, std::move(captures)}; 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<true>(const Selection&, const Regex&);
template Selection select_next_match<false>(const Selection&, const String&); template Selection select_next_match<false>(const Selection&, const Regex&);
SelectionList select_all_matches(const Selection& selection, const String& regex) SelectionList select_all_matches(const Selection& selection, const Regex& regex)
{ {
try RegexIterator re_it(selection.begin(), selection.end(), regex);
{
Regex ex(regex.begin(), regex.end());
RegexIterator re_it(selection.begin(), selection.end(), ex);
RegexIterator re_end; RegexIterator re_end;
SelectionList result; SelectionList result;
@ -483,20 +472,12 @@ SelectionList select_all_matches(const Selection& selection, const String& regex
std::move(captures))); std::move(captures)));
} }
return result; return result;
}
catch (boost::regex_error& err)
{
throw runtime_error(String("regex error: ") + err.what());
}
} }
SelectionList split_selection(const Selection& selection, SelectionList split_selection(const Selection& selection,
const String& separator_regex) const Regex& regex)
{ {
try RegexIterator re_it(selection.begin(), selection.end(), regex,
{
Regex ex(separator_regex.begin(), separator_regex.end());
RegexIterator re_it(selection.begin(), selection.end(), ex,
boost::regex_constants::match_nosubs); boost::regex_constants::match_nosubs);
RegexIterator re_end; RegexIterator re_end;
@ -512,11 +493,6 @@ SelectionList split_selection(const Selection& selection,
result.push_back(Selection(begin, std::max(selection.first(), result.push_back(Selection(begin, std::max(selection.first(),
selection.last()))); selection.last())));
return result; return result;
}
catch (boost::regex_error& err)
{
throw runtime_error(String("regex error: ") + err.what());
}
} }
} }

View File

@ -31,13 +31,13 @@ Selection select_whole_lines(const Selection& selection);
Selection select_whole_buffer(const Selection& selection); Selection select_whole_buffer(const Selection& selection);
template<bool forward> template<bool forward>
Selection select_next_match(const Selection& selection, const String& regex); Selection select_next_match(const Selection& selection, const Regex& regex);
SelectionList select_all_matches(const Selection& selection, SelectionList select_all_matches(const Selection& selection,
const String& regex); const Regex& regex);
SelectionList split_selection(const Selection& selection, SelectionList split_selection(const Selection& selection,
const String& separator_regex); const Regex& separator_regex);
enum class SurroundFlags enum class SurroundFlags
{ {

View File

@ -58,7 +58,7 @@ void test_editor()
{ {
scoped_edition edition{editor}; scoped_edition edition{editor};
editor.select(select_whole_buffer); editor.select(select_whole_buffer);
editor.multi_select(std::bind(select_all_matches, std::placeholders::_1, "\\n\\h*")); editor.multi_select(std::bind(select_all_matches, std::placeholders::_1, Regex{"\\n\\h*"}));
for (auto& sel : editor.selections()) for (auto& sel : editor.selections())
{ {
assert(*sel.begin() == '\n'); assert(*sel.begin() == '\n');