parent
37b4eacdc8
commit
bbf48e1d39
179
src/normal.cc
179
src/normal.cc
|
@ -489,98 +489,6 @@ void select_next_match(const Buffer& buffer, SelectionList& selections,
|
||||||
selections.sort_and_merge_overlapping();
|
selections.sort_and_merge_overlapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<SelectMode mode, Direction direction>
|
|
||||||
void search(Context& context, int)
|
|
||||||
{
|
|
||||||
const char* prompt = direction == Forward ? "search:" : "reverse search:";
|
|
||||||
DynamicSelectionList selections{context.buffer(), context.selections()};
|
|
||||||
context.input_handler().prompt(prompt, get_color("Prompt"), complete_nothing,
|
|
||||||
[selections](const String& str, PromptEvent event, Context& context) {
|
|
||||||
try
|
|
||||||
{
|
|
||||||
context.selections() = selections;
|
|
||||||
|
|
||||||
if (event == PromptEvent::Abort)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Regex ex{str};
|
|
||||||
context.input_handler().set_prompt_colors(get_color("Prompt"));
|
|
||||||
if (event == PromptEvent::Validate)
|
|
||||||
{
|
|
||||||
if (str.empty())
|
|
||||||
ex = Regex{RegisterManager::instance()['/'].values(context)[0]};
|
|
||||||
else
|
|
||||||
RegisterManager::instance()['/'] = str;
|
|
||||||
context.push_jump();
|
|
||||||
}
|
|
||||||
else if (str.empty() or not context.options()["incsearch"].get<bool>())
|
|
||||||
return;
|
|
||||||
|
|
||||||
select_next_match<direction, mode>(context.buffer(), context.selections(), ex);
|
|
||||||
}
|
|
||||||
catch (boost::regex_error& err)
|
|
||||||
{
|
|
||||||
if (event == PromptEvent::Validate)
|
|
||||||
throw runtime_error("regex error: "_str + err.what());
|
|
||||||
else
|
|
||||||
context.input_handler().set_prompt_colors(get_color("Error"));
|
|
||||||
}
|
|
||||||
catch (runtime_error&)
|
|
||||||
{
|
|
||||||
context.selections() = selections;
|
|
||||||
// only validation should propagate errors,
|
|
||||||
// incremental search should not.
|
|
||||||
if (event == PromptEvent::Validate)
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SelectMode mode, Direction direction>
|
|
||||||
void search_next(Context& context, int param)
|
|
||||||
{
|
|
||||||
const String& str = RegisterManager::instance()['/'].values(context)[0];
|
|
||||||
if (not str.empty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Regex ex{str};
|
|
||||||
do {
|
|
||||||
select_next_match<direction, mode>(context.buffer(), context.selections(), ex);
|
|
||||||
} while (--param > 0);
|
|
||||||
}
|
|
||||||
catch (boost::regex_error& err)
|
|
||||||
{
|
|
||||||
throw runtime_error("regex error: "_str + err.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw runtime_error("no search pattern");
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool smart>
|
|
||||||
void use_selection_as_search_pattern(Context& context, int)
|
|
||||||
{
|
|
||||||
std::vector<String> patterns;
|
|
||||||
auto& sels = context.selections();
|
|
||||||
const auto& buffer = context.buffer();
|
|
||||||
for (auto& sel : sels)
|
|
||||||
{
|
|
||||||
auto begin = utf8::make_iterator(buffer.iterator_at(sel.min()));
|
|
||||||
auto end = utf8::make_iterator(buffer.iterator_at(sel.max()))+1;
|
|
||||||
auto content = "\\Q" + String{begin.base(), end.base()} + "\\E";
|
|
||||||
if (smart)
|
|
||||||
{
|
|
||||||
if (begin == buffer.begin() or (is_word(*begin) and not is_word(*(begin-1))))
|
|
||||||
content = "\\b" + content;
|
|
||||||
if (end == buffer.end() or (is_word(*(end-1)) and not is_word(*end)))
|
|
||||||
content = content + "\\b";
|
|
||||||
}
|
|
||||||
patterns.push_back(std::move(content));
|
|
||||||
}
|
|
||||||
RegisterManager::instance()['/'] = patterns;
|
|
||||||
}
|
|
||||||
|
|
||||||
void yank(Context& context, int)
|
void yank(Context& context, int)
|
||||||
{
|
{
|
||||||
RegisterManager::instance()['"'] = context.selections_content();
|
RegisterManager::instance()['"'] = context.selections_content();
|
||||||
|
@ -653,27 +561,100 @@ void paste(Context& context, int)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void regex_prompt(Context& context, const String prompt, T on_validate)
|
void regex_prompt(Context& context, const String prompt, T func)
|
||||||
{
|
{
|
||||||
|
DynamicSelectionList selections{context.buffer(), context.selections()};
|
||||||
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) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
context.selections() = selections;
|
||||||
|
context.input_handler().set_prompt_colors(get_color("Prompt"));
|
||||||
|
if (event == PromptEvent::Abort)
|
||||||
|
return;
|
||||||
|
if (event == PromptEvent::Change and
|
||||||
|
(str.empty() or not context.options()["incsearch"].get<bool>()))
|
||||||
|
return;
|
||||||
|
|
||||||
if (event == PromptEvent::Validate)
|
if (event == PromptEvent::Validate)
|
||||||
|
context.push_jump();
|
||||||
|
func(str.empty() ? Regex{} : Regex{str}, context);
|
||||||
|
}
|
||||||
|
catch (boost::regex_error& err)
|
||||||
|
{
|
||||||
|
if (event == PromptEvent::Validate)
|
||||||
|
throw runtime_error("regex error: "_str + err.what());
|
||||||
|
else
|
||||||
|
context.input_handler().set_prompt_colors(get_color("Error"));
|
||||||
|
}
|
||||||
|
catch (runtime_error&)
|
||||||
|
{
|
||||||
|
context.selections() = selections;
|
||||||
|
// only validation should propagate errors,
|
||||||
|
// incremental search should not.
|
||||||
|
if (event == PromptEvent::Validate)
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<SelectMode mode, Direction direction>
|
||||||
|
void search(Context& context, int)
|
||||||
|
{
|
||||||
|
regex_prompt(context, direction == Forward ? "search:" : "reverse search:",
|
||||||
|
[](Regex ex, Context& context) {
|
||||||
|
if (ex.empty())
|
||||||
|
ex = Regex{RegisterManager::instance()['/'].values(context)[0]};
|
||||||
|
else
|
||||||
|
RegisterManager::instance()['/'] = String{ex.str()};
|
||||||
|
if (not ex.empty() and not ex.str().empty())
|
||||||
|
select_next_match<direction, mode>(context.buffer(), context.selections(), ex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<SelectMode mode, Direction direction>
|
||||||
|
void search_next(Context& context, int param)
|
||||||
|
{
|
||||||
|
const String& str = RegisterManager::instance()['/'].values(context)[0];
|
||||||
|
if (not str.empty())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
on_validate(str.empty() ? Regex{} : Regex{str}, context);
|
Regex ex{str};
|
||||||
|
do {
|
||||||
|
select_next_match<direction, mode>(context.buffer(), context.selections(), ex);
|
||||||
|
} while (--param > 0);
|
||||||
}
|
}
|
||||||
catch (boost::regex_error& err)
|
catch (boost::regex_error& err)
|
||||||
{
|
{
|
||||||
throw runtime_error("regex error: "_str + err.what());
|
throw runtime_error("regex error: "_str + err.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (event == PromptEvent::Change)
|
else
|
||||||
{
|
throw runtime_error("no search pattern");
|
||||||
const bool ok = Regex{str, boost::regex_constants::no_except}.status() == 0;
|
|
||||||
context.input_handler().set_prompt_colors(get_color(ok ? "Prompt" : "Error"));
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
template<bool smart>
|
||||||
|
void use_selection_as_search_pattern(Context& context, int)
|
||||||
|
{
|
||||||
|
std::vector<String> patterns;
|
||||||
|
auto& sels = context.selections();
|
||||||
|
const auto& buffer = context.buffer();
|
||||||
|
for (auto& sel : sels)
|
||||||
|
{
|
||||||
|
auto begin = utf8::make_iterator(buffer.iterator_at(sel.min()));
|
||||||
|
auto end = utf8::make_iterator(buffer.iterator_at(sel.max()))+1;
|
||||||
|
auto content = "\\Q" + String{begin.base(), end.base()} + "\\E";
|
||||||
|
if (smart)
|
||||||
|
{
|
||||||
|
if (begin == buffer.begin() or (is_word(*begin) and not is_word(*(begin-1))))
|
||||||
|
content = "\\b" + content;
|
||||||
|
if (end == buffer.end() or (is_word(*(end-1)) and not is_word(*end)))
|
||||||
|
content = content + "\\b";
|
||||||
|
}
|
||||||
|
patterns.push_back(std::move(content));
|
||||||
|
}
|
||||||
|
RegisterManager::instance()['/'] = patterns;
|
||||||
}
|
}
|
||||||
|
|
||||||
void select_regex(Context& context, int)
|
void select_regex(Context& context, int)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user