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