Refactor select_arguments and slightly change behaviour for non-inner

non inner argument contains the argument, preceeding whitespaces,
and eventual ending comma, except for first arguments (that
contains the whitespaces after the comma), and last argument (that
contains the comma before it).
This commit is contained in:
Maxime Coste 2015-07-01 23:47:22 +01:00
parent 33616f4192
commit 28ebe776c0
7 changed files with 88 additions and 94 deletions

View File

@ -434,16 +434,14 @@ Selection select_indent(const Buffer& buffer, const Selection& selection, Object
Selection select_argument(const Buffer& buffer, const Selection& selection, Selection select_argument(const Buffer& buffer, const Selection& selection,
int level, ObjectFlags flags) int level, ObjectFlags flags)
{ {
auto is_whitespace = [](Codepoint c) { auto get_kind = [](Codepoint c) -> char {
return c == ' ' or c == '\t' or c == '\n';
};
auto get_kind = [](Codepoint c) -> int {
switch (c) switch (c)
{ {
case '(': case ')': return 1; case '(': case ')': return 1;
case '[': case ']': return 2; case '[': case ']': return 2;
case '{': case '}': return 3; case '{': case '}': return 3;
case '<': case '>': return 4; case '<': case '>': return 4;
default: kak_assert(false); return 0;
} }
}; };
enum Class { None, Opening, Closing }; enum Class { None, Opening, Closing };
@ -456,108 +454,99 @@ Selection select_argument(const Buffer& buffer, const Selection& selection,
} }
}; };
auto pairs = std::vector<int>(); Vector<char> pairs;
Utf8Iterator pos = buffer.iterator_at(selection.cursor()); BufferIterator pos = buffer.iterator_at(selection.cursor());
if (classify(*pos) == Closing) if (classify(*pos) == Closing)
++pos; ++pos;
Utf8Iterator begin = pos; bool first_arg = false;
Utf8Iterator end = begin; BufferIterator begin = pos;
bool fail = false; for (int lev = level; begin != buffer.begin(); --begin)
skip_while(end, buffer.end(), [&](Codepoint cur)
{ {
if (cur == ',' && level == 0) Codepoint cur = *begin;
{ Class c = classify(cur);
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) if (c == Closing)
{ {
pairs.push_back(-get_kind(cur)); pairs.push_back(get_kind(cur));
++lev;
} }
else if (c == Opening) else if (c == Opening)
{ {
if (pairs.back() == 0 || pairs.back() == -get_kind(cur)) if (not pairs.empty())
{ {
if (pairs.back() != get_kind(cur))
return selection;
pairs.pop_back(); pairs.pop_back();
return !pairs.empty();
} }
fail = true; if (lev-- == 0)
return false; {
first_arg = true;
++begin;
break;
}
} }
return true; else if (cur == ',' and lev == 0)
}); {
if (fail || begin == buffer.begin()) ++begin;
return selection; break;
}
}
kak_assert(pairs.empty());
bool last_arg = false;
BufferIterator end = pos;
for (int lev = level; end != buffer.end(); ++end)
{
Codepoint cur = *end;
Class c = classify(cur);
if (c == Opening)
{
pairs.push_back(get_kind(cur));
++lev;
}
else if (c == Closing)
{
if (not pairs.empty())
{
if (pairs.back() != get_kind(cur))
return selection;
pairs.pop_back();
}
if (lev-- == 0)
{
last_arg = true;
--end;
break;
}
}
else if (cur == ',' and lev == 0)
{
// include whitespaces *after* the comma only for first argument
if (first_arg and not (flags & ObjectFlags::Inner))
{
while (end + 1 != buffer.end() and is_blank(*(end+1)))
++end;
}
break;
}
}
if (flags & ObjectFlags::Inner) if (flags & ObjectFlags::Inner)
{ {
++begin; if (not last_arg)
skip_while(begin, end, is_whitespace); --end;
skip_while(begin, end, is_blank);
skip_while_reverse(end, begin, is_blank);
}
// get starting comma for non inner last arg
else if (not first_arg and last_arg)
--begin;
if (end == buffer.end())
--end; --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)) if (flags & ObjectFlags::ToBegin and not (flags & ObjectFlags::ToEnd))
return utf8_range(pos, begin); return utf8_range(pos, begin);

View File

@ -18,6 +18,11 @@ inline bool is_horizontal_blank(Codepoint c)
return c == ' ' or c == '\t'; return c == ' ' or c == '\t';
} }
inline bool is_blank(Codepoint c)
{
return c == ' ' or c == '\t' or c == '\n';
}
enum WordType { Word, WORD }; enum WordType { Word, WORD };
template<WordType word_type = Word> template<WordType word_type = Word>

View File

@ -1 +1 @@
(and some, blub and), (and some, blub and),

View File

@ -1 +1 @@
"something", "something",

View File

@ -1 +1 @@
some stuff, some stuff,

View File

@ -1 +1 @@
some, some,

View File

@ -1 +1 @@
"somethi "somethi