changeset 82310:b9c61edbe743

(Finsert_file_contents): Run format-decode and after_insert_file_functions on entire buffer when REPLACE is non-nil and inhibit modification_hooks and point_motion_hooks. For consistency, run after_insert_file_functions iff something got inserted. Move signal_after_change and update_compositions after code running after_insert_file_functions. Make sure that undo_list doesn't record intermediate steps of the decoding process.
author Martin Rudalics <rudalics@gmx.at>
date Tue, 07 Aug 2007 12:22:00 +0000
parents d004a08e9402
children 274ccf527227
files src/fileio.c
diffstat 1 files changed, 120 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/src/fileio.c	Tue Aug 07 08:56:08 2007 +0000
+++ b/src/fileio.c	Tue Aug 07 12:22:00 2007 +0000
@@ -3690,27 +3690,25 @@
        1, 5, 0,
        doc: /* Insert contents of file FILENAME after point.
 Returns list of absolute file name and number of characters inserted.
-If second argument VISIT is non-nil, the buffer's visited filename
-and last save file modtime are set, and it is marked unmodified.
-If visiting and the file does not exist, visiting is completed
-before the error is signaled.
-The optional third and fourth arguments BEG and END
-specify what portion of the file to insert.
-These arguments count bytes in the file, not characters in the buffer.
-If VISIT is non-nil, BEG and END must be nil.
-
-If optional fifth argument REPLACE is non-nil,
-it means replace the current buffer contents (in the accessible portion)
-with the file contents.  This is better than simply deleting and inserting
-the whole thing because (1) it preserves some marker positions
-and (2) it puts less data in the undo list.
-When REPLACE is non-nil, the value is the number of characters actually read,
-which is often less than the number of characters to be read.
-
-This does code conversion according to the value of
-`coding-system-for-read' or `file-coding-system-alist',
-and sets the variable `last-coding-system-used' to the coding system
-actually used.  */)
+If second argument VISIT is non-nil, the buffer's visited filename and
+last save file modtime are set, and it is marked unmodified.  If
+visiting and the file does not exist, visiting is completed before the
+error is signaled.
+
+The optional third and fourth arguments BEG and END specify what portion
+of the file to insert.  These arguments count bytes in the file, not
+characters in the buffer.  If VISIT is non-nil, BEG and END must be nil.
+
+If optional fifth argument REPLACE is non-nil, replace the current
+buffer contents (in the accessible portion) with the file contents.
+This is better than simply deleting and inserting the whole thing
+because (1) it preserves some marker positions and (2) it puts less data
+in the undo list.  When REPLACE is non-nil, the second return value is
+the number of characters that replace previous buffer contents.
+
+This function does code conversion according to the value of
+`coding-system-for-read' or `file-coding-system-alist', and sets the
+variable `last-coding-system-used' to the coding system actually used.  */)
      (filename, visit, beg, end, replace)
      Lisp_Object filename, visit, beg, end, replace;
 {
@@ -3720,8 +3718,8 @@
   register int how_much;
   register int unprocessed;
   int count = SPECPDL_INDEX ();
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
-  Lisp_Object handler, val, insval, orig_filename;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
+  Lisp_Object handler, val, insval, orig_filename, old_undo;
   Lisp_Object p;
   int total = 0;
   int not_regular = 0;
@@ -3744,8 +3742,9 @@
   val = Qnil;
   p = Qnil;
   orig_filename = Qnil;
-
-  GCPRO4 (filename, val, p, orig_filename);
+  old_undo = Qnil;
+
+  GCPRO5 (filename, val, p, orig_filename, old_undo);
 
   CHECK_STRING (filename);
   filename = Fexpand_file_name (filename, Qnil);
@@ -4704,24 +4703,105 @@
   /* Decode file format */
   if (inserted > 0)
     {
-      int empty_undo_list_p = 0;
-
-      /* If we're anyway going to discard undo information, don't
-	 record it in the first place.  The buffer's undo list at this
-	 point is either nil or t when visiting a file.  */
-      if (!NILP (visit))
+      /* Don't run point motion or modification hooks when decoding. */
+      int count = SPECPDL_INDEX ();
+      specbind (Qinhibit_point_motion_hooks, Qt);
+      specbind (Qinhibit_modification_hooks, Qt);
+
+      /* Save old undo list and don't record undo for decoding. */
+      old_undo = current_buffer->undo_list;
+      current_buffer->undo_list = Qt;
+
+      if (NILP (replace))
+	{
+	  insval = call3 (Qformat_decode,
+			  Qnil, make_number (inserted), visit);
+	  CHECK_NUMBER (insval);
+	  inserted = XFASTINT (insval);
+	}
+      else
+	{
+	  /* If REPLACE is non-nil and we succeeded in not replacing the
+	  beginning or end of the buffer text with the file's contents,
+	  call format-decode with `point' positioned at the beginning of
+	  the buffer and `inserted' equalling the number of characters
+	  in the buffer.  Otherwise, format-decode might fail to
+	  correctly analyze the beginning or end of the buffer.  Hence
+	  we temporarily save `point' and `inserted' here and restore
+	  `point' iff format-decode did not insert or delete any text.
+	  Otherwise we leave `point' at point-min. */
+	  int opoint = PT;
+	  int opoint_byte = PT_BYTE;
+	  int oinserted = ZV - BEGV;
+	  
+	  TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE); 
+	  insval = call3 (Qformat_decode,
+			  Qnil, make_number (oinserted), visit);
+	  CHECK_NUMBER (insval);
+	  if (insval = oinserted)
+	    SET_PT_BOTH (opoint, opoint_byte);
+	  inserted = XFASTINT (insval);
+	}
+
+      /* For consistency with format-decode call these now iff inserted > 0
+	 (martin 2007-06-28) */
+      p = Vafter_insert_file_functions;
+      while (CONSP (p))
 	{
-	  empty_undo_list_p = NILP (current_buffer->undo_list);
-	  current_buffer->undo_list = Qt;
+	  if (NILP (replace))
+	    {
+	      insval = call1 (XCAR (p), make_number (inserted));
+	      if (!NILP (insval))
+		{
+		  CHECK_NUMBER (insval);
+		  inserted = XFASTINT (insval);
+		}
+	    }
+	  else
+	    {
+	      /* For the rationale of this see the comment on format-decode above. */
+	      int opoint = PT;
+	      int opoint_byte = PT_BYTE;
+	      int oinserted = ZV - BEGV;
+
+	      TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
+	      insval = call1 (XCAR (p), make_number (oinserted));
+	      if (!NILP (insval))
+		{
+		  CHECK_NUMBER (insval);
+		  if (insval = oinserted)
+		    SET_PT_BOTH (opoint, opoint_byte);
+		  inserted = XFASTINT (insval);
+		}
+	    }
+
+	  QUIT;
+	  p = XCDR (p);
 	}
 
-      insval = call3 (Qformat_decode,
-		      Qnil, make_number (inserted), visit);
-      CHECK_NUMBER (insval);
-      inserted = XFASTINT (insval);
-
-      if (!NILP (visit))
-	current_buffer->undo_list = empty_undo_list_p ? Qnil : Qt;
+      if (NILP (visit))
+	{
+	  Lisp_Object lbeg, lend;
+	  XSETINT (lbeg, PT);
+	  XSETINT (lend, PT + inserted);
+	  if (CONSP (old_undo))
+	    {
+	      Lisp_Object tem = XCAR (old_undo);
+	      if (CONSP (tem) && INTEGERP (XCAR (tem)) &&
+		  INTEGERP (XCDR (tem)) && (XCAR (tem)) == lbeg)
+		/* In the non-visiting case record only the final insertion. */
+		current_buffer->undo_list =
+		  Fcons (Fcons (lbeg, lend), Fcdr (old_undo));
+	    }
+	}
+      else if (old_undo == Qt)
+	/* If undo_list was Qt before, keep it that way. */
+	current_buffer->undo_list = Qt;
+      else
+	/* Otherwise start with an empty undo_list. */
+	current_buffer->undo_list = Qnil;
+
+      unbind_to (count, Qnil);
     }
 
   /* Call after-change hooks for the inserted text, aside from the case
@@ -4734,19 +4814,6 @@
       update_compositions (PT, PT, CHECK_BORDER);
     }
 
-  p = Vafter_insert_file_functions;
-  while (CONSP (p))
-    {
-      insval = call1 (XCAR (p), make_number (inserted));
-      if (!NILP (insval))
-	{
-	  CHECK_NUMBER (insval);
-	  inserted = XFASTINT (insval);
-	}
-      QUIT;
-      p = XCDR (p);
-    }
-
   if (!NILP (visit)
       && current_buffer->modtime == -1)
     {