aboutsummaryrefslogtreecommitdiff
path: root/text-motions.c
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2014-08-25 18:47:00 +0200
committerMarc André Tanner <mat@brain-dump.org>2014-08-25 18:47:00 +0200
commitb5d121dc1ca4edc0cfff888ba411f0837e6e0ebc (patch)
tree35a3aef6d494c93674922f6b5500e0d273cb0848 /text-motions.c
parentbc0f09dce9fb9420ea1d5c10ebfacf50916b10af (diff)
downloadvis-b5d121dc1ca4edc0cfff888ba411f0837e6e0ebc.tar.gz
vis-b5d121dc1ca4edc0cfff888ba411f0837e6e0ebc.tar.xz
Move motion related stuff into own file
Diffstat (limited to 'text-motions.c')
-rw-r--r--text-motions.c228
1 files changed, 228 insertions, 0 deletions
diff --git a/text-motions.c b/text-motions.c
new file mode 100644
index 0000000..1313c94
--- /dev/null
+++ b/text-motions.c
@@ -0,0 +1,228 @@
+#include <ctype.h>
+#include "text-motions.h"
+
+// TODO: consistent usage of iterators either char or byte based where appropriate.
+
+size_t text_line_begin(Text *txt, size_t pos) {
+ char c;
+ Iterator it = text_iterator_get(txt, pos);
+ if (!text_iterator_byte_get(&it, &c))
+ return pos;
+ if (c == '\r')
+ text_iterator_byte_prev(&it, &c);
+ if (c == '\n')
+ text_iterator_byte_prev(&it, &c);
+ while (text_iterator_byte_get(&it, &c)) {
+ if (c == '\n' || c == '\r') {
+ it.pos++;
+ break;
+ }
+ text_iterator_byte_prev(&it, NULL);
+ }
+ return pos;
+}
+
+size_t text_line_start(Text *txt, size_t pos) {
+ char c;
+ Iterator it = text_iterator_get(txt, text_line_begin(txt, pos));
+ while (text_iterator_byte_get(&it, &c) && c != '\n' && isspace(c))
+ text_iterator_byte_next(&it, NULL);
+ return it.pos;
+}
+
+size_t text_line_finish(Text *txt, size_t pos) {
+ char c;
+ Iterator it = text_iterator_get(txt, text_line_end(txt, pos));
+ do text_iterator_byte_prev(&it, NULL);
+ while (text_iterator_byte_get(&it, &c) && c != '\n' && c != '\r' && isspace(c));
+ return it.pos;
+}
+
+size_t text_line_end(Text *txt, size_t pos) {
+ char c;
+ Iterator it = text_iterator_get(txt, pos);
+ while (text_iterator_byte_get(&it, &c) && c != '\n')
+ text_iterator_byte_next(&it, NULL);
+ return it.pos;
+}
+
+
+size_t text_word_boundry_start_next(Text *txt, size_t pos, int (*isboundry)(int)) {
+ char c;
+ Iterator it = text_iterator_get(txt, pos);
+ while (text_iterator_byte_get(&it, &c) && !isboundry(c))
+ text_iterator_byte_next(&it, NULL);
+ while (text_iterator_byte_get(&it, &c) && isboundry(c))
+ text_iterator_byte_next(&it, NULL);
+ return it.pos;
+}
+
+size_t text_word_boundry_start_prev(Text *txt, size_t pos, int (*isboundry)(int)) {
+ char c;
+ Iterator it = text_iterator_get(txt, pos);
+ while (text_iterator_byte_prev(&it, &c) && isboundry(c));
+ do pos = it.pos; while (text_iterator_char_prev(&it, &c) && !isboundry(c));
+ return pos;
+}
+
+size_t text_word_boundry_end_next(Text *txt, size_t pos, int (*isboundry)(int)) {
+ char c;
+ Iterator it = text_iterator_get(txt, pos);
+ while (text_iterator_char_next(&it, &c) && isboundry(c));
+ do pos = it.pos; while (text_iterator_char_next(&it, &c) && !isboundry(c));
+ return pos;
+}
+
+size_t text_word_boundry_end_prev(Text *txt, size_t pos, int (*isboundry)(int)) {
+ char c;
+ Iterator it = text_iterator_get(txt, pos);
+ while (text_iterator_byte_prev(&it, &c) && !isboundry(c));
+ while (text_iterator_char_prev(&it, &c) && isboundry(c));
+ return it.pos;
+}
+
+size_t text_word_end_next(Text *txt, size_t pos) {
+ return text_word_boundry_end_next(txt, pos, isspace);
+}
+
+size_t text_word_end_prev(Text *txt, size_t pos) {
+ return text_word_boundry_end_prev(txt, pos, isspace);
+}
+
+size_t text_word_start_next(Text *txt, size_t pos) {
+ return text_word_boundry_start_next(txt, pos, isspace);
+}
+
+size_t text_word_start_prev(Text *txt, size_t pos) {
+ return text_word_boundry_start_prev(txt, pos, isspace);
+}
+
+static size_t text_paragraph_sentence_next(Text *txt, size_t pos, bool sentence) {
+ char c;
+ bool content = false, paragraph = false;
+ Iterator it = text_iterator_get(txt, pos);
+ while (text_iterator_byte_next(&it, &c)) {
+ content |= !isspace(c);
+ if (sentence && (c == '.' || c == '?' || c == '!') && text_iterator_byte_next(&it, &c) && isspace(c)) {
+ if (c == '\n' && text_iterator_byte_next(&it, &c)) {
+ if (c == '\r')
+ text_iterator_byte_next(&it, &c);
+ } else {
+ while (text_iterator_byte_get(&it, &c) && c == ' ')
+ text_iterator_byte_next(&it, NULL);
+ }
+ break;
+ }
+ if (c == '\n' && text_iterator_byte_next(&it, &c)) {
+ if (c == '\r')
+ text_iterator_byte_next(&it, &c);
+ content |= !isspace(c);
+ if (c == '\n')
+ paragraph = true;
+ }
+ if (content && paragraph)
+ break;
+ }
+ return it.pos;
+}
+
+static size_t text_paragraph_sentence_prev(Text *txt, size_t pos, bool sentence) {
+ char prev, c;
+ bool content = false, paragraph = false;
+
+ Iterator it = text_iterator_get(txt, pos);
+ if (!text_iterator_byte_get(&it, &prev))
+ return pos;
+
+ while (text_iterator_byte_prev(&it, &c)) {
+ content |= !isspace(c) && c != '.' && c != '?' && c != '!';
+ if (sentence && content && (c == '.' || c == '?' || c == '!') && isspace(prev)) {
+ do text_iterator_byte_next(&it, NULL);
+ while (text_iterator_byte_get(&it, &c) && isspace(c));
+ break;
+ }
+ if (c == '\r')
+ text_iterator_byte_prev(&it, &c);
+ if (c == '\n' && text_iterator_byte_prev(&it, &c)) {
+ content |= !isspace(c);
+ if (c == '\r')
+ text_iterator_byte_prev(&it, &c);
+ if (c == '\n') {
+ paragraph = true;
+ if (content) {
+ do text_iterator_byte_next(&it, NULL);
+ while (text_iterator_byte_get(&it, &c) && isspace(c));
+ break;
+ }
+ }
+ }
+ if (content && paragraph) {
+ do text_iterator_byte_next(&it, NULL);
+ while (text_iterator_byte_get(&it, &c) && !isspace(c));
+ break;
+ }
+ prev = c;
+ }
+ return it.pos;
+}
+
+size_t text_sentence_next(Text *txt, size_t pos) {
+ return text_paragraph_sentence_next(txt, pos, true);
+}
+
+size_t text_sentence_prev(Text *txt, size_t pos) {
+ return text_paragraph_sentence_prev(txt, pos, true);
+}
+
+size_t text_paragraph_next(Text *txt, size_t pos) {
+ return text_paragraph_sentence_next(txt, pos, false);
+}
+
+size_t text_paragraph_prev(Text *txt, size_t pos) {
+ return text_paragraph_sentence_prev(txt, pos, false);
+}
+
+size_t text_bracket_match(Text *txt, size_t pos) {
+ int direction, count = 1;
+ char search, current, c;
+ Iterator it = text_iterator_get(txt, pos);
+ if (!text_iterator_byte_get(&it, &current))
+ return pos;
+
+ switch (current) {
+ case '(': search = ')'; direction = 1; break;
+ case ')': search = '('; direction = -1; break;
+ case '{': search = '}'; direction = 1; break;
+ case '}': search = '{'; direction = -1; break;
+ case '[': search = ']'; direction = 1; break;
+ case ']': search = '['; direction = -1; break;
+ case '<': search = '>'; direction = 1; break;
+ case '>': search = '<'; direction = -1; break;
+ // TODO: heuristic basic on neighbouring chars shared with text-object
+ case '"': search = '"'; direction = 1; break;
+ case '\'': search = '\''; direction = 1; break;
+ default: return pos;
+ }
+
+ if (direction >= 0) { /* forward search */
+ while (text_iterator_byte_next(&it, &c)) {
+ if (c == search && --count == 0) {
+ pos = it.pos;
+ break;
+ } else if (c == current) {
+ count++;
+ }
+ }
+ } else { /* backwards */
+ while (text_iterator_byte_prev(&it, &c)) {
+ if (c == search && --count == 0) {
+ pos = it.pos;
+ break;
+ } else if (c == current) {
+ count++;
+ }
+ }
+ }
+
+ return pos;
+}