aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/progmodes/grep.el459
1 files changed, 274 insertions, 185 deletions
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index 6afa3f29348..e100910e8cf 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -35,7 +35,7 @@
35 35
36 36
37(defgroup grep nil 37(defgroup grep nil
38 "Run compiler as inferior of Emacs, parse error messages." 38 "Run grep as inferior of Emacs, parse error messages."
39 :group 'tools 39 :group 'tools
40 :group 'processes) 40 :group 'processes)
41 41
@@ -48,23 +48,6 @@
48 :version "22.1" 48 :version "22.1"
49 :group 'grep) 49 :group 'grep)
50 50
51(defcustom grep-auto-highlight t
52 "*Specify how many grep matches to highlight (and parse) initially.
53\(Highlighting applies to an grep match when the mouse is over it.)
54If this is a number N, all grep matches in the first N lines
55are highlighted and parsed as soon as they arrive in Emacs.
56If t, highlight and parse the whole grep output as soon as it arrives.
57If nil, don't highlight or parse any of the grep buffer until you try to
58move to the error messages.
59
60Those grep matches which are not parsed and highlighted initially
61will be parsed and highlighted as soon as you try to move to them."
62 :type '(choice (const :tag "All" t)
63 (const :tag "None" nil)
64 (integer :tag "First N lines"))
65 :version "22.1"
66 :group 'grep)
67
68(defcustom grep-highlight-matches 'auto-detect 51(defcustom grep-highlight-matches 'auto-detect
69 "If t, use special markers to highlight grep matches. 52 "If t, use special markers to highlight grep matches.
70 53
@@ -108,6 +91,20 @@ call that function before using this variable in your program."
108 (const :tag "Not Set" nil)) 91 (const :tag "Not Set" nil))
109 :group 'grep) 92 :group 'grep)
110 93
94(defcustom grep-template nil
95 "The default command to run for \\[lgrep].
96The default value of this variable is set up by `grep-compute-defaults';
97call that function before using this variable in your program.
98The following place holders should be present in the string:
99 <C> - place to put -i if case insensitive grep.
100 <F> - file names and wildcards to search.
101 <R> - the regular expression searched for.
102 <N> - place to insert null-device."
103 :type '(choice string
104 (const :tag "Not Set" nil))
105 :version "22.1"
106 :group 'grep)
107
111(defcustom grep-use-null-device 'auto-detect 108(defcustom grep-use-null-device 'auto-detect
112 "If t, append the value of `null-device' to `grep' commands. 109 "If t, append the value of `null-device' to `grep' commands.
113This is done to ensure that the output of grep includes the filename of 110This is done to ensure that the output of grep includes the filename of
@@ -130,8 +127,8 @@ call that function before using this variable in your program."
130 (const :tag "Not Set" nil)) 127 (const :tag "Not Set" nil))
131 :group 'grep) 128 :group 'grep)
132 129
133(defcustom grep-tree-command nil 130(defcustom grep-find-template nil
134 "The default find command for \\[grep-tree]. 131 "The default command to run for \\[rgrep].
135The default value of this variable is set up by `grep-compute-defaults'; 132The default value of this variable is set up by `grep-compute-defaults';
136call that function before using this variable in your program. 133call that function before using this variable in your program.
137The following place holders should be present in the string: 134The following place holders should be present in the string:
@@ -145,27 +142,22 @@ The following place holders should be present in the string:
145 :version "22.1" 142 :version "22.1"
146 :group 'grep) 143 :group 'grep)
147 144
148(defcustom grep-tree-files-aliases '( 145(defcustom grep-files-aliases '(
146 ("el" . "*.el")
149 ("ch" . "*.[ch]") 147 ("ch" . "*.[ch]")
150 ("c" . "*.c") 148 ("c" . "*.c")
151 ("h" . "*.h") 149 ("h" . "*.h")
152 ("m" . "[Mm]akefile*")
153 ("asm" . "*.[sS]") 150 ("asm" . "*.[sS]")
154 ("all" . "*") 151 ("m" . "[Mm]akefile*")
155 ("el" . "*.el") 152 ("l" . "[Cc]hange[Ll]og*")
156 ) 153 )
157 "*Alist of aliases for the FILES argument to `grep-tree'." 154 "*Alist of aliases for the FILES argument to `lgrep' and `rgrep'."
158 :type 'alist 155 :type 'alist
159 :group 'grep) 156 :group 'grep)
160 157
161(defcustom grep-tree-ignore-case t 158(defcustom grep-find-ignored-directories '("CVS" ".hg" "{arch}")
162 "*If non-nil, `grep-tree' ignores case in matches." 159 "*List of names of sub-directories which `rgrep' shall not recurse into."
163 :type 'boolean 160 :type '(repeat string)
164 :group 'grep)
165
166(defcustom grep-tree-ignore-CVS-directories t
167 "*If non-nil, `grep-tree' does no recurse into CVS directories."
168 :type 'boolean
169 :group 'grep) 161 :group 'grep)
170 162
171(defcustom grep-error-screen-columns nil 163(defcustom grep-error-screen-columns nil
@@ -208,6 +200,8 @@ See `compilation-error-screen-columns'"
208 '("Compile..." . compile)) 200 '("Compile..." . compile))
209 (define-key map [menu-bar grep compilation-grep] 201 (define-key map [menu-bar grep compilation-grep]
210 '("Another grep..." . grep)) 202 '("Another grep..." . grep))
203 (define-key map [menu-bar grep compilation-grep-find]
204 '("Recursive grep..." . grep-find))
211 (define-key map [menu-bar grep compilation-recompile] 205 (define-key map [menu-bar grep compilation-recompile]
212 '("Repeat grep" . recompile)) 206 '("Repeat grep" . recompile))
213 (define-key map [menu-bar grep compilation-separator2] 207 (define-key map [menu-bar grep compilation-separator2]
@@ -353,6 +347,11 @@ This variable's value takes effect when `grep-compute-defaults' is called.")
353;;;###autoload 347;;;###autoload
354(defvar grep-find-history nil) 348(defvar grep-find-history nil)
355 349
350;; History of lgrep and rgrep regexp and files args.
351(defvar grep-regexp-history nil)
352(defvar grep-files-history '("ch" "el"))
353
354
356;;;###autoload 355;;;###autoload
357(defun grep-process-setup () 356(defun grep-process-setup ()
358 "Setup compilation variables and buffer for `grep'. 357 "Setup compilation variables and buffer for `grep'.
@@ -378,6 +377,12 @@ Set up `compilation-exit-message-function' and run `grep-setup-hook'."
378 (cons msg code)))) 377 (cons msg code))))
379 (run-hooks 'grep-setup-hook)) 378 (run-hooks 'grep-setup-hook))
380 379
380(defun grep-probe (command args &optional func result)
381 (equal (condition-case nil
382 (apply (or func 'call-process) command args)
383 (error nil))
384 (or result 0)))
385
381;;;###autoload 386;;;###autoload
382(defun grep-compute-defaults () 387(defun grep-compute-defaults ()
383 (unless (or (not grep-use-null-device) (eq grep-use-null-device t)) 388 (unless (or (not grep-use-null-device) (eq grep-use-null-device t))
@@ -385,73 +390,67 @@ Set up `compilation-exit-message-function' and run `grep-setup-hook'."
385 (with-temp-buffer 390 (with-temp-buffer
386 (let ((hello-file (expand-file-name "HELLO" data-directory))) 391 (let ((hello-file (expand-file-name "HELLO" data-directory)))
387 (not 392 (not
388 (and (equal (condition-case nil 393 (and (if grep-command
389 (if grep-command 394 ;; `grep-command' is already set, so
390 ;; `grep-command' is already set, so 395 ;; use that for testing.
391 ;; use that for testing. 396 (grep-probe grep-command
392 (call-process-shell-command 397 `(nil t nil "^English" ,hello-file)
393 grep-command nil t nil 398 #'call-process-shell-command)
394 "^English" hello-file) 399 ;; otherwise use `grep-program'
395 ;; otherwise use `grep-program' 400 (grep-probe grep-program
396 (call-process grep-program nil t nil 401 `(nil t nil "-nH" "^English" ,hello-file)))
397 "-nH" "^English" hello-file))
398 (error nil))
399 0)
400 (progn 402 (progn
401 (goto-char (point-min)) 403 (goto-char (point-min))
402 (looking-at 404 (looking-at
403 (concat (regexp-quote hello-file) 405 (concat (regexp-quote hello-file)
404 ":[0-9]+:English"))))))))) 406 ":[0-9]+:English")))))))))
405 (unless grep-command 407 (unless (and grep-command grep-find-command
406 (setq grep-command 408 grep-template grep-find-template)
407 (let ((required-options (if grep-use-null-device "-n" "-nH"))) 409 (let ((grep-options
408 (if (equal (condition-case nil ; in case "grep" isn't in exec-path 410 (concat (if grep-use-null-device "-n" "-nH")
409 (call-process grep-program nil nil nil 411 (if (grep-probe grep-program
410 "-e" "foo" null-device) 412 `(nil nil nil "-e" "foo" ,null-device)
411 (error nil)) 413 nil 1)
412 1) 414 " -e"))))
413 (format "%s %s -e " grep-program required-options) 415 (unless grep-command
414 (format "%s %s " grep-program required-options))))) 416 (setq grep-command
415 (unless grep-find-use-xargs 417 (format "%s %s " grep-program grep-options)))
416 (setq grep-find-use-xargs 418 (unless grep-template
417 (if (and 419 (setq grep-template
418 (equal (call-process "find" nil nil nil 420 (format "%s <C> %s <R> <F>" grep-program grep-options)))
419 null-device "-print0") 421 (unless grep-find-use-xargs
420 0) 422 (setq grep-find-use-xargs
421 (equal (call-process "xargs" nil nil nil 423 (if (and
422 "-0" "-e" "echo") 424 (grep-probe find-program `(nil nil nil ,null-device "-print0"))
423 0)) 425 (grep-probe "xargs" `(nil nil nil "-0" "-e" "echo")))
424 'gnu))) 426 'gnu)))
425 (unless grep-find-command 427 (unless grep-find-command
426 (setq grep-find-command 428 (setq grep-find-command
427 (cond ((eq grep-find-use-xargs 'gnu) 429 (cond ((eq grep-find-use-xargs 'gnu)
428 (format "%s . -type f -print0 | xargs -0 -e %s" 430 (format "%s . -type f -print0 | xargs -0 -e %s"
429 find-program grep-command)) 431 find-program grep-command))
430 (grep-find-use-xargs 432 (grep-find-use-xargs
431 (format "%s . -type f -print | xargs %s" 433 (format "%s . -type f -print | xargs %s"
432 find-program grep-command)) 434 find-program grep-command))
433 (t (cons (format "%s . -type f -exec %s {} %s \\;" 435 (t (cons (format "%s . -type f -exec %s {} %s \\;"
434 find-program grep-command null-device) 436 find-program grep-command null-device)
435 (+ 22 (length grep-command))))))) 437 (+ 22 (length grep-command)))))))
436 (unless grep-tree-command 438 (unless grep-find-template
437 (setq grep-tree-command 439 (setq grep-find-template
438 (let* ((glen (length grep-program)) 440 (let ((gcmd (format "%s <C> %s <R>"
439 (gcmd (concat grep-program " <C>" (substring grep-command glen)))) 441 grep-program grep-options)))
440 (cond ((eq grep-find-use-xargs 'gnu) 442 (cond ((eq grep-find-use-xargs 'gnu)
441 (format "%s <D> <X> -type f <F> -print0 | xargs -0 -e %s <R>" 443 (format "%s . <X> -type f <F> -print0 | xargs -0 -e %s"
442 find-program gcmd)) 444 find-program gcmd))
443 (grep-find-use-xargs 445 (grep-find-use-xargs
444 (format "%s <D> <X> -type f <F> -print | xargs %s <R>" 446 (format "%s . <X> -type f <F> -print | xargs %s"
445 find-program gcmd)) 447 find-program gcmd))
446 (t (format "%s <D> <X> -type f <F> -exec %s <R> {} %s \\;" 448 (t (format "%s . <X> -type f <F> -exec %s {} %s \\;"
447 find-program gcmd null-device)))))) 449 find-program gcmd null-device))))))))
448 (unless (or (not grep-highlight-matches) (eq grep-highlight-matches t)) 450 (unless (or (not grep-highlight-matches) (eq grep-highlight-matches t))
449 (setq grep-highlight-matches 451 (setq grep-highlight-matches
450 (with-temp-buffer 452 (with-temp-buffer
451 (and (equal (condition-case nil 453 (and (grep-probe grep-program '(nil t nil "--help"))
452 (call-process grep-program nil t nil "--help")
453 (error nil))
454 0)
455 (progn 454 (progn
456 (goto-char (point-min)) 455 (goto-char (point-min))
457 (search-forward "--color" nil t)) 456 (search-forward "--color" nil t))
@@ -487,8 +486,22 @@ Set up `compilation-exit-message-function' and run `grep-setup-hook'."
487 (file-name-extension buffer-file-name)))) 486 (file-name-extension buffer-file-name))))
488 (replace-match tag-default t t grep-default 1)))) 487 (replace-match tag-default t t grep-default 1))))
489 488
489
490;;;###autoload 490;;;###autoload
491(defun grep (command-args &optional highlight-regexp) 491(define-compilation-mode grep-mode "Grep"
492 "Sets `grep-last-buffer' and `compilation-window-height'."
493 (setq grep-last-buffer (current-buffer))
494 (set (make-local-variable 'compilation-error-face)
495 grep-hit-face)
496 (set (make-local-variable 'compilation-error-regexp-alist)
497 grep-regexp-alist)
498 (set (make-local-variable 'compilation-process-setup-function)
499 'grep-process-setup)
500 (set (make-local-variable 'compilation-disable-input) t))
501
502
503;;;###autoload
504(defun grep (command-args)
492 "Run grep, with user-specified args, and collect output in a buffer. 505 "Run grep, with user-specified args, and collect output in a buffer.
493While grep runs asynchronously, you can use \\[next-error] (M-x next-error), 506While grep runs asynchronously, you can use \\[next-error] (M-x next-error),
494or \\<grep-mode-map>\\[compile-goto-error] in the grep \ 507or \\<grep-mode-map>\\[compile-goto-error] in the grep \
@@ -501,15 +514,10 @@ easily repeat a grep command.
501A prefix argument says to default the argument based upon the current 514A prefix argument says to default the argument based upon the current
502tag the cursor is over, substituting it into the last grep command 515tag the cursor is over, substituting it into the last grep command
503in the grep command history (or into `grep-command' 516in the grep command history (or into `grep-command'
504if that history list is empty). 517if that history list is empty)."
505
506If specified, optional second arg HIGHLIGHT-REGEXP is the regexp to
507temporarily highlight in visited source lines."
508 (interactive 518 (interactive
509 (progn 519 (progn
510 (unless (and grep-command 520 (grep-compute-defaults)
511 (or (not grep-use-null-device) (eq grep-use-null-device t)))
512 (grep-compute-defaults))
513 (let ((default (grep-default-command))) 521 (let ((default (grep-default-command)))
514 (list (read-from-minibuffer "Run grep (like this): " 522 (list (read-from-minibuffer "Run grep (like this): "
515 (if current-prefix-arg 523 (if current-prefix-arg
@@ -522,19 +530,8 @@ temporarily highlight in visited source lines."
522 (compilation-start (if (and grep-use-null-device null-device) 530 (compilation-start (if (and grep-use-null-device null-device)
523 (concat command-args " " null-device) 531 (concat command-args " " null-device)
524 command-args) 532 command-args)
525 'grep-mode nil highlight-regexp)) 533 'grep-mode))
526 534
527;;;###autoload
528(define-compilation-mode grep-mode "Grep"
529 "Sets `grep-last-buffer' and `compilation-window-height'."
530 (setq grep-last-buffer (current-buffer))
531 (set (make-local-variable 'compilation-error-face)
532 grep-hit-face)
533 (set (make-local-variable 'compilation-error-regexp-alist)
534 grep-regexp-alist)
535 (set (make-local-variable 'compilation-process-setup-function)
536 'grep-process-setup)
537 (set (make-local-variable 'compilation-disable-input) t))
538 535
539;;;###autoload 536;;;###autoload
540(defun grep-find (command-args) 537(defun grep-find (command-args)
@@ -547,9 +544,7 @@ This command uses a special history list for its arguments, so you can
547easily repeat a find command." 544easily repeat a find command."
548 (interactive 545 (interactive
549 (progn 546 (progn
550 (unless (and grep-command 547 (grep-compute-defaults)
551 (or (not grep-use-null-device) (eq grep-use-null-device t)))
552 (grep-compute-defaults))
553 (if grep-find-command 548 (if grep-find-command
554 (list (read-from-minibuffer "Run find (like this): " 549 (list (read-from-minibuffer "Run find (like this): "
555 grep-find-command nil nil 550 grep-find-command nil nil
@@ -565,84 +560,178 @@ easily repeat a find command."
565;;;###autoload 560;;;###autoload
566(defalias 'find-grep 'grep-find) 561(defalias 'find-grep 'grep-find)
567 562
568(defun grep-expand-command-macros (command &optional regexp files dir excl case-fold) 563
569 "Patch grep COMMAND replacing <D>, etc." 564;; User-friendly interactive API.
570 (setq command 565
571 (replace-regexp-in-string "<D>" 566(defconst grep-expand-keywords
572 (or dir ".") command t t)) 567 '(("<C>" . (and cf (isearch-no-upper-case-p regexp t) "-i"))
573 (setq command 568 ("<D>" . dir)
574 (replace-regexp-in-string "<X>" 569 ("<F>" . files)
575 (or excl "") command t t)) 570 ("<N>" . null-device)
576 (setq command 571 ("<X>" . excl)
577 (replace-regexp-in-string "<F>" 572 ("<R>" . (shell-quote-argument (or regexp ""))))
578 (or files "") command t t)) 573 "List of substitutions performed by `grep-expand-template'.
579 (setq command 574If car of an element matches, the cdr is evalled in to get the
580 (replace-regexp-in-string "<C>" 575substitution string. Note dynamic scoping of variables.")
581 (if case-fold "-i" "") command t t)) 576
582 (setq command 577(defun grep-expand-template (template &optional regexp files dir excl)
583 (replace-regexp-in-string "<R>" 578 "Patch grep COMMAND string replacing <C>, <D>, <F>, <R>, and <X>."
584 (or regexp "") command t t)) 579 (let ((command template)
585 command) 580 (cf case-fold-search)
586 581 (case-fold-search nil))
587(defvar grep-tree-last-regexp "") 582 (dolist (kw grep-expand-keywords command)
588(defvar grep-tree-last-files (car (car grep-tree-files-aliases))) 583 (if (string-match (car kw) command)
584 (setq command (replace-match (or (eval (cdr kw)) "")
585 t t command))))))
586
587(defun grep-read-regexp ()
588 "Read regexp arg for interactive grep."
589 (let ((default
590 (or (funcall (or find-tag-default-function
591 (get major-mode 'find-tag-default-function)
592 'find-tag-default))
593 "")))
594 (read-string
595 (concat "Search for"
596 (if (and default (> (length default) 0))
597 (format " (default %s): " default) ": "))
598 nil 'grep-regexp-history default)))
599
600(defun grep-read-files (regexp)
601 "Read files arg for interactive grep."
602 (let* ((default
603 (or (and (stringp (buffer-file-name))
604 (let ((fn (file-name-nondirectory (buffer-file-name)))
605 (aliases grep-files-aliases)
606 alias)
607 (while aliases
608 (setq alias (car aliases)
609 aliases (cdr aliases))
610 (if (string-match (wildcard-to-regexp (cdr alias)) fn)
611 (setq aliases nil)
612 (setq alias nil)))
613 (cdr alias)))
614 (car grep-files-history)))
615 (files (read-string
616 (concat "Search for \"" regexp
617 "\" in files (default " default "): ")
618 nil 'grep-files-history default)))
619 (and files
620 (or (cdr (assoc files grep-files-aliases))
621 files))))
589 622
590;;;###autoload 623;;;###autoload
591(defun grep-tree (regexp files dir &optional subdirs) 624(defun lgrep (regexp &optional files)
592 "Grep for REGEXP in FILES in directory tree rooted at DIR. 625 "Run grep, searching for REGEXP in FILES in current directory.
593Collect output in a buffer.
594Interactively, prompt separately for each search parameter.
595With prefix arg, reuse previous REGEXP.
596The search is limited to file names matching shell pattern FILES. 626The search is limited to file names matching shell pattern FILES.
597FILES may use abbreviations defined in `grep-tree-files-aliases', e.g. 627FILES may use abbreviations defined in `grep-files-aliases', e.g.
598entering `ch' is equivalent to `*.[ch]'. 628entering `ch' is equivalent to `*.[ch]'.
599 629
600While find runs asynchronously, you can use the \\[next-error] command 630With \\[universal-argument] prefix, allow user to edit the constructed
601to find the text that grep hits refer to. 631shell command line before it is executed.
632With two \\[universal-argument] prefixes, edit and run grep shell command.
602 633
603This command uses a special history list for its arguments, so you can 634Collect output in a buffer. While grep runs asynchronously, you
604easily repeat a find command. 635can use \\[next-error] (M-x next-error), or \\<grep-mode-map>\\[compile-goto-error]
636in the grep output buffer, to go to the lines where grep found matches.
605 637
606When used non-interactively, optional arg SUBDIRS limits the search to 638This command shares argument histories with \\[rgrep] and \\[grep]."
607those sub directories of DIR."
608 (interactive 639 (interactive
609 (let* ((regexp 640 (progn
610 (if current-prefix-arg 641 (grep-compute-defaults)
611 grep-tree-last-regexp 642 (cond
612 (let* ((default (current-word)) 643 ((and grep-command (equal current-prefix-arg '(16)))
613 (spec (read-string 644 (list (read-from-minibuffer "Run: " grep-command
614 (concat "Search for" 645 nil nil 'grep-history)
615 (if (and default (> (length default) 0)) 646 nil))
616 (format " (default %s): " default) ": "))))) 647 ((not grep-template)
617 (if (equal spec "") default spec)))) 648 (list nil
618 (files 649 (read-string "grep.el: No `grep-template' available. Press RET.")))
619 (read-string (concat "Search for \"" regexp "\" in files (default " grep-tree-last-files "): "))) 650 (t (let* ((regexp (grep-read-regexp))
620 (dir 651 (files (grep-read-files regexp)))
621 (read-directory-name "Base directory: " nil default-directory t))) 652 (list regexp files))))))
622 (list regexp files dir))) 653 (when (and (stringp regexp) (> (length regexp) 0))
623 (unless grep-tree-command 654 (let ((command regexp))
624 (grep-compute-defaults)) 655 (if (null files)
625 (unless (and (stringp files) (> (length files) 0)) 656 (if (string= command grep-command)
626 (setq files grep-tree-last-files)) 657 (setq command nil))
627 (when files 658 (setq command (grep-expand-template
628 (setq grep-tree-last-files files) 659 grep-template
629 (let ((mf (assoc files grep-tree-files-aliases))) 660 regexp
630 (if mf 661 files))
631 (setq files (cdr mf))))) 662 (when command
632 (let ((command-args (grep-expand-command-macros 663 (if (equal current-prefix-arg '(4))
633 grep-tree-command 664 (setq command
634 (setq grep-tree-last-regexp regexp) 665 (read-from-minibuffer "Confirm: "
635 (and files (concat "-name '" files "'")) 666 command nil nil 'grep-history))
636 (if subdirs 667 (push command grep-history))))
637 (if (stringp subdirs) 668 (when command
638 subdirs 669 ;; Setting process-setup-function makes exit-message-function work
639 (mapconcat 'identity subdirs " ")) 670 ;; even when async processes aren't supported.
640 nil) ;; we change default-directory to dir 671 (compilation-start (if (and grep-use-null-device null-device)
641 (and grep-tree-ignore-CVS-directories "-path '*/CVS' -prune -o ") 672 (concat command " " null-device)
642 grep-tree-ignore-case)) 673 command) 'grep-mode)))))
643 (default-directory (file-name-as-directory (expand-file-name dir))) 674
644 (null-device nil)) ; see grep 675
645 (grep command-args regexp))) 676;;;###autoload
677(defun rgrep (regexp &optional files dir)
678 "Recusively grep for REGEXP in FILES in directory tree rooted at DIR.
679The search is limited to file names matching shell pattern FILES.
680FILES may use abbreviations defined in `grep-files-aliases', e.g.
681entering `ch' is equivalent to `*.[ch]'.
682
683With \\[universal-argument] prefix, allow user to edit the constructed
684shell command line before it is executed.
685With two \\[universal-argument] prefixes, edit and run grep-find shell command.
686
687Collect output in a buffer. While find runs asynchronously, you
688can use \\[next-error] (M-x next-error), or \\<grep-mode-map>\\[compile-goto-error]
689in the grep output buffer, to go to the lines where grep found matches.
690
691This command shares argument histories with \\[lgrep] and \\[grep-find]."
692 (interactive
693 (progn
694 (grep-compute-defaults)
695 (cond
696 ((and grep-find-command (equal current-prefix-arg '(16)))
697 (list (read-from-minibuffer "Run: " grep-find-command
698 nil nil 'grep-find-history)
699 nil))
700 ((not grep-find-template)
701 (list nil nil
702 (read-string "grep.el: No `grep-find-template' available. Press RET.")))
703 (t (let* ((regexp (grep-read-regexp))
704 (files (grep-read-files regexp))
705 (dir (read-directory-name "Base directory: "
706 nil default-directory t)))
707 (list regexp files dir))))))
708 (when (and (stringp regexp) (> (length regexp) 0))
709 (if (null files)
710 (if (not (string= regexp grep-find-command))
711 (compilation-start regexp 'grep-mode))
712 (let* ((default-directory (file-name-as-directory (expand-file-name dir)))
713 (command (grep-expand-template
714 grep-find-template
715 regexp
716 (concat "\\( -name "
717 (mapconcat #'shell-quote-argument
718 (split-string files)
719 " -o -name ")
720 " \\)")
721 default-directory
722 (and grep-find-ignored-directories
723 (concat "\\( -path '*/"
724 (mapconcat #'identity
725 grep-find-ignored-directories
726 "' -o -path '*/")
727 "' \\) -prune -o ")))))
728 (when command
729 (if current-prefix-arg
730 (setq command
731 (read-from-minibuffer "Confirm: "
732 command nil nil 'grep-find-history))
733 (push command grep-find-history))
734 (compilation-start command 'grep-mode))))))
646 735
647 736
648(provide 'grep) 737(provide 'grep)