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