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