emacs-diffs
[Top][All Lists]
Advanced

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

[Emacs-diffs] master 89ce83b: Merge from origin/emacs-25


From: Paul Eggert
Subject: [Emacs-diffs] master 89ce83b: Merge from origin/emacs-25
Date: Fri, 06 May 2016 06:14:37 +0000

branch: master
commit 89ce83b20249dfb4e45f09dfdddf4c4b66d82968
Merge: d546ed1 50650cb
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    Merge from origin/emacs-25
    
    50650cb Doc fixes for fclist and grep
    5e814e0 Minor doc fixes for quoting
    3347a73 `nreverse' the marker pairs list
    1a4127d Use save-excursion in xref-location-marker more
    ab3ba91 shell-quote-argument DIR when appropriate
    922c7a3 Rework xref-query-replace-in-results
    3fe3510 * lisp/replace.el (query-replace-read-from): Use minibuffer-w...
    0932b94 Fix todo-mode bug involving archived items (bug#23447)
    e68ad1f ; * etc/NEWS: Tiny edit. (Bug#23432)
    adc80b7 ; * test/automated/xref-tests.el: Add copyright and license.
    4d8fd9c Handle "empty line" regexp in xref searches
    f559b37 Add tests for xref-collect-matches
    6428aa0 Use grep-find-ignored-directories instead of vc-directory-exc...
    6f82d8e Clear buffer-undo-list when showing xrefs
    c68a091 Note the quote translation in `message' in section "incompati...
    52f86a7 * etc/NEWS: Mention (message "%s" (format ...)).
    93703c5 (Common Keywords): Correct what missing :group means
    79e5800 Improve documentation of Dired's 'A' and 'Q' commands
    2ea2a2f Doc fixes for quoting
    8544b98 posnp doc clarification
    805204f Mention what a missing :group does
    ec554d7 Fix documentation of dired-aux search/replace commands
---
 doc/emacs/dired.texi                |   14 ++++
 doc/emacs/frames.texi               |    5 +-
 doc/emacs/text.texi                 |    4 +-
 doc/lispintro/emacs-lisp-intro.texi |   28 +++----
 doc/lispref/control.texi            |   11 ++-
 doc/lispref/customize.texi          |    9 ++-
 doc/lispref/display.texi            |   11 ++-
 doc/lispref/help.texi               |    4 +
 doc/lispref/strings.texi            |   10 ++-
 etc/NEWS                            |   23 +++---
 etc/PROBLEMS                        |    2 +-
 lisp/calendar/todo-mode.el          |   39 +++++-----
 lisp/cedet/cedet-cscope.el          |    2 +-
 lisp/cedet/semantic/symref.el       |    2 +-
 lisp/dired-aux.el                   |   19 ++++-
 lisp/man.el                         |    2 +-
 lisp/progmodes/elisp-mode.el        |    5 +-
 lisp/progmodes/etags.el             |    5 +-
 lisp/progmodes/project.el           |    3 +-
 lisp/progmodes/xref.el              |  146 ++++++++++++++++++++++-------------
 lisp/replace.el                     |   21 +++--
 lisp/subr.el                        |   15 +++-
 src/bidi.c                          |    4 +-
 src/callint.c                       |    2 +-
 src/doprnt.c                        |    6 +-
 src/editfns.c                       |   13 ++--
 test/automated/data/xref/file1.txt  |    2 +
 test/automated/data/xref/file2.txt  |    2 +
 test/automated/xref-tests.el        |   91 ++++++++++++++++++++++
 29 files changed, 343 insertions(+), 157 deletions(-)

diff --git a/doc/emacs/dired.texi b/doc/emacs/dired.texi
index 68c6813..486e92a 100644
--- a/doc/emacs/dired.texi
+++ b/doc/emacs/dired.texi
@@ -795,6 +795,14 @@ This command is a variant of @code{xref-find-references}
 where you can navigate between matches and display them as needed
 using the commands described in @ref{Xref Commands}.
 
address@hidden grep-find-ignored-files @r{(Dired)}
address@hidden grep-find-ignored-directories @r{(Dired)}
+If any of the marked files are directories, then this command searches
+all of the files in those directories, and any of their
+subdirectories, recursively, except files whose names match
address@hidden and subdirectories whose names match
address@hidden
+
 @kindex Q @r{(Dired)}
 @findex dired-do-find-regexp-and-replace
 @cindex search and replace in multiple files (in Dired)
@@ -809,6 +817,12 @@ and you can use the special commands in that buffer 
(@pxref{Xref
 Commands}).  In particular, if you exit the query replace loop, you
 can use @kbd{r} in that buffer to replace more matches.
 @xref{Identifier Search}.
+
+Like with @code{dired-do-find-regexp}, if any of the marked files are
+directories, this command performs replacements in all of the files in
+those directories, and in any of their subdirectories, recursively,
+except for files whose names match @code{grep-find-ignored-files} and
+subdirectories whose names match @code{grep-find-ignored-directories}.
 @end table
 
 @node Shell Commands in Dired
diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index 23ccd6a..a7e709f 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -764,7 +764,8 @@ Fontconfig fonts, you can use the @command{fc-list} command 
to list
 the available fixed-width fonts, like this:
 
 @example
-fc-list :spacing=mono fc-list :spacing=charcell
+fc-list :spacing=mono
+fc-list :spacing=charcell
 @end example
 
 @noindent
@@ -772,7 +773,7 @@ For server-side X fonts, you can use the @command{xlsfonts} 
program to
 list the available fixed-width fonts, like this:
 
 @example
-xlsfonts -fn '*x*' | egrep "^[0-9]+x[0-9]+"
+xlsfonts -fn '*x*' | grep -E '^[0-9]+x[0-9]+'
 xlsfonts -fn '*-*-*-*-*-*-*-*-*-*-*-m*'
 xlsfonts -fn '*-*-*-*-*-*-*-*-*-*-*-c*'
 @end example
diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi
index 66f01b4..579f788 100644
--- a/doc/emacs/text.texi
+++ b/doc/emacs/text.texi
@@ -862,8 +862,8 @@ indenting the current line.  @xref{Indentation}, for 
details.
 
   Text mode turns off the features concerned with comments except when
 you explicitly invoke them.  It changes the syntax table so that
-single-quotes are considered part of words (e.g., @samp{don't} is
-considered one word).  However, if a word starts with a single-quote,
+apostrophes are considered part of words (e.g., @samp{don't} is
+considered one word).  However, if a word starts with an apostrophe,
 it is treated as a prefix for the purposes of capitalization
 (e.g., @kbd{M-c} converts @samp{'hello'} into @samp{'Hello'}, as
 expected).
diff --git a/doc/lispintro/emacs-lisp-intro.texi 
b/doc/lispintro/emacs-lisp-intro.texi
index 78c1865..eea46af 100644
--- a/doc/lispintro/emacs-lisp-intro.texi
+++ b/doc/lispintro/emacs-lisp-intro.texi
@@ -1004,11 +1004,11 @@ the name stands for ``Lots of Isolated Silly 
Parentheses''.  But the
 claim is unwarranted.  Lisp stands for LISt Processing, and the
 programming language handles @emph{lists} (and lists of lists) by
 putting them between parentheses.  The parentheses mark the boundaries
-of the list.  Sometimes a list is preceded by a single apostrophe or
-quotation mark, @samp{'address@hidden single apostrophe or quotation
-mark is an abbreviation for the function @code{quote}; you need not
-think about functions now; functions are defined in @ref{Making
-Errors, , Generate an Error Message}.}  Lists are the basis of Lisp.
+of the list.  Sometimes a list is preceded by an apostrophe @samp{'},
+called a @dfn{single-quote} in address@hidden single-quote is an
+abbreviation for the special form @code{quote}; you need not think
+about special forms now.  @xref{Complications}.}  Lists are the basis
+of Lisp.
 
 @menu
 * Lisp Lists::                  What are lists?
@@ -2490,14 +2490,7 @@ in the list and then at the function definition bound to 
that symbol.
 Then the instructions in the function definition are carried out.
 
 @item
-A single quotation mark,
address@hidden
-'
address@hidden ifinfo
address@hidden
address@hidden'}
address@hidden ifnotinfo
-, tells the Lisp interpreter that it should
+A single-quote @samp{'} tells the Lisp interpreter that it should
 return the following expression as written, and not evaluate it as it
 would if the quote were not there.
 
@@ -7610,7 +7603,8 @@ displays in which grave accent and apostrophe were often 
mirror images
 suitable for use as quotes.  On most modern displays this is no longer
 true, and when these two ASCII characters appear in documentation
 strings or diagnostic message formats, Emacs typically transliterates
-them to curved single quotes, so that the abovequoted symbol appears
+them to @dfn{curved quotes} (left and right single quotation marks),
+so that the abovequoted symbol appears
 as @t{‘case-fold-search’}.  Source-code strings can also simply use
 curved quotes directly.
 
@@ -17117,7 +17111,7 @@ This line is a short, but complete Emacs Lisp 
expression.
 
 We are already familiar with @code{setq}.  It sets the following variable,
 @code{major-mode}, to the subsequent value, which is @code{text-mode}.
-The single quote mark before @code{text-mode} tells Emacs to deal directly
+The single-quote before @code{text-mode} tells Emacs to deal directly
 with the @code{text-mode} symbol, not with whatever it might stand for.
 @xref{set & setq, , Setting the Value of a Variable},
 for a reminder of how @code{setq} works.
@@ -17284,11 +17278,11 @@ Rebinding Keys in Your Init File, emacs, The GNU 
Emacs Manual}, for
 details.)
 
 The command invoked by the keys is @code{compare-windows}.  Note that
address@hidden is preceded by a single quote; otherwise, Emacs
address@hidden is preceded by a single-quote; otherwise, Emacs
 would first try to evaluate the symbol to determine its value.
 
 These three things, the double quotation marks, the backslash before
-the @samp{C}, and the single quote mark are necessary parts of
+the @samp{C}, and the single-quote are necessary parts of
 keybinding that I tend to forget.  Fortunately, I have come to
 remember that I should look at my existing @file{.emacs} file, and
 adapt what is there.
diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index 3f48c45..0cdb035 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -1100,10 +1100,13 @@ These examples show typical uses of @code{error}:
 error symbol @code{error}, and a list containing the string returned by
 @code{format-message}.
 
-In a format string containing single quotes, curved quotes @t{‘like
-this’} and grave quotes @t{`like this'} work better than straight
-quotes @t{'like this'}, as @code{error} typically formats every
-straight quote as a curved closing quote.
+The @code{text-quoting-style} variable controls what quotes are
+generated; @xref{Keys in Documentation}.  A call using a format like
address@hidden"Missing `%s'"} with grave accents and apostrophes typically
+generates a message like @t{"Missing ‘foo’"} with matching curved
+quotes.  In contrast, a call using a format like @t{"Missing '%s'"}
+with only apostrophes typically generates a message like @t{"Missing
+’foo’"} with only closing curved quotes, an unusual style in English.
 
 @strong{Warning:} If you want to use your own string as an error message
 verbatim, don't just write @code{(error @var{string})}.  If @var{string}
diff --git a/doc/lispref/customize.texi b/doc/lispref/customize.texi
index 14e6eb3..4a6f7f2 100644
--- a/doc/lispref/customize.texi
+++ b/doc/lispref/customize.texi
@@ -66,9 +66,12 @@ cause confusion.}
 
 @kindex address@hidden, customization keyword}
 @item :group @var{group}
-Put this customization item in group @var{group}.  When you use
address@hidden:group} in a @code{defgroup}, it makes the new group a subgroup of
address@hidden
+Put this customization item in group @var{group}.  If this keyword is
+missing from a customization item, it'll be placed in the same group
+that was last defined (in the current file).
+
+When you use @code{:group} in a @code{defgroup}, it makes the new
+group a subgroup of @var{group}.
 
 If you use this keyword more than once, you can put a single item into
 more than one group.  Displaying any of those groups will show this
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 3673d11..87126f9 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -265,10 +265,13 @@ properties, it is displayed with the specified faces 
(@pxref{Faces}).
 The string is also added to the @file{*Messages*} buffer, but without
 text properties (@pxref{Logging Messages}).
 
-In a format string containing single quotes, curved quotes @t{‘like
-this’} and grave quotes @t{`like this'} work better than straight
-quotes @t{'like this'}, as @code{message} typically formats every
-straight quote as a curved closing quote.
+The @code{text-quoting-style} variable controls what quotes are
+generated; @xref{Keys in Documentation}.  A call using a format like
address@hidden"Missing `%s'"} with grave accents and apostrophes typically
+generates a message like @t{"Missing ‘foo’"} with matching curved
+quotes.  In contrast, a call using a format like @t{"Missing '%s'"}
+with only apostrophes typically generates a message like @t{"Missing
+’foo’"} with only closing curved quotes, an unusual style in English.
 
 In batch mode, the message is printed to the standard error stream,
 followed by a newline.
diff --git a/doc/lispref/help.texi b/doc/lispref/help.texi
index 58a11f2..b945e43 100644
--- a/doc/lispref/help.texi
+++ b/doc/lispref/help.texi
@@ -335,10 +335,14 @@ specifies @var{mapvar}'s value as the keymap for any 
following
 @item ‘
 @itemx `
 (left single quotation mark and grave accent) both stand for a left quote.
+This generates a left single quotation mark, an apostrophe, or a grave
+accent depending on the value of @code{text-quoting-style}.
 
 @item ’
 @itemx '
 (right single quotation mark and apostrophe) both stand for a right quote.
+This generates a right single quotation mark or an apostrophe
+depending on the value of @code{text-quoting-style}.
 
 @item \=
 quotes the following character and is discarded; thus, @samp{\=`} puts
diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index ce629aa..58ab02d 100644
--- a/doc/lispref/strings.texi
+++ b/doc/lispref/strings.texi
@@ -842,8 +842,14 @@ if any.
 This function acts like @code{format}, except it also converts any
 curved single quotes in @var{string} as per the value of
 @code{text-quoting-style}, and treats grave accent (@t{`}) and
-apostrophe (@t{'}) as if they were curved single quotes.  @xref{Keys
-in Documentation}.
+apostrophe (@t{'}) as if they were curved single quotes.
+
+A format that quotes with grave accents and apostrophes @t{`like
+this'} typically generates curved quotes @t{‘like this’}.  In
+contrast, a format that quotes with only apostrophes @t{'like this'}
+typically generates two closing curved quotes @t{’like this’}, an
+unusual style in English.  @xref{Keys in Documentation}, for how the
address@hidden variable affects generated quotes.
 @end defun
 
 @cindex @samp{%} in format
diff --git a/etc/NEWS b/etc/NEWS
index e202612..29559d1 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1917,6 +1917,14 @@ display of diagnostics and help, but not of info.  As 
the variable is
 not intended for casual use, it is not a user option.
 
 +++
+** Message-issuing functions like 'message' and 'error' now translate
+various sorts of single quotes in their format strings according to
+the value of 'text-quoting-style' (see above).  This translation
+cannot be disabled.  To get the old behavior, use 'format', which is
+not affected by 'text-quoting-style', e.g., (message "%s" (format
+"...." foo bar)).
+
++++
 ** substitute-command-keys now replaces quotes.
 That is, it converts documentation strings' quoting style as per the
 value of 'text-quoting-style'.  Doc strings in source code can use
@@ -1924,13 +1932,6 @@ either curved single quotes or grave accents and 
apostrophes.  As
 before, characters preceded by \= are output as-is.
 
 +++
-** Message-issuing functions 'error', 'message', etc. now convert quotes.
-They use the new 'format-message' function instead of plain 'format',
-so that they now follow user preference as per 'text-quoting-style'
-when processing curved single quotes, grave accents, and apostrophes
-in their format argument.
-
-+++
 ** The character classes [:alpha:] and [:alnum:] in regular expressions
 now match multibyte characters using Unicode character properties.
 If you want the old behavior where they matched any character with
@@ -2148,9 +2149,11 @@ permissions set to temporary values (e.g., for creating 
private files).
 
 ---
 ** Function 'system-name' now returns an updated value if the current
-system's name has changed or if the Emacs process has changed systems,
-and to avoid long waits it no longer consults DNS to canonicalize the
-name.  The variable 'system-name' is now obsolete.
+system's name has changed or if the Emacs process has changed systems.
+To avoid long waits it no longer consults DNS to canonicalize the name
+(in some cases this may affect generated message-id headers - customize
+'message-user-fqdn' if this bothers you). The variable 'system-name'
+is now obsolete.
 
 +++
 ** Function 'write-region' no longer outputs "Wrote FILE" in batch mode.
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index 4288808..49dada9 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -1624,7 +1624,7 @@ which combination produces "M-x" in the echo area.  You 
can also use
 the 'xmodmap' utility to show all the keys which produce a Meta
 modifier:
 
-         xmodmap -pk | egrep -i "meta|alt"
+         xmodmap -pk | grep -Ei "meta|alt"
 
 A more convenient way of finding out which keys produce a Meta modifier
 is to use the 'xkbprint' utility, if it's available on your system:
diff --git a/lisp/calendar/todo-mode.el b/lisp/calendar/todo-mode.el
index 0529e97..8e75258 100644
--- a/lisp/calendar/todo-mode.el
+++ b/lisp/calendar/todo-mode.el
@@ -902,17 +902,19 @@ Categories mode."
       (todo-show)
     (let* ((archive (eq where 'archive))
           (cat (unless archive where))
+           (goto-archive (and cat
+                              todo-skip-archived-categories
+                              (zerop (todo-get-count 'todo cat))
+                              (zerop (todo-get-count 'done cat))
+                              (not (zerop (todo-get-count 'archived cat)))))
           (file0 (when cat             ; We're in Todo Categories mode.
-                   ;; With non-nil `todo-skip-archived-categories'
-                   ;; jump to archive file of a category with only
-                   ;; archived items.
-                   (if (and todo-skip-archived-categories
-                            (zerop (todo-get-count 'todo cat))
-                            (zerop (todo-get-count 'done cat))
-                            (not (zerop (todo-get-count 'archived cat))))
+                   (if goto-archive
+                       ;; If the category has only archived items and
+                       ;; `todo-skip-archived-categories' is non-nil, jump to
+                       ;; the archive category.
                        (concat (file-name-sans-extension
                                 todo-current-todo-file) ".toda")
-                     ;; Otherwise, jump to current todo file.
+                     ;; Otherwise, jump to the category in the todo file.
                      todo-current-todo-file)))
           (len (length todo-categories))
           (cat+file (unless cat
@@ -923,18 +925,15 @@ Categories mode."
           (category (or cat (car cat+file))))
       (unless cat (setq file0 (cdr cat+file)))
       (with-current-buffer (find-file-noselect file0 'nowarn)
-       (setq todo-current-todo-file file0)
-       ;; If called from Todo Categories mode, clean up before jumping.
-       (if (string= (buffer-name) todo-categories-buffer)
-           (kill-buffer))
-       (set-window-buffer (selected-window)
-                          (set-buffer (find-buffer-visiting file0)))
-       (unless todo-global-current-todo-file
-         (setq todo-global-current-todo-file todo-current-todo-file))
-       (todo-category-number category)
-       (todo-category-select)
-       (goto-char (point-min))
-       (when add-item (todo-insert-item--basic))))))
+        (when goto-archive (todo-archive-mode))
+        (set-window-buffer (selected-window)
+                           (set-buffer (find-buffer-visiting file0)))
+        (unless todo-global-current-todo-file
+          (setq todo-global-current-todo-file todo-current-todo-file))
+        (todo-category-number category)
+        (todo-category-select)
+        (goto-char (point-min))
+        (when add-item (todo-insert-item--basic))))))
 
 (defun todo-next-item (&optional count)
   "Move point down to the beginning of the next item.
diff --git a/lisp/cedet/cedet-cscope.el b/lisp/cedet/cedet-cscope.el
index 9a54d34..373149c 100644
--- a/lisp/cedet/cedet-cscope.el
+++ b/lisp/cedet/cedet-cscope.el
@@ -52,7 +52,7 @@ SCOPE is the scope of the search, such as 'project or 
'subdirs."
   ;; -0 = Find C symbol
   ;; -1 = Find global definition
   ;; -3 = Find references
-  ;; -6 = Find egrep pattern
+  ;; -6 = Find grep -E pattern
   ;; -7 = Find file
   (let ((idx (cond ((eq type 'file)
                    "-7")
diff --git a/lisp/cedet/semantic/symref.el b/lisp/cedet/semantic/symref.el
index 088740b..516a4f3 100644
--- a/lisp/cedet/semantic/symref.el
+++ b/lisp/cedet/semantic/symref.el
@@ -266,7 +266,7 @@ Returns an object of class `semantic-symref-result'."
 ;;;###autoload
 (defun semantic-symref-find-text (text &optional scope)
   "Find a list of occurrences of TEXT in the current project.
-TEXT is a regexp formatted for use with egrep.
+TEXT is a regexp formatted for use with grep -E.
 Optional SCOPE specifies which file set to search.  Defaults to `project'.
 Refers to `semantic-symref-tool', to determine the reference tool to use
 for the current buffer.
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index b23b04a..8d6f665 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -2747,14 +2747,21 @@ with the command \\[tags-loop-continue]."
 
 ;;;###autoload
 (defun dired-do-find-regexp (regexp)
-  "Find all matches for REGEXP in all marked files, recursively."
+  "Find all matches for REGEXP in all marked files.
+For any marked directory, all of its files are searched recursively.
+However, files matching `grep-find-ignored-files' and subdirectories
+matching `grep-find-ignored-directories' are skipped in the marked
+directories.
+
+REGEXP should use constructs supported by your local `grep' command."
   (interactive "sSearch marked files (regexp): ")
   (require 'grep)
   (defvar grep-find-ignored-files)
+  (defvar grep-find-ignored-directories)
   (let* ((files (dired-get-marked-files))
          (ignores (nconc (mapcar
                           (lambda (s) (concat s "/"))
-                          vc-directory-exclusion-list)
+                          grep-find-ignored-directories)
                          grep-find-ignored-files))
          (xrefs (cl-mapcan
                  (lambda (file)
@@ -2768,7 +2775,13 @@ with the command \\[tags-loop-continue]."
 
 ;;;###autoload
 (defun dired-do-find-regexp-and-replace (from to)
-  "Replace matches of FROM with TO, in all marked files, recursively."
+  "Replace matches of FROM with TO, in all marked files.
+For any marked directory, matches in all of its files are replaced,
+recursively.  However, files matching `grep-find-ignored-files'
+and subdirectories matching `grep-find-ignored-directories' are skipped
+in the marked directories.
+
+REGEXP should use constructs supported by your local `grep' command."
   (interactive
    (let ((common
           (query-replace-read-args
diff --git a/lisp/man.el b/lisp/man.el
index 2b2ee99..5acf90b 100644
--- a/lisp/man.el
+++ b/lisp/man.el
@@ -964,7 +964,7 @@ otherwise look like a page name.
 
 An \"apropos\" query with -k gives a buffer of matching page
 names or descriptions.  The pattern argument is usually an
-\"egrep\" style regexp.
+\"grep -E\" style regexp.
 
     -k pattern"
 
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 1c72848..2ad22dd 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -823,8 +823,9 @@ non-nil result supercedes the xrefs produced by
   (pcase-let (((cl-struct xref-elisp-location symbol type file) l))
     (let ((buffer-point (find-function-search-for-symbol symbol type file)))
       (with-current-buffer (car buffer-point)
-        (goto-char (or (cdr buffer-point) (point-min)))
-        (point-marker)))))
+        (save-excursion
+          (goto-char (or (cdr buffer-point) (point-min)))
+          (point-marker))))))
 
 (cl-defmethod xref-location-group ((l xref-elisp-location))
   (xref-elisp-location-file l))
diff --git a/lisp/progmodes/etags.el b/lisp/progmodes/etags.el
index a2a0df2..890d552 100644
--- a/lisp/progmodes/etags.el
+++ b/lisp/progmodes/etags.el
@@ -2146,8 +2146,9 @@ for \\[find-tag] (which see)."
   (with-slots (tag-info file) l
     (let ((buffer (find-file-noselect file)))
       (with-current-buffer buffer
-        (etags-goto-tag-location tag-info)
-        (point-marker)))))
+        (save-excursion
+          (etags-goto-tag-location tag-info)
+          (point-marker))))))
 
 (cl-defmethod xref-location-line ((l xref-etags-location))
   (with-slots (tag-info) l
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 9c8a88c..a51c383 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -172,7 +172,8 @@ to find the list of ignores for each directory."
            (let ((command
                   (format "%s %s %s -type f -print0"
                           find-program
-                          dir
+                           (shell-quote-argument
+                            (expand-file-name dir))
                           (xref--find-ignores-arguments
                            (project-ignores project dir)
                            (expand-file-name dir)))))
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index b5632af..f651dc9 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -521,58 +521,86 @@ references displayed in the current *xref* buffer."
    (let ((fr (read-regexp "Xref query-replace (regexp)" ".*")))
      (list fr
            (read-regexp (format "Xref query-replace (regexp) %s with: " fr)))))
-  (let ((reporter (make-progress-reporter (format "Saving search results...")
-                                          0 (line-number-at-pos (point-max))))
-        (counter 0)
-        pairs item)
+  (let* (item xrefs iter)
+    (save-excursion
+      (while (setq item (xref--search-property 'xref-item))
+        (when (xref-match-length item)
+          (push item xrefs))))
     (unwind-protect
         (progn
-          (save-excursion
-            (goto-char (point-min))
-            ;; TODO: This list should be computed on-demand instead.
-            ;; As long as the UI just iterates through matches one by
-            ;; one, there's no need to compute them all in advance.
-            ;; Then we can throw away the reporter.
-            (while (setq item (xref--search-property 'xref-item))
-              (when (xref-match-length item)
-                (save-excursion
-                  (let* ((loc (xref-item-location item))
-                         (beg (xref-location-marker loc))
-                         (end (move-marker (make-marker)
-                                           (+ beg (xref-match-length item))
-                                           (marker-buffer beg))))
-                    ;; Perform sanity check first.
-                    (xref--goto-location loc)
-                    ;; FIXME: The check should probably be a generic
-                    ;; function, instead of the assumption that all
-                    ;; matches contain the full line as summary.
-                    ;; TODO: Offer to re-scan otherwise.
-                    (unless (equal (buffer-substring-no-properties
-                                    (line-beginning-position)
-                                    (line-end-position))
-                                   (xref-item-summary item))
-                      (user-error "Search results out of date"))
-                    (progress-reporter-update reporter (cl-incf counter))
-                    (push (cons beg end) pairs)))))
-            (setq pairs (nreverse pairs)))
-          (unless pairs (user-error "No suitable matches here"))
-          (progress-reporter-done reporter)
-          (xref--query-replace-1 from to pairs))
-      (dolist (pair pairs)
-        (move-marker (car pair) nil)
-        (move-marker (cdr pair) nil)))))
+          (goto-char (point-min))
+          (setq iter (xref--buf-pairs-iterator (nreverse xrefs)))
+          (xref--query-replace-1 from to iter))
+      (funcall iter :cleanup))))
+
+(defun xref--buf-pairs-iterator (xrefs)
+  (let (chunk-done item next-pair file-buf pairs all-pairs)
+    (lambda (action)
+      (pcase action
+        (:next
+         (when (or xrefs next-pair)
+           (setq chunk-done nil)
+           (when next-pair
+             (setq file-buf (marker-buffer (car next-pair))
+                   pairs (list next-pair)
+                   next-pair nil))
+           (while (and (not chunk-done)
+                       (setq item (pop xrefs)))
+             (save-excursion
+               (let* ((loc (xref-item-location item))
+                      (beg (xref-location-marker loc))
+                      (end (move-marker (make-marker)
+                                        (+ beg (xref-match-length item))
+                                        (marker-buffer beg))))
+                 (let ((pair (cons beg end)))
+                   (push pair all-pairs)
+                   ;; Perform sanity check first.
+                   (xref--goto-location loc)
+                   (if (xref--outdated-p item
+                                         (buffer-substring-no-properties
+                                          (line-beginning-position)
+                                          (line-end-position)))
+                       (message "Search result out of date, skipping")
+                     (cond
+                      ((null file-buf)
+                       (setq file-buf (marker-buffer beg))
+                       (push pair pairs))
+                      ((equal file-buf (marker-buffer beg))
+                       (push pair pairs))
+                      (t
+                       (setq chunk-done t
+                             next-pair pair))))))))
+           (cons file-buf (nreverse pairs))))
+        (:cleanup
+         (dolist (pair all-pairs)
+           (move-marker (car pair) nil)
+           (move-marker (cdr pair) nil)))))))
+
+(defun xref--outdated-p (item line-text)
+  ;; FIXME: The check should probably be a generic function instead of
+  ;; the assumption that all matches contain the full line as summary.
+  (let ((summary (xref-item-summary item))
+        (strip (lambda (s) (if (string-match "\r\\'" s)
+                          (substring-no-properties s 0 -1)
+                        s))))
+    (not
+     ;; Sometimes buffer contents include ^M, and sometimes Grep
+     ;; output includes it, and they don't always match.
+     (equal (funcall strip line-text)
+            (funcall strip summary)))))
 
 ;; FIXME: Write a nicer UI.
-(defun xref--query-replace-1 (from to pairs)
+(defun xref--query-replace-1 (from to iter)
   (let* ((query-replace-lazy-highlight nil)
-         current-beg current-end current-buf
+         (continue t)
+         did-it-once buf-pairs pairs
+         current-beg current-end
          ;; Counteract the "do the next match now" hack in
          ;; `perform-replace'.  And still, it'll report that those
          ;; matches were "filtered out" at the end.
          (isearch-filter-predicate
           (lambda (beg end)
             (and current-beg
-                 (eq (current-buffer) current-buf)
                  (>= beg current-beg)
                  (<= end current-end))))
          (replace-re-search-function
@@ -581,19 +609,22 @@ references displayed in the current *xref* buffer."
               (while (and (not found) pairs)
                 (setq pair (pop pairs)
                       current-beg (car pair)
-                      current-end (cdr pair)
-                      current-buf (marker-buffer current-beg))
-                (xref--with-dedicated-window
-                 (pop-to-buffer current-buf))
+                      current-end (cdr pair))
                 (goto-char current-beg)
                 (when (re-search-forward from current-end noerror)
                   (setq found t)))
               found))))
-    ;; FIXME: Despite this being a multi-buffer replacement, `N'
-    ;; doesn't work, because we're not using
-    ;; `multi-query-replace-map', and it would expect the below
-    ;; function to be called once per buffer.
-    (perform-replace from to t t nil)))
+    (while (and continue (setq buf-pairs (funcall iter :next)))
+      (if did-it-once
+          ;; Reuse the same window for subsequent buffers.
+          (switch-to-buffer (car buf-pairs))
+        (xref--with-dedicated-window
+         (pop-to-buffer (car buf-pairs)))
+        (setq did-it-once t))
+      (setq pairs (cdr buf-pairs))
+      (setq continue
+            (perform-replace from to t t nil nil multi-query-replace-map)))
+    (unless did-it-once (user-error "No suitable matches here"))))
 
 (defvar xref--xref-buffer-mode-map
   (let ((map (make-sparse-keymap)))
@@ -687,7 +718,9 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)."
 (defun xref--show-xref-buffer (xrefs alist)
   (let ((xref-alist (xref--analyze xrefs)))
     (with-current-buffer (get-buffer-create xref-buffer-name)
-      (let ((inhibit-read-only t))
+      (setq buffer-undo-list nil)
+      (let ((inhibit-read-only t)
+            (buffer-undo-list t))
         (erase-buffer)
         (xref--insert-xrefs xref-alist)
         (xref--xref-buffer-mode)
@@ -908,6 +941,8 @@ IGNORES is a list of glob patterns."
   (require 'find-dired)      ; for `find-name-arg'
   (defvar grep-find-template)
   (defvar find-name-arg)
+  ;; `shell-quote-argument' quotes the tilde as well.
+  (cl-assert (not (string-match-p "\\`~" dir)))
   (grep-expand-template
    grep-find-template
    regexp
@@ -919,14 +954,13 @@ IGNORES is a list of glob patterns."
             (concat " -o " find-name-arg " "))
            " "
            (shell-quote-argument ")"))
-   dir
+   (shell-quote-argument dir)
    (xref--find-ignores-arguments ignores dir)))
 
 (defun xref--find-ignores-arguments (ignores dir)
   "Convert IGNORES and DIR to a list of arguments for 'find'.
 IGNORES is a list of glob patterns.  DIR is an absolute
 directory, used as the root of the ignore globs."
-  ;; `shell-quote-argument' quotes the tilde as well.
   (cl-assert (not (string-match-p "\\`~" dir)))
   (when ignores
     (concat
@@ -1014,7 +1048,11 @@ directory, used as the root of the ignore globs."
     (syntax-propertize line-end)
     ;; FIXME: This results in several lines with the same
     ;; summary. Solve with composite pattern?
-    (while (re-search-forward regexp line-end t)
+    (while (and
+            ;; REGEXP might match an empty string.  Or line.
+            (or (null matches)
+                (> (point) line-beg))
+            (re-search-forward regexp line-end t))
       (let* ((beg-column (- (match-beginning 0) line-beg))
              (end-column (- (match-end 0) line-beg))
              (loc (xref-make-file-location file line beg-column))
diff --git a/lisp/replace.el b/lisp/replace.el
index 169fc3f..0b25200 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -191,18 +191,15 @@ wants to replace FROM with TO."
            ;; a region in order to specify the minibuffer input.
            ;; That should not clobber the region for the query-replace itself.
            (save-excursion
-              ;; The `with-current-buffer' ensures that the binding
-              ;; for `text-property-default-nonsticky' isn't a buffer
-              ;; local binding in the current buffer, which
-              ;; `read-from-minibuffer' wouldn't see.
-              (with-current-buffer (window-buffer (minibuffer-window))
-                (let ((text-property-default-nonsticky
-                       (cons '(separator . t) 
text-property-default-nonsticky)))
-                  (if regexp-flag
-                      (read-regexp prompt nil 'query-replace-from-to-history)
-                    (read-from-minibuffer
-                     prompt nil nil nil 'query-replace-from-to-history
-                     (car (if regexp-flag regexp-search-ring search-ring)) 
t))))))
+              (minibuffer-with-setup-hook
+                  (lambda ()
+                    (setq-local text-property-default-nonsticky
+                                (cons '(separator . t) 
text-property-default-nonsticky)))
+                (if regexp-flag
+                    (read-regexp prompt nil 'query-replace-from-to-history)
+                  (read-from-minibuffer
+                   prompt nil nil nil 'query-replace-from-to-history
+                   (car (if regexp-flag regexp-search-ring search-ring)) t)))))
            (to))
       (if (and (zerop (length from)) query-replace-defaults)
          (cons (caar query-replace-defaults)
diff --git a/lisp/subr.el b/lisp/subr.el
index f67f70f..094710b 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -291,21 +291,27 @@ This function accepts any number of arguments, but 
ignores them."
 
 ;; Signal a compile-error if the first arg is missing.
 (defun error (&rest args)
-  "Signal an error, making error message by passing all args to `format'.
+  "Signal an error, making a message by passing args to `format-message'.
 In Emacs, the convention is that error messages start with a capital
 letter but *do not* end with a period.  Please follow this convention
-for the sake of consistency."
+for the sake of consistency.
+
+Note: (error \"%s\" VALUE) makes the message VALUE without
+interpreting format characters like `%', `\\=`', and `\\=''."
   (declare (advertised-calling-convention (string &rest args) "23.1"))
   (signal 'error (list (apply #'format-message args))))
 
 (defun user-error (format &rest args)
-  "Signal a pilot error, making error message by passing all args to `format'.
+  "Signal a pilot error, making a message by passing args to `format-message'.
 In Emacs, the convention is that error messages start with a capital
 letter but *do not* end with a period.  Please follow this convention
 for the sake of consistency.
 This is just like `error' except that `user-error's are expected to be the
 result of an incorrect manipulation on the part of the user, rather than the
-result of an actual problem."
+result of an actual problem.
+
+Note: (user-error \"%s\" VALUE) makes the message VALUE without
+interpreting format characters like `%', `\\=`', and `\\=''."
   (signal 'user-error (list (apply #'format-message format args))))
 
 (defun define-error (name message &optional parent)
@@ -1123,6 +1129,7 @@ The return value is a positive integer."
 
 (defun posnp (obj)
   "Return non-nil if OBJ appears to be a valid `posn' object specifying a 
window.
+A `posn' object is returned from functions such as `event-start'.
 If OBJ is a valid `posn' object, but specifies a frame rather
 than a window, return nil."
   ;; FIXME: Correct the behavior of this function so that all valid
diff --git a/src/bidi.c b/src/bidi.c
index c23ff95..573e513 100644
--- a/src/bidi.c
+++ b/src/bidi.c
@@ -2498,10 +2498,10 @@ typedef struct bpa_stack_entry {
 
    And finally, cross-reference these two:
 
-    fgrep -w -f brackets.txt decompositions.txt
+    grep -Fw -f brackets.txt decompositions.txt
 
    where "decompositions.txt" was produced by the 1st script, and
-   "brackets.txt" by the 2nd script.  In the output of fgrep, look
+   "brackets.txt" by the 2nd script.  In the output of grep, look
    only for decompositions that don't begin with some compatibility
    formatting tag, such as "<compat>".  Only decompositions that
    consist solely of character codepoints are relevant to bidi
diff --git a/src/callint.c b/src/callint.c
index e56f7cd..053ee6c 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -272,7 +272,7 @@ invoke it.  If KEYS is omitted or nil, the return value of
 {
   /* `args' will contain the array of arguments to pass to the function.
      `visargs' will contain the same list but in a nicer form, so that if we
-     pass it to `Fformat' it will be understandable to a human.  */
+     pass it to `Fformat_message' it will be understandable to a human.  */
   Lisp_Object *args, *visargs;
   Lisp_Object specs;
   Lisp_Object filter_specs;
diff --git a/src/doprnt.c b/src/doprnt.c
index 506bbc3..9d8b783 100644
--- a/src/doprnt.c
+++ b/src/doprnt.c
@@ -46,15 +46,15 @@ along with GNU Emacs.  If not, see 
<http://www.gnu.org/licenses/>.  */
    ignored %s and %c conversions.  (See below for the detailed documentation of
    what is supported.)  However, this is okay, as this function is supposed to
    be called from `error' and similar functions, and thus does not need to
-   support features beyond those in `Fformat', which is used by `error' on the
-   Lisp level.  */
+   support features beyond those in `Fformat_message', which is used
+   by `error' on the Lisp level.  */
 
 /* In the FORMAT argument this function supports ` and ' as directives
    that output left and right quotes as per ‘text-quoting style’.  It
    also supports the following %-sequences:
 
    %s means print a string argument.
-   %S is silently treated as %s, for loose compatibility with `Fformat'.
+   %S is treated as %s, for loose compatibility with `Fformat_message'.
    %d means print a `signed int' argument in decimal.
    %o means print an `unsigned int' argument in octal.
    %x means print an `unsigned int' argument in hex.
diff --git a/src/editfns.c b/src/editfns.c
index 11a82c3..0e1a6e3 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3716,10 +3716,11 @@ In batch mode, the message is printed to the standard 
error stream,
 followed by a newline.
 
 The first argument is a format control string, and the rest are data
-to be formatted under control of the string.  See `format' for details.
+to be formatted under control of the string.  See `format-message' for
+details.
 
-Note: Use (message "%s" VALUE) to print the value of expressions and
-variables to avoid accidentally interpreting `%' as format specifiers.
+Note: (message "%s" VALUE) displays the string VALUE without
+interpreting format characters like `%', `\\=`', and `\\=''.
 
 If the first argument is nil or the empty string, the function clears
 any existing message; this lets the minibuffer contents show.  See
@@ -3747,7 +3748,8 @@ DEFUN ("message-box", Fmessage_box, Smessage_box, 1, 
MANY, 0,
        doc: /* Display a message, in a dialog box if possible.
 If a dialog box is not available, use the echo area.
 The first argument is a format control string, and the rest are data
-to be formatted under control of the string.  See `format' for details.
+to be formatted under control of the string.  See `format-message' for
+details.
 
 If the first argument is nil or the empty string, clear any existing
 message; let the minibuffer contents show.
@@ -3778,7 +3780,8 @@ If this command was invoked with the mouse, use a dialog 
box if
 `use-dialog-box' is non-nil.
 Otherwise, use the echo area.
 The first argument is a format control string, and the rest are data
-to be formatted under control of the string.  See `format' for details.
+to be formatted under control of the string.  See `format-message' for
+details.
 
 If the first argument is nil or the empty string, clear any existing
 message; let the minibuffer contents show.
diff --git a/test/automated/data/xref/file1.txt 
b/test/automated/data/xref/file1.txt
new file mode 100644
index 0000000..5d7cc54
--- /dev/null
+++ b/test/automated/data/xref/file1.txt
@@ -0,0 +1,2 @@
+foo foo
+bar
diff --git a/test/automated/data/xref/file2.txt 
b/test/automated/data/xref/file2.txt
new file mode 100644
index 0000000..9f075f2
--- /dev/null
+++ b/test/automated/data/xref/file2.txt
@@ -0,0 +1,2 @@
+
+bar
diff --git a/test/automated/xref-tests.el b/test/automated/xref-tests.el
new file mode 100644
index 0000000..079b196
--- /dev/null
+++ b/test/automated/xref-tests.el
@@ -0,0 +1,91 @@
+;;; xref-tests.el --- tests for xref
+
+;; Copyright (C) 2016 Free Software Foundation, Inc.
+
+;; Author: Dmitry Gutov <address@hidden>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'xref)
+(require 'cl-lib)
+
+(defvar xref-tests-data-dir
+  (expand-file-name "data/xref/"
+                    (file-name-directory (or load-file-name 
(buffer-file-name)))))
+
+(ert-deftest xref-collect-matches-finds-none-for-some-regexp ()
+  (should (null (xref-collect-matches "zzz" "*" xref-tests-data-dir nil))))
+
+(ert-deftest xref-collect-matches-finds-some-for-bar ()
+  (let* ((matches (xref-collect-matches "bar" "*" xref-tests-data-dir nil))
+         (locs (cl-sort (mapcar #'xref-item-location matches)
+                        #'string<
+                        :key #'xref-location-group)))
+    (should (= 2 (length matches)))
+    (should (string-match-p "file1\\.txt\\'" (xref-location-group (nth 0 
locs))))
+    (should (string-match-p "file2\\.txt\\'" (xref-location-group (nth 1 
locs))))))
+
+(ert-deftest xref-collect-matches-finds-two-matches-on-the-same-line ()
+  (let* ((matches (xref-collect-matches "foo" "*" xref-tests-data-dir nil))
+         (locs (mapcar #'xref-item-location matches)))
+    (should (= 2 (length matches)))
+    (should (string-match-p "file1\\.txt\\'" (xref-location-group (nth 0 
locs))))
+    (should (string-match-p "file1\\.txt\\'" (xref-location-group (nth 1 
locs))))
+    (should (equal 1 (xref-location-line (nth 0 locs))))
+    (should (equal 1 (xref-location-line (nth 1 locs))))
+    (should (equal 0 (xref-file-location-column (nth 0 locs))))
+    (should (equal 4 (xref-file-location-column (nth 1 locs))))))
+
+(ert-deftest xref-collect-matches-finds-an-empty-line-regexp-match ()
+  (let* ((matches (xref-collect-matches "^$" "*" xref-tests-data-dir nil))
+         (locs (mapcar #'xref-item-location matches)))
+    (should (= 1 (length matches)))
+    (should (string-match-p "file2\\.txt\\'" (xref-location-group (nth 0 
locs))))
+    (should (equal 1 (xref-location-line (nth 0 locs))))
+    (should (equal 0 (xref-file-location-column (nth 0 locs))))))
+
+(ert-deftest xref--buf-pairs-iterator-groups-markers-by-buffers-1 ()
+  (let* ((xrefs (xref-collect-matches "foo" "*" xref-tests-data-dir nil))
+         (iter (xref--buf-pairs-iterator xrefs))
+         (cons (funcall iter :next)))
+    (should (null (funcall iter :next)))
+    (should (string-match "file1\\.txt\\'" (buffer-file-name (car cons))))
+    (should (= 2 (length (cdr cons))))))
+
+(ert-deftest xref--buf-pairs-iterator-groups-markers-by-buffers-2 ()
+  (let* ((xrefs (xref-collect-matches "bar" "*" xref-tests-data-dir nil))
+         (iter (xref--buf-pairs-iterator xrefs))
+         (cons1 (funcall iter :next))
+         (cons2 (funcall iter :next)))
+    (should (null (funcall iter :next)))
+    (should-not (equal (car cons1) (car cons2)))
+    (should (= 1 (length (cdr cons1))))
+    (should (= 1 (length (cdr cons2))))))
+
+(ert-deftest xref--buf-pairs-iterator-cleans-up-markers ()
+  (let* ((xrefs (xref-collect-matches "bar" "*" xref-tests-data-dir nil))
+         (iter (xref--buf-pairs-iterator xrefs))
+         (cons1 (funcall iter :next))
+         (cons2 (funcall iter :next)))
+    (funcall iter :cleanup)
+    (should (null (marker-position (car (nth 0 (cdr cons1))))))
+    (should (null (marker-position (cdr (nth 0 (cdr cons1))))))
+    (should (null (marker-position (car (nth 0 (cdr cons2))))))
+    (should (null (marker-position (cdr (nth 0 (cdr cons2))))))))



reply via email to

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