Commit 1a86b5d6 authored by Paul Eggert's avatar Paul Eggert
Browse files

Merge from origin/emacs-25

d4c6774f Fix missing point information in undo
3a9d6296 Avoid crashes when buffer modification hooks clobber match data
178b2f59 Note combine-and-quote-strings doesn't shell quote
dec75675 Explain when package-initialize isn't called
113d1e2b Fix escaping in sh-indent-after-continuation docstr
80e2044a ; * etc/NEWS: Improve previous change.
5bb9e6ce ; * etc/NEWS: Document how to avoid horizontal scroll bars.
38f4b8ea Clarify the documentation of back-references in replacements
parents c5823cda d4c6774f
......@@ -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. @samp{\@var{d}} 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''.)
@samp{\#} 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,
@samp{\#} 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}
......
......@@ -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 non-@code{nil}, 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
@code{package-enable-at-startup} 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
......
......@@ -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
@code{call-process-shell-command}), arguments should still be
protected by @code{shell-quote-argument};
@code{combine-and-quote-strings} 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
......
......@@ -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.
......
......@@ -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.
......
......@@ -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.
......
......@@ -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
......
......@@ -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];
......
......@@ -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 ();
......
......@@ -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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment