Fix file's header line.
[bpt/emacs.git] / lisp / progmodes / grep.el
CommitLineData
09e22417 1;;; grep.el --- run Grep as inferior of Emacs, parse match messages
318e2976 2
1bcd42e2 3;; Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
5ad24c0b 4;; 2001, 2002, 2004, 2005 Free Software Foundation, Inc.
318e2976
KS
5
6;; Author: Roland McGrath <roland@gnu.org>
7;; Maintainer: FSF
8;; Keywords: tools, processes
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
26
27;;; Commentary:
28
29;; This package provides the grep facilities documented in the Emacs
30;; user's manual.
31
32;;; Code:
33
34(require 'compile)
35
36(defgroup grep nil
37 "Run compiler as inferior of Emacs, parse error messages."
38 :group 'tools
39 :group 'processes)
40
41
42;;;###autoload
43(defcustom grep-window-height nil
44 "*Number of lines in a grep window. If nil, use `compilation-window-height'."
45 :type '(choice (const :tag "Default" nil)
46 integer)
bf247b6e 47 :version "22.1"
318e2976
KS
48 :group 'grep)
49
50(defcustom grep-auto-highlight t
51 "*Specify how many grep matches to highlight (and parse) initially.
52\(Highlighting applies to an grep match when the mouse is over it.)
53If this is a number N, all grep matches in the first N lines
54are highlighted and parsed as soon as they arrive in Emacs.
55If t, highlight and parse the whole grep output as soon as it arrives.
56If nil, don't highlight or parse any of the grep buffer until you try to
57move to the error messages.
58
59Those grep matches which are not parsed and highlighted initially
60will be parsed and highlighted as soon as you try to move to them."
61 :type '(choice (const :tag "All" t)
62 (const :tag "None" nil)
63 (integer :tag "First N lines"))
bf247b6e 64 :version "22.1"
318e2976
KS
65 :group 'grep)
66
00889cf9 67(defcustom grep-highlight-matches 'auto-detect
a58c94a2 68 "If t, use special markers to highlight grep matches.
277df088
JL
69
70Some grep programs are able to surround matches with special
71markers in grep output. Such markers can be used to highlight
72matches in grep mode.
73
74This option sets the environment variable GREP_COLOR to specify
75markers for highlighting and GREP_OPTIONS to add the --color
76option in front of any explicit grep options before starting
a58c94a2
JL
77the grep.
78
79The default value of this variable is set up by `grep-compute-defaults';
80call that function before using this variable in your program."
00889cf9
JL
81 :type '(choice (const :tag "Do not highlight matches with grep markers" nil)
82 (const :tag "Highlight matches with grep markers" t)
83 (other :tag "Not Set" auto-detect))
bf247b6e 84 :version "22.1"
277df088
JL
85 :group 'grep)
86
318e2976
KS
87(defcustom grep-scroll-output nil
88 "*Non-nil to scroll the *grep* buffer window as output appears.
89
90Setting it causes the grep commands to put point at the end of their
91output window so that the end of the output is always visible rather
92than the begining."
93 :type 'boolean
bf247b6e 94 :version "22.1"
318e2976
KS
95 :group 'grep)
96
9b19858e 97;;;###autoload
318e2976
KS
98(defcustom grep-command nil
99 "The default grep command for \\[grep].
100If the grep program used supports an option to always include file names
101in its output (such as the `-H' option to GNU grep), it's a good idea to
102include it when specifying `grep-command'.
103
104The default value of this variable is set up by `grep-compute-defaults';
105call that function before using this variable in your program."
106 :type '(choice string
107 (const :tag "Not Set" nil))
108 :group 'grep)
109
110(defcustom grep-use-null-device 'auto-detect
111 "If t, append the value of `null-device' to `grep' commands.
112This is done to ensure that the output of grep includes the filename of
113any match in the case where only a single file is searched, and is not
114necessary if the grep program used supports the `-H' option.
115
116The default value of this variable is set up by `grep-compute-defaults';
117call that function before using this variable in your program."
318e2976
KS
118 :type '(choice (const :tag "Do Not Append Null Device" nil)
119 (const :tag "Append Null Device" t)
120 (other :tag "Not Set" auto-detect))
121 :group 'grep)
122
9b19858e 123;;;###autoload
318e2976
KS
124(defcustom grep-find-command nil
125 "The default find command for \\[grep-find].
126The default value of this variable is set up by `grep-compute-defaults';
127call that function before using this variable in your program."
128 :type '(choice string
129 (const :tag "Not Set" nil))
130 :group 'grep)
131
132(defcustom grep-tree-command nil
133 "The default find command for \\[grep-tree].
134The default value of this variable is set up by `grep-compute-defaults';
135call that function before using this variable in your program.
136The following place holders should be present in the string:
137 <D> - base directory for find
138 <X> - find options to restrict or expand the directory list
139 <F> - find options to limit the files matched
140 <C> - place to put -i if case insensitive grep
141 <R> - the regular expression searched for."
142 :type '(choice string
143 (const :tag "Not Set" nil))
bf247b6e 144 :version "22.1"
318e2976
KS
145 :group 'grep)
146
147(defcustom grep-tree-files-aliases '(
148 ("ch" . "*.[ch]")
149 ("c" . "*.c")
150 ("h" . "*.h")
151 ("m" . "[Mm]akefile*")
152 ("asm" . "*.[sS]")
153 ("all" . "*")
154 ("el" . "*.el")
155 )
156 "*Alist of aliases for the FILES argument to `grep-tree'."
157 :type 'alist
158 :group 'grep)
159
160(defcustom grep-tree-ignore-case t
161 "*If non-nil, `grep-tree' ignores case in matches."
162 :type 'boolean
163 :group 'grep)
164
165(defcustom grep-tree-ignore-CVS-directories t
166 "*If non-nil, `grep-tree' does no recurse into CVS directories."
167 :type 'boolean
168 :group 'grep)
169
bb72b9d0
DP
170(defcustom grep-error-screen-columns nil
171 "*If non-nil, column numbers in grep hits are screen columns.
172See `compilation-error-screen-columns'"
173 :type '(choice (const :tag "Default" nil)
174 integer)
bf247b6e 175 :version "22.1"
bb72b9d0
DP
176 :group 'grep)
177
318e2976
KS
178;;;###autoload
179(defcustom grep-setup-hook nil
180 "List of hook functions run by `grep-process-setup' (see `run-hooks')."
181 :type 'hook
182 :group 'grep)
183
184(defvar grep-mode-map
185 (let ((map (cons 'keymap compilation-minor-mode-map)))
186 (define-key map " " 'scroll-up)
187 (define-key map "\^?" 'scroll-down)
0443d889 188 (define-key map "\C-c\C-f" 'next-error-follow-minor-mode)
318e2976 189
05218277
RS
190 ;; This is intolerable -- rms
191;;; (define-key map [remap next-line] 'compilation-next-error)
192;;; (define-key map [remap previous-line] 'compilation-previous-error)
318e2976
KS
193
194 (define-key map "\r" 'compile-goto-error) ;; ?
195 (define-key map "n" 'next-error-no-select)
196 (define-key map "p" 'previous-error-no-select)
197 (define-key map "{" 'compilation-previous-file)
198 (define-key map "}" 'compilation-next-file)
199 (define-key map "\t" 'compilation-next-file)
200
201 ;; Set up the menu-bar
202 (define-key map [menu-bar grep]
203 (cons "Grep" (make-sparse-keymap "Grep")))
204
205 (define-key map [menu-bar grep compilation-kill-compilation]
206 '("Kill Grep" . kill-compilation))
207 (define-key map [menu-bar grep compilation-separator2]
208 '("----" . nil))
209 (define-key map [menu-bar grep compilation-compile]
210 '("Compile..." . compile))
211 (define-key map [menu-bar grep compilation-grep]
212 '("Another grep" . grep))
213 (define-key map [menu-bar grep compilation-recompile]
214 '("Repeat grep" . recompile))
215 (define-key map [menu-bar grep compilation-separator2]
216 '("----" . nil))
217 (define-key map [menu-bar grep compilation-first-error]
218 '("First Match" . first-error))
219 (define-key map [menu-bar grep compilation-previous-error]
220 '("Previous Match" . previous-error))
221 (define-key map [menu-bar grep compilation-next-error]
222 '("Next Match" . next-error))
223 map)
224 "Keymap for grep buffers.
225`compilation-minor-mode-map' is a cdr of this.")
226
ab55f76f
SM
227(defalias 'kill-grep 'kill-compilation)
228
318e2976
KS
229;;;; TODO --- refine this!!
230
5f032b50
KS
231;;; (defcustom grep-use-compilation-buffer t
232;;; "When non-nil, grep specific commands update `compilation-last-buffer'.
233;;; This means that standard compile commands like \\[next-error] and \\[compile-goto-error]
234;;; can be used to navigate between grep matches (the default).
235;;; Otherwise, the grep specific commands like \\[grep-next-match] must
236;;; be used to navigate between grep matches."
237;;; :type 'boolean
238;;; :group 'grep)
318e2976
KS
239
240;; override compilation-last-buffer
241(defvar grep-last-buffer nil
242 "The most recent grep buffer.
243A grep buffer becomes most recent when its process is started
244or when it is used with \\[grep-next-match].
245Notice that using \\[next-error] or \\[compile-goto-error] modifies
246`complation-last-buffer' rather than `grep-last-buffer'.")
247
9b19858e 248;;;###autoload
318e2976 249(defvar grep-regexp-alist
bde94a7f
RS
250 ;; rms: I removed the code to match parens around the line number
251 ;; because it causes confusion and so we will find out if anyone needs it.
252 ;; It causes confusion with a file name that contains a number in parens.
253 '(("^\\(.+?\\)[: \t]+\
bb72b9d0 254\\([0-9]+\\)\\([.:]?\\)\\([0-9]+\\)?\
bde94a7f 255\\(?:-\\(?:\\([0-9]+\\)\\3\\)?\\.?\\([0-9]+\\)?\\)?[: \t]" 1 (2 . 5) (4 . 6))
e7eaabae 256 ("^\\(.+?\\)[:(]+\\([0-9]+\\)\\([:)]\\).*?\\(\033\\[01;41m\\)\\(.*?\\)\\(\033\\[00m\\(\033\\[K\\)?\\)"
277df088 257 1 2
1bcd42e2 258 ;; Calculate column positions (beg . end) of first grep match on a line
277df088
JL
259 ((lambda ()
260 (setq compilation-error-screen-columns nil)
261 (- (match-beginning 5) (match-end 3) 8))
262 .
1bcd42e2 263 (lambda () (- (match-end 5) (match-end 3) 8))))
ab55f76f 264 ("^Binary file \\(.+\\) matches$" 1 nil nil 1))
318e2976
KS
265 "Regexp used to match grep hits. See `compilation-error-regexp-alist'.")
266
ab55f76f
SM
267(defvar grep-error "grep hit"
268 "Message to print when no matches are found.")
269
270;; Reverse the colors because grep hits are not errors (though we jump there
271;; with `next-error'), and unreadable files can't be gone to.
272(defvar grep-hit-face compilation-info-face
273 "Face name to use for grep hits.")
274
275(defvar grep-error-face compilation-error-face
276 "Face name to use for grep error messages.")
277
f30c45e1
JL
278(defvar grep-match-face 'match
279 "Face name to use for grep matches.")
280
ab55f76f
SM
281(defvar grep-mode-font-lock-keywords
282 '(;; Command output lines.
283 ("^\\([A-Za-z_0-9/\.+-]+\\)[ \t]*:" 1 font-lock-function-name-face)
284 (": \\(.+\\): \\(?:Permission denied\\|No such \\(?:file or directory\\|device or address\\)\\)$"
285 1 grep-error-face)
286 ;; remove match from grep-regexp-alist before fontifying
287 ("^Grep finished \\(?:(\\(matches found\\))\\|with \\(no matches found\\)\\).*"
288 (0 '(face nil message nil help-echo nil mouse-face nil) t)
289 (1 grep-hit-face nil t)
290 (2 grep-error-face nil t))
291 ("^Grep \\(exited abnormally\\) with code \\([0-9]+\\).*"
292 (0 '(face nil message nil help-echo nil mouse-face nil) t)
293 (1 compilation-warning-face)
1bcd42e2
JL
294 (2 compilation-line-face))
295 ;; Highlight grep matches and delete markers
e7eaabae 296 ("\\(\033\\[01;41m\\)\\(.*?\\)\\(\033\\[00m\\(\033\\[K\\)?\\)"
5ad24c0b
LK
297 ;; Refontification does not work after the markers have been
298 ;; deleted. So we use the font-lock-face property here as Font
299 ;; Lock does not clear that.
300 (2 (list 'face nil 'font-lock-face grep-match-face))
1bcd42e2
JL
301 ((lambda (p))
302 (progn
303 ;; Delete markers with `replace-match' because it updates
304 ;; the match-data, whereas `delete-region' would render it obsolete.
305 (replace-match "" t t nil 3)
306 (replace-match "" t t nil 1)))))
ab55f76f
SM
307 "Additional things to highlight in grep output.
308This gets tacked on the end of the generated expressions.")
309
9b19858e 310;;;###autoload
318e2976
KS
311(defvar grep-program
312 ;; Currently zgrep has trouble. It runs egrep instead of grep,
313 ;; and it doesn't pass along long options right.
314 "grep"
315 ;; (if (equal (condition-case nil ; in case "zgrep" isn't in exec-path
316 ;; (call-process "zgrep" nil nil nil
317 ;; "foo" null-device)
318 ;; (error nil))
319 ;; 1)
320 ;; "zgrep"
321 ;; "grep")
322 "The default grep program for `grep-command' and `grep-find-command'.
323This variable's value takes effect when `grep-compute-defaults' is called.")
324
9b19858e 325;;;###autoload
318e2976
KS
326(defvar find-program "find"
327 "The default find program for `grep-find-command'.
328This variable's value takes effect when `grep-compute-defaults' is called.")
329
9b19858e 330;;;###autoload
318e2976
KS
331(defvar grep-find-use-xargs nil
332 "Whether \\[grep-find] uses the `xargs' utility by default.
333
334If nil, it uses `find -exec'; if `gnu', it uses `find -print0' and `xargs -0';
335if not nil and not `gnu', it uses `find -print' and `xargs'.
336
337This variable's value takes effect when `grep-compute-defaults' is called.")
338
339;; History of grep commands.
9b19858e 340;;;###autoload
318e2976 341(defvar grep-history nil)
9b19858e 342;;;###autoload
318e2976
KS
343(defvar grep-find-history nil)
344
9b19858e 345;;;###autoload
318e2976
KS
346(defun grep-process-setup ()
347 "Setup compilation variables and buffer for `grep'.
ab55f76f 348Set up `compilation-exit-message-function' and run `grep-setup-hook'."
a58c94a2
JL
349 (unless (or (not grep-highlight-matches) (eq grep-highlight-matches t))
350 (grep-compute-defaults))
351 (when (eq grep-highlight-matches t)
277df088
JL
352 ;; Modify `process-environment' locally bound in `compilation-start'
353 (setenv "GREP_OPTIONS" (concat (getenv "GREP_OPTIONS") " --color=always"))
354 (setenv "GREP_COLOR" "01;41"))
318e2976
KS
355 (set (make-local-variable 'compilation-exit-message-function)
356 (lambda (status code msg)
357 (if (eq status 'exit)
358 (cond ((zerop code)
359 '("finished (matches found)\n" . "matched"))
360 ((= code 1)
361 '("finished with no matches found\n" . "no match"))
362 (t
363 (cons msg code)))
364 (cons msg code))))
318e2976
KS
365 (run-hooks 'grep-setup-hook))
366
9b19858e 367;;;###autoload
318e2976
KS
368(defun grep-compute-defaults ()
369 (unless (or (not grep-use-null-device) (eq grep-use-null-device t))
370 (setq grep-use-null-device
371 (with-temp-buffer
372 (let ((hello-file (expand-file-name "HELLO" data-directory)))
373 (not
374 (and (equal (condition-case nil
375 (if grep-command
376 ;; `grep-command' is already set, so
377 ;; use that for testing.
378 (call-process-shell-command
379 grep-command nil t nil
380 "^English" hello-file)
381 ;; otherwise use `grep-program'
382 (call-process grep-program nil t nil
383 "-nH" "^English" hello-file))
384 (error nil))
385 0)
386 (progn
387 (goto-char (point-min))
388 (looking-at
389 (concat (regexp-quote hello-file)
390 ":[0-9]+:English")))))))))
391 (unless grep-command
392 (setq grep-command
393 (let ((required-options (if grep-use-null-device "-n" "-nH")))
394 (if (equal (condition-case nil ; in case "grep" isn't in exec-path
395 (call-process grep-program nil nil nil
396 "-e" "foo" null-device)
397 (error nil))
398 1)
399 (format "%s %s -e " grep-program required-options)
400 (format "%s %s " grep-program required-options)))))
401 (unless grep-find-use-xargs
402 (setq grep-find-use-xargs
403 (if (and
404 (equal (call-process "find" nil nil nil
405 null-device "-print0")
406 0)
407 (equal (call-process "xargs" nil nil nil
408 "-0" "-e" "echo")
409 0))
410 'gnu)))
411 (unless grep-find-command
412 (setq grep-find-command
24fa1cf1 413 (cond ((eq grep-find-use-xargs 'gnu)
318e2976
KS
414 (format "%s . -type f -print0 | xargs -0 -e %s"
415 find-program grep-command))
416 (grep-find-use-xargs
417 (format "%s . -type f -print | xargs %s"
418 find-program grep-command))
419 (t (cons (format "%s . -type f -exec %s {} %s \\;"
420 find-program grep-command null-device)
421 (+ 22 (length grep-command)))))))
422 (unless grep-tree-command
423 (setq grep-tree-command
424 (let* ((glen (length grep-program))
425 (gcmd (concat grep-program " <C>" (substring grep-command glen))))
426 (cond ((eq grep-find-use-xargs 'gnu)
427 (format "%s <D> <X> -type f <F> -print0 | xargs -0 -e %s <R>"
428 find-program gcmd))
429 (grep-find-use-xargs
430 (format "%s <D> <X> -type f <F> -print | xargs %s <R>"
431 find-program gcmd))
432 (t (format "%s <D> <X> -type f <F> -exec %s <R> {} %s \\;"
00889cf9
JL
433 find-program gcmd null-device))))))
434 (unless (or (not grep-highlight-matches) (eq grep-highlight-matches t))
435 (setq grep-highlight-matches
436 (with-temp-buffer
a58c94a2
JL
437 (and (equal (condition-case nil
438 (call-process grep-program nil t nil "--help")
439 (error nil))
440 0)
441 (progn
442 (goto-char (point-min))
443 (search-forward "--color" nil t))
444 t)))))
318e2976
KS
445
446(defun grep-default-command ()
447 (let ((tag-default
02b73b97
TTN
448 (shell-quote-argument
449 (or (funcall (or find-tag-default-function
450 (get major-mode 'find-tag-default-function)
451 'find-tag-default))
452 "")))
318e2976
KS
453 (sh-arg-re "\\(\\(?:\"\\(?:[^\"]\\|\\\\\"\\)+\"\\|'[^']+'\\|[^\"' \t\n]\\)+\\)")
454 (grep-default (or (car grep-history) grep-command)))
455 ;; Replace the thing matching for with that around cursor.
456 (when (or (string-match
457 (concat "[^ ]+\\s +\\(?:-[^ ]+\\s +\\)*"
458 sh-arg-re "\\(\\s +\\(\\S +\\)\\)?")
459 grep-default)
460 ;; If the string is not yet complete.
461 (string-match "\\(\\)\\'" grep-default))
462 (unless (or (not (stringp buffer-file-name))
463 (when (match-beginning 2)
464 (save-match-data
465 (string-match
466 (wildcard-to-regexp
467 (file-name-nondirectory
468 (match-string 3 grep-default)))
469 (file-name-nondirectory buffer-file-name)))))
470 (setq grep-default (concat (substring grep-default
471 0 (match-beginning 2))
472 " *."
473 (file-name-extension buffer-file-name))))
02b73b97 474 (replace-match tag-default t t grep-default 1))))
318e2976
KS
475
476;;;###autoload
477(defun grep (command-args &optional highlight-regexp)
478 "Run grep, with user-specified args, and collect output in a buffer.
479While grep runs asynchronously, you can use \\[next-error] (M-x next-error),
c426452f 480or \\<grep-mode-map>\\[compile-goto-error] in the grep \
318e2976
KS
481output buffer, to go to the lines
482where grep found matches.
483
484This command uses a special history list for its COMMAND-ARGS, so you can
485easily repeat a grep command.
486
487A prefix argument says to default the argument based upon the current
488tag the cursor is over, substituting it into the last grep command
489in the grep command history (or into `grep-command'
490if that history list is empty).
491
492If specified, optional second arg HIGHLIGHT-REGEXP is the regexp to
493temporarily highlight in visited source lines."
494 (interactive
495 (progn
496 (unless (and grep-command
497 (or (not grep-use-null-device) (eq grep-use-null-device t)))
498 (grep-compute-defaults))
499 (let ((default (grep-default-command)))
500 (list (read-from-minibuffer "Run grep (like this): "
501 (if current-prefix-arg
502 default grep-command)
503 nil nil 'grep-history
504 (if current-prefix-arg nil default))))))
505
506 ;; Setting process-setup-function makes exit-message-function work
507 ;; even when async processes aren't supported.
ab55f76f
SM
508 (let ((compilation-process-setup-function 'grep-process-setup))
509 (compilation-start (if (and grep-use-null-device null-device)
510 (concat command-args " " null-device)
511 command-args)
512 'grep-mode nil highlight-regexp)))
513
7f0d4d29
JD
514(define-compilation-mode grep-mode "Grep"
515 "Sets `grep-last-buffer' and `compilation-window-height'."
516 (setq grep-last-buffer (current-buffer))
517 (set (make-local-variable 'compilation-error-face)
518 grep-hit-face)
519 (set (make-local-variable 'compilation-error-regexp-alist)
520 grep-regexp-alist))
318e2976 521
318e2976
KS
522;;;###autoload
523(defun grep-find (command-args)
524 "Run grep via find, with user-specified args COMMAND-ARGS.
525Collect output in a buffer.
526While find runs asynchronously, you can use the \\[next-error] command
527to find the text that grep hits refer to.
528
529This command uses a special history list for its arguments, so you can
530easily repeat a find command."
531 (interactive
532 (progn
52a7f9bd
RS
533 (unless (and grep-command
534 (or (not grep-use-null-device) (eq grep-use-null-device t)))
318e2976 535 (grep-compute-defaults))
87f54c05
RS
536 (if grep-find-command
537 (list (read-from-minibuffer "Run find (like this): "
538 grep-find-command nil nil
539 'grep-find-history))
540 ;; No default was set
541 (read-string
542 "compile.el: No `grep-find-command' command available. Press RET.")
543 (list nil))))
544 (when (and grep-find-command command-args)
545 (let ((null-device nil)) ; see grep
546 (grep command-args))))
318e2976 547
3d4d788a
DK
548;;;###autoload
549(defalias 'find-grep 'grep-find)
550
318e2976
KS
551(defun grep-expand-command-macros (command &optional regexp files dir excl case-fold)
552 "Patch grep COMMAND replacing <D>, etc."
553 (setq command
554 (replace-regexp-in-string "<D>"
555 (or dir ".") command t t))
556 (setq command
557 (replace-regexp-in-string "<X>"
558 (or excl "") command t t))
559 (setq command
560 (replace-regexp-in-string "<F>"
561 (or files "") command t t))
562 (setq command
563 (replace-regexp-in-string "<C>"
564 (if case-fold "-i" "") command t t))
565 (setq command
566 (replace-regexp-in-string "<R>"
567 (or regexp "") command t t))
568 command)
569
570(defvar grep-tree-last-regexp "")
571(defvar grep-tree-last-files (car (car grep-tree-files-aliases)))
572
573;;;###autoload
574(defun grep-tree (regexp files dir &optional subdirs)
575 "Grep for REGEXP in FILES in directory tree rooted at DIR.
576Collect output in a buffer.
577Interactively, prompt separately for each search parameter.
578With prefix arg, reuse previous REGEXP.
579The search is limited to file names matching shell pattern FILES.
580FILES may use abbreviations defined in `grep-tree-files-aliases', e.g.
581entering `ch' is equivalent to `*.[ch]'.
582
583While find runs asynchronously, you can use the \\[next-error] command
584to find the text that grep hits refer to.
585
586This command uses a special history list for its arguments, so you can
587easily repeat a find command.
588
589When used non-interactively, optional arg SUBDIRS limits the search to
590those sub directories of DIR."
591 (interactive
592 (let* ((regexp
593 (if current-prefix-arg
594 grep-tree-last-regexp
595 (let* ((default (current-word))
596 (spec (read-string
597 (concat "Search for"
598 (if (and default (> (length default) 0))
599 (format " (default %s): " default) ": ")))))
600 (if (equal spec "") default spec))))
601 (files
602 (read-string (concat "Search for \"" regexp "\" in files (default " grep-tree-last-files "): ")))
603 (dir
f833e227 604 (read-directory-name "Base directory: " nil default-directory t)))
318e2976
KS
605 (list regexp files dir)))
606 (unless grep-tree-command
607 (grep-compute-defaults))
608 (unless (and (stringp files) (> (length files) 0))
609 (setq files grep-tree-last-files))
610 (when files
611 (setq grep-tree-last-files files)
612 (let ((mf (assoc files grep-tree-files-aliases)))
613 (if mf
614 (setq files (cdr mf)))))
615 (let ((command-args (grep-expand-command-macros
616 grep-tree-command
617 (setq grep-tree-last-regexp regexp)
618 (and files (concat "-name '" files "'"))
619 (if subdirs
620 (if (stringp subdirs)
621 subdirs
622 (mapconcat 'identity subdirs " "))
623 nil) ;; we change default-directory to dir
624 (and grep-tree-ignore-CVS-directories "-path '*/CVS' -prune -o ")
625 grep-tree-ignore-case))
f833e227 626 (default-directory (file-name-as-directory (expand-file-name dir)))
318e2976
KS
627 (null-device nil)) ; see grep
628 (grep command-args regexp)))
629
630
631(provide 'grep)
632
cbd5542a 633;; arch-tag: 5a5b9169-a79d-4f38-9c38-f69615f39c4d
06626cf2 634;;; grep.el ends here