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

From: Markus Teich <markus.teich_AT_stusta.mhn.de>
Date: Wed, 3 Feb 2016 13:07:00 +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
- simplify text_line_empty_{prev,next}
- save a few lines of code
---
 text-motions.c | 153 +++++++++++++++++++++++----------------------------------
 1 file changed, 62 insertions(+), 91 deletions(-)
diff --git a/text-motions.c b/text-motions.c
index f406da3..cc98dee 100644
--- a/text-motions.c
+++ b/text-motions.c
_AT_@ -357,119 +357,90 @@ 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;
+	Iterator it = text_iterator_get(txt, pos);
+
+	while (text_iterator_byte_get(&it, &c) && (c == '\n' || c == '\r'))
+		text_iterator_byte_next(&it, NULL);
+	return text_line_empty_next(txt, it.pos);
 }
 
 size_t text_paragraph_prev(Text *txt, size_t pos) {
-	return text_paragraph_sentence_prev(txt, pos, false);
+	char c;
+	Iterator it = text_iterator_get(txt, pos);
+
+	/* c == \0 catches starting the search at EOF */
+	while (text_iterator_byte_get(&it, &c) && (c == '\n' || c == '\r' || c == '\0'))
+		text_iterator_byte_prev(&it, NULL);
+	return text_line_empty_prev(txt, it.pos);
 }
 
 size_t text_line_empty_next(Text *txt, size_t pos) {
-	// TODO refactor search \n\n
-	char c;
+	char c, prev = 'X', dos;
 	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;
-		}
+		if ((dos = c == '\r')) /* dos is 1 when we have a \r\n line break */
+			text_iterator_byte_next(&it, &c);
+		if (prev == '\n' && c == '\n')
+			return it.pos - dos;
+		prev = c;
 		text_iterator_byte_next(&it, NULL);
 	}
-	return pos;
+	return it.pos;
 }
 
 size_t text_line_empty_prev(Text *txt, size_t pos) {
-	// TODO refactor search \n\n
-	char c;
+	char c, prev = 'X';
 	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;
-		}
+		if (c == '\r')
+			text_iterator_byte_prev(&it, &c);
+		if (prev == '\n' && c == '\n')
+			return it.pos + 1;
+		prev = c;
 	}
 	return pos;
 }
-- 
2.4.10
Received on Wed Feb 03 2016 - 13:07:00 CET

This archive was generated by hypermail 2.3.0 : Wed Feb 03 2016 - 13:12:12 CET