[hackers] [vis] [PATCH] fix {, }, (, ) movements

From: Markus Teich <markus.teich_AT_stusta.mhn.de>
Date: Tue, 2 Feb 2016 22:14:52 +0100

- Split the functions, so the algorithms are more clear
- Paragraph movements work backwards
- Paragraph movements work consistently with \r\n line breaks always placing the
  cursor on the first character of the first empty line before/after the
  paragraph
- Sentence movements now work better at BOF/EOF
- save a few lines of code
---
 text-motions.c | 141 ++++++++++++++++++++++++++++-----------------------------
 1 file changed, 68 insertions(+), 73 deletions(-)
diff --git a/text-motions.c b/text-motions.c
index f406da3..6f8d0b4 100644
--- a/text-motions.c
+++ b/text-motions.c
_AT_@ -357,89 +357,84 @@ size_t text_word_start_prev(Text *txt, size_t pos) {
 	return text_customword_start_prev(txt, pos, is_word_boundry);
 }
 
-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((unsigned char)c);
-		if (sentence && (c == '.' || c == '?' || c == '!') && text_iterator_byte_next(&it, &c) && isspace((unsigned char)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((unsigned char)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((unsigned char)c) && c != '.' && c != '?' && c != '!';
-		if (sentence && content && (c == '.' || c == '?' || c == '!') && isspace((unsigned char)prev)) {
-			do text_iterator_byte_next(&it, NULL);
-			while (text_iterator_byte_get(&it, &c) && isspace((unsigned char)c));
-			break;
-		}
-		if (c == '\r')
-			text_iterator_byte_prev(&it, &c);
-		if (c == '\n' && text_iterator_byte_prev(&it, &c)) {
-			content |= !isspace((unsigned char)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((unsigned char)c));
-					break;
-				}
-			}
-		}
-		if (content && paragraph) {
-			do text_iterator_byte_next(&it, NULL);
-			while (text_iterator_byte_get(&it, &c) && !isspace((unsigned char)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);
+	char c, prev = 'X';
+	Iterator it = text_iterator_get(txt, pos), rev = text_iterator_get(txt, pos);
+
+	if (!text_iterator_byte_get(&it, &c))
+		return pos;
+
+	while (text_iterator_byte_get(&rev, &prev) && isspace((unsigned char)prev))
+		text_iterator_byte_prev(&rev, NULL);
+	prev = rev.pos == 0 ? '.' : prev; /* simulate punctuation at BOF */
+
+	do {
+		if ((prev == '.' || prev == '?' || prev == '!') && isspace((unsigned char)c)) {
+			do text_iterator_byte_next(&it, NULL);
+			while (text_iterator_byte_get(&it, &c) && isspace((unsigned char)c));
+			return it.pos;
+		}
+		prev = c;
+	} while (text_iterator_byte_next(&it, &c));
+	return it.pos;
 }
 
 size_t text_sentence_prev(Text *txt, size_t pos) {
-	return text_paragraph_sentence_prev(txt, pos, true);
+	char c, prev = 'X';
+	bool content = false;
+	Iterator it = text_iterator_get(txt, pos);
+
+	while (it.pos != 0 && text_iterator_byte_prev(&it, &c)) {
+		if (content && isspace((unsigned char)prev) && (c == '.' || c == '?' || c == '!')) {
+			do text_iterator_byte_next(&it, NULL);
+			while (text_iterator_byte_get(&it, &c) && isspace((unsigned char)c));
+			return it.pos;
+		}
+		content |= !isspace((unsigned char)c);
+		prev = c;
+	} /* The loop only ends on hitting BOF or error */
+	if (content) /* starting pos was after first sentence in file => find that sentences start */
+		while (text_iterator_byte_get(&it, &c) && isspace((unsigned char)c))
+			text_iterator_byte_next(&it, NULL);
+	return it.pos;
 }
 
 size_t text_paragraph_next(Text *txt, size_t pos) {
-	return text_paragraph_sentence_next(txt, pos, false);
+	char c, dos, prev = 'X';
+	bool content = false;
+	Iterator it = text_iterator_get(txt, pos);
+
+	if (!text_iterator_byte_get(&it, &c))
+		return pos;
+
+	do {
+		content |= c != '\n' && c != '\r';
+		if ((dos = c == '\r')) /* dos is 1 when we have a \r\n line break */
+			text_iterator_byte_next(&it, &c);
+		if (content && prev == '\n' && c == '\n')
+			return it.pos - dos;
+		prev = c;
+	} while (text_iterator_byte_next(&it, &c));
+	return it.pos;
 }
 
 size_t text_paragraph_prev(Text *txt, size_t pos) {
-	return text_paragraph_sentence_prev(txt, pos, false);
+	char c, prev = 'X';
+	bool content = false;
+	Iterator it = text_iterator_get(txt, pos);
+
+	if (!text_iterator_byte_get(&it, &c))
+		return pos;
+
+	do {
+		content |= c != '\n' && c != '\r' && c != '\0'; /* \0 checks for EOF */
+		if (c == '\r')
+			text_iterator_byte_prev(&it, &c);
+		if (content && prev == '\n' && c == '\n')
+			return it.pos + 1;
+		prev = c;
+	} while (text_iterator_byte_prev(&it, &c));
+	return it.pos;
 }
 
 size_t text_line_empty_next(Text *txt, size_t pos) {
-- 
2.4.10
Received on Tue Feb 02 2016 - 22:14:52 CET

This archive was generated by hypermail 2.3.0 : Tue Feb 02 2016 - 22:24:06 CET