From dc3618a1273007a4113c9ef382faf1d0dfd0c365 Mon Sep 17 00:00:00 2001
From: Benno Schulenberg <bensberg@telfort.nl>
Date: Mon, 18 Dec 2017 20:08:06 +0100
Subject: [PATCH v3] text: set and reset the Modified state correctly when
 undoing/redoing

Unset the "Modified" marker only at the point where the file was last
saved -- if there is such a point, because it can be missing when the
undo stack was discarded.

This fixes https://savannah.gnu.org/bugs/?52689.
Reported-by: Liu Hao <lh_mouse@126.com>

Original-idea-by: Brand Huntsman <alpha@qzx.com>
---
 src/files.c |  6 +++++-
 src/nano.h  |  5 ++---
 src/text.c  | 20 +++++++++++++-------
 3 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/src/files.c b/src/files.c
index 071bab21..1f18ea94 100644
--- a/src/files.c
+++ b/src/files.c
@@ -99,8 +99,8 @@ void make_new_buffer(void)
 
     openfile->undotop = NULL;
     openfile->current_undo = NULL;
+    openfile->last_saved = NULL;
     openfile->last_action = OTHER;
-    openfile->pristine = TRUE;
 
     openfile->current_stat = NULL;
     openfile->lock_filename = NULL;
@@ -1953,6 +1953,10 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
 #ifndef NANO_TINY
 	    /* Get or update the stat info to reflect the current state. */
 	    stat_with_alloc(realname, &openfile->current_stat);
+
+	    /* Record at which point in the undo stack the file was saved. */
+	    openfile->last_saved = openfile->current_undo;
+	    openfile->last_action = OTHER;
 #endif
 	    openfile->modified = FALSE;
 	    titlebar(NULL);
diff --git a/src/nano.h b/src/nano.h
index 7e6d8f81..62867b26 100644
--- a/src/nano.h
+++ b/src/nano.h
@@ -394,11 +394,10 @@ typedef struct openfilestruct {
 	/* The top of the undo list. */
     undo *current_undo;
 	/* The current (i.e. next) level of undo. */
+    undo *last_saved;
+	/* The undo item at which the file was last saved. */
     undo_type last_action;
 	/* The type of the last action the user performed. */
-    bool pristine;
-	/* Whether the undo stack still contains the first edit -- it won't
-	 * when a justification or spell check discarded the undo stack. */
     char *lock_filename;
 	/* The path of the lockfile, if we created one. */
 #endif
diff --git a/src/text.c b/src/text.c
index a01bcc86..84e432e0 100644
--- a/src/text.c
+++ b/src/text.c
@@ -868,8 +868,8 @@ void do_undo(void)
 
     openfile->totsize = u->wassize;
 
-    /* If *everything* was undone, then unset the "Modified" marker. */
-    if (openfile->current_undo == NULL && openfile->pristine) {
+    /* When at the point where the file was last saved, unset "Modified". */
+    if (openfile->current_undo == openfile->last_saved) {
 	openfile->modified = FALSE;
 	titlebar(NULL);
     } else
@@ -1028,7 +1028,13 @@ void do_redo(void)
     openfile->placewewant = xplustabs();
 
     openfile->totsize = u->newsize;
-    set_modified();
+
+    /* When at the point where the file was last saved, unset "Modified". */
+    if (openfile->current_undo == openfile->last_saved) {
+	openfile->modified = FALSE;
+	titlebar(NULL);
+    } else
+	set_modified();
 }
 #endif /* !NANO_TINY */
 
@@ -1191,7 +1197,7 @@ bool execute_command(const char *command)
 }
 
 /* Discard undo items that are newer than the given one, or all if NULL.
- * When keep is TRUE, do not touch the pristine flag. */
+ * When keep is TRUE, do not touch the last_saved pointer. */
 void discard_until(const undo *thisitem, openfilestruct *thefile, bool keep)
 {
     undo *dropit = thefile->undotop;
@@ -1209,7 +1215,6 @@ void discard_until(const undo *thisitem, openfilestruct *thefile, bool keep)
 	    free(group);
 	    group = next;
 	}
-	free(dropit);
 	dropit = thefile->undotop;
     }
 
@@ -1219,9 +1224,10 @@ void discard_until(const undo *thisitem, openfilestruct *thefile, bool keep)
     /* Prevent a chain of editing actions from continuing. */
     thefile->last_action = OTHER;
 
-    /* When requested, record that the undo stack was chopped. */
+    /* When requested, record that the undo stack was chopped, and
+     * that thus there is no point at which the file was last saved. */
     if (!keep)
-	thefile->pristine = FALSE;
+	thefile->last_saved = (undo *)0xbeeb;
 }
 
 /* Add a new undo struct to the top of the current pile. */
-- 
2.14.3

