summaryrefslogtreecommitdiff
path: root/src/normal.cc
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2014-01-26 18:53:34 +0000
committerMaxime Coste <frrrwww@gmail.com>2014-01-27 19:51:58 +0000
commitbbf48e1d39d34b02c54f7b5104b0ff17dff3d7b5 (patch)
tree9327e12951dd3a93e7a4fe2f64e511bdaee9f159 /src/normal.cc
parent37b4eacdc86e04dbca168b430eaedd829dd24ae6 (diff)
Honor incsearch option for select/split/keep
fixes #37
Diffstat (limited to 'src/normal.cc')
-rw-r--r--src/normal.cc189
1 files changed, 85 insertions, 104 deletions
diff --git a/src/normal.cc b/src/normal.cc
index 420fd147..7f1944df 100644
--- a/src/normal.cc
+++ b/src/normal.cc
@@ -489,98 +489,6 @@ void select_next_match(const Buffer& buffer, SelectionList& selections,
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)
{
RegisterManager::instance()['"'] = context.selections_content();
@@ -653,29 +561,102 @@ void paste(Context& context, int)
}
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,
[=](const String& str, PromptEvent event, Context& context) {
- if (event == PromptEvent::Validate)
+ try
{
- try
- {
- on_validate(str.empty() ? Regex{} : Regex{str}, context);
- }
- catch (boost::regex_error& err)
- {
+ 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)
+ 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"));
}
- else if (event == PromptEvent::Change)
+ catch (runtime_error&)
{
- const bool ok = Regex{str, boost::regex_constants::no_except}.status() == 0;
- context.input_handler().set_prompt_colors(get_color(ok ? "Prompt" : "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
+ {
+ 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 select_regex(Context& context, int)
{
regex_prompt(context, "select:", [](Regex ex, Context& context) {