From ab925686ab40896778a9111677379f1eabc1629c Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 8 Oct 2013 19:24:56 +0100 Subject: [PATCH] Improve object selection support * A count is supported for nestable objects so that we can specify the surrounding level. * more symetric behavior for select to end/ to begin --- src/normal.cc | 67 +++++++++++++++++++++++++++++------------------- src/selectors.cc | 38 +++++++++++++++++---------- src/selectors.hh | 2 +- 3 files changed, 67 insertions(+), 40 deletions(-) diff --git a/src/normal.cc b/src/normal.cc index abe46943..d240dad1 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -580,33 +580,48 @@ void deindent(Context& context) template void select_object(Context& context) { - on_next_key_with_autoinfo(context, [](Key key, Context& context) { - typedef std::function Selector; - static const std::unordered_map key_to_selector = - { - { { Key::Modifiers::None, '(' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '(', ')' }, flags) }, - { { Key::Modifiers::None, ')' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '(', ')' }, flags) }, - { { Key::Modifiers::None, 'b' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '(', ')' }, flags) }, - { { Key::Modifiers::None, '{' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '{', '}' }, flags) }, - { { Key::Modifiers::None, '}' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '{', '}' }, flags) }, - { { Key::Modifiers::None, 'B' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '{', '}' }, flags) }, - { { Key::Modifiers::None, '[' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '[', ']' }, flags) }, - { { Key::Modifiers::None, ']' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '[', ']' }, flags) }, - { { Key::Modifiers::None, 'r' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '[', ']' }, flags) }, - { { Key::Modifiers::None, '<' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '<', '>' }, flags) }, - { { Key::Modifiers::None, '>' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '<', '>' }, flags) }, - { { Key::Modifiers::None, '"' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '"', '"' }, flags) }, - { { Key::Modifiers::None, '\'' }, std::bind(select_surrounding, _1, _2, CodepointPair{ '\'', '\'' }, flags) }, - { { Key::Modifiers::None, 'w' }, std::bind(select_whole_word, _1, _2, flags) }, - { { Key::Modifiers::None, 'W' }, std::bind(select_whole_word, _1, _2, flags) }, - { { Key::Modifiers::None, 's' }, std::bind(select_whole_sentence, _1, _2, flags) }, - { { Key::Modifiers::None, 'p' }, std::bind(select_whole_paragraph, _1, _2, flags) }, - { { Key::Modifiers::None, 'i' }, std::bind(select_whole_indent, _1, _2, flags) }, - }; + int level = context.numeric_param() <= 0 ? 0 : context.numeric_param() - 1; + on_next_key_with_autoinfo(context, [level](Key key, Context& context) { + if (key.modifiers != Key::Modifiers::None) + return; + const Codepoint c = key.key; - auto it = key_to_selector.find(key); - if (it != key_to_selector.end()) - context.editor().select(it->second); + static constexpr struct + { + Codepoint key; + Selection (*func)(const Buffer&, const Selection&, ObjectFlags); + } selectors[] = { + { 'w', select_whole_word }, + { 'W', select_whole_word }, + { 's', select_whole_sentence }, + { 'p', select_whole_paragraph }, + { 'i', select_whole_indent }, + }; + for (auto& sel : selectors) + { + if (c == sel.key) + return context.editor().select(std::bind(sel.func, _1, _2, flags)); + } + + static constexpr struct + { + CodepointPair pair; + Codepoint name; + } surrounding_pairs[] = { + { { '(', ')' }, 'b' }, + { { '{', '}' }, 'B' }, + { { '[', ']' }, 'r' }, + { { '<', '>' }, '\0' }, + { { '"', '"' }, '\0' }, + { { '\'', '\'' }, '\0' }, + }; + for (auto& sur : surrounding_pairs ) + { + if (sur.pair.first == c or sur.pair.second == c or + (sur.name != 0 and sur.name == c)) + return context.editor().select(std::bind(select_surrounding, _1, _2, + sur.pair, level, flags)); + } }, "╭──────┤select object├───────╮\n" "│ b,(,): parenthesis block │\n" diff --git a/src/selectors.cc b/src/selectors.cc index fb344486..e8c09849 100644 --- a/src/selectors.cc +++ b/src/selectors.cc @@ -227,7 +227,7 @@ using boost::optional; static optional find_surrounding(const Buffer& buffer, BufferCoord coord, CodepointPair matching, - ObjectFlags flags) + ObjectFlags flags, int init_level) { const bool to_begin = flags & ObjectFlags::ToBegin; const bool to_end = flags & ObjectFlags::ToEnd; @@ -236,7 +236,7 @@ static optional find_surrounding(const Buffer& buffer, Utf8Iterator first = pos; if (to_begin) { - int level = 0; + int level = nestable ? init_level : 0; while (first != buffer.begin()) { if (nestable and first != pos and *first == matching.second) @@ -257,11 +257,10 @@ static optional find_surrounding(const Buffer& buffer, Utf8Iterator last = pos; if (to_end) { - int level = 0; - last = first + 1; + int level = nestable ? init_level : 0; while (last != buffer.end()) { - if (nestable and *last == matching.first) + if (nestable and last != pos and *last == matching.first) ++level; else if (*last == matching.second) { @@ -272,13 +271,13 @@ static optional find_surrounding(const Buffer& buffer, } ++last; } - if (level != 0 or *last != matching.second) + if (level != 0 or last == buffer.end()) return optional{}; } if (flags & ObjectFlags::Inner) { - if (to_begin) + if (to_begin and first != last) ++first; if (to_end and first != last) --last; @@ -287,19 +286,32 @@ static optional find_surrounding(const Buffer& buffer, } Selection select_surrounding(const Buffer& buffer, const Selection& selection, - CodepointPair matching, + CodepointPair matching, int level, ObjectFlags flags) { - auto res = find_surrounding(buffer, selection.last(), matching, flags); + const bool nestable = matching.first != matching.second; + auto pos = selection.last(); + if (not nestable or flags & ObjectFlags::Inner) + { + if (auto res = find_surrounding(buffer, pos, matching, flags, level)) + return *res; + return selection; + } + + auto c = buffer.byte_at(pos); + if ((flags == ObjectFlags::ToBegin and c == matching.first) or + (flags == ObjectFlags::ToEnd and c == matching.second)) + ++level; + + auto res = find_surrounding(buffer, pos, matching, flags, level); if (not res) return selection; if (flags == (ObjectFlags::ToBegin | ObjectFlags::ToEnd) and - matching.first != matching.second and not buffer.is_end(res->last()) and - (*res == selection or Range{res->last(), res->first()} == selection)) + res->min() == selection.min() and res->max() == selection.max()) { - res = find_surrounding(buffer, buffer.next(res->last()), matching, flags); - return res ? Selection{*res} : selection; + if (auto res_parent = find_surrounding(buffer, pos, matching, flags, level+1)) + return Selection{*res_parent}; } return *res; } diff --git a/src/selectors.hh b/src/selectors.hh index 997f144d..47194f41 100644 --- a/src/selectors.hh +++ b/src/selectors.hh @@ -70,7 +70,7 @@ SelectionList split_selection(const Buffer& buffer, const Selection& selection, using CodepointPair = std::pair; Selection select_surrounding(const Buffer& buffer, const Selection& selection, - CodepointPair matching, ObjectFlags flags); + CodepointPair matching, int level, ObjectFlags flags); }