summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2013-12-12 23:56:53 +0000
committerMaxime Coste <frrrwww@gmail.com>2013-12-14 14:38:17 +0000
commitdb048a079267ecea1c0aff5080a027afed16ae46 (patch)
tree0ec1b8a0fb20d9e126372b1b9115b80d4943e252 /src
parent894ee0297ea60c043a711fbbb5612eff8a68c3ee (diff)
MultiSelectors now transforms the whole selection
Diffstat (limited to 'src')
-rw-r--r--src/editor.cc21
-rw-r--r--src/editor.hh2
-rw-r--r--src/normal.cc83
-rw-r--r--src/selectors.cc120
-rw-r--r--src/selectors.hh73
5 files changed, 153 insertions, 146 deletions
diff --git a/src/editor.cc b/src/editor.cc
index b3572333..2e39bacf 100644
--- a/src/editor.cc
+++ b/src/editor.cc
@@ -282,26 +282,7 @@ struct nothing_selected : public runtime_error
void Editor::multi_select(const MultiSelector& selector)
{
- SelectionList new_selections;
- for (auto& sel : m_selections)
- {
- SelectionList res = selector(*m_buffer, sel);
- new_selections.reserve(new_selections.size() + res.size());
- for (auto& new_sel : res)
- {
- // preserve captures when selectors captures nothing.
- if (new_sel.captures().empty())
- new_selections.emplace_back(new_sel.first(), new_sel.last(),
- sel.captures());
- else
- new_selections.push_back(std::move(new_sel));
- }
- }
- if (new_selections.empty())
- throw nothing_selected();
- new_selections.set_main_index(new_selections.size() - 1);
- new_selections.sort_and_merge_overlapping();
- m_selections = std::move(new_selections);
+ m_selections = selector(*m_buffer, std::move(m_selections));
check_invariant();
}
diff --git a/src/editor.hh b/src/editor.hh
index 4037a76e..be832da3 100644
--- a/src/editor.hh
+++ b/src/editor.hh
@@ -40,7 +40,7 @@ class Editor : public SafeCountable
{
public:
typedef std::function<Selection (const Buffer&, const Selection&)> Selector;
- typedef std::function<SelectionList (const Buffer&, const Selection&)> MultiSelector;
+ typedef std::function<SelectionList (const Buffer&, SelectionList)> MultiSelector;
Editor(Buffer& buffer);
virtual ~Editor() {}
diff --git a/src/normal.cc b/src/normal.cc
index 0b50195d..08d4d990 100644
--- a/src/normal.cc
+++ b/src/normal.cc
@@ -321,7 +321,7 @@ void search(Context& context, int)
else if (str.empty() or not context.options()["incsearch"].get<bool>())
return;
- context.editor().select(std::bind(select_next_match<direction>, _1, _2, ex), mode);
+ context.editor().multi_select(std::bind(select_next_match<direction, mode>, _1, _2, ex));
}
catch (boost::regex_error& err)
{
@@ -351,7 +351,7 @@ void search_next(Context& context, int param)
{
Regex ex{str};
do {
- context.editor().select(std::bind(select_next_match<direction>, _1, _2, ex), mode);
+ context.editor().multi_select(std::bind(select_next_match<direction, mode>, _1, _2, ex));
} while (--param > 0);
}
catch (boost::regex_error& err)
@@ -496,16 +496,20 @@ void split_regex(Context& context, int)
void split_lines(Context& context, int)
{
- context.editor().multi_select([](const Buffer& buffer, const Selection& sel) {
- if (sel.first().line == sel.last().line)
- return SelectionList{ sel };
+ context.editor().multi_select([](const Buffer& buffer,
+ SelectionList selections) {
SelectionList res;
- auto min = sel.min();
- auto max = sel.max();
- res.push_back({min, {min.line, buffer[min.line].length()-1}});
- for (auto line = min.line+1; line < max.line; ++line)
- res.push_back({line, {line, buffer[line].length()-1}});
- res.push_back({max.line, max});
+ for (auto& sel : selections)
+ {
+ if (sel.first().line == sel.last().line)
+ return SelectionList{ sel };
+ auto min = sel.min();
+ auto max = sel.max();
+ res.push_back({min, {min.line, buffer[min.line].length()-1}});
+ for (auto line = min.line+1; line < max.line; ++line)
+ res.push_back({line, {line, buffer[line].length()-1}});
+ res.push_back({max.line, max});
+ }
return res;
});
}
@@ -515,9 +519,10 @@ void join_select_spaces(Context& context, int)
Editor& editor = context.editor();
editor.select(select_whole_lines);
editor.select(select_to_eol, SelectMode::Extend);
- editor.multi_select([](const Buffer& buffer, const Selection& sel)
+ editor.multi_select([](const Buffer& buffer, SelectionList sel)
{
- SelectionList res = select_all_matches(buffer, sel, Regex{"(\n\\h*)+"});
+ SelectionList res = select_all_matches(buffer, std::move(sel),
+ Regex{"(\n\\h*)+"});
// remove last end of line if selected
kak_assert(std::is_sorted(res.begin(), res.end(),
[](const Selection& lhs, const Selection& rhs)
@@ -568,12 +573,15 @@ void indent(Context& context, int)
Editor& editor = context.editor();
DynamicSelectionList sels{editor.buffer(), editor.selections()};
auto restore_sels = on_scope_end([&]{ editor.select((SelectionList)std::move(sels)); });
- editor.multi_select([&indent](const Buffer& buf, const Selection& sel) {
+ editor.multi_select([&indent](const Buffer& buf, SelectionList selections) {
SelectionList res;
- for (auto line = sel.min().line; line < sel.max().line+1; ++line)
+ for (auto& sel : selections)
{
- if (indent_empty or buf[line].length() > 1)
- res.emplace_back(line, line);
+ for (auto line = sel.min().line; line < sel.max().line+1; ++line)
+ {
+ if (indent_empty or buf[line].length() > 1)
+ res.emplace_back(line, line);
+ }
}
return res;
});
@@ -592,29 +600,32 @@ void deindent(Context& context, int)
DynamicSelectionList sels{editor.buffer(), editor.selections()};
auto restore_sels = on_scope_end([&]{ editor.select((SelectionList)std::move(sels)); });
- editor.multi_select([indent_width,tabstop](const Buffer& buf, const Selection& sel) {
+ editor.multi_select([indent_width,tabstop](const Buffer& buf, SelectionList selections) {
SelectionList res;
- for (auto line = sel.min().line; line < sel.max().line+1; ++line)
+ for (auto& sel : selections)
{
- CharCount width = 0;
- auto& content = buf[line];
- for (auto column = 0_byte; column < content.length(); ++column)
+ for (auto line = sel.min().line; line < sel.max().line+1; ++line)
{
- const char c = content[column];
- if (c == '\t')
- width = (width / tabstop + 1) * tabstop;
- else if (c == ' ')
- ++width;
- else
- {
- if (deindent_incomplete and width != 0)
- res.emplace_back(line, BufferCoord{line, column-1});
- break;
- }
- if (width == indent_width)
+ CharCount width = 0;
+ auto& content = buf[line];
+ for (auto column = 0_byte; column < content.length(); ++column)
{
- res.emplace_back(line, BufferCoord{line, column});
- break;
+ const char c = content[column];
+ if (c == '\t')
+ width = (width / tabstop + 1) * tabstop;
+ else if (c == ' ')
+ ++width;
+ else
+ {
+ if (deindent_incomplete and width != 0)
+ res.emplace_back(line, BufferCoord{line, column-1});
+ break;
+ }
+ if (width == indent_width)
+ {
+ res.emplace_back(line, BufferCoord{line, column});
+ break;
+ }
}
}
}
diff --git a/src/selectors.cc b/src/selectors.cc
index 7d0c4192..2e71b014 100644
--- a/src/selectors.cc
+++ b/src/selectors.cc
@@ -597,107 +597,57 @@ Selection select_whole_buffer(const Buffer& buffer, const Selection&)
return Selection({0,0}, buffer.back_coord());
}
-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<Direction direction>
-bool find_match_in_buffer(const Buffer& buffer, const BufferIterator pos,
- MatchResults& matches, const Regex& ex)
-{
- if (direction == Forward)
- return (boost::regex_search(pos, buffer.end(), matches, ex) or
- boost::regex_search(buffer.begin(), pos, matches, ex));
- else
- return (find_last_match(buffer.begin(), pos, matches, ex) or
- find_last_match(pos, buffer.end(), matches, ex));
-}
-
-
-template<Direction direction>
-Selection select_next_match(const Buffer& buffer, const Selection& selection, const Regex& regex)
-{
- // regex matching do not use Utf8Iterator as boost::regex handle utf8
- // decoding itself
- BufferIterator begin = buffer.iterator_at(selection.last());
- BufferIterator end = begin;
- CaptureList captures;
-
- MatchResults matches;
-
- bool found = false;
- if ((found = find_match_in_buffer<direction>(buffer, utf8::next(begin), matches, regex)))
- {
- begin = matches[0].first;
- end = matches[0].second;
- for (auto& match : matches)
- captures.push_back(String(match.first, match.second));
- }
- if (not found or begin == buffer.end())
- throw runtime_error("'" + regex.str() + "': no matches found");
-
- end = (begin == end) ? end : utf8::previous(end);
- if (direction == Backward)
- std::swap(begin, end);
- return Selection{begin.coord(), end.coord(), std::move(captures)};
-}
-template Selection select_next_match<Forward>(const Buffer&, const Selection&, const Regex&);
-template Selection select_next_match<Backward>(const Buffer&, const Selection&, const Regex&);
-
-SelectionList select_all_matches(const Buffer& buffer, const Selection& selection, const Regex& regex)
+SelectionList select_all_matches(const Buffer& buffer, SelectionList selections,
+ const Regex& regex)
{
- auto sel_end = utf8::next(buffer.iterator_at(selection.max()));
- RegexIterator re_it(buffer.iterator_at(selection.min()), sel_end, regex);
- RegexIterator re_end;
-
SelectionList result;
- for (; re_it != re_end; ++re_it)
+ for (auto& sel : selections)
{
- BufferIterator begin = (*re_it)[0].first;
- BufferIterator end = (*re_it)[0].second;
+ auto sel_end = utf8::next(buffer.iterator_at(sel.max()));
+ RegexIterator re_it(buffer.iterator_at(sel.min()), sel_end, regex);
+ RegexIterator re_end;
- if (begin == sel_end)
- continue;
+ for (; re_it != re_end; ++re_it)
+ {
+ auto& begin = (*re_it)[0].first;
+ auto& end = (*re_it)[0].second;
+
+ if (begin == sel_end)
+ continue;
- CaptureList captures;
- for (auto& match : *re_it)
- captures.push_back(String(match.first, match.second));
+ CaptureList captures;
+ for (auto& match : *re_it)
+ captures.emplace_back(match.first, match.second);
- result.push_back(Selection(begin.coord(), (begin == end ? end : utf8::previous(end)).coord(),
- std::move(captures)));
+ result.emplace_back(begin.coord(),
+ (begin == end ? end : utf8::previous(end)).coord(),
+ std::move(captures));
+ }
}
return result;
}
-SelectionList split_selection(const Buffer& buffer, const Selection& selection,
+SelectionList split_selection(const Buffer& buffer, SelectionList selections,
const Regex& regex)
{
- auto begin = buffer.iterator_at(selection.min());
- auto sel_end = utf8::next(buffer.iterator_at(selection.max()));
- RegexIterator re_it(begin, sel_end, regex, boost::regex_constants::match_nosubs);
- RegexIterator re_end;
-
SelectionList result;
- for (; re_it != re_end; ++re_it)
+ for (auto& sel : selections)
{
- BufferIterator end = (*re_it)[0].first;
+ auto begin = buffer.iterator_at(sel.min());
+ auto sel_end = utf8::next(buffer.iterator_at(sel.max()));
+ RegexIterator re_it(begin, sel_end, regex,
+ boost::regex_constants::match_nosubs);
+ RegexIterator re_end;
- result.push_back(Selection(begin.coord(), (begin == end) ? end.coord() : utf8::previous(end).coord()));
- begin = (*re_it)[0].second;
+ for (; re_it != re_end; ++re_it)
+ {
+ BufferIterator end = (*re_it)[0].first;
+
+ result.emplace_back(begin.coord(), (begin == end) ? end.coord() : utf8::previous(end).coord());
+ begin = (*re_it)[0].second;
+ }
+ result.emplace_back(begin.coord(), sel.max());
}
- result.push_back(Selection(begin.coord(), selection.max()));
return result;
}
diff --git a/src/selectors.hh b/src/selectors.hh
index 47194f41..684562c3 100644
--- a/src/selectors.hh
+++ b/src/selectors.hh
@@ -3,6 +3,7 @@
#include "selection.hh"
#include "unicode.hh"
+#include "editor.hh"
namespace Kakoune
{
@@ -58,14 +59,78 @@ Selection trim_partial_lines(const Buffer& buffer, const Selection& selection);
enum Direction { Forward, Backward };
+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<Direction direction>
-Selection select_next_match(const Buffer& buffer, const Selection& selection,
- const Regex& regex);
+bool find_match_in_buffer(const Buffer& buffer, const BufferIterator pos,
+ MatchResults& matches, const Regex& ex)
+{
+ if (direction == Forward)
+ return (boost::regex_search(pos, buffer.end(), matches, ex) or
+ boost::regex_search(buffer.begin(), pos, matches, ex));
+ else
+ return (find_last_match(buffer.begin(), pos, matches, ex) or
+ find_last_match(pos, buffer.end(), matches, ex));
+}
+
+template<Direction direction, SelectMode mode>
+SelectionList select_next_match(const Buffer& buffer, SelectionList selections,
+ const Regex& regex)
+{
+ auto& sel = selections.main();
+ auto begin = buffer.iterator_at(sel.last());
+ auto end = begin;
+ CaptureList captures;
+
+ MatchResults matches;
+
+ bool found = false;
+ if ((found = find_match_in_buffer<direction>(buffer, utf8::next(begin), matches, regex)))
+ {
+ begin = matches[0].first;
+ end = matches[0].second;
+ for (auto& match : matches)
+ captures.emplace_back(match.first, match.second);
+ }
+ if (not found or begin == buffer.end())
+ throw runtime_error("'" + regex.str() + "': no matches found");
+
+ end = (begin == end) ? end : utf8::previous(end);
+ if (direction == Backward)
+ std::swap(begin, end);
+
+ Selection res{begin.coord(), end.coord(), std::move(captures)};
+ if (mode == SelectMode::Replace)
+ return SelectionList{ std::move(res) };
+ else if (mode == SelectMode::ReplaceMain)
+ sel = std::move(res);
+ else if (mode == SelectMode::Append)
+ {
+ selections.push_back(std::move(res));
+ selections.set_main_index(selections.size() - 1);
+ }
+ selections.sort_and_merge_overlapping();
+ return selections;
+}
-SelectionList select_all_matches(const Buffer& buffer, const Selection& selection,
+SelectionList select_all_matches(const Buffer& buffer, SelectionList selection,
const Regex& regex);
-SelectionList split_selection(const Buffer& buffer, const Selection& selection,
+SelectionList split_selection(const Buffer& buffer, SelectionList selection,
const Regex& separator_regex);
using CodepointPair = std::pair<Codepoint, Codepoint>;