emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 1a86b5d 05/15: Merge from origin/emacs-25


From: Paul Eggert
Subject: [Emacs-diffs] master 1a86b5d 05/15: Merge from origin/emacs-25
Date: Fri, 5 Aug 2016 21:15:39 +0000 (UTC)

branch: master
commit 1a86b5d6074d26d1a3a978cb52b2147b6f359694
Merge: c5823cd d4c6774
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    Merge from origin/emacs-25
    
    d4c6774 Fix missing point information in undo
    3a9d629 Avoid crashes when buffer modification hooks clobber match data
    178b2f5 Note combine-and-quote-strings doesn't shell quote
    dec7567 Explain when package-initialize isn't called
    113d1e2 Fix escaping in sh-indent-after-continuation docstr
    80e2044 ; * etc/NEWS: Improve previous change.
    5bb9e6c ; * etc/NEWS: Document how to avoid horizontal scroll bars.
    38f4b8e Clarify the documentation of back-references in replacements
---
 doc/emacs/search.texi       |   12 +++++-----
 doc/lispref/os.texi         |   10 +++++---
 doc/lispref/processes.texi  |    5 ++++
 etc/NEWS                    |    9 +++++++
 lisp/progmodes/sh-script.el |   12 +++++-----
 lisp/replace.el             |   17 +++++++------
 lisp/subr.el                |    5 +++-
 src/search.c                |   13 ++++++++++
 src/undo.c                  |   56 +++++++++++++++++++++++--------------------
 test/lisp/simple-tests.el   |   19 ++++++++++++++-
 10 files changed, 108 insertions(+), 50 deletions(-)

diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi
index d841934..b41214d 100644
--- a/doc/emacs/search.texi
+++ b/doc/emacs/search.texi
@@ -1356,12 +1356,12 @@ Replace every match for @var{regexp} with 
@var{newstring}.
 it can refer to all or part of what is matched by the @var{regexp}.
 @samp{\&} in @var{newstring} stands for the entire match being
 replaced.  @address@hidden in @var{newstring}, where @var{d} is a
-digit, stands for whatever matched the @var{d}th parenthesized
-grouping in @var{regexp}.  (This is called a ``back reference''.)
address@hidden refers to the count of replacements already made in this
-command, as a decimal number.  In the first replacement, @samp{\#}
-stands for @samp{0}; in the second, for @samp{1}; and so on.  For
-example,
+digit starting from 1, stands for whatever matched the @var{d}th
+parenthesized grouping in @var{regexp}.  (This is called a ``back
+reference''.)  @samp{\#} refers to the count of replacements already
+made in this command, as a decimal number.  In the first replacement,
address@hidden stands for @samp{0}; in the second, for @samp{1}; and so on.
+For example,
 
 @example
 M-x replace-regexp @key{RET} c[ad]+r @key{RET} \&-safe @key{RET}
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index 38dde26..08c69d3 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -155,9 +155,13 @@ It loads your abbrevs from the file specified by
 option @samp{--batch} was specified.
 
 @item
-If @code{package-enable-at-startup} is address@hidden, it calls the
-function @code{package-initialize} to activate any optional Emacs Lisp
-package that has been installed.  @xref{Packaging Basics}.
+It calls the function @code{package-initialize} to activate any
+optional Emacs Lisp package that has been installed.  @xref{Packaging
+Basics}.  However, Emacs doesn't initialize packages when
address@hidden is @code{nil} or when it's started
+with one of the options @samp{-q}, @samp{-Q}, or @samp{--batch}.  To
+initialize packages in the latter case, @code{package-initialize}
+should be called explicitly (e.g., via the @samp{--funcall} option).
 
 @vindex after-init-time
 @item
diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi
index f859b3a..cd12012 100644
--- a/doc/lispref/processes.texi
+++ b/doc/lispref/processes.texi
@@ -215,6 +215,11 @@ converting user input in the minibuffer, a Lisp string, 
into a list of
 string arguments to be passed to @code{call-process} or
 @code{start-process}, or for converting such lists of arguments into
 a single Lisp string to be presented in the minibuffer or echo area.
+Note that if a shell is involved (e.g., if using
address@hidden), arguments should still be
+protected by @code{shell-quote-argument};
address@hidden is @emph{not} intended to protect
+special characters from shell evaluation.
 
 @defun split-string-and-unquote string &optional separators
 This function splits @var{string} into substrings at matches for the
diff --git a/etc/NEWS b/etc/NEWS
index f845c1d..c9b33c8 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2452,6 +2452,15 @@ scroll bars on the selected frame.
 'scroll-bar-height' to set horizontal scroll bars and their height
 for individual frames and in 'default-frame-alist'.
 
+***** The 'horizontal-scroll-bars' parameter was already present and non-nil
+by default in Emacs 24 and before (although it didn't have any
+effect).  This could cause a problem if you share your desktop files
+with older versions of Emacs: saving desktop in Emacs before v25.1,
+then restoring it in v25.1 would turn on horizontal scroll bars in all
+buffers.  To resolve this issue, put this in your ~/.emacs init file:
+
+  (modify-all-frames-parameters '((horizontal-scroll-bars . nil)))
+
 **** New functions 'frame-scroll-bar-height' and
 'window-scroll-bar-height' return the height of horizontal scroll
 bars on a specific frame or window.
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el
index 10e56d0..39e9707 100644
--- a/lisp/progmodes/sh-script.el
+++ b/lisp/progmodes/sh-script.el
@@ -2003,16 +2003,16 @@ Does not preserve point."
 Continued lines can either be indented as \"one long wrapped line\" without
 paying attention to the actual syntactic structure, as in:
 
-   for f \
-       in a; do \
-       toto; \
+   for f \\
+       in a; do \\
+       toto; \\
        done
 
 or as lines that just don't have implicit semi-colons between them, as in:
 
-   for f \
-   in a; do \
-       toto; \
+   for f \\
+   in a; do \\
+       toto; \\
    done
 
 With `always' you get the former behavior whereas with nil you get the latter.
diff --git a/lisp/replace.el b/lisp/replace.el
index 9e2d521..e6124f4 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -391,9 +391,10 @@ replace backward.
 
 Fourth and fifth arg START and END specify the region to operate on.
 
-In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
-and `\\=\\N' (where N is a digit) stands for
-whatever what matched the Nth `\\(...\\)' in REGEXP.
+In TO-STRING, `\\&' or `\\0' stands for whatever matched the whole of
+REGEXP, and `\\=\\N' (where N is a digit) stands for whatever matched
+the Nth `\\(...\\)' (1-based) in REGEXP.  The `\\(...\\)' groups are
+counted from 1.
 `\\?' lets you edit the replacement text in the minibuffer
 at the given position for each replacement.
 
@@ -451,7 +452,9 @@ If the result of TO-EXPR is not a string, it is converted 
to one using
 
 For convenience, when entering TO-EXPR interactively, you can use `\\&' or
 `\\0' to stand for whatever matched the whole of REGEXP, and `\\N' (where
-N is a digit) to stand for whatever matched the Nth `\\(...\\)' in REGEXP.
+N is a digit) to stand for whatever matched the Nth `\\(...\\)' (1-based)
+in REGEXP.
+
 Use `\\#&' or `\\#N' if you want a number instead of a string.
 In interactive use, `\\#' in itself stands for `replace-count'.
 
@@ -635,9 +638,9 @@ replace backward.
 
 Fourth and fifth arg START and END specify the region to operate on.
 
-In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
-and `\\=\\N' (where N is a digit) stands for
-whatever what matched the Nth `\\(...\\)' in REGEXP.
+In TO-STRING, `\\&' or `\\0' stands for whatever matched the whole of
+REGEXP, and `\\=\\N' (where N is a digit) stands for
+whatever matched the Nth `\\(...\\)' (1-based) in REGEXP.
 `\\?' lets you edit the replacement text in the minibuffer
 at the given position for each replacement.
 
diff --git a/lisp/subr.el b/lisp/subr.el
index aa9b751..8ab1178 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -3740,7 +3740,10 @@ Modifies the match data; use `save-match-data' if 
necessary."
   "Concatenate the STRINGS, adding the SEPARATOR (default \" \").
 This tries to quote the strings to avoid ambiguity such that
   (split-string-and-unquote (combine-and-quote-strings strs)) == strs
-Only some SEPARATORs will work properly."
+Only some SEPARATORs will work properly.
+
+Note that this is not intended to protect STRINGS from
+interpretation by shells, use `shell-quote-argument' for that."
   (let* ((sep (or separator " "))
          (re (concat "[\\\"]" "\\|" (regexp-quote sep))))
     (mapconcat
diff --git a/src/search.c b/src/search.c
index 7f2b4f9..7c4a024 100644
--- a/src/search.c
+++ b/src/search.c
@@ -2677,6 +2677,14 @@ since only regular expressions have distinguished 
subexpressions.  */)
       xfree (substed);
     }
 
+  /* The functions below modify the buffer, so they could trigger
+     various modification hooks (see signal_before_change and
+     signal_after_change), which might clobber the match data we need
+     to adjust after the replacement.  If that happens, we error out.  */
+  ptrdiff_t sub_start = search_regs.start[sub];
+  ptrdiff_t sub_end = search_regs.end[sub];
+  unsigned  num_regs = search_regs.num_regs;
+
   /* Replace the old text with the new in the cleanest possible way.  */
   replace_range (search_regs.start[sub], search_regs.end[sub],
                 newtext, 1, 0, 1);
@@ -2690,6 +2698,11 @@ since only regular expressions have distinguished 
subexpressions.  */)
     Fupcase_initials_region (make_number (search_regs.start[sub]),
                             make_number (newpoint));
 
+  if (search_regs.start[sub] != sub_start
+      || search_regs.end[sub] != sub_end
+      || search_regs.num_regs != num_regs)
+    error ("Match data clobbered by buffer modification hooks");
+
   /* Adjust search data for this change.  */
   {
     ptrdiff_t oldend = search_regs.end[sub];
diff --git a/src/undo.c b/src/undo.c
index be5b270..ed69a62 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -31,25 +31,21 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
    an undo-boundary.  */
 static Lisp_Object pending_boundary;
 
-/* Record point as it was at beginning of this command (if necessary)
-   and prepare the undo info for recording a change.
-   Prepare the undo info for recording a change. */
+/* Prepare the undo info for recording a change. */
 static void
 prepare_record (void)
 {
   /* Allocate a cons cell to be the undo boundary after this command.  */
   if (NILP (pending_boundary))
     pending_boundary = Fcons (Qnil, Qnil);
-
-  if (MODIFF <= SAVE_MODIFF)
-    record_first_change ();
 }
 
-/* Record point as it was at beginning of this command.
-   PT is the position of point that will naturally occur as a result of the
-   undo record that will be added just after this command terminates.  */
+/* Record point, if necessary, as it was at beginning of this command.
+   BEG is the position of point that will naturally occur as a result
+   of the undo record that will be added just after this command
+   terminates.  */
 static void
-record_point (ptrdiff_t pt)
+record_point (ptrdiff_t beg)
 {
   /* Don't record position of pt when undo_inhibit_record_point holds.  */
   if (undo_inhibit_record_point)
@@ -57,16 +53,28 @@ record_point (ptrdiff_t pt)
 
   bool at_boundary;
 
+  /* Check whether we are at a boundary now, in case we record the
+  first change. FIXME: This check is currently dependent on being
+  called before record_first_change, but could be made not to by
+  ignoring timestamp undo entries */
   at_boundary = ! CONSP (BVAR (current_buffer, undo_list))
                 || NILP (XCAR (BVAR (current_buffer, undo_list)));
 
-  prepare_record ();
+  /* If this is the first change since save, then record this.*/
+  if (MODIFF <= SAVE_MODIFF)
+    record_first_change ();
 
-  /* If we are just after an undo boundary, and
-     point wasn't at start of deleted range, record where it was.  */
-  if (at_boundary)
+  /* We may need to record point if we are immediately after a
+     boundary, so that this will be restored correctly after undo. We
+     do not need to do this if point is at the start of a change
+     region since it will be restored there anyway, and we must not do
+     this if the buffer has changed since the last command, since the
+     value of point that we have will be for that buffer, not this.*/
+  if (at_boundary
+      && point_before_last_command_or_undo != beg
+      && buffer_before_last_command_or_undo == current_buffer )
     bset_undo_list (current_buffer,
-                   Fcons (make_number (pt),
+                   Fcons (make_number (point_before_last_command_or_undo),
                           BVAR (current_buffer, undo_list)));
 }
 
@@ -85,6 +93,8 @@ record_insert (ptrdiff_t beg, ptrdiff_t length)
 
   prepare_record ();
 
+  record_point (beg);
+
   /* If this is following another insertion and consecutive with it
      in the buffer, combine the two.  */
   if (CONSP (BVAR (current_buffer, undo_list)))
@@ -120,9 +130,7 @@ record_marker_adjustments (ptrdiff_t from, ptrdiff_t to)
   register struct Lisp_Marker *m;
   register ptrdiff_t charpos, adjustment;
 
-  /* Allocate a cons cell to be the undo boundary after this command.  */
-  if (NILP (pending_boundary))
-    pending_boundary = Fcons (Qnil, Qnil);
+  prepare_record();
 
   for (m = BUF_MARKERS (current_buffer); m; m = m->next)
     {
@@ -163,19 +171,17 @@ record_delete (ptrdiff_t beg, Lisp_Object string, bool 
record_markers)
   if (EQ (BVAR (current_buffer, undo_list), Qt))
     return;
 
-  if (point_before_last_command_or_undo != beg
-      && buffer_before_last_command_or_undo == current_buffer)
-    record_point (point_before_last_command_or_undo);
+  prepare_record ();
+
+  record_point (beg);
 
   if (PT == beg + SCHARS (string))
     {
       XSETINT (sbeg, -beg);
-      prepare_record ();
     }
   else
     {
       XSETFASTINT (sbeg, beg);
-      prepare_record ();
     }
 
   /* primitive-undo assumes marker adjustments are recorded
@@ -234,9 +240,7 @@ record_property_change (ptrdiff_t beg, ptrdiff_t length,
   if (EQ (BVAR (buf, undo_list), Qt))
     return;
 
-  /* Allocate a cons cell to be the undo boundary after this command.  */
-  if (NILP (pending_boundary))
-    pending_boundary = Fcons (Qnil, Qnil);
+  prepare_record();
 
   if (MODIFF <= SAVE_MODIFF)
     record_first_change ();
diff --git a/test/lisp/simple-tests.el b/test/lisp/simple-tests.el
index 97b6c49..d022240 100644
--- a/test/lisp/simple-tests.el
+++ b/test/lisp/simple-tests.el
@@ -325,6 +325,7 @@
       (undo-test-point-after-forward-kill))))
 
 (defmacro simple-test-undo-with-switched-buffer (buffer &rest body)
+  (declare (indent 1) (debug t))
   (let ((before-buffer (make-symbol "before-buffer")))
     `(let ((,before-buffer (current-buffer)))
        (unwind-protect
@@ -354,8 +355,24 @@ C-/                     ;; undo
        (point-min)
        (point-max))))))
 
+(ert-deftest missing-record-point-in-undo ()
+  "Check point is being restored correctly.
 
-
+See Bug#21722."
+  (should
+   (= 5
+      (with-temp-buffer
+       (generate-new-buffer " *temp*")
+       (emacs-lisp-mode)
+       (setq buffer-undo-list nil)
+       (insert "(progn (end-of-line) (insert \"hello\"))")
+       (beginning-of-line)
+       (forward-char 4)
+       (undo-boundary)
+       (eval-defun nil)
+       (undo-boundary)
+       (undo)
+       (point)))))
 
 (provide 'simple-test)
 ;;; simple-test.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]