diff options
| author | Paul Eggert | 2016-05-05 23:11:11 -0700 |
|---|---|---|
| committer | Paul Eggert | 2016-05-05 23:11:11 -0700 |
| commit | 89ce83b20249dfb4e45f09dfdddf4c4b66d82968 (patch) | |
| tree | 3d75245a5514df2ad7b17ae6d56727b9629846a9 /lisp/progmodes | |
| parent | d546ed13b04521308ef7ec8e7e5b68e03f1bbb38 (diff) | |
| parent | 50650cb6887d99b01eeb1e686fc1f695c2a0c64a (diff) | |
| download | emacs-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.el | 5 | ||||
| -rw-r--r-- | lisp/progmodes/etags.el | 5 | ||||
| -rw-r--r-- | lisp/progmodes/project.el | 3 | ||||
| -rw-r--r-- | lisp/progmodes/xref.el | 146 |
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'. |
| 927 | IGNORES is a list of glob patterns. DIR is an absolute | 962 | IGNORES is a list of glob patterns. DIR is an absolute |
| 928 | directory, used as the root of the ignore globs." | 963 | directory, 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)) |