aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.def.h4
-rw-r--r--text-motions.c107
-rw-r--r--text-motions.h8
-rw-r--r--vis.c8
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);
diff --git a/vis.c b/vis.c
index c0c7390..aae95f8 100644
--- a/vis.c
+++ b/vis.c
@@ -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 },