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)))