]> git.eshelyaron.com Git - emacs.git/commitdiff
Fixes: debbugs:19161
authorStefan Monnier <monnier@iro.umontreal.ca>
Thu, 11 Dec 2014 21:07:23 +0000 (16:07 -0500)
committerStefan Monnier <monnier@iro.umontreal.ca>
Thu, 11 Dec 2014 21:07:23 +0000 (16:07 -0500)
* src/fileio.c: Better preserve window-points during revert.

(Qget_buffer_window_list): New var.
(get_window_points_and_markers, restore_window_points): New functions.
(Finsert_file_contents): Use them to save and restore window-points.

src/ChangeLog
src/fileio.c
src/insdel.c

index 27c08580cb86410df524875287c74c63ed40946e..887ca89261a7c59b2a737a9c8c456bcee2e8d9eb 100644 (file)
@@ -1,3 +1,10 @@
+2014-12-11  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * fileio.c: Better preserve window-points during revert (bug#19161).
+       (Qget_buffer_window_list): New var.
+       (get_window_points_and_markers, restore_window_points): New functions.
+       (Finsert_file_contents): Use them to save and restore window-points.
+
 2014-12-11  Dmitry Antipov  <dmantipov@yandex.ru>
 
        * xterm.c (x_delete_terminal): Call emacs_close for X connection
        its initial value.
        (bidi_cache_search): Handle overflown cache.  Improve commentary.
        (bidi_cache_ensure_space): Limit allocations to the current value
-       of bidi_cache_max_elts.  Force xpalloc not to over-allocate.  If
-       less than a full BIDI_CACHE_CHUNK is left to the limit, decrease
+       of bidi_cache_max_elts.  Force xpalloc not to over-allocate.
+       If less than a full BIDI_CACHE_CHUNK is left to the limit, decrease
        the increment to not exceed the limit.
        (bidi_cache_iterator_state): Now returns non-zero if succeeded to
        cache, zero otherwise (meaning the cache overflowed).  In the
        latter case, set bidi_cache_last_idx to -1.
        (bidi_peek_at_next_level): Handle overflown cache.
-       (bidi_push_it): Increase the cache limit for iterating the new
-       object.
+       (bidi_push_it): Increase the cache limit for iterating the new object.
        (bidi_pop_it): Decrease the cache limit back to previous value.
        (bidi_shelve_cache): Shelve the current value of the cache limit.
        (bidi_unshelve_cache): Restore the value of cache limit.
 
        * xml.c (parse_region): Take care of new optional parameter
        'discard-comments' of 'libxml-parse(html|xml)-region'.
-       (Flibxml_parse_html_region, Flibxml_parse_xml_region): New
-       optional parameter 'discard-comments'.
+       (Flibxml_parse_html_region, Flibxml_parse_xml_region):
+       New optional parameter 'discard-comments'.
 
 2014-11-17  Paul Eggert  <eggert@cs.ucla.edu>
 
 2014-11-16  Eli Zaretskii  <eliz@gnu.org>
 
        * window.c (window_scroll_pixel_based): Avoid truncation/rounding
-       errors in computing the number of pixels to scroll.  Suggested by
-       Kelly Dean <kelly@prtime.org>.  (Bug#19060)
+       errors in computing the number of pixels to scroll.
+       Suggested by Kelly Dean <kelly@prtime.org>.  (Bug#19060)
 
 2014-11-16  Jan Djärv  <jan.h.d@swipnet.se>
 
        * frame.h (frame): Split `official' into `can_x_set_window_size'
        and `can_run_window_configuration_change_hook'.
        * nsfns.m (Fx_create_frame): Set f->can_x_set_window_size.
-       * w32fns.c (Fx_create_frame, x_create_tip_frame): Set
-       f->can_x_set_window_size.
-       * window.c (run_window_configuration_change_hook): Return
-       immediately if either f->can_x_set_window_size or
+       * w32fns.c (Fx_create_frame, x_create_tip_frame):
+       Set f->can_x_set_window_size.
+       * window.c (run_window_configuration_change_hook):
+       Return immediately if either f->can_x_set_window_size or
        f->can_run_window_configuration_change_hook are false.
        (Fset_window_configuration): Instead of f->official set
        f->can_x_set_window_size.
-       * xfns.c (Fx_create_frame, x_create_tip_frame): Set
-       f->can_x_set_window_size.
+       * xfns.c (Fx_create_frame, x_create_tip_frame):
+       Set f->can_x_set_window_size.
 
 2014-11-08  Jan Djärv  <jan.h.d@swipnet.se>
 
index b8dec3a2041ac1b193d01106cf5de2b74263a47a..83b4954b74546c332aff5dd32c7f9ba09ac59749 100644 (file)
@@ -148,6 +148,7 @@ static Lisp_Object Qcopy_directory;
 static Lisp_Object Qdelete_directory;
 
 static Lisp_Object Qsubstitute_env_in_file_name;
+static Lisp_Object Qget_buffer_window_list;
 
 Lisp_Object Qfile_error, Qfile_notify_error;
 static Lisp_Object Qfile_already_exists, Qfile_date_error;
@@ -197,7 +198,7 @@ check_writable (const char *filename, int amode)
   bool res = faccessat (AT_FDCWD, filename, amode, AT_EACCESS) == 0;
 #ifdef CYGWIN
   /* faccessat may have returned failure because Cygwin couldn't
-     determine the file's UID or GID; if so, we return success. */
+     determine the file's UID or GID; if so, we return success.  */
   if (!res)
     {
       int faccessat_errno = errno;
@@ -3410,6 +3411,56 @@ time_error_value (int errnum)
   return make_timespec (0, ns);
 }
 
+static Lisp_Object
+get_window_points_and_markers (void)
+{
+  Lisp_Object pt_marker = Fpoint_marker ();
+  Lisp_Object windows
+    = call3 (Qget_buffer_window_list, Fcurrent_buffer (), Qnil, Qt);
+  Lisp_Object window_markers = windows;
+  /* Window markers (and point) are handled specially: rather than move to
+     just before or just after the modified text, we try to keep the
+     markers at the same distance (bug#19161).
+     In general, this is wrong, but for window-markers, this should be harmless
+     and is convenient for the end user when most of the file is unmodified,
+     except for a few minor details near the beginning and near the end.  */
+  for (; CONSP (windows); windows = XCDR (windows))
+    if (WINDOWP (XCAR (windows)))
+      {
+       Lisp_Object window_marker = XWINDOW (XCAR (windows))->pointm;
+       XSETCAR (windows,
+                Fcons (window_marker, Fmarker_position (window_marker)));
+      }
+  return Fcons (Fcons (pt_marker, Fpoint ()), window_markers);
+}
+
+static void
+restore_window_points (Lisp_Object window_markers, ptrdiff_t inserted,
+                      ptrdiff_t same_at_start, ptrdiff_t same_at_end)
+{
+  for (; CONSP (window_markers); window_markers = XCDR (window_markers))
+    if (CONSP (XCAR (window_markers)))
+      {
+       Lisp_Object car = XCAR (window_markers);
+       Lisp_Object marker = XCAR (car);
+       Lisp_Object oldpos = XCDR (car);
+       if (MARKERP (marker) && INTEGERP (oldpos)
+           && XINT (oldpos) > same_at_start
+           && XINT (oldpos) < same_at_end)
+         {
+           ptrdiff_t oldsize = same_at_end - same_at_start;
+           ptrdiff_t newsize = inserted;
+           double growth = newsize / (double)oldsize;
+           ptrdiff_t newpos
+             = same_at_start + growth * (XINT (oldpos) - same_at_start);
+           Fset_marker (marker, make_number (newpos), Qnil);
+         }
+      }
+}
+
+/* FIXME: insert-file-contents should be split with the top-level moved to
+   Elisp and only the core kept in C.  */
+
 DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
        1, 5, 0,
        doc: /* Insert contents of file FILENAME after point.
@@ -3454,18 +3505,23 @@ by calling `format-decode', which see.  */)
   int save_errno = 0;
   char read_buf[READ_BUF_SIZE];
   struct coding_system coding;
-  bool replace_handled = 0;
-  bool set_coding_system = 0;
+  bool replace_handled = false;
+  bool set_coding_system = false;
   Lisp_Object coding_system;
-  bool read_quit = 0;
+  bool read_quit = false;
   /* If the undo log only contains the insertion, there's no point
      keeping it.  It's typically when we first fill a file-buffer.  */
   bool empty_undo_list_p
     = (!NILP (visit) && NILP (BVAR (current_buffer, undo_list))
        && BEG == Z);
   Lisp_Object old_Vdeactivate_mark = Vdeactivate_mark;
-  bool we_locked_file = 0;
+  bool we_locked_file = false;
   ptrdiff_t fd_index;
+  Lisp_Object window_markers = Qnil;
+  /* same_at_start and same_at_end count bytes, because file access counts
+     bytes and BEG and END count bytes.  */
+  ptrdiff_t same_at_start = BEGV_BYTE;
+  ptrdiff_t same_at_end = ZV_BYTE;
 
   if (current_buffer->base_buffer && ! NILP (visit))
     error ("Cannot do file visiting in an indirect buffer");
@@ -3521,7 +3577,11 @@ by calling `format-decode', which see.  */)
 
   /* Replacement should preserve point as it preserves markers.  */
   if (!NILP (replace))
-    record_unwind_protect (restore_point_unwind, Fpoint_marker ());
+    {
+      window_markers = get_window_points_and_markers ();
+      record_unwind_protect (restore_point_unwind,
+                            XCAR (XCAR (window_markers)));
+    }
 
   if (fstat (fd, &st) != 0)
     report_file_error ("Input file status", orig_filename);
@@ -3599,14 +3659,14 @@ by calling `format-decode', which see.  */)
     }
 
   /* Prevent redisplay optimizations.  */
-  current_buffer->clip_changed = 1;
+  current_buffer->clip_changed = true;
 
   if (EQ (Vcoding_system_for_read, Qauto_save_coding))
     {
       coding_system = coding_inherit_eol_type (Qutf_8_emacs, Qunix);
       setup_coding_system (coding_system, &coding);
       /* Ensure we set Vlast_coding_system_used.  */
-      set_coding_system = 1;
+      set_coding_system = true;
     }
   else if (BEG < Z)
     {
@@ -3712,7 +3772,7 @@ by calling `format-decode', which see.  */)
 
       setup_coding_system (coding_system, &coding);
       /* Ensure we set Vlast_coding_system_used.  */
-      set_coding_system = 1;
+      set_coding_system = true;
     }
 
   /* If requested, replace the accessible part of the buffer
@@ -3734,16 +3794,11 @@ by calling `format-decode', which see.  */)
       && (NILP (coding_system)
          || ! CODING_REQUIRE_DECODING (&coding)))
     {
-      /* same_at_start and same_at_end count bytes,
-        because file access counts bytes
-        and BEG and END count bytes.  */
-      ptrdiff_t same_at_start = BEGV_BYTE;
-      ptrdiff_t same_at_end = ZV_BYTE;
       ptrdiff_t overlap;
       /* There is still a possibility we will find the need to do code
         conversion.  If that happens, set this variable to
         give up on handling REPLACE in the optimized way.  */
-      bool giveup_match_end = 0;
+      bool giveup_match_end = false;
 
       if (beg_offset != 0)
        {
@@ -3777,7 +3832,7 @@ by calling `format-decode', which see.  */)
            /* We found that the file should be decoded somehow.
                Let's give up here.  */
            {
-             giveup_match_end = 1;
+             giveup_match_end = true;
              break;
            }
 
@@ -3790,7 +3845,7 @@ by calling `format-decode', which see.  */)
          if (bufpos != nread)
            break;
        }
-      immediate_quit = 0;
+      immediate_quit = false;
       /* If the file matches the buffer completely,
         there's no need to replace anything.  */
       if (same_at_start - BEGV_BYTE == end_offset - beg_offset)
@@ -3802,7 +3857,7 @@ by calling `format-decode', which see.  */)
          del_range_1 (same_at_start, same_at_end, 0, 0);
          goto handled;
        }
-      immediate_quit = 1;
+      immediate_quit = true;
       QUIT;
       /* Count how many chars at the end of the file
         match the text at the end of the buffer.  But, if we have
@@ -3853,7 +3908,7 @@ by calling `format-decode', which see.  */)
                  && FETCH_BYTE (same_at_end - 1) >= 0200
                  && ! NILP (BVAR (current_buffer, enable_multibyte_characters))
                  && (CODING_MAY_REQUIRE_DECODING (&coding)))
-               giveup_match_end = 1;
+               giveup_match_end = true;
              break;
            }
 
@@ -3906,7 +3961,7 @@ by calling `format-decode', which see.  */)
          if (XBUFFER (XWINDOW (selected_window)->contents) == current_buffer)
            XWINDOW (selected_window)->start_at_line_beg = !NILP (Fbolp ());
 
-         replace_handled = 1;
+         replace_handled = true;
        }
     }
 
@@ -3921,8 +3976,6 @@ by calling `format-decode', which see.  */)
      in a more optimized way.  */
   if (!NILP (replace) && ! replace_handled && BEGV < ZV)
     {
-      ptrdiff_t same_at_start = BEGV_BYTE;
-      ptrdiff_t same_at_end = ZV_BYTE;
       ptrdiff_t same_at_start_charpos;
       ptrdiff_t inserted_chars;
       ptrdiff_t overlap;
@@ -3986,7 +4039,7 @@ by calling `format-decode', which see.  */)
        }
 
       coding_system = CODING_ID_NAME (coding.id);
-      set_coding_system = 1;
+      set_coding_system = true;
       decoded = BUF_BEG_ADDR (XBUFFER (conversion_buffer));
       inserted = (BUF_Z_BYTE (XBUFFER (conversion_buffer))
                  - BUF_BEG_BYTE (XBUFFER (conversion_buffer)));
@@ -4111,7 +4164,7 @@ by calling `format-decode', which see.  */)
          /* Make binding buffer-file-name to nil effective.  */
          && !NILP (BVAR (current_buffer, filename))
          && SAVE_MODIFF >= MODIFF)
-       we_locked_file = 1;
+       we_locked_file = true;
       prepare_to_modify_buffer (PT, PT, NULL);
     }
 
@@ -4141,7 +4194,7 @@ by calling `format-decode', which see.  */)
 
     while (how_much < total)
       {
-       /* try is reserved in some compilers (Microsoft C) */
+       /* `try' is reserved in some compilers (Microsoft C).  */
        ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE);
        ptrdiff_t this;
 
@@ -4166,7 +4219,7 @@ by calling `format-decode', which see.  */)
 
            if (NILP (nbytes))
              {
-               read_quit = 1;
+               read_quit = true;
                break;
              }
 
@@ -4299,7 +4352,7 @@ by calling `format-decode', which see.  */)
        coding_system = raw_text_coding_system (coding_system);
       setup_coding_system (coding_system, &coding);
       /* Ensure we set Vlast_coding_system_used.  */
-      set_coding_system = 1;
+      set_coding_system = true;
     }
 
   if (!NILP (visit))
@@ -4310,7 +4363,7 @@ by calling `format-decode', which see.  */)
          /* Can't do this if part of the buffer might be preserved.  */
          && NILP (replace))
        /* Visiting a file with these coding system makes the buffer
-          unibyte. */
+          unibyte.  */
        bset_enable_multibyte_characters (current_buffer, Qnil);
     }
 
@@ -4349,6 +4402,11 @@ by calling `format-decode', which see.  */)
 
  handled:
 
+  if (inserted > 0)
+    restore_window_points (window_markers, inserted,
+                          BYTE_TO_CHAR (same_at_start),
+                          BYTE_TO_CHAR (same_at_end));
+
   if (!NILP (visit))
     {
       if (empty_undo_list_p)
@@ -6037,6 +6095,7 @@ This includes interactive calls to `delete-file' and
   DEFSYM (Qcopy_directory, "copy-directory");
   DEFSYM (Qdelete_directory, "delete-directory");
   DEFSYM (Qsubstitute_env_in_file_name, "substitute-env-in-file-name");
+  DEFSYM (Qget_buffer_window_list, "get-buffer-window-list");
 
   defsubr (&Sfind_file_name_handler);
   defsubr (&Sfile_name_directory);
index 3133ca4bd2c242c5158da0a229008c9598676535..7b4ee3b7b06a90b0e7b44880af71a18f4f035f02 100644 (file)
@@ -1202,10 +1202,10 @@ adjust_after_replace (ptrdiff_t from, ptrdiff_t from_byte,
 
   /* Update various buffer positions for the new text.  */
   GAP_SIZE -= len_byte;
-  ZV += len; Z+= len;
+  ZV += len; Z += len;
   ZV_BYTE += len_byte; Z_BYTE += len_byte;
   GPT += len; GPT_BYTE += len_byte;
-  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
+  if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor.  */
 
   if (nchars_del > 0)
     adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
@@ -1228,7 +1228,7 @@ adjust_after_replace (ptrdiff_t from, ptrdiff_t from_byte,
   if (from < PT)
     adjust_point (len - nchars_del, len_byte - nbytes_del);
 
-  /* As byte combining will decrease Z, we must check this again. */
+  /* As byte combining will decrease Z, we must check this again.  */
   if (Z - GPT < END_UNCHANGED)
     END_UNCHANGED = Z - GPT;
 
@@ -1599,7 +1599,7 @@ del_range_byte (ptrdiff_t from_byte, ptrdiff_t to_byte, bool prepare)
 {
   ptrdiff_t from, to;
 
-  /* Make args be valid */
+  /* Make args be valid */
   if (from_byte < BEGV_BYTE)
     from_byte = BEGV_BYTE;
   if (to_byte > ZV_BYTE)
@@ -1681,7 +1681,7 @@ del_range_both (ptrdiff_t from, ptrdiff_t from_byte,
 /* Delete a range of text, specified both as character positions
    and byte positions.  FROM and TO are character positions,
    while FROM_BYTE and TO_BYTE are byte positions.
-   If RET_STRING, the deleted area is returned as a string. */
+   If RET_STRING, the deleted area is returned as a string.  */
 
 Lisp_Object
 del_range_2 (ptrdiff_t from, ptrdiff_t from_byte,