aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Gutov2016-01-18 22:11:46 +0300
committerDmitry Gutov2016-01-18 22:14:17 +0300
commit36b0729ce765c132e04586be0e2deca405b4c313 (patch)
tree73bb61012ea69e263966e9b743b8544c8a4c71c5
parent5b62b980f9d89758211959486681dcb8d416ef84 (diff)
downloademacs-36b0729ce765c132e04586be0e2deca405b4c313.tar.gz
emacs-36b0729ce765c132e04586be0e2deca405b4c313.zip
Add xref-based replacements for Dired search commands
* lisp/dired-aux.el (dired-do-find-regexp) (dired-do-find-regexp-and-replace): New commands. http://lists.gnu.org/archive/html/emacs-devel/2016-01/msg00864.html * lisp/dired.el (dired-mode-map): Change bindings for `A' and `Q' to the new commands. * lisp/progmodes/xref.el (xref-query-replace) (xref-collect-matches): Add progress reporters. (xref--find-ignores-arguments): Return nil for zero ignores. (xref--show-xrefs): Add an optional argument. (xref-collect-matches): Drop the assert. 'find' accepts a regular file in place of directory argument, too.
-rw-r--r--lisp/dired-aux.el35
-rw-r--r--lisp/dired.el16
-rw-r--r--lisp/progmodes/xref.el65
3 files changed, 91 insertions, 25 deletions
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index a8c40b2835c..831278cb762 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -2713,6 +2713,41 @@ with the command \\[tags-loop-continue]."
2713 (tags-query-replace from to delimited 2713 (tags-query-replace from to delimited
2714 '(dired-get-marked-files nil nil 'dired-nondirectory-p))) 2714 '(dired-get-marked-files nil nil 'dired-nondirectory-p)))
2715 2715
2716(declare-function xref--show-xrefs "xref")
2717(declare-function xref-query-replace "xref")
2718
2719;;;###autoload
2720(defun dired-do-find-regexp (regexp)
2721 "Find all matches for REGEXP in all marked files, recursively."
2722 (interactive "sSearch marked files (regexp): ")
2723 (require 'grep)
2724 (defvar grep-find-ignored-files)
2725 (let* ((files (dired-get-marked-files))
2726 (ignores (nconc (mapcar
2727 (lambda (s) (concat s "/"))
2728 vc-directory-exclusion-list)
2729 grep-find-ignored-files))
2730 (xrefs (cl-mapcan
2731 (lambda (file)
2732 (xref-collect-matches regexp "*" file
2733 (and (file-directory-p file)
2734 ignores)))
2735 files)))
2736 (unless xrefs
2737 (user-error "No matches for: %s" regexp))
2738 (xref--show-xrefs xrefs nil t)))
2739
2740;;;###autoload
2741(defun dired-do-find-regexp-and-replace (from to)
2742 "Replace matches of FROM with TO, in all marked files, recursively."
2743 (interactive
2744 (let ((common
2745 (query-replace-read-args
2746 "Query replace regexp in marked files" t t)))
2747 (list (nth 0 common) (nth 1 common))))
2748 (with-current-buffer (dired-do-find-regexp from)
2749 (xref-query-replace from to)))
2750
2716(defun dired-nondirectory-p (file) 2751(defun dired-nondirectory-p (file)
2717 (not (file-directory-p file))) 2752 (not (file-directory-p file)))
2718 2753
diff --git a/lisp/dired.el b/lisp/dired.el
index d7bc318d17b..0ca14b30e2c 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -1450,7 +1450,7 @@ Do so according to the former subdir alist OLD-SUBDIR-ALIST."
1450 (define-key map "." 'dired-clean-directory) 1450 (define-key map "." 'dired-clean-directory)
1451 (define-key map "~" 'dired-flag-backup-files) 1451 (define-key map "~" 'dired-flag-backup-files)
1452 ;; Upper case keys (except !) for operating on the marked files 1452 ;; Upper case keys (except !) for operating on the marked files
1453 (define-key map "A" 'dired-do-search) 1453 (define-key map "A" 'dired-do-find-regexp)
1454 (define-key map "C" 'dired-do-copy) 1454 (define-key map "C" 'dired-do-copy)
1455 (define-key map "B" 'dired-do-byte-compile) 1455 (define-key map "B" 'dired-do-byte-compile)
1456 (define-key map "D" 'dired-do-delete) 1456 (define-key map "D" 'dired-do-delete)
@@ -1460,7 +1460,7 @@ Do so according to the former subdir alist OLD-SUBDIR-ALIST."
1460 (define-key map "M" 'dired-do-chmod) 1460 (define-key map "M" 'dired-do-chmod)
1461 (define-key map "O" 'dired-do-chown) 1461 (define-key map "O" 'dired-do-chown)
1462 (define-key map "P" 'dired-do-print) 1462 (define-key map "P" 'dired-do-print)
1463 (define-key map "Q" 'dired-do-query-replace-regexp) 1463 (define-key map "Q" 'dired-do-find-regexp-and-replace)
1464 (define-key map "R" 'dired-do-rename) 1464 (define-key map "R" 'dired-do-rename)
1465 (define-key map "S" 'dired-do-symlink) 1465 (define-key map "S" 'dired-do-symlink)
1466 (define-key map "T" 'dired-do-touch) 1466 (define-key map "T" 'dired-do-touch)
@@ -3905,7 +3905,7 @@ Ask means pop up a menu for the user to select one of copy, move or link."
3905 3905
3906;;; Start of automatically extracted autoloads. 3906;;; Start of automatically extracted autoloads.
3907 3907
3908;;;### (autoloads nil "dired-aux" "dired-aux.el" "7b7e39be8bcaf5f35b2735c3f5635f40") 3908;;;### (autoloads nil "dired-aux" "dired-aux.el" "ab7321f16a90251f12f0031ddd6a710c")
3909;;; Generated autoloads from dired-aux.el 3909;;; Generated autoloads from dired-aux.el
3910 3910
3911(autoload 'dired-diff "dired-aux" "\ 3911(autoload 'dired-diff "dired-aux" "\
@@ -4408,6 +4408,16 @@ with the command \\[tags-loop-continue].
4408 4408
4409\(fn FROM TO &optional DELIMITED)" t nil) 4409\(fn FROM TO &optional DELIMITED)" t nil)
4410 4410
4411(autoload 'dired-do-find-regexp "dired-aux" "\
4412Find all matches for REGEXP in all marked files, recursively.
4413
4414\(fn REGEXP)" t nil)
4415
4416(autoload 'dired-do-find-regexp-and-replace "dired-aux" "\
4417Replace matches of FROM with TO, in all marked files, recursively.
4418
4419\(fn FROM TO)" t nil)
4420
4411(autoload 'dired-show-file-type "dired-aux" "\ 4421(autoload 'dired-show-file-type "dired-aux" "\
4412Print the type of FILE, according to the `file' command. 4422Print the type of FILE, according to the `file' command.
4413If you give a prefix to this command, and FILE is a symbolic 4423If you give a prefix to this command, and FILE is a symbolic
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 6220b4cdc92..2bccd857576 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -511,11 +511,18 @@ references displayed in the current *xref* buffer."
511 (let ((fr (read-regexp "Xref query-replace (regexp)" ".*"))) 511 (let ((fr (read-regexp "Xref query-replace (regexp)" ".*")))
512 (list fr 512 (list fr
513 (read-regexp (format "Xref query-replace (regexp) %s with: " fr))))) 513 (read-regexp (format "Xref query-replace (regexp) %s with: " fr)))))
514 (let (pairs item) 514 (let ((reporter (make-progress-reporter (format "Saving search results...")
515 0 (line-number-at-pos (point-max))))
516 (counter 0)
517 pairs item)
515 (unwind-protect 518 (unwind-protect
516 (progn 519 (progn
517 (save-excursion 520 (save-excursion
518 (goto-char (point-min)) 521 (goto-char (point-min))
522 ;; TODO: This list should be computed on-demand instead.
523 ;; As long as the UI just iterates through matches one by
524 ;; one, there's no need to compute them all in advance.
525 ;; Then we can throw away the reporter.
519 (while (setq item (xref--search-property 'xref-item)) 526 (while (setq item (xref--search-property 'xref-item))
520 (when (xref-match-length item) 527 (when (xref-match-length item)
521 (save-excursion 528 (save-excursion
@@ -535,9 +542,11 @@ references displayed in the current *xref* buffer."
535 (line-end-position)) 542 (line-end-position))
536 (xref-item-summary item)) 543 (xref-item-summary item))
537 (user-error "Search results out of date")) 544 (user-error "Search results out of date"))
545 (progress-reporter-update reporter (cl-incf counter))
538 (push (cons beg end) pairs))))) 546 (push (cons beg end) pairs)))))
539 (setq pairs (nreverse pairs))) 547 (setq pairs (nreverse pairs)))
540 (unless pairs (user-error "No suitable matches here")) 548 (unless pairs (user-error "No suitable matches here"))
549 (progress-reporter-done reporter)
541 (xref--query-replace-1 from to pairs)) 550 (xref--query-replace-1 from to pairs))
542 (dolist (pair pairs) 551 (dolist (pair pairs)
543 (move-marker (car pair) nil) 552 (move-marker (car pair) nil)
@@ -713,9 +722,9 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)."
713 722
714(defvar xref--read-pattern-history nil) 723(defvar xref--read-pattern-history nil)
715 724
716(defun xref--show-xrefs (xrefs window) 725(defun xref--show-xrefs (xrefs window &optional always-show-list)
717 (cond 726 (cond
718 ((not (cdr xrefs)) 727 ((and (not (cdr xrefs)) (not always-show-list))
719 (xref-push-marker-stack) 728 (xref-push-marker-stack)
720 (xref--pop-to-location (car xrefs) window)) 729 (xref--pop-to-location (car xrefs) window))
721 (t 730 (t
@@ -866,11 +875,12 @@ tools are used, and when."
866 (mapc #'kill-buffer 875 (mapc #'kill-buffer
867 (cl-set-difference (buffer-list) orig-buffers))))) 876 (cl-set-difference (buffer-list) orig-buffers)))))
868 877
878;;;###autoload
869(defun xref-collect-matches (regexp files dir ignores) 879(defun xref-collect-matches (regexp files dir ignores)
870 "Collect matches for REGEXP inside FILES in DIR. 880 "Collect matches for REGEXP inside FILES in DIR.
871FILES is a string with glob patterns separated by spaces. 881FILES is a string with glob patterns separated by spaces.
872IGNORES is a list of glob patterns." 882IGNORES is a list of glob patterns."
873 (cl-assert (directory-name-p dir)) 883 ;; DIR can also be a regular file for now; let's not advertise that.
874 (require 'semantic/fw) 884 (require 'semantic/fw)
875 (grep-compute-defaults) 885 (grep-compute-defaults)
876 (defvar grep-find-template) 886 (defvar grep-find-template)
@@ -885,6 +895,8 @@ IGNORES is a list of glob patterns."
885 (orig-buffers (buffer-list)) 895 (orig-buffers (buffer-list))
886 (buf (get-buffer-create " *xref-grep*")) 896 (buf (get-buffer-create " *xref-grep*"))
887 (grep-re (caar grep-regexp-alist)) 897 (grep-re (caar grep-regexp-alist))
898 (counter 0)
899 reporter
888 hits) 900 hits)
889 (with-current-buffer buf 901 (with-current-buffer buf
890 (erase-buffer) 902 (erase-buffer)
@@ -894,9 +906,17 @@ IGNORES is a list of glob patterns."
894 (push (cons (string-to-number (match-string 2)) 906 (push (cons (string-to-number (match-string 2))
895 (match-string 1)) 907 (match-string 1))
896 hits))) 908 hits)))
909 (setq reporter (make-progress-reporter
910 (format "Collecting search results...")
911 0 (length hits)))
897 (unwind-protect 912 (unwind-protect
898 (cl-mapcan (lambda (hit) (xref--collect-matches hit regexp)) 913 (cl-mapcan (lambda (hit)
914 (prog1
915 (progress-reporter-update reporter counter)
916 (cl-incf counter))
917 (xref--collect-matches hit regexp))
899 (nreverse hits)) 918 (nreverse hits))
919 (progress-reporter-done reporter)
900 ;; TODO: Same as above. 920 ;; TODO: Same as above.
901 (mapc #'kill-buffer 921 (mapc #'kill-buffer
902 (cl-set-difference (buffer-list) orig-buffers))))) 922 (cl-set-difference (buffer-list) orig-buffers)))))
@@ -922,23 +942,24 @@ IGNORES is a list of glob patterns."
922(defun xref--find-ignores-arguments (ignores dir) 942(defun xref--find-ignores-arguments (ignores dir)
923 ;; `shell-quote-argument' quotes the tilde as well. 943 ;; `shell-quote-argument' quotes the tilde as well.
924 (cl-assert (not (string-match-p "\\`~" dir))) 944 (cl-assert (not (string-match-p "\\`~" dir)))
925 (concat 945 (when ignores
926 (shell-quote-argument "(") 946 (concat
927 " -path " 947 (shell-quote-argument "(")
928 (mapconcat 948 " -path "
929 (lambda (ignore) 949 (mapconcat
930 (when (string-match-p "/\\'" ignore) 950 (lambda (ignore)
931 (setq ignore (concat ignore "*"))) 951 (when (string-match-p "/\\'" ignore)
932 (if (string-match "\\`\\./" ignore) 952 (setq ignore (concat ignore "*")))
933 (setq ignore (replace-match dir t t ignore)) 953 (if (string-match "\\`\\./" ignore)
934 (unless (string-prefix-p "*" ignore) 954 (setq ignore (replace-match dir t t ignore))
935 (setq ignore (concat "*/" ignore)))) 955 (unless (string-prefix-p "*" ignore)
936 (shell-quote-argument ignore)) 956 (setq ignore (concat "*/" ignore))))
937 ignores 957 (shell-quote-argument ignore))
938 " -o -path ") 958 ignores
939 " " 959 " -o -path ")
940 (shell-quote-argument ")") 960 " "
941 " -prune -o ")) 961 (shell-quote-argument ")")
962 " -prune -o ")))
942 963
943(defun xref--regexp-to-extended (str) 964(defun xref--regexp-to-extended (str)
944 (replace-regexp-in-string 965 (replace-regexp-in-string