diff options
| author | Marc André Tanner <mat@brain-dump.org> | 2015-08-01 19:46:48 +0200 |
|---|---|---|
| committer | Marc André Tanner <mat@brain-dump.org> | 2015-08-02 00:13:51 +0200 |
| commit | dd3a6e2d9487c970fd007989833fc68a3261183a (patch) | |
| tree | 621a03395217b0237b90afc2230b8a0b17583642 /text-motions.c | |
| parent | 7c5c6581bca271f41c7ae3ac53107b89249a5fa9 (diff) | |
| download | vis-dd3a6e2d9487c970fd007989833fc68a3261183a.tar.gz vis-dd3a6e2d9487c970fd007989833fc68a3261183a.tar.xz | |
vis: add motions [[, [], ][, ]]
They behave not like in vim, but instead try to find the
start/end of C-like function definitions.
The first character stands for the direction [ for backwards,
] for forwards. The second character denotes the start [ or
end ] respectively.
Diffstat (limited to 'text-motions.c')
| -rw-r--r-- | text-motions.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/text-motions.c b/text-motions.c index 8b349c2..306e54c 100644 --- a/text-motions.c +++ b/text-motions.c @@ -421,6 +421,113 @@ size_t text_paragraph_prev(Text *txt, size_t pos) { return text_paragraph_sentence_prev(txt, pos, false); } +size_t text_line_empty_next(Text *txt, size_t pos) { + // TODO refactor search \n\n + char c; + Iterator it = text_iterator_get(txt, pos); + while (text_iterator_byte_get(&it, &c)) { + if (c == '\n' && text_iterator_byte_next(&it, &c)) { + size_t match = it.pos; + if (c == '\r') + text_iterator_byte_next(&it, &c); + if (c == '\n') + return match; + } + text_iterator_byte_next(&it, NULL); + } + return pos; +} + +size_t text_line_empty_prev(Text *txt, size_t pos) { + // TODO refactor search \n\n + char c; + Iterator it = text_iterator_get(txt, pos); + while (text_iterator_byte_prev(&it, &c)) { + if (c == '\n' && text_iterator_byte_prev(&it, &c)) { + if (c == '\r') + text_iterator_byte_prev(&it, &c); + if (c == '\n') + return it.pos + 1; + } + } + return pos; +} + +size_t text_function_start_next(Text *txt, size_t pos) { + size_t a = text_function_end_next(txt, pos); + size_t b = a; + char c; + if (a != pos) { + Iterator it = text_iterator_get(txt, a); + while (text_iterator_byte_next(&it, &c) && (c == '\r' || c == '\n')); + a = it.pos; + } + if (b != pos) { + size_t match = text_bracket_match(txt, b); + b = match != b ? text_line_next(txt, text_line_empty_prev(txt, match)) : pos; + } + if (a <= pos && b <= pos) + return pos; + else if (a <= pos) + return b; + else if (b <= pos) + return a; + else + return MIN(a, b); +} + +size_t text_function_start_prev(Text *txt, size_t pos) { + char c; + size_t apos = text_byte_get(txt, pos, &c) && c == '}' && pos > 0 ? pos - 1 : pos; + size_t a = text_function_end_next(txt, apos); + size_t b = text_function_end_prev(txt, pos); + if (a != apos) { + size_t match = text_bracket_match(txt, a); + a = match != a ? text_line_next(txt, text_line_empty_prev(txt, match)) : pos; + } + if (b != pos) { + size_t match = text_bracket_match(txt, b); + b = match != b ? text_line_next(txt, text_line_empty_prev(txt, match)) : pos; + } + if (a >= pos && b >= pos) + return pos; + else if (a >= pos) + return b; + else if (b >= pos) + return a; + else + return MAX(a, b); +} + +static size_t text_function_end_direction(Text *txt, size_t pos, int direction) { + size_t start = pos, match; + if (direction < 0 && pos > 0) + pos--; + for (;;) { + char c[3]; + if (direction > 0) + match = text_find_next(txt, pos, "\n}"); + else + match = text_find_prev(txt, pos, "\n}"); + if (text_bytes_get(txt, match, sizeof c, c) != 3 || c[0] != '\n' || c[1] != '}') + break; + if (c[2] == '\r' || c[2] == '\n') + return match+1; + if (match == pos) + match += direction; + pos = match; + } + return start; +} + +size_t text_function_end_next(Text *txt, size_t pos) { + return text_function_end_direction(txt, pos, +1); +} + +size_t text_function_end_prev(Text *txt, size_t pos) { + return text_function_end_direction(txt, pos, -1); +} + size_t text_bracket_match(Text *txt, size_t pos) { return text_bracket_match_except(txt, pos, NULL); } |
