]> code.delx.au - gnu-emacs/blob - lisp/progmodes/grep.el
(compilation-context-lines): Default now 0.
[gnu-emacs] / lisp / progmodes / grep.el
1 ;;; grep.el --- run compiler as inferior of Emacs, parse error messages
2
3 ;; Copyright (C) 1985, 86, 87, 93, 94, 95, 96, 97, 98, 1999, 2001, 02, 2004
4 ;; 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., 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)
47 :version "21.4"
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.)
53 If this is a number N, all grep matches in the first N lines
54 are highlighted and parsed as soon as they arrive in Emacs.
55 If t, highlight and parse the whole grep output as soon as it arrives.
56 If nil, don't highlight or parse any of the grep buffer until you try to
57 move to the error messages.
58
59 Those grep matches which are not parsed and highlighted initially
60 will 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"))
64 :version "21.4"
65 :group 'grep)
66
67 (defcustom grep-scroll-output nil
68 "*Non-nil to scroll the *grep* buffer window as output appears.
69
70 Setting it causes the grep commands to put point at the end of their
71 output window so that the end of the output is always visible rather
72 than the begining."
73 :type 'boolean
74 :version "21.4"
75 :group 'grep)
76
77 (defcustom grep-command nil
78 "The default grep command for \\[grep].
79 If the grep program used supports an option to always include file names
80 in its output (such as the `-H' option to GNU grep), it's a good idea to
81 include it when specifying `grep-command'.
82
83 The default value of this variable is set up by `grep-compute-defaults';
84 call that function before using this variable in your program."
85 :type '(choice string
86 (const :tag "Not Set" nil))
87 :group 'grep)
88
89 (defcustom grep-use-null-device 'auto-detect
90 "If t, append the value of `null-device' to `grep' commands.
91 This is done to ensure that the output of grep includes the filename of
92 any match in the case where only a single file is searched, and is not
93 necessary if the grep program used supports the `-H' option.
94
95 The default value of this variable is set up by `grep-compute-defaults';
96 call that function before using this variable in your program."
97 :type 'boolean
98 :type '(choice (const :tag "Do Not Append Null Device" nil)
99 (const :tag "Append Null Device" t)
100 (other :tag "Not Set" auto-detect))
101 :group 'grep)
102
103 (defcustom grep-find-command nil
104 "The default find command for \\[grep-find].
105 The default value of this variable is set up by `grep-compute-defaults';
106 call that function before using this variable in your program."
107 :type '(choice string
108 (const :tag "Not Set" nil))
109 :group 'grep)
110
111 (defcustom grep-tree-command nil
112 "The default find command for \\[grep-tree].
113 The default value of this variable is set up by `grep-compute-defaults';
114 call that function before using this variable in your program.
115 The following place holders should be present in the string:
116 <D> - base directory for find
117 <X> - find options to restrict or expand the directory list
118 <F> - find options to limit the files matched
119 <C> - place to put -i if case insensitive grep
120 <R> - the regular expression searched for."
121 :type '(choice string
122 (const :tag "Not Set" nil))
123 :version "21.4"
124 :group 'grep)
125
126 (defcustom grep-tree-files-aliases '(
127 ("ch" . "*.[ch]")
128 ("c" . "*.c")
129 ("h" . "*.h")
130 ("m" . "[Mm]akefile*")
131 ("asm" . "*.[sS]")
132 ("all" . "*")
133 ("el" . "*.el")
134 )
135 "*Alist of aliases for the FILES argument to `grep-tree'."
136 :type 'alist
137 :group 'grep)
138
139 (defcustom grep-tree-ignore-case t
140 "*If non-nil, `grep-tree' ignores case in matches."
141 :type 'boolean
142 :group 'grep)
143
144 (defcustom grep-tree-ignore-CVS-directories t
145 "*If non-nil, `grep-tree' does no recurse into CVS directories."
146 :type 'boolean
147 :group 'grep)
148
149 ;;;###autoload
150 (defcustom grep-setup-hook nil
151 "List of hook functions run by `grep-process-setup' (see `run-hooks')."
152 :type 'hook
153 :group 'grep)
154
155 (defvar grep-mode-map
156 (let ((map (cons 'keymap compilation-minor-mode-map)))
157 (define-key map " " 'scroll-up)
158 (define-key map "\^?" 'scroll-down)
159
160 ;; This is intolerable -- rms
161 ;;; (define-key map [remap next-line] 'compilation-next-error)
162 ;;; (define-key map [remap previous-line] 'compilation-previous-error)
163
164 (define-key map "\r" 'compile-goto-error) ;; ?
165 (define-key map "n" 'next-error-no-select)
166 (define-key map "p" 'previous-error-no-select)
167 (define-key map "{" 'compilation-previous-file)
168 (define-key map "}" 'compilation-next-file)
169 (define-key map "\t" 'compilation-next-file)
170
171 ;; Set up the menu-bar
172 (define-key map [menu-bar grep]
173 (cons "Grep" (make-sparse-keymap "Grep")))
174
175 (define-key map [menu-bar grep compilation-kill-compilation]
176 '("Kill Grep" . kill-compilation))
177 (define-key map [menu-bar grep compilation-separator2]
178 '("----" . nil))
179 (define-key map [menu-bar grep compilation-compile]
180 '("Compile..." . compile))
181 (define-key map [menu-bar grep compilation-grep]
182 '("Another grep" . grep))
183 (define-key map [menu-bar grep compilation-recompile]
184 '("Repeat grep" . recompile))
185 (define-key map [menu-bar grep compilation-separator2]
186 '("----" . nil))
187 (define-key map [menu-bar grep compilation-first-error]
188 '("First Match" . first-error))
189 (define-key map [menu-bar grep compilation-previous-error]
190 '("Previous Match" . previous-error))
191 (define-key map [menu-bar grep compilation-next-error]
192 '("Next Match" . next-error))
193 map)
194 "Keymap for grep buffers.
195 `compilation-minor-mode-map' is a cdr of this.")
196
197 (defalias 'kill-grep 'kill-compilation)
198
199 ;;;; TODO --- refine this!!
200
201 ;;; (defcustom grep-use-compilation-buffer t
202 ;;; "When non-nil, grep specific commands update `compilation-last-buffer'.
203 ;;; This means that standard compile commands like \\[next-error] and \\[compile-goto-error]
204 ;;; can be used to navigate between grep matches (the default).
205 ;;; Otherwise, the grep specific commands like \\[grep-next-match] must
206 ;;; be used to navigate between grep matches."
207 ;;; :type 'boolean
208 ;;; :group 'grep)
209
210 ;; override compilation-last-buffer
211 (defvar grep-last-buffer nil
212 "The most recent grep buffer.
213 A grep buffer becomes most recent when its process is started
214 or when it is used with \\[grep-next-match].
215 Notice that using \\[next-error] or \\[compile-goto-error] modifies
216 `complation-last-buffer' rather than `grep-last-buffer'.")
217
218 (defvar grep-regexp-alist
219 '(("^\\(.+?\\)[:( \t]+\\([0-9]+\\)[:) \t]" 1 2)
220 ("^Binary file \\(.+\\) matches$" 1 nil nil 1))
221 "Regexp used to match grep hits. See `compilation-error-regexp-alist'.")
222
223 (defvar grep-error "grep hit"
224 "Message to print when no matches are found.")
225
226 ;; Reverse the colors because grep hits are not errors (though we jump there
227 ;; with `next-error'), and unreadable files can't be gone to.
228 (defvar grep-hit-face compilation-info-face
229 "Face name to use for grep hits.")
230
231 (defvar grep-error-face compilation-error-face
232 "Face name to use for grep error messages.")
233
234 (defvar grep-mode-font-lock-keywords
235 '(;; Command output lines.
236 ("^\\([A-Za-z_0-9/\.+-]+\\)[ \t]*:" 1 font-lock-function-name-face)
237 (": \\(.+\\): \\(?:Permission denied\\|No such \\(?:file or directory\\|device or address\\)\\)$"
238 1 grep-error-face)
239 ;; remove match from grep-regexp-alist before fontifying
240 ("^Grep finished \\(?:(\\(matches found\\))\\|with \\(no matches found\\)\\).*"
241 (0 '(face nil message nil help-echo nil mouse-face nil) t)
242 (1 grep-hit-face nil t)
243 (2 grep-error-face nil t))
244 ("^Grep \\(exited abnormally\\) with code \\([0-9]+\\).*"
245 (0 '(face nil message nil help-echo nil mouse-face nil) t)
246 (1 compilation-warning-face)
247 (2 compilation-line-face)))
248 "Additional things to highlight in grep output.
249 This gets tacked on the end of the generated expressions.")
250
251 (defvar grep-program
252 ;; Currently zgrep has trouble. It runs egrep instead of grep,
253 ;; and it doesn't pass along long options right.
254 "grep"
255 ;; (if (equal (condition-case nil ; in case "zgrep" isn't in exec-path
256 ;; (call-process "zgrep" nil nil nil
257 ;; "foo" null-device)
258 ;; (error nil))
259 ;; 1)
260 ;; "zgrep"
261 ;; "grep")
262 "The default grep program for `grep-command' and `grep-find-command'.
263 This variable's value takes effect when `grep-compute-defaults' is called.")
264
265 (defvar find-program "find"
266 "The default find program for `grep-find-command'.
267 This variable's value takes effect when `grep-compute-defaults' is called.")
268
269 (defvar grep-find-use-xargs nil
270 "Whether \\[grep-find] uses the `xargs' utility by default.
271
272 If nil, it uses `find -exec'; if `gnu', it uses `find -print0' and `xargs -0';
273 if not nil and not `gnu', it uses `find -print' and `xargs'.
274
275 This variable's value takes effect when `grep-compute-defaults' is called.")
276
277 ;; History of grep commands.
278 (defvar grep-history nil)
279 (defvar grep-find-history nil)
280
281 (defun grep-process-setup ()
282 "Setup compilation variables and buffer for `grep'.
283 Set up `compilation-exit-message-function' and run `grep-setup-hook'."
284 (set (make-local-variable 'compilation-exit-message-function)
285 (lambda (status code msg)
286 (if (eq status 'exit)
287 (cond ((zerop code)
288 '("finished (matches found)\n" . "matched"))
289 ((= code 1)
290 '("finished with no matches found\n" . "no match"))
291 (t
292 (cons msg code)))
293 (cons msg code))))
294 (run-hooks 'grep-setup-hook))
295
296 (defun grep-compute-defaults ()
297 (unless (or (not grep-use-null-device) (eq grep-use-null-device t))
298 (setq grep-use-null-device
299 (with-temp-buffer
300 (let ((hello-file (expand-file-name "HELLO" data-directory)))
301 (not
302 (and (equal (condition-case nil
303 (if grep-command
304 ;; `grep-command' is already set, so
305 ;; use that for testing.
306 (call-process-shell-command
307 grep-command nil t nil
308 "^English" hello-file)
309 ;; otherwise use `grep-program'
310 (call-process grep-program nil t nil
311 "-nH" "^English" hello-file))
312 (error nil))
313 0)
314 (progn
315 (goto-char (point-min))
316 (looking-at
317 (concat (regexp-quote hello-file)
318 ":[0-9]+:English")))))))))
319 (unless grep-command
320 (setq grep-command
321 (let ((required-options (if grep-use-null-device "-n" "-nH")))
322 (if (equal (condition-case nil ; in case "grep" isn't in exec-path
323 (call-process grep-program nil nil nil
324 "-e" "foo" null-device)
325 (error nil))
326 1)
327 (format "%s %s -e " grep-program required-options)
328 (format "%s %s " grep-program required-options)))))
329 (unless grep-find-use-xargs
330 (setq grep-find-use-xargs
331 (if (and
332 (equal (call-process "find" nil nil nil
333 null-device "-print0")
334 0)
335 (equal (call-process "xargs" nil nil nil
336 "-0" "-e" "echo")
337 0))
338 'gnu)))
339 (unless grep-find-command
340 (setq grep-find-command
341 (cond ((eq grep-find-use-xargs 'gnu)
342 (format "%s . -type f -print0 | xargs -0 -e %s"
343 find-program grep-command))
344 (grep-find-use-xargs
345 (format "%s . -type f -print | xargs %s"
346 find-program grep-command))
347 (t (cons (format "%s . -type f -exec %s {} %s \\;"
348 find-program grep-command null-device)
349 (+ 22 (length grep-command)))))))
350 (unless grep-tree-command
351 (setq grep-tree-command
352 (let* ((glen (length grep-program))
353 (gcmd (concat grep-program " <C>" (substring grep-command glen))))
354 (cond ((eq grep-find-use-xargs 'gnu)
355 (format "%s <D> <X> -type f <F> -print0 | xargs -0 -e %s <R>"
356 find-program gcmd))
357 (grep-find-use-xargs
358 (format "%s <D> <X> -type f <F> -print | xargs %s <R>"
359 find-program gcmd))
360 (t (format "%s <D> <X> -type f <F> -exec %s <R> {} %s \\;"
361 find-program gcmd null-device)))))))
362
363 (defun grep-default-command ()
364 (let ((tag-default
365 (funcall (or find-tag-default-function
366 (get major-mode 'find-tag-default-function)
367 ;; We use grep-tag-default instead of
368 ;; find-tag-default, to avoid loading etags.
369 'grep-tag-default)))
370 (sh-arg-re "\\(\\(?:\"\\(?:[^\"]\\|\\\\\"\\)+\"\\|'[^']+'\\|[^\"' \t\n]\\)+\\)")
371 (grep-default (or (car grep-history) grep-command)))
372 ;; Replace the thing matching for with that around cursor.
373 (when (or (string-match
374 (concat "[^ ]+\\s +\\(?:-[^ ]+\\s +\\)*"
375 sh-arg-re "\\(\\s +\\(\\S +\\)\\)?")
376 grep-default)
377 ;; If the string is not yet complete.
378 (string-match "\\(\\)\\'" grep-default))
379 (unless (or (not (stringp buffer-file-name))
380 (when (match-beginning 2)
381 (save-match-data
382 (string-match
383 (wildcard-to-regexp
384 (file-name-nondirectory
385 (match-string 3 grep-default)))
386 (file-name-nondirectory buffer-file-name)))))
387 (setq grep-default (concat (substring grep-default
388 0 (match-beginning 2))
389 " *."
390 (file-name-extension buffer-file-name))))
391 (replace-match (or tag-default "") t t grep-default 1))))
392
393 ;;;###autoload
394 (defun grep (command-args &optional highlight-regexp)
395 "Run grep, with user-specified args, and collect output in a buffer.
396 While grep runs asynchronously, you can use \\[next-error] (M-x next-error),
397 or \\<grep-minor-mode-map>\\[compile-goto-error] in the grep \
398 output buffer, to go to the lines
399 where grep found matches.
400
401 This command uses a special history list for its COMMAND-ARGS, so you can
402 easily repeat a grep command.
403
404 A prefix argument says to default the argument based upon the current
405 tag the cursor is over, substituting it into the last grep command
406 in the grep command history (or into `grep-command'
407 if that history list is empty).
408
409 If specified, optional second arg HIGHLIGHT-REGEXP is the regexp to
410 temporarily highlight in visited source lines."
411 (interactive
412 (progn
413 (unless (and grep-command
414 (or (not grep-use-null-device) (eq grep-use-null-device t)))
415 (grep-compute-defaults))
416 (let ((default (grep-default-command)))
417 (list (read-from-minibuffer "Run grep (like this): "
418 (if current-prefix-arg
419 default grep-command)
420 nil nil 'grep-history
421 (if current-prefix-arg nil default))))))
422
423 ;; Setting process-setup-function makes exit-message-function work
424 ;; even when async processes aren't supported.
425 (let ((compilation-process-setup-function 'grep-process-setup))
426 (compilation-start (if (and grep-use-null-device null-device)
427 (concat command-args " " null-device)
428 command-args)
429 'grep-mode nil highlight-regexp)))
430
431 ;;;###autoload (autoload 'grep-mode "grep" nil t)
432 (define-compilation-mode grep-mode "Grep"
433 "Sets `grep-last-buffer' and `compilation-window-height'."
434 (setq grep-last-buffer (current-buffer))
435 (set (make-local-variable 'compilation-error-face)
436 grep-hit-face)
437 (set (make-local-variable 'compilation-error-regexp-alist)
438 grep-regexp-alist))
439
440 ;; This is a copy of find-tag-default from etags.el.
441 (defun grep-tag-default ()
442 (save-excursion
443 (while (looking-at "\\sw\\|\\s_")
444 (forward-char 1))
445 (when (or (re-search-backward "\\sw\\|\\s_"
446 (save-excursion (beginning-of-line) (point))
447 t)
448 (re-search-forward "\\(\\sw\\|\\s_\\)+"
449 (save-excursion (end-of-line) (point))
450 t))
451 (goto-char (match-end 0))
452 (buffer-substring (point)
453 (progn (forward-sexp -1)
454 (while (looking-at "\\s'")
455 (forward-char 1))
456 (point))))))
457
458 ;;;###autoload
459 (defun grep-find (command-args)
460 "Run grep via find, with user-specified args COMMAND-ARGS.
461 Collect output in a buffer.
462 While find runs asynchronously, you can use the \\[next-error] command
463 to find the text that grep hits refer to.
464
465 This command uses a special history list for its arguments, so you can
466 easily repeat a find command."
467 (interactive
468 (progn
469 (unless grep-find-command
470 (grep-compute-defaults))
471 (if grep-find-command
472 (list (read-from-minibuffer "Run find (like this): "
473 grep-find-command nil nil
474 'grep-find-history))
475 ;; No default was set
476 (read-string
477 "compile.el: No `grep-find-command' command available. Press RET.")
478 (list nil))))
479 (when (and grep-find-command command-args)
480 (let ((null-device nil)) ; see grep
481 (grep command-args))))
482
483 (defun grep-expand-command-macros (command &optional regexp files dir excl case-fold)
484 "Patch grep COMMAND replacing <D>, etc."
485 (setq command
486 (replace-regexp-in-string "<D>"
487 (or dir ".") command t t))
488 (setq command
489 (replace-regexp-in-string "<X>"
490 (or excl "") command t t))
491 (setq command
492 (replace-regexp-in-string "<F>"
493 (or files "") command t t))
494 (setq command
495 (replace-regexp-in-string "<C>"
496 (if case-fold "-i" "") command t t))
497 (setq command
498 (replace-regexp-in-string "<R>"
499 (or regexp "") command t t))
500 command)
501
502 (defvar grep-tree-last-regexp "")
503 (defvar grep-tree-last-files (car (car grep-tree-files-aliases)))
504
505 ;;;###autoload
506 (defun grep-tree (regexp files dir &optional subdirs)
507 "Grep for REGEXP in FILES in directory tree rooted at DIR.
508 Collect output in a buffer.
509 Interactively, prompt separately for each search parameter.
510 With prefix arg, reuse previous REGEXP.
511 The search is limited to file names matching shell pattern FILES.
512 FILES may use abbreviations defined in `grep-tree-files-aliases', e.g.
513 entering `ch' is equivalent to `*.[ch]'.
514
515 While find runs asynchronously, you can use the \\[next-error] command
516 to find the text that grep hits refer to.
517
518 This command uses a special history list for its arguments, so you can
519 easily repeat a find command.
520
521 When used non-interactively, optional arg SUBDIRS limits the search to
522 those sub directories of DIR."
523 (interactive
524 (let* ((regexp
525 (if current-prefix-arg
526 grep-tree-last-regexp
527 (let* ((default (current-word))
528 (spec (read-string
529 (concat "Search for"
530 (if (and default (> (length default) 0))
531 (format " (default %s): " default) ": ")))))
532 (if (equal spec "") default spec))))
533 (files
534 (read-string (concat "Search for \"" regexp "\" in files (default " grep-tree-last-files "): ")))
535 (dir
536 (read-directory-name "Base directory: " nil default-directory t)))
537 (list regexp files dir)))
538 (unless grep-tree-command
539 (grep-compute-defaults))
540 (unless (and (stringp files) (> (length files) 0))
541 (setq files grep-tree-last-files))
542 (when files
543 (setq grep-tree-last-files files)
544 (let ((mf (assoc files grep-tree-files-aliases)))
545 (if mf
546 (setq files (cdr mf)))))
547 (let ((command-args (grep-expand-command-macros
548 grep-tree-command
549 (setq grep-tree-last-regexp regexp)
550 (and files (concat "-name '" files "'"))
551 (if subdirs
552 (if (stringp subdirs)
553 subdirs
554 (mapconcat 'identity subdirs " "))
555 nil) ;; we change default-directory to dir
556 (and grep-tree-ignore-CVS-directories "-path '*/CVS' -prune -o ")
557 grep-tree-ignore-case))
558 (default-directory dir)
559 (null-device nil)) ; see grep
560 (grep command-args regexp)))
561
562
563 (provide 'grep)
564
565 ;;; arch-tag: 5a5b9169-a79d-4f38-9c38-f69615f39c4d
566 ;;; grep.el ends here