diff options
Diffstat (limited to 'lisp/progmodes/xref.el')
-rw-r--r-- | lisp/progmodes/xref.el | 119 |
1 files changed, 86 insertions, 33 deletions
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index c36a9bd9940..e1dd6e56bbf 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -1,6 +1,11 @@ -;; xref.el --- Cross-referencing commands -*-lexical-binding:t-*- +;;; xref.el --- Cross-referencing commands -*-lexical-binding:t-*- ;; Copyright (C) 2014-2020 Free Software Foundation, Inc. +;; Version: 1.0.3 +;; Package-Requires: ((emacs "26.3")) + +;; This is a GNU ELPA :core package. Avoid functionality that is not +;; compatible with the version of Emacs recorded above. ;; This file is part of GNU Emacs. @@ -258,17 +263,24 @@ be found, return nil. The default implementation uses `semantic-symref-tool-alist' to find a search tool; by default, this uses \"find | grep\" in the -`project-current' roots." - (cl-mapcan +current project's main and external roots." + (mapcan (lambda (dir) (xref-references-in-directory identifier dir)) (let ((pr (project-current t))) - (append - (project-roots pr) + (cons + (if (fboundp 'project-root) + (project-root pr) + (with-no-warnings + (project-roots pr))) (project-external-roots pr))))) (cl-defgeneric xref-backend-apropos (backend pattern) - "Find all symbols that match regexp PATTERN.") + "Find all symbols that match PATTERN string. +The second argument has the same meaning as in `apropos'. + +If BACKEND is implemented in Lisp, it can use +`xref-apropos-regexp' to convert the pattern to regexp.") (cl-defgeneric xref-backend-identifier-at-point (_backend) "Return the relevant identifier at point. @@ -588,15 +600,18 @@ SELECT is `quit', also quit the *xref* window." (defun xref-goto-xref (&optional quit) "Jump to the xref on the current line and select its window. -Non-interactively, non-nil QUIT means to first quit the *xref* -buffer." - (interactive) +Non-interactively, non-nil QUIT, or interactively, with prefix argument +means to first quit the *xref* buffer." + (interactive "P") (let* ((buffer (current-buffer)) (xref (or (xref--item-at-point) (user-error "No reference at point"))) (xref--current-item xref)) (xref--show-location (xref-item-location xref) (if quit 'quit t)) - (next-error-found buffer (current-buffer)))) + (if (fboundp 'next-error-found) + (next-error-found buffer (current-buffer)) + ;; Emacs < 27 + (setq next-error-last-buffer buffer)))) (defun xref-quit-and-goto-xref () "Quit *xref* buffer, then jump to xref on current line." @@ -946,8 +961,18 @@ Accepts the same arguments as `xref-show-xrefs-function'." (defvar xref--read-pattern-history nil) -(defun xref--show-xrefs (fetcher display-action) +(defun xref--show-xrefs (fetcher display-action &optional _always-show-list) (xref--push-markers) + (unless (functionp fetcher) + ;; Old convention. + (let ((xrefs fetcher)) + (setq fetcher + (lambda () + (if (eq xrefs 'called-already) + (user-error "Refresh is not supported") + (prog1 + xrefs + (setq xrefs 'called-already))))))) (funcall xref-show-xrefs-function fetcher `((window . ,(selected-window)) (display-action . ,display-action)))) @@ -1093,14 +1118,24 @@ The argument has the same meaning as in `apropos'." "Search for pattern (word list or regexp): " nil 'xref--read-pattern-history))) (require 'apropos) - (xref--find-xrefs pattern 'apropos - (apropos-parse-pattern - (if (string-equal (regexp-quote pattern) pattern) - ;; Split into words - (or (split-string pattern "[ \t]+" t) - (user-error "No word list given")) - pattern)) - nil)) + (let* ((newpat + (if (and (version< emacs-version "28.0.50") + (memq (xref-find-backend) '(elisp etags))) + ;; Handle backends in older Emacs. + (xref-apropos-regexp pattern) + ;; Delegate pattern handling to the backend fully. + ;; The old way didn't work for "external" backends. + pattern))) + (xref--find-xrefs pattern 'apropos newpat nil))) + +(defun xref-apropos-regexp (pattern) + "Return an Emacs regexp from PATTERN similar to `apropos'." + (apropos-parse-pattern + (if (string-equal (regexp-quote pattern) pattern) + ;; Split into words + (or (split-string pattern "[ \t]+" t) + (user-error "No word list given")) + pattern))) ;;; Key bindings @@ -1262,13 +1297,13 @@ FILES must be a list of absolute file names." (insert (mapconcat #'identity files "\0")) (setq default-directory dir) (setq status - (project--process-file-region (point-min) - (point-max) - shell-file-name - output - nil - shell-command-switch - command))) + (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)) @@ -1283,6 +1318,24 @@ FILES must be a list of absolute file names." hits))) (xref--convert-hits (nreverse hits) regexp))) +(defun xref--process-file-region ( start end program + &optional buffer display + &rest args) + ;; FIXME: This branching shouldn't be necessary, but + ;; call-process-region *is* measurably faster, even for a program + ;; doing some actual work (for a period of time). Even though + ;; call-process-region also creates a temp file internally + ;; (https://lists.gnu.org/archive/html/emacs-devel/2019-01/msg00211.html). + (if (not (file-remote-p default-directory)) + (apply #'call-process-region + start end program nil buffer display args) + (let ((infile (make-temp-file "ppfr"))) + (unwind-protect + (progn + (write-region start end infile nil 'silent) + (apply #'process-file program infile buffer display args)) + (delete-file infile))))) + (defun xref--rgrep-command (regexp files dir ignores) (require 'find-dired) ; for `find-name-arg' (defvar grep-find-template) @@ -1317,11 +1370,11 @@ directory, used as the root of the ignore globs." (lambda (ignore) (when (string-match-p "/\\'" ignore) (setq ignore (concat ignore "*"))) - (if (string-match "\\`\\./" ignore) - (setq ignore (replace-match dir t t ignore)) - (unless (string-prefix-p "*" ignore) - (setq ignore (concat "*/" ignore)))) - (shell-quote-argument ignore)) + (shell-quote-argument (if (string-match "\\`\\./" ignore) + (replace-match dir t t ignore) + (if (string-prefix-p "*" ignore) + ignore + (concat "*/" ignore))))) ignores " -o -path ") " " @@ -1364,8 +1417,8 @@ Such as the current syntax table and the applied syntax properties." (let (xref--last-file-buffer (tmp-buffer (generate-new-buffer " *xref-temp*"))) (unwind-protect - (cl-mapcan (lambda (hit) (xref--collect-matches hit regexp tmp-buffer)) - hits) + (mapcan (lambda (hit) (xref--collect-matches hit regexp tmp-buffer)) + hits) (kill-buffer tmp-buffer)))) (defun xref--collect-matches (hit regexp tmp-buffer) |