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 | |
| 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.
| -rw-r--r-- | config.def.h | 4 | ||||
| -rw-r--r-- | text-motions.c | 107 | ||||
| -rw-r--r-- | text-motions.h | 8 | ||||
| -rw-r--r-- | vis.c | 8 |
4 files changed, 127 insertions, 0 deletions
diff --git a/config.def.h b/config.def.h index 1a3a24c..910e1e7 100644 --- a/config.def.h +++ b/config.def.h @@ -123,6 +123,10 @@ static KeyBinding vis_movements[] = { { { NONE('}') }, movement, { .i = MOVE_PARAGRAPH_NEXT } }, { { NONE('(') }, movement, { .i = MOVE_SENTENCE_PREV } }, { { NONE(')') }, movement, { .i = MOVE_SENTENCE_NEXT } }, + { { NONE('['), NONE('[') }, movement, { .i = MOVE_FUNCTION_START_PREV } }, + { { NONE('['), NONE(']') }, movement, { .i = MOVE_FUNCTION_END_PREV } }, + { { NONE(']'), NONE('[') }, movement, { .i = MOVE_FUNCTION_START_NEXT } }, + { { NONE(']'), NONE(']') }, movement, { .i = MOVE_FUNCTION_END_NEXT } }, { { NONE('g'), NONE('g') }, gotoline, { .i = -1 } }, { { NONE('g'), NONE('0') }, movement, { .i = MOVE_SCREEN_LINE_BEGIN } }, { { NONE('g'), NONE('m') }, movement, { .i = MOVE_SCREEN_LINE_MIDDLE } }, 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); } diff --git a/text-motions.h b/text-motions.h index c89c256..ce3c5d5 100644 --- a/text-motions.h +++ b/text-motions.h @@ -43,6 +43,9 @@ size_t text_line_char_set(Text*, size_t pos, int count); /* move to the next/previous character on the same line */ size_t text_line_char_next(Text*, size_t pos); size_t text_line_char_prev(Text*, size_t pos); +/* move to the next/previous empty line */ +size_t text_line_empty_next(Text*, size_t pos); +size_t text_line_empty_prev(Text*, size_t pos); /* move to same offset in previous/next line */ size_t text_line_up(Text*, size_t pos); size_t text_line_down(Text*, size_t pos); @@ -86,6 +89,11 @@ size_t text_sentence_prev(Text*, size_t pos); */ size_t text_paragraph_next(Text*, size_t pos); size_t text_paragraph_prev(Text*, size_t pos); +/* Find next/previous start/end of a C like function definition */ +size_t text_function_start_next(Text*, size_t pos); +size_t text_function_start_prev(Text*, size_t pos); +size_t text_function_end_next(Text*, size_t pos); +size_t text_function_end_prev(Text*, size_t pos); /* A section begins after a form-feed in the first column. size_t text_section_next(Text*, size_t pos); size_t text_section_prev(Text*, size_t pos); @@ -124,6 +124,10 @@ enum { MOVE_SENTENCE_NEXT, MOVE_PARAGRAPH_PREV, MOVE_PARAGRAPH_NEXT, + MOVE_FUNCTION_START_PREV, + MOVE_FUNCTION_START_NEXT, + MOVE_FUNCTION_END_PREV, + MOVE_FUNCTION_END_NEXT, MOVE_BRACKET_MATCH, MOVE_LEFT_TO, MOVE_RIGHT_TO, @@ -207,6 +211,10 @@ static Movement moves[] = { [MOVE_SENTENCE_NEXT] = { .txt = text_sentence_next, .type = LINEWISE }, [MOVE_PARAGRAPH_PREV] = { .txt = text_paragraph_prev, .type = LINEWISE|JUMP }, [MOVE_PARAGRAPH_NEXT] = { .txt = text_paragraph_next, .type = LINEWISE|JUMP }, + [MOVE_FUNCTION_START_PREV] = { .txt = text_function_start_prev, .type = LINEWISE|JUMP }, + [MOVE_FUNCTION_START_NEXT] = { .txt = text_function_start_next, .type = LINEWISE|JUMP }, + [MOVE_FUNCTION_END_PREV] = { .txt = text_function_end_prev, .type = LINEWISE|JUMP }, + [MOVE_FUNCTION_END_NEXT] = { .txt = text_function_end_next, .type = LINEWISE|JUMP }, [MOVE_BRACKET_MATCH] = { .txt = text_bracket_match, .type = INCLUSIVE|JUMP }, [MOVE_FILE_BEGIN] = { .txt = text_begin, .type = LINEWISE|JUMP }, [MOVE_FILE_END] = { .txt = text_end, .type = LINEWISE|JUMP }, |
