From 13d212f4458b0bfe12f190c47e77265be72eed29 Mon Sep 17 00:00:00 2001 From: Viktor Palmkvist Date: Thu, 25 Jun 2015 15:44:43 +0200 Subject: [PATCH] Added argument text object --- src/normal.cc | 8 ++- src/selectors.cc | 133 +++++++++++++++++++++++++++++++++++++++++++++++ src/selectors.hh | 4 ++ 3 files changed, 144 insertions(+), 1 deletion(-) diff --git a/src/normal.cc b/src/normal.cc index a9357806..94e1f294 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -925,6 +925,11 @@ void select_object(Context& context, NormalParams params) return select(context, std::bind(sel.func, _1, _2, flags)); } + if (c == 'u') + { + return select(context, std::bind(select_argument, _1, _2, level, flags)); + } + static constexpr struct { MatchingPair pair; @@ -958,7 +963,8 @@ void select_object(Context& context, NormalParams params) "s: sentence \n" "p: paragraph \n" "␣: whitespaces \n" - "i: indent \n"); + "i: indent \n" + "u: argument \n"); } template diff --git a/src/selectors.cc b/src/selectors.cc index 8d3d5005..758a48f4 100644 --- a/src/selectors.cc +++ b/src/selectors.cc @@ -431,6 +431,139 @@ Selection select_indent(const Buffer& buffer, const Selection& selection, Object return Selection{begin_line, {end_line, buffer[end_line].length() - 1}}; } +Selection select_argument(const Buffer& buffer, const Selection& selection, + int level, ObjectFlags flags) +{ + auto is_whitespace = [](Codepoint c) { + return c == ' ' or c == '\t' or c == '\n'; + }; + auto get_kind = [](Codepoint c) -> int { + switch (c) + { + case '(': case ')': return 1; + case '[': case ']': return 2; + case '{': case '}': return 3; + case '<': case '>': return 4; + } + }; + enum Class { None, Opening, Closing }; + auto classify = [](Codepoint c) { + switch (c) + { + case '(': case '[': case '{': case '<': return Opening; + case ')': case ']': case '}': case '>': return Closing; + default: return None; + } + }; + + auto pairs = std::vector(); + + Utf8Iterator pos = buffer.iterator_at(selection.cursor()); + if (classify(*pos) == Closing) + ++pos; + Utf8Iterator begin = pos; + Utf8Iterator end = begin; + bool fail = false; + + skip_while(end, buffer.end(), [&](Codepoint cur) + { + if (cur == ',' && level == 0) + { + pairs.push_back(0); + return false; + } + auto c = classify(cur); + if (c == Opening) + { + pairs.push_back(get_kind(cur)); + ++level; + } + else if (c == Closing) + { + --level; + if (pairs.empty() || pairs.back() < 0) + { + pairs.push_back(-get_kind(cur)); + return level >= 0; + } + else if (pairs.back() == get_kind(cur)) + { + pairs.pop_back(); + return true; + } + fail = true; + return false; + } + return true; + }); + if (fail || end == buffer.end()) + return selection; + + write_to_debug_buffer("before reverse:"); + for (auto it = pairs.begin(); it != pairs.end(); ++it) + write_to_debug_buffer(format("{}", *it)); + std::reverse(pairs.begin(), pairs.end()); + write_to_debug_buffer("before reverse:"); + for (auto it = pairs.begin(); it != pairs.end(); ++it) + write_to_debug_buffer(format("{}", *it)); + + --begin; + skip_while_reverse(begin, buffer.begin(), [&](Codepoint cur) + { + if (cur == ',' && pairs.size() == 1) + { + return false; + } + auto c = classify(cur); + if (c == Closing) + { + pairs.push_back(-get_kind(cur)); + } + else if (c == Opening) + { + if (pairs.back() == 0 || pairs.back() == -get_kind(cur)) + { + pairs.pop_back(); + return !pairs.empty(); + } + fail = true; + return false; + } + return true; + }); + if (fail || begin == buffer.begin()) + return selection; + + if (flags & ObjectFlags::Inner) + { + ++begin; + skip_while(begin, end, is_whitespace); + --end; + skip_while_reverse(end, begin, is_whitespace); + } + else + { + if (classify(*end) == Closing) + { + --end; + if (classify(*begin) == Opening) + ++begin; + } + else + { + ++begin; + skip_while(begin, end, is_whitespace); + ++end; + skip_while(end, buffer.end(), is_whitespace); + --end; + } + } + + if (flags & ObjectFlags::ToBegin and not (flags & ObjectFlags::ToEnd)) + return utf8_range(pos, begin); + return utf8_range(flags & ObjectFlags::ToBegin ? begin : pos, end); +} + Selection select_lines(const Buffer& buffer, const Selection& selection) { // no need to be utf8 aware for is_eol as we only use \n as line seperator diff --git a/src/selectors.hh b/src/selectors.hh index 57731bd8..8e61a151 100644 --- a/src/selectors.hh +++ b/src/selectors.hh @@ -219,6 +219,10 @@ Selection select_indent(const Buffer& buffer, const Selection& selection, ObjectFlags flags); +Selection select_argument(const Buffer& buffer, + const Selection& selection, + int level, ObjectFlags flags); + Selection select_lines(const Buffer& buffer, const Selection& selection); Selection trim_partial_lines(const Buffer& buffer, const Selection& selection);