- 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
@@ -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


Reply via email to