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:
parent
33616f4192
commit
28ebe776c0
167
src/selectors.cc
167
src/selectors.cc
|
@ -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())
|
||||||
{
|
{
|
||||||
pairs.pop_back();
|
if (pairs.back() != get_kind(cur))
|
||||||
return !pairs.empty();
|
|
||||||
}
|
|
||||||
fail = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
if (fail || begin == buffer.begin())
|
|
||||||
return selection;
|
return selection;
|
||||||
|
|
||||||
|
pairs.pop_back();
|
||||||
|
}
|
||||||
|
if (lev-- == 0)
|
||||||
|
{
|
||||||
|
first_arg = true;
|
||||||
|
++begin;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cur == ',' and lev == 0)
|
||||||
|
{
|
||||||
|
++begin;
|
||||||
|
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;
|
--end;
|
||||||
skip_while_reverse(end, begin, is_whitespace);
|
skip_while(begin, end, is_blank);
|
||||||
|
skip_while_reverse(end, begin, is_blank);
|
||||||
}
|
}
|
||||||
else
|
// get starting comma for non inner last arg
|
||||||
{
|
else if (not first_arg and last_arg)
|
||||||
if (classify(*end) == Closing)
|
--begin;
|
||||||
{
|
|
||||||
|
if (end == buffer.end())
|
||||||
--end;
|
--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);
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user