mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-30 12:21:25 -08:00
Merge from origin/emacs-25
50650cbDoc fixes for fclist and grep5e814e0Minor doc fixes for quoting3347a73`nreverse' the marker pairs list1a4127dUse save-excursion in xref-location-marker moreab3ba91shell-quote-argument DIR when appropriate922c7a3Rework xref-query-replace-in-results3fe3510* lisp/replace.el (query-replace-read-from): Use minibuffer-w...0932b94Fix 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.4d8fd9cHandle "empty line" regexp in xref searchesf559b37Add tests for xref-collect-matches6428aa0Use grep-find-ignored-directories instead of vc-directory-exc...6f82d8eClear buffer-undo-list when showing xrefsc68a091Note the quote translation in `message' in section "incompati...52f86a7* etc/NEWS: Mention (message "%s" (format ...)).93703c5(Common Keywords): Correct what missing :group means79e5800Improve documentation of Dired's 'A' and 'Q' commands2ea2a2fDoc fixes for quoting8544b98posnp doc clarification805204fMention what a missing :group doesec554d7Fix documentation of dired-aux search/replace commands
This commit is contained in:
commit
89ce83b202
29 changed files with 343 additions and 157 deletions
|
|
@ -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}.
|
||||
|
||||
@vindex grep-find-ignored-files @r{(Dired)}
|
||||
@vindex 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
|
||||
@code{grep-find-ignored-files} and subdirectories whose names match
|
||||
@code{grep-find-ignored-directories}.
|
||||
|
||||
@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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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{'}@footnote{The 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 Lisp.@footnote{A 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,
|
||||
@ifinfo
|
||||
'
|
||||
@end ifinfo
|
||||
@ifnotinfo
|
||||
@code{'}
|
||||
@end 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
|
||||
@code{compare-windows} is preceded by a single quote; otherwise, Emacs
|
||||
@code{compare-windows} 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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
@t{"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}
|
||||
|
|
|
|||
|
|
@ -66,9 +66,12 @@ cause confusion.}
|
|||
|
||||
@kindex group@r{, customization keyword}
|
||||
@item :group @var{group}
|
||||
Put this customization item in group @var{group}. When you use
|
||||
@code{:group} in a @code{defgroup}, it makes the new group a subgroup of
|
||||
@var{group}.
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
@t{"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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
@code{text-quoting-style} variable affects generated quotes.
|
||||
@end defun
|
||||
|
||||
@cindex @samp{%} in format
|
||||
|
|
|
|||
23
etc/NEWS
23
etc/NEWS
|
|
@ -1916,6 +1916,14 @@ displayable, and like 'grave' otherwise. The new variable affects
|
|||
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
|
||||
|
|
@ -1923,13 +1931,6 @@ value of 'text-quoting-style'. Doc strings in source code can use
|
|||
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.
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)))))
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
15
lisp/subr.el
15
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
2
test/automated/data/xref/file1.txt
Normal file
2
test/automated/data/xref/file1.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
foo foo
|
||||
bar
|
||||
2
test/automated/data/xref/file2.txt
Normal file
2
test/automated/data/xref/file2.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
bar
|
||||
91
test/automated/xref-tests.el
Normal file
91
test/automated/xref-tests.el
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
;;; xref-tests.el --- tests for xref
|
||||
|
||||
;; Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Dmitry Gutov <dgutov@yandex.ru>
|
||||
|
||||
;; 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))))))))
|
||||
Loading…
Add table
Add a link
Reference in a new issue