add paragraph searching ability


git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1538 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
diff --git a/nano.c b/nano.c
index 202bab2..65c9bcb 100644
--- a/nano.c
+++ b/nano.c
@@ -2244,17 +2244,17 @@
 	space_loc++;
     return space_loc;
 }
-#endif /* !DISABLE_JUSTIFY */
 
-/* This function justifies the current paragraph. */
-int do_justify(void)
+/* This function performs operations on paragraphs: justify, go to
+ * beginning, and go to end. */
+int do_para_operation(int operation)
 {
-#ifdef DISABLE_JUSTIFY
-    nano_disabled_msg();
-    return 1;
-#else
-
-/* To explain the justifying algorithm, I first need to define some
+/* operation == 0 means we're justifying the paragraph, operation == 1
+ * means we're moving to the beginning line of the paragraph, and
+ * operation == 2 means we're moving to the ending line of the
+ * paragraph.
+ *
+ * To explain the justifying algorithm, I first need to define some
  * phrases about paragraphs and quotation:
  *   A line of text consists of a "quote part", followed by an
  *   "indentation part", followed by text.  The functions quote_length()
@@ -2314,6 +2314,10 @@
     filestruct *line;	/* generic line of text */
     size_t i;		/* generic loop variable */
 
+    static int no_restart = 0;
+    	/* whether we're blocking restarting when searching for the
+    	 * beginning line of the paragraph */
+
 #ifdef HAVE_REGEX_H
     regex_t qreg;	/* qreg is the compiled quotation regexp. 
 			 * We no longer care about quotestr. */
@@ -2333,13 +2337,15 @@
     /* Here is an assumption that is always true anyway. */
     assert(current != NULL);
 
+    current_x = 0;
+
+  restart_bps:
 /* Here we find the first line of the paragraph to justify.  If the
  * current line is in a paragraph, then we move back to the first line. 
  * Otherwise we move down to the first line that is in a paragraph. */
     quote_len = quote_length(IFREG(current->data, &qreg));
     indent_len = indent_length(current->data + quote_len);
 
-    current_x = 0;
     if (current->data[quote_len + indent_len] != '\0') {
 	/* This line is part of a paragraph.  So we must search back to
 	 * the first line of this paragraph.  First we check items 1) and
@@ -2365,6 +2371,25 @@
 	    current = current->prev;
 	    current_y--;
 	}
+    } else if (operation == 1) {
+	/* This line is not part of a paragraph.  Move up until we get
+	 * to a non "blank" line, and then move down once. */
+	do {
+	    /* There is no previous paragraph, so nothing to move to. */
+	    if (current->prev == NULL) {
+		placewewant = 0;
+		if (current_y < 0)
+		    edit_update(current, CENTER);
+		else
+		    edit_refresh();
+		return 0;
+	    }
+	    current = current->prev;
+	    current_y--;
+	    quote_len = quote_length(IFREG(current->data, &qreg));
+	    indent_len = indent_length(current->data + quote_len);
+	} while (current->data[quote_len + indent_len] == '\0');
+	current = current->next;
     } else {
 	/* This line is not part of a paragraph.  Move down until we get
 	 * to a non "blank" line. */
@@ -2410,12 +2435,29 @@
 	par_len++;
     }
 #ifdef HAVE_REGEX_H
-    /* We no longer need to check quotation. */
-    regfree(&qreg);
+    /* We no longer need to check quotation, unless we're searching for
+       the beginning of the paragraph. */
+    if (operation != 1)
+	regfree(&qreg);
 #endif
 /* Now par_len is the number of lines in this paragraph.  Should never
  * call quotes_match() or quote_length() again. */
 
+    /* If operation is nonzero, skip the justification, since we're only
+     * searching through the paragraph.  If operation is 2, move down the
+     * number of lines in the paragraph, so that we end up at the
+     * paragraph's end. */
+    if (operation != 0) {
+	if (operation == 2) {
+	    while (par_len > 0) {
+		current = current->next;
+		current_y++;
+		par_len--;
+	    }
+	}
+	goto skip_justify;
+    }
+
 /* Next step, we loop through the lines of this paragraph, justifying
  * each one individually. */
     SET(JUSTIFY_MODE);
@@ -2572,8 +2614,8 @@
     }
     UNSET(JUSTIFY_MODE);
 
-/* We are now done justifying the paragraph.  There are cleanup things to
- * do, and we check for unjustify. */
+/* We are now done justifying the paragraph.  There are cleanup things
+ * to do, and we check for unjustify. */
 
     /* totlines, totsize, and current_y have been maintained above.  We
      * now set last_par_line to the new end of the paragraph, update
@@ -2586,6 +2628,67 @@
 	renumber(first_mod_line);
     }
 
+  skip_justify:
+    if (operation != 0) {
+	switch (operation) {
+	    case 1:
+		/* We're on the same line we started on.  Search for the
+		 * first non-"blank" line before the line we're on (if
+		 * there is one), continually restart that search from
+		 * the current position until we find a line that's part
+		 * of a paragraph, and then search once more from there,
+		 * so that we end up on the first line of that
+		 * paragraph.  In the process, skip over lines
+		 * consisting only of spacing characters, as searching
+		 * for the end of the paragraph does.  Then update the
+		 * screen. */
+		if (current != fileage && current == current_save &&
+			!no_restart) {
+		    while (current->prev != NULL) {
+			int j, j_space = 0;
+			current = current->prev;
+			current_y--;
+			for (j = 0; j < strlen(current->data); j++) {
+			    if (isspace(current->data[j]))
+				j_space++;
+			    else {
+				j = -1;
+				break;
+			    }
+			}
+			if (j != j_space && strlen(current->data) >=
+				(quote_len + indent_len) &&
+				current->data[quote_len + indent_len] != '\0') {
+			    no_restart = 1;
+			    break;
+			}
+		    }
+		    goto restart_bps;
+		} else
+		    no_restart = 0;
+#ifdef HAVE_REGEX_H
+		/* We no longer need to check quotation, if we were
+		   searching for the beginning of the paragraph. */
+		regfree(&qreg);
+#endif
+		if (current_y < 0)
+		    edit_update(current, CENTER);
+		else
+		    edit_refresh();
+		break;
+	    case 2:
+		/* We've already moved to the end of the paragraph.
+		 * Update the screen. */
+		if (current_y > editwinrows - 1)
+		    edit_update(current, CENTER);
+		else
+		    edit_refresh();
+		break;
+	}
+	if (operation != 0)
+	    return 0;
+    }
+
     if (current_y > editwinrows - 1)
 	edit_update(current, CENTER);
     else
@@ -2663,9 +2766,31 @@
     display_main_list();
 
     return 0;
+}
+#endif /* !DISABLE_JUSTIFY */
+
+int do_justify(void)
+{
+#ifdef DISABLE_JUSTIFY
+    nano_disabled_msg();
+    return 1;
+#else
+    return do_para_operation(0);
 #endif
 }
 
+#ifndef DISABLE_JUSTIFY
+int do_para_begin(void)
+{
+    return do_para_operation(1);
+}
+
+int do_para_end(void)
+{
+    return do_para_operation(2);
+}
+#endif
+
 int do_exit(void)
 {
     int i;