Function: xref-matches-in-files
xref-matches-in-files is an autoloaded and byte-compiled function
defined in xref.el.gz.
Signature
(xref-matches-in-files REGEXP FILES)
Documentation
Find all matches for REGEXP in FILES.
Return a list of xref values. FILES must be a list of absolute file names.
See xref-search-program and xref-search-program-alist for how
to control which program to use when looking for matches.
Source Code
;; Defined in /usr/src/emacs/lisp/progmodes/xref.el.gz
;;;###autoload
(defun xref-matches-in-files (regexp files)
"Find all matches for REGEXP in FILES.
Return a list of xref values.
FILES must be a list of absolute file names.
See `xref-search-program' and `xref-search-program-alist' for how
to control which program to use when looking for matches."
(cl-assert (consp files))
(require 'grep)
(defvar grep-highlight-matches)
(pcase-let*
((output (get-buffer-create " *project grep output*"))
(`(,grep-re ,file-group ,line-group . ,_) (car grep-regexp-alist))
(status nil)
(hits nil)
;; Support for remote files. The assumption is that, if the
;; first file is remote, they all are, and on the same host.
(dir (file-name-directory (car files)))
(remote-id (file-remote-p dir))
;; The 'auto' default would be fine too, but ripgrep can't handle
;; the options we pass in that case.
(grep-highlight-matches nil)
(command (grep-expand-template (cdr
(or
(assoc
xref-search-program
xref-search-program-alist)
(user-error "Unknown search program `%s'"
xref-search-program)))
(xref--regexp-to-extended regexp))))
(when remote-id
(require 'tramp)
(setq files (mapcar
(if (tramp-tramp-file-p dir)
#'tramp-file-local-name
#'file-local-name)
files)))
(when (file-name-quoted-p (car files))
(setq files (mapcar #'file-name-unquote files)))
(with-current-buffer output
(erase-buffer)
(with-temp-buffer
(insert (mapconcat #'identity files "\0"))
(setq default-directory dir)
(setq status
(xref--process-file-region (point-min)
(point-max)
shell-file-name
output
nil
shell-command-switch
command)))
(goto-char (point-min))
(when (and (/= (point-min) (point-max))
(not (looking-at grep-re))
;; TODO: Show these matches as well somehow?
(not (looking-at "Binary file .* matches")))
(user-error "Search failed with status %d: %s" status
(buffer-substring (point-min) (line-end-position))))
(while (re-search-forward grep-re nil t)
(push (list (string-to-number (match-string line-group))
(match-string file-group)
(buffer-substring-no-properties (point) (line-end-position)))
hits)))
;; By default, ripgrep's output order is non-deterministic
;; (https://github.com/BurntSushi/ripgrep/issues/152)
;; because it does the search in parallel.
;; Grep's output also comes out in seemingly arbitrary order,
;; though stable one. Let's sort both for better UI.
(setq hits
(sort (nreverse hits)
(lambda (h1 h2)
(string< (cadr h1) (cadr h2)))))
(xref--convert-hits hits regexp)))