[geany/geany] f403e7: Merge pull request #188 from artros/feature/keep-edit-history-on-reload

Colomban Wendling git-noreply at xxxxx
Wed Jan 28 14:16:40 UTC 2015


Branch:      refs/heads/master
Author:      Colomban Wendling <ban at herbesfolles.org>
Committer:   Colomban Wendling <ban at herbesfolles.org>
Date:        Wed, 28 Jan 2015 14:16:40 UTC
Commit:      f403e7e8c26a100534017f8ca2c5c1f1f9bac81f
             https://github.com/geany/geany/commit/f403e7e8c26a100534017f8ca2c5c1f1f9bac81f

Log Message:
-----------
Merge pull request #188 from artros/feature/keep-edit-history-on-reload

Maintain edit history on document reload

Conflicts:
 * src/callbacks.c: document_reload_prompt().

Amendments:
 * src/document.c: document_redo(), document_undo(): for loop style.


Modified Paths:
--------------
    doc/geany.txt
    src/document.c
    src/document.h
    src/documentprivate.h
    src/keyfile.c

Modified: doc/geany.txt
6 lines changed, 4 insertions(+), 2 deletions(-)
===================================================================
@@ -2646,6 +2646,9 @@ use_gio_unsafe_file_saving        Whether to use GIO as the unsafe file        t
                                   correctly on some complex setups.
 gio_unsafe_save_backup            Make a backup when using GIO unsafe file     false       immediately
                                   saving. Backup is named `filename~`.
+keep_edit_history_on_reload       Whether to maintain the edit history when    true        immediately
+                                  reloading a file, and allow the operation
+                                  to be reverted.
 **Filetype related**
 extract_filetype_regex            Regex to extract filetype name from file     See below.  immediately
                                   via capture group one.
@@ -3370,8 +3373,7 @@ Close all                       Ctrl-Shift-W              Closes all open files.
 
 Close                           Ctrl-W  (C)               Closes the current file.
 
-Reload file                     Ctrl-R  (C)               Reloads the current file. All unsaved changes
-                                                          will be lost.
+Reload file                     Ctrl-R  (C)               Reloads the current file.
 
 Print                           Ctrl-P  (C)               Prints the current file.
 


Modified: src/document.c
130 lines changed, 124 insertions(+), 6 deletions(-)
===================================================================
@@ -1215,6 +1215,8 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
 	gchar *locale_filename = NULL;
 	GeanyFiletype *use_ft;
 	FileData filedata;
+	UndoReloadData *undo_reload_data;
+	gboolean add_undo_reload_action;
 
 	g_return_val_if_fail(doc == NULL || doc->is_valid, NULL);
 
@@ -1274,8 +1276,31 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
 			monitor_file_setup(doc);
 		}
 
-		sci_set_undo_collection(doc->editor->sci, FALSE); /* avoid creation of an undo action */
-		sci_empty_undo_buffer(doc->editor->sci);
+		if (! reload || ! file_prefs.keep_edit_history_on_reload)
+		{
+			sci_set_undo_collection(doc->editor->sci, FALSE); /* avoid creation of an undo action */
+			sci_empty_undo_buffer(doc->editor->sci);
+			undo_reload_data = NULL;
+		}
+		else
+		{
+			undo_reload_data = (UndoReloadData*) g_malloc(sizeof(UndoReloadData));
+
+			/* We will be adding a UNDO_RELOAD action to the undo stack that undoes
+			 * this reload. To do that, we keep collecting undo actions during
+			 * reloading, and at the end add an UNDO_RELOAD action that performs
+			 * all these actions in bulk. To keep track of how many undo actions
+			 * were added during this time, we compare the current undo-stack height
+			 * with its height at the end of the process. Note that g_trash_stack_height()
+			 * is O(N), which is a little ugly, but this seems like the most maintainable
+			 * option. */
+			undo_reload_data->actions_count = g_trash_stack_height(&doc->priv->undo_actions);
+
+			/* We use add_undo_reload_action to track any changes to the document that
+			 * require adding an undo action to revert the reload, but that do not
+			 * generate an undo action themselves. */
+			add_undo_reload_action = FALSE;
+		}
 
 		/* add the text to the ScintillaObject */
 		sci_set_readonly(doc->editor->sci, FALSE);	/* to allow replacing text */
@@ -1284,11 +1309,28 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
 
 		/* detect & set line endings */
 		editor_mode = utils_get_line_endings(filedata.data, filedata.len);
+		if (undo_reload_data)
+		{
+			undo_reload_data->eol_mode = editor_get_eol_char_mode(doc->editor);
+			/* Force adding an undo-reload action if the EOL mode changed. */
+			if (editor_mode != undo_reload_data->eol_mode)
+				add_undo_reload_action = TRUE;
+		}
 		sci_set_eol_mode(doc->editor->sci, editor_mode);
 		g_free(filedata.data);
 
 		sci_set_undo_collection(doc->editor->sci, TRUE);
 
+		/* If reloading and the current and new encodings or BOM states differ,
+		 * add appropriate undo actions. */
+		if (undo_reload_data)
+		{
+			if (! utils_str_equal(doc->encoding, filedata.enc))
+				document_undo_add(doc, UNDO_ENCODING, g_strdup(doc->encoding));
+			if (doc->has_bom != filedata.bom)
+				document_undo_add(doc, UNDO_BOM, GINT_TO_POINTER(doc->has_bom));
+		}
+
 		doc->priv->mtime = filedata.mtime; /* get the modification time from file and keep it */
 		g_free(doc->encoding);	/* if reloading, free old encoding */
 		doc->encoding = filedata.enc;
@@ -1314,7 +1356,34 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
 		}
 		else
 		{	/* reloading */
-			document_undo_clear(doc);
+			if (undo_reload_data)
+			{
+				/* Calculate the number of undo actions that are part of the reloading
+				 * process, and add the UNDO_RELOAD action. */
+				undo_reload_data->actions_count =
+					g_trash_stack_height(&doc->priv->undo_actions) - undo_reload_data->actions_count;
+
+				/* We only add an undo-reload action if the document has actually changed.
+				 * At the time of writing, this condition is moot because sci_set_text
+				 * generates an undo action even when the text hasn't really changed, so
+				 * actions_count is always greater than zero. In the future this might change.
+				 * It's arguable whether we should add an undo-reload action unconditionally,
+				 * especially since it's possible (if unlikely) that there had only
+				 * been "invisible" changes to the document, such as changes in encoding and
+				 * EOL mode, but for the time being that's how we roll. */
+				if (undo_reload_data->actions_count > 0 || add_undo_reload_action)
+					document_undo_add(doc, UNDO_RELOAD, undo_reload_data);
+				else
+					g_free(undo_reload_data);
+
+				/* We didn't save the document per-se, but its contents are now
+				 * synchronized with the file on disk, hence set a save point here.
+				 * We need to do this in this case only, because we don't clear
+				 * Scintilla's undo stack. */
+				sci_set_savepoint(doc->editor->sci);
+			}
+			else
+				document_undo_clear(doc);
 
 			use_ft = ft;
 		}
@@ -1458,8 +1527,9 @@ gboolean document_reload_prompt(GeanyDocument *doc, const gchar *forced_enc)
 		forced_enc = doc->encoding;
 
 	base_name = g_path_get_basename(doc->file_name);
-	/* don't prompt if file hasn't been edited at all */
-	prompt = doc->changed || (document_can_undo(doc) || document_can_redo(doc));
+	/* don't prompt if edit history is maintained, or if file hasn't been edited at all */
+	prompt = !file_prefs.keep_edit_history_on_reload &&
+			(doc->changed || (document_can_undo(doc) || document_can_redo(doc)));
 
 	if (!prompt || dialogs_show_question_full(NULL, _("_Reload"), GTK_STOCK_CANCEL,
 		doc->changed ? _("Any unsaved changes will be lost.") :
@@ -2715,7 +2785,9 @@ void document_undo_clear_stack(GTrashStack **stack)
 		{
 			switch (a->type)
 			{
-				case UNDO_ENCODING: g_free(a->data); break;
+				case UNDO_ENCODING:
+				case UNDO_RELOAD:
+					g_free(a->data); break;
 				default: break;
 			}
 			g_free(a);
@@ -2837,6 +2909,29 @@ void document_undo(GeanyDocument *doc)
 				g_free(action->data);
 				break;
 			}
+			case UNDO_RELOAD:
+			{
+				UndoReloadData *data = (UndoReloadData*)action->data;
+				gint eol_mode = data->eol_mode;
+				guint i;
+
+				/* We reuse 'data' for the redo action, so read the current EOL mode
+				 * into it before proceeding. */
+				data->eol_mode = editor_get_eol_char_mode(doc->editor);
+
+				/* Undo the rest of the actions which are part of the reloading process. */
+				for (i = 0; i < data->actions_count; i++)
+					document_undo(doc);
+
+				/* Restore the previous EOL mode. */
+				sci_set_eol_mode(doc->editor->sci, eol_mode);
+				/* This might affect the status bar and document menu, so update them. */
+				ui_update_statusbar(doc, -1);
+				ui_document_show_hide(doc);
+
+				document_redo_add(doc, UNDO_RELOAD, data);
+				break;
+			}
 			default: break;
 		}
 	}
@@ -2905,6 +3000,29 @@ void document_redo(GeanyDocument *doc)
 				g_free(action->data);
 				break;
 			}
+			case UNDO_RELOAD:
+			{
+				UndoReloadData *data = (UndoReloadData*)action->data;
+				gint eol_mode = data->eol_mode;
+				guint i;
+
+				/* We reuse 'data' for the undo action, so read the current EOL mode
+				 * into it before proceeding. */
+				data->eol_mode = editor_get_eol_char_mode(doc->editor);
+
+				/* Redo the rest of the actions which are part of the reloading process. */
+				for (i = 0; i < data->actions_count; i++)
+					document_redo(doc);
+
+				/* Restore the previous EOL mode. */
+				sci_set_eol_mode(doc->editor->sci, eol_mode);
+				/* This might affect the status bar and document menu, so update them. */
+				ui_update_statusbar(doc, -1);
+				ui_document_show_hide(doc);
+
+				document_undo_add_internal(doc, UNDO_RELOAD, data);
+				break;
+			}
 			default: break;
 		}
 	}


Modified: src/document.h
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -64,6 +64,7 @@ typedef struct GeanyFilePrefs
 	gboolean		use_gio_unsafe_file_saving; /* whether to use GIO as the unsafe backend */
 	gchar			*extract_filetype_regex;	/* regex to extract filetype on opening */
 	gboolean		tab_close_switch_to_mru;
+	gboolean		keep_edit_history_on_reload; /* Keep undo stack upon, and allow undoing of, document reloading. */
 }
 GeanyFilePrefs;
 


Modified: src/documentprivate.h
8 lines changed, 8 insertions(+), 0 deletions(-)
===================================================================
@@ -34,9 +34,17 @@ enum
 	UNDO_SCINTILLA = 0,
 	UNDO_ENCODING,
 	UNDO_BOM,
+	UNDO_RELOAD,
 	UNDO_ACTIONS_MAX
 };
 
+typedef struct UndoReloadData
+{
+	guint actions_count; /* How many following undo/redo actions need to be applied. */
+	gint eol_mode;       /* End-Of-Line mode before/after reloading. */
+}
+UndoReloadData;
+
 typedef enum
 {
 	FILE_OK,


Modified: src/keyfile.c
2 lines changed, 2 insertions(+), 0 deletions(-)
===================================================================
@@ -224,6 +224,8 @@ static void init_pref_groups(void)
 		"gio_unsafe_save_backup", FALSE);
 	stash_group_add_boolean(group, &file_prefs.use_gio_unsafe_file_saving,
 		"use_gio_unsafe_file_saving", TRUE);
+	stash_group_add_boolean(group, &file_prefs.keep_edit_history_on_reload,
+		"keep_edit_history_on_reload", TRUE);
 	/* for backwards-compatibility */
 	stash_group_add_integer(group, &editor_prefs.indentation->hard_tab_width,
 		"indent_hard_tab_width", 8);



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list