aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes
diff options
context:
space:
mode:
authorPaul Eggert2016-05-05 23:11:11 -0700
committerPaul Eggert2016-05-05 23:11:11 -0700
commit89ce83b20249dfb4e45f09dfdddf4c4b66d82968 (patch)
tree3d75245a5514df2ad7b17ae6d56727b9629846a9 /lisp/progmodes
parentd546ed13b04521308ef7ec8e7e5b68e03f1bbb38 (diff)
parent50650cb6887d99b01eeb1e686fc1f695c2a0c64a (diff)
downloademacs-89ce83b20249dfb4e45f09dfdddf4c4b66d82968.tar.gz
emacs-89ce83b20249dfb4e45f09dfdddf4c4b66d82968.zip
Merge from origin/emacs-25
50650cb Doc fixes for fclist and grep 5e814e0 Minor doc fixes for quoting 3347a73 `nreverse' the marker pairs list 1a4127d Use save-excursion in xref-location-marker more ab3ba91 shell-quote-argument DIR when appropriate 922c7a3 Rework xref-query-replace-in-results 3fe3510 * lisp/replace.el (query-replace-read-from): Use minibuffer-w... 0932b94 Fix 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. 4d8fd9c Handle "empty line" regexp in xref searches f559b37 Add tests for xref-collect-matches 6428aa0 Use grep-find-ignored-directories instead of vc-directory-exc... 6f82d8e Clear buffer-undo-list when showing xrefs c68a091 Note the quote translation in `message' in section "incompati... 52f86a7 * etc/NEWS: Mention (message "%s" (format ...)). 93703c5 (Common Keywords): Correct what missing :group means 79e5800 Improve documentation of Dired's 'A' and 'Q' commands 2ea2a2f Doc fixes for quoting 8544b98 posnp doc clarification 805204f Mention what a missing :group does ec554d7 Fix documentation of dired-aux search/replace commands
Diffstat (limited to 'lisp/progmodes')
-rw-r--r--lisp/progmodes/elisp-mode.el5
-rw-r--r--lisp/progmodes/etags.el5
-rw-r--r--lisp/progmodes/project.el3
-rw-r--r--lisp/progmodes/xref.el146
4 files changed, 100 insertions, 59 deletions
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 1c728484ab5..2ad22ddd0ff 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -823,8 +823,9 @@ non-nil result supercedes the xrefs produced by
823 (pcase-let (((cl-struct xref-elisp-location symbol type file) l)) 823 (pcase-let (((cl-struct xref-elisp-location symbol type file) l))
824 (let ((buffer-point (find-function-search-for-symbol symbol type file))) 824 (let ((buffer-point (find-function-search-for-symbol symbol type file)))
825 (with-current-buffer (car buffer-point) 825 (with-current-buffer (car buffer-point)
826 (goto-char (or (cdr buffer-point) (point-min))) 826 (save-excursion
827 (point-marker))))) 827 (goto-char (or (cdr buffer-point) (point-min)))
828 (point-marker))))))
828 829
829(cl-defmethod xref-location-group ((l xref-elisp-location)) 830(cl-defmethod xref-location-group ((l xref-elisp-location))
830 (xref-elisp-location-file l)) 831 (xref-elisp-location-file l))
diff --git a/lisp/progmodes/etags.el b/lisp/progmodes/etags.el
index a2a0df2d6e1..890d55294cf 100644
--- a/lisp/progmodes/etags.el
+++ b/lisp/progmodes/etags.el
@@ -2146,8 +2146,9 @@ for \\[find-tag] (which see)."
2146 (with-slots (tag-info file) l 2146 (with-slots (tag-info file) l
2147 (let ((buffer (find-file-noselect file))) 2147 (let ((buffer (find-file-noselect file)))
2148 (with-current-buffer buffer 2148 (with-current-buffer buffer
2149 (etags-goto-tag-location tag-info) 2149 (save-excursion
2150 (point-marker))))) 2150 (etags-goto-tag-location tag-info)
2151 (point-marker))))))
2151 2152
2152(cl-defmethod xref-location-line ((l xref-etags-location)) 2153(cl-defmethod xref-location-line ((l xref-etags-location))
2153 (with-slots (tag-info) l 2154 (with-slots (tag-info) l
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 9c8a88c80fc..a51c383b93b 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -172,7 +172,8 @@ to find the list of ignores for each directory."
172 (let ((command 172 (let ((command
173 (format "%s %s %s -type f -print0" 173 (format "%s %s %s -type f -print0"
174 find-program 174 find-program
175 dir 175 (shell-quote-argument
176 (expand-file-name dir))
176 (xref--find-ignores-arguments 177 (xref--find-ignores-arguments
177 (project-ignores project dir) 178 (project-ignores project dir)
178 (expand-file-name dir))))) 179 (expand-file-name dir)))))
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index b5632af13ab..f651dc9cd18 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -521,58 +521,86 @@ references displayed in the current *xref* buffer."
521 (let ((fr (read-regexp "Xref query-replace (regexp)" ".*"))) 521 (let ((fr (read-regexp "Xref query-replace (regexp)" ".*")))
522 (list fr 522 (list fr
523 (read-regexp (format "Xref query-replace (regexp) %s with: " fr))))) 523 (read-regexp (format "Xref query-replace (regexp) %s with: " fr)))))
524 (let ((reporter (make-progress-reporter (format "Saving search results...") 524 (let* (item xrefs iter)
525 0 (line-number-at-pos (point-max)))) 525 (save-excursion
526 (counter 0) 526 (while (setq item (xref--search-property 'xref-item))
527 pairs item) 527 (when (xref-match-length item)
528 (push item xrefs))))
528 (unwind-protect 529 (unwind-protect
529 (progn 530 (progn
530 (save-excursion 531 (goto-char (point-min))
531 (goto-char (point-min)) 532 (setq iter (xref--buf-pairs-iterator (nreverse xrefs)))
532 ;; TODO: This list should be computed on-demand instead. 533 (xref--query-replace-1 from to iter))
533 ;; As long as the UI just iterates through matches one by 534 (funcall iter :cleanup))))
534 ;; one, there's no need to compute them all in advance. 535
535 ;; Then we can throw away the reporter. 536(defun xref--buf-pairs-iterator (xrefs)
536 (while (setq item (xref--search-property 'xref-item)) 537 (let (chunk-done item next-pair file-buf pairs all-pairs)
537 (when (xref-match-length item) 538 (lambda (action)
538 (save-excursion 539 (pcase action
539 (let* ((loc (xref-item-location item)) 540 (:next
540 (beg (xref-location-marker loc)) 541 (when (or xrefs next-pair)
541 (end (move-marker (make-marker) 542 (setq chunk-done nil)
542 (+ beg (xref-match-length item)) 543 (when next-pair
543 (marker-buffer beg)))) 544 (setq file-buf (marker-buffer (car next-pair))
544 ;; Perform sanity check first. 545 pairs (list next-pair)
545 (xref--goto-location loc) 546 next-pair nil))
546 ;; FIXME: The check should probably be a generic 547 (while (and (not chunk-done)
547 ;; function, instead of the assumption that all 548 (setq item (pop xrefs)))
548 ;; matches contain the full line as summary. 549 (save-excursion
549 ;; TODO: Offer to re-scan otherwise. 550 (let* ((loc (xref-item-location item))
550 (unless (equal (buffer-substring-no-properties 551 (beg (xref-location-marker loc))
551 (line-beginning-position) 552 (end (move-marker (make-marker)
552 (line-end-position)) 553 (+ beg (xref-match-length item))
553 (xref-item-summary item)) 554 (marker-buffer beg))))
554 (user-error "Search results out of date")) 555 (let ((pair (cons beg end)))
555 (progress-reporter-update reporter (cl-incf counter)) 556 (push pair all-pairs)
556 (push (cons beg end) pairs))))) 557 ;; Perform sanity check first.
557 (setq pairs (nreverse pairs))) 558 (xref--goto-location loc)
558 (unless pairs (user-error "No suitable matches here")) 559 (if (xref--outdated-p item
559 (progress-reporter-done reporter) 560 (buffer-substring-no-properties
560 (xref--query-replace-1 from to pairs)) 561 (line-beginning-position)
561 (dolist (pair pairs) 562 (line-end-position)))
562 (move-marker (car pair) nil) 563 (message "Search result out of date, skipping")
563 (move-marker (cdr pair) nil))))) 564 (cond
565 ((null file-buf)
566 (setq file-buf (marker-buffer beg))
567 (push pair pairs))
568 ((equal file-buf (marker-buffer beg))
569 (push pair pairs))
570 (t
571 (setq chunk-done t
572 next-pair pair))))))))
573 (cons file-buf (nreverse pairs))))
574 (:cleanup
575 (dolist (pair all-pairs)
576 (move-marker (car pair) nil)
577 (move-marker (cdr pair) nil)))))))
578
579(defun xref--outdated-p (item line-text)
580 ;; FIXME: The check should probably be a generic function instead of
581 ;; the assumption that all matches contain the full line as summary.
582 (let ((summary (xref-item-summary item))
583 (strip (lambda (s) (if (string-match "\r\\'" s)
584 (substring-no-properties s 0 -1)
585 s))))
586 (not
587 ;; Sometimes buffer contents include ^M, and sometimes Grep
588 ;; output includes it, and they don't always match.
589 (equal (funcall strip line-text)
590 (funcall strip summary)))))
564 591
565;; FIXME: Write a nicer UI. 592;; FIXME: Write a nicer UI.
566(defun xref--query-replace-1 (from to pairs) 593(defun xref--query-replace-1 (from to iter)
567 (let* ((query-replace-lazy-highlight nil) 594 (let* ((query-replace-lazy-highlight nil)
568 current-beg current-end current-buf 595 (continue t)
596 did-it-once buf-pairs pairs
597 current-beg current-end
569 ;; Counteract the "do the next match now" hack in 598 ;; Counteract the "do the next match now" hack in
570 ;; `perform-replace'. And still, it'll report that those 599 ;; `perform-replace'. And still, it'll report that those
571 ;; matches were "filtered out" at the end. 600 ;; matches were "filtered out" at the end.
572 (isearch-filter-predicate 601 (isearch-filter-predicate
573 (lambda (beg end) 602 (lambda (beg end)
574 (and current-beg 603 (and current-beg
575 (eq (current-buffer) current-buf)
576 (>= beg current-beg) 604 (>= beg current-beg)
577 (<= end current-end)))) 605 (<= end current-end))))
578 (replace-re-search-function 606 (replace-re-search-function
@@ -581,19 +609,22 @@ references displayed in the current *xref* buffer."
581 (while (and (not found) pairs) 609 (while (and (not found) pairs)
582 (setq pair (pop pairs) 610 (setq pair (pop pairs)
583 current-beg (car pair) 611 current-beg (car pair)
584 current-end (cdr pair) 612 current-end (cdr pair))
585 current-buf (marker-buffer current-beg))
586 (xref--with-dedicated-window
587 (pop-to-buffer current-buf))
588 (goto-char current-beg) 613 (goto-char current-beg)
589 (when (re-search-forward from current-end noerror) 614 (when (re-search-forward from current-end noerror)
590 (setq found t))) 615 (setq found t)))
591 found)))) 616 found))))
592 ;; FIXME: Despite this being a multi-buffer replacement, `N' 617 (while (and continue (setq buf-pairs (funcall iter :next)))
593 ;; doesn't work, because we're not using 618 (if did-it-once
594 ;; `multi-query-replace-map', and it would expect the below 619 ;; Reuse the same window for subsequent buffers.
595 ;; function to be called once per buffer. 620 (switch-to-buffer (car buf-pairs))
596 (perform-replace from to t t nil))) 621 (xref--with-dedicated-window
622 (pop-to-buffer (car buf-pairs)))
623 (setq did-it-once t))
624 (setq pairs (cdr buf-pairs))
625 (setq continue
626 (perform-replace from to t t nil nil multi-query-replace-map)))
627 (unless did-it-once (user-error "No suitable matches here"))))
597 628
598(defvar xref--xref-buffer-mode-map 629(defvar xref--xref-buffer-mode-map
599 (let ((map (make-sparse-keymap))) 630 (let ((map (make-sparse-keymap)))
@@ -687,7 +718,9 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)."
687(defun xref--show-xref-buffer (xrefs alist) 718(defun xref--show-xref-buffer (xrefs alist)
688 (let ((xref-alist (xref--analyze xrefs))) 719 (let ((xref-alist (xref--analyze xrefs)))
689 (with-current-buffer (get-buffer-create xref-buffer-name) 720 (with-current-buffer (get-buffer-create xref-buffer-name)
690 (let ((inhibit-read-only t)) 721 (setq buffer-undo-list nil)
722 (let ((inhibit-read-only t)
723 (buffer-undo-list t))
691 (erase-buffer) 724 (erase-buffer)
692 (xref--insert-xrefs xref-alist) 725 (xref--insert-xrefs xref-alist)
693 (xref--xref-buffer-mode) 726 (xref--xref-buffer-mode)
@@ -908,6 +941,8 @@ IGNORES is a list of glob patterns."
908 (require 'find-dired) ; for `find-name-arg' 941 (require 'find-dired) ; for `find-name-arg'
909 (defvar grep-find-template) 942 (defvar grep-find-template)
910 (defvar find-name-arg) 943 (defvar find-name-arg)
944 ;; `shell-quote-argument' quotes the tilde as well.
945 (cl-assert (not (string-match-p "\\`~" dir)))
911 (grep-expand-template 946 (grep-expand-template
912 grep-find-template 947 grep-find-template
913 regexp 948 regexp
@@ -919,14 +954,13 @@ IGNORES is a list of glob patterns."
919 (concat " -o " find-name-arg " ")) 954 (concat " -o " find-name-arg " "))
920 " " 955 " "
921 (shell-quote-argument ")")) 956 (shell-quote-argument ")"))
922 dir 957 (shell-quote-argument dir)
923 (xref--find-ignores-arguments ignores dir))) 958 (xref--find-ignores-arguments ignores dir)))
924 959
925(defun xref--find-ignores-arguments (ignores dir) 960(defun xref--find-ignores-arguments (ignores dir)
926 "Convert IGNORES and DIR to a list of arguments for 'find'. 961 "Convert IGNORES and DIR to a list of arguments for 'find'.
927IGNORES is a list of glob patterns. DIR is an absolute 962IGNORES is a list of glob patterns. DIR is an absolute
928directory, used as the root of the ignore globs." 963directory, used as the root of the ignore globs."
929 ;; `shell-quote-argument' quotes the tilde as well.
930 (cl-assert (not (string-match-p "\\`~" dir))) 964 (cl-assert (not (string-match-p "\\`~" dir)))
931 (when ignores 965 (when ignores
932 (concat 966 (concat
@@ -1014,7 +1048,11 @@ directory, used as the root of the ignore globs."
1014 (syntax-propertize line-end) 1048 (syntax-propertize line-end)
1015 ;; FIXME: This results in several lines with the same 1049 ;; FIXME: This results in several lines with the same
1016 ;; summary. Solve with composite pattern? 1050 ;; summary. Solve with composite pattern?
1017 (while (re-search-forward regexp line-end t) 1051 (while (and
1052 ;; REGEXP might match an empty string. Or line.
1053 (or (null matches)
1054 (> (point) line-beg))
1055 (re-search-forward regexp line-end t))
1018 (let* ((beg-column (- (match-beginning 0) line-beg)) 1056 (let* ((beg-column (- (match-beginning 0) line-beg))
1019 (end-column (- (match-end 0) line-beg)) 1057 (end-column (- (match-end 0) line-beg))
1020 (loc (xref-make-file-location file line beg-column)) 1058 (loc (xref-make-file-location file line beg-column))