From 4710ce1fcb4f9f467698aa18e0d0e15b64486547 Mon Sep 17 00:00:00 2001
From: David Lawrence Ramsey <pooka109@gmail.com>
Date: Fri, 27 Jul 2018 00:20:01 -0500
Subject: [PATCH 2/2] justify: refactor to use justify_paragraph()

This new function is called once for ^J, and multiple times for M-J.
It was originally moved out of do_justify().  Accordingly, in
do_justify(), a few redundant checks for when the user justified
something have been removed.

Major problem: backup_lines() no longer knows whether it's being used
for ^J or M-J, so it will back up only one paragraph at a time.  When
using M-J, this causes a crash, since it should be backing up the entire
file.  Commenting out the backup_lines() call makes M-J work properly,
but makes unjustify crash instead.

Making the function justify text in its own buffer instead of the
current buffer will eliminate the need for backup_lines() and fix this.
---
 src/text.c | 160 ++++++++++++++++++++++++++++-------------------------
 1 file changed, 86 insertions(+), 74 deletions(-)

diff --git a/src/text.c b/src/text.c
index 77d96ede..a9f50d10 100644
--- a/src/text.c
+++ b/src/text.c
@@ -2165,44 +2165,13 @@ bool find_paragraph(size_t *const quote, size_t *const par)
 	return TRUE;
 }
 
-/* Justify the current paragraph, and justify the entire file when
- * full_justify is TRUE. */
-void do_justify(bool full_justify)
+/* Justify a single paragraph starting at or after openfile->current.  Return
+ * TRUE if we found a paragraph.  If we did, indicate the starting and ending
+ * lines of the paragraph in first_par_line and last_par_line, and whether
+ * filebot is the last line of the paragraph in filebot_inpar. */
+bool justify_paragraph(filestruct **first_par_line, filestruct **last_par_line,
+						bool *filebot_inpar)
 {
-	filestruct *first_par_line = NULL;
-		/* Will be the first line of the justified paragraph(s), if any.
-		 * For restoring after unjustify. */
-	filestruct *last_par_line = NULL;
-		/* Will be the line after the last line of the justified
-		 * paragraph(s), if any.  Also for restoring after unjustify. */
-	bool filebot_inpar = FALSE;
-		/* Whether the text at filebot is part of the current paragraph. */
-	int kbinput;
-		/* The first keystroke after a justification. */
-	functionptrtype func;
-		/* The function associated with that keystroke. */
-
-	/* We save these variables to be restored if the user unjustifies. */
-	filestruct *edittop_save = openfile->edittop;
-	size_t firstcolumn_save = openfile->firstcolumn;
-	filestruct *current_save = openfile->current;
-	size_t current_x_save = openfile->current_x;
-#ifndef NANO_TINY
-	filestruct *was_mark = openfile->mark;
-	size_t was_mark_x = openfile->mark_x;
-#endif
-	bool modified_save = openfile->modified;
-
-	/* Move to the beginning of the current line, so that justifying at
-	 * the end of the last line of the file, if that line isn't blank,
-	 * will work the first time through. */
-	openfile->current_x = 0;
-
-	/* If we're justifying the entire file, start at the beginning. */
-	if (full_justify)
-		openfile->current = openfile->fileage;
-
-	while (TRUE) {
 		filestruct *firstline;
 			/* The first line of the current paragraph. */
 		filestruct *sampleline;
@@ -2225,39 +2194,23 @@ void do_justify(bool full_justify)
 		 * length (number of lines).  Don't refresh the screen yet,
 		 * since we'll do that after we justify.
 		 *
-		 * If the search failed, we do one of two things.  If we're
-		 * justifying the whole file, and we've found at least one
-		 * paragraph, it means that we should justify all the way to the
-		 * last line of the file, so set the last line of the text to be
-		 * justified to the last line of the file and break out of the
-		 * loop.  Otherwise, it means that there are no paragraph(s) to
-		 * justify, so refresh the screen and get out. */
-		if (!find_paragraph(&quote_len, &par_len)) {
-			if (full_justify && first_par_line != NULL) {
-				last_par_line = openfile->filebot;
-				break;
-			} else {
-				refresh_needed = TRUE;
-				return;
-			}
-		}
+		 * If the search failed, it means that there is no paragraph to
+		 * justify, so get out. */
+		if (!find_paragraph(&quote_len, &par_len))
+			return FALSE;
 
 		/* par_len will be one greater than the number of lines between
 		 * current and filebot if filebot is the last line in the
 		 * paragraph.  Set filebot_inpar to TRUE if this is the case. */
-		filebot_inpar = (openfile->current->lineno + par_len ==
+		*filebot_inpar = (openfile->current->lineno + par_len ==
 								openfile->filebot->lineno + 1);
 
-		/* If we haven't already done it, move the original paragraph(s)
-		 * to the justify buffer, splice a copy of the original
-		 * paragraph(s) into the file in the same place, and set
-		 * first_par_line to the first line of the copy. */
-		if (first_par_line == NULL) {
-			backup_lines(openfile->current, full_justify ?
-				openfile->filebot->lineno - openfile->current->lineno +
-				((openfile->filebot->data[0] != '\0') ? 1 : 0) : par_len);
-			first_par_line = openfile->current;
-		}
+		/* Move the original paragraph to the justify buffer, and splice a copy
+		 * of the original paragraph into the file in the same place. */
+		backup_lines(openfile->current, par_len);
+
+		/* We're on the first line of the paragraph.  Save it. */
+		*first_par_line = openfile->current;
 
 		/* Remember the first line of the current paragraph. */
 		firstline = openfile->current;
@@ -2379,22 +2332,81 @@ void do_justify(bool full_justify)
 		else
 			openfile->current_x = strlen(openfile->current->data);
 
+		/* We're on the last line of the paragraph.  Save it. */
+		*last_par_line = openfile->current;
+
 		/* Renumber the now-justified paragraph, since both refreshing the
 		 * edit window and finding a paragraph need correct line numbers. */
 		renumber(firstline);
 
-		/* We've just finished justifying the paragraph.  If we're not
-		 * justifying the entire file, break out of the loop.
-		 * Otherwise, continue the loop so that we justify all the
-		 * paragraphs in the file. */
-		if (!full_justify)
-			break;
+		return TRUE;
+}
+
+/* Justify the current paragraph, and justify the entire file when
+ * full_justify is TRUE. */
+void do_justify(bool full_justify)
+{
+	filestruct *first_par_line = NULL;
+		/* Will be the first line of the justified paragraph(s), if any.
+		 * For restoring after unjustify. */
+	filestruct *last_par_line = NULL;
+		/* Will be the line after the last line of the justified
+		 * paragraph(s), if any.  Also for restoring after unjustify. */
+	bool filebot_inpar = FALSE;
+		/* Whether the text at filebot is part of the current paragraph. */
+	bool justified_one = FALSE;
+		/* Whether we justified one paragraph. */
+	bool justified_any = FALSE;
+		/* Whether we justified any paragraphs. */
+	int kbinput;
+		/* The first keystroke after a justification. */
+	functionptrtype func;
+		/* The function associated with that keystroke. */
+
+	/* We save these variables to be restored if the user unjustifies. */
+	filestruct *edittop_save = openfile->edittop;
+	size_t firstcolumn_save = openfile->firstcolumn;
+	filestruct *current_save = openfile->current;
+	size_t current_x_save = openfile->current_x;
+#ifndef NANO_TINY
+	filestruct *was_mark = openfile->mark;
+	size_t was_mark_x = openfile->mark_x;
+#endif
+	bool modified_save = openfile->modified;
+
+	/* Move to the beginning of the current line, so that justifying at
+	 * the end of the last line of the file, if that line isn't blank,
+	 * will work the first time through. */
+	openfile->current_x = 0;
+
+	/* If we're justifying the entire file, start at the beginning. */
+	if (full_justify)
+		openfile->current = openfile->fileage;
+
+	/* Do the actual justify. */
+	do
+	{
+		if ((justified_one = justify_paragraph(&first_par_line, &last_par_line,
+												&filebot_inpar)))
+			justified_any = TRUE;
+ 	}
+	while (full_justify && justified_one);
+
+	/* If we couldn't justify anything, refresh the screen and get out. */
+	if (!justified_any) {
+		refresh_needed = TRUE;
+		return;
 	}
 
-	/* We are now done justifying the paragraph or the file, so clean
-	 * up.  totsize has been maintained above.
-	 * Set last_par_line to the new end of the paragraph. */
-		last_par_line = openfile->current;
+	/* If we're justifying the entire file, stop at the end.  Also, set the new
+	 * beginning and end of the paragraph to the beginning and end of the file,
+	 * since the justify loop above may have set them differently. */
+	if (full_justify) {
+		openfile->current = openfile->filebot;
+
+		first_par_line = openfile->fileage;
+		last_par_line = openfile->filebot;
+	}
 
 #ifndef NANO_TINY
 	/* Let a justification cancel a soft mark. */
-- 
2.17.1

