;; NOTE: The xref API is still experimental and can change in major,
;; backward-incompatible ways. Everyone is encouraged to try it, and
-;; report to us any problems or use cases we hadn't anticiated, by
+;; report to us any problems or use cases we hadn't anticipated, by
;; sending an email to emacs-devel, or `M-x report-emacs-bug'.
;;
;; This file provides a somewhat generic infrastructure for cross
(require 'semantic/symref)) ;; for hit-lines slot
(defgroup xref nil "Cross-referencing commands"
+ :version "25.1"
:group 'tools)
\f
(defvar xref-backend-functions nil
"Special hook to find the xref backend for the current context.
-Each functions on this hook is called in turn with no arguments
+Each function on this hook is called in turn with no arguments,
and should return either nil to mean that it is not applicable,
or an xref backend, which is a value to be used to dispatch the
generic functions.")
(xref--pop-to-location xref window)))
(defun xref-query-replace (from to)
- "Perform interactive replacement in all current matches."
+ "Perform interactive replacement of FROM with TO in all displayed xrefs.
+
+This command interactively replaces FROM with TO in the names of the
+references displayed in the current *xref* buffer."
(interactive
- (list (read-regexp "Query replace regexp in matches" ".*")
- (read-regexp "Replace with: ")))
- (let (pairs item)
+ (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)
(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
(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)
(defvar xref--read-pattern-history nil)
-(defun xref--show-xrefs (xrefs window)
+(defun xref--show-xrefs (xrefs window &optional always-show-list)
(cond
- ((not (cdr xrefs))
+ ((and (not (cdr xrefs)) (not always-show-list))
(xref-push-marker-stack)
(xref--pop-to-location (car xrefs) window))
(t
With prefix argument or when there's no identifier at point,
prompt for it.
-If the backend has sufficient information to determine a unique
-definition for IDENTIFIER, it returns only that definition. If
-there are multiple possible definitions, it returns all of them.
-
-If the backend returns one definition, jump to it; otherwise,
-display the list in a buffer."
+If sufficient information is available to determine a unique
+definition for IDENTIFIER, display it in the selected window.
+Otherwise, display the list of the possible definitions in a
+buffer where the user can select from the list."
(interactive (list (xref--read-identifier "Find definitions of: ")))
(xref--find-definitions identifier nil))
(mapc #'kill-buffer
(cl-set-difference (buffer-list) orig-buffers)))))
+;;;###autoload
(defun xref-collect-matches (regexp files dir ignores)
"Collect matches for REGEXP inside FILES in DIR.
FILES is a string with glob patterns separated by spaces.
IGNORES is a list of glob patterns."
- (cl-assert (directory-name-p dir))
+ ;; DIR can also be a regular file for now; let's not advertise that.
(require 'semantic/fw)
(grep-compute-defaults)
(defvar grep-find-template)
grep-find-template t t))
(grep-highlight-matches nil)
(command (xref--rgrep-command (xref--regexp-to-extended regexp)
- files dir ignores))
+ files
+ (expand-file-name dir)
+ ignores))
(orig-buffers (buffer-list))
(buf (get-buffer-create " *xref-grep*"))
(grep-re (caar grep-regexp-alist))
+ (counter 0)
+ reporter
hits)
(with-current-buffer buf
(erase-buffer)
(push (cons (string-to-number (match-string 2))
(match-string 1))
hits)))
+ (setq reporter (make-progress-reporter
+ (format "Collecting search results...")
+ 0 (length hits)))
(unwind-protect
- (cl-mapcan (lambda (hit) (xref--collect-matches hit regexp))
+ (cl-mapcan (lambda (hit)
+ (prog1
+ (progress-reporter-update reporter counter)
+ (cl-incf counter))
+ (xref--collect-matches hit regexp))
(nreverse hits))
+ (progress-reporter-done reporter)
;; TODO: Same as above.
(mapc #'kill-buffer
(cl-set-difference (buffer-list) orig-buffers)))))
" "
(shell-quote-argument ")"))
dir
- (concat
- (shell-quote-argument "(")
- " -path "
- (mapconcat
- (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))
- ignores
- " -o -path ")
- " "
- (shell-quote-argument ")")
- " -prune -o ")))
+ (xref--find-ignores-arguments ignores dir)))
+
+(defun xref--find-ignores-arguments (ignores dir)
+ ;; `shell-quote-argument' quotes the tilde as well.
+ (cl-assert (not (string-match-p "\\`~" dir)))
+ (when ignores
+ (concat
+ (shell-quote-argument "(")
+ " -path "
+ (mapconcat
+ (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))
+ ignores
+ " -o -path ")
+ " "
+ (shell-quote-argument ")")
+ " -prune -o ")))
(defun xref--regexp-to-extended (str)
(replace-regexp-in-string