Fix bug #9221 with memory leak in bidi display.
[bpt/emacs.git] / lisp / progmodes / grep.el
CommitLineData
d9c54a06 1;;; grep.el --- run `grep' and display the results
318e2976 2
73b0cd50 3;; Copyright (C) 1985-1987, 1993-1999, 2001-2011
26dac56c 4;; 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
b1fc2b50 12;; GNU Emacs is free software: you can redistribute it and/or modify
318e2976 13;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
318e2976
KS
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
b1fc2b50 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
318e2976
KS
24
25;;; Commentary:
26
27;; This package provides the grep facilities documented in the Emacs
28;; user's manual.
29
30;;; Code:
31
32(require 'compile)
33
d70b5ac5 34
318e2976 35(defgroup grep nil
d9c54a06 36 "Run `grep' and display the results."
318e2976
KS
37 :group 'tools
38 :group 'processes)
39
d4bbd646
CY
40(defvar grep-host-defaults-alist nil
41 "Default values depending on target host.
42`grep-compute-defaults' returns default values for every local or
43remote host `grep' runs. These values can differ from host to
44host. Once computed, the default values are kept here in order
45to avoid computing them again.")
46
47(defun grep-apply-setting (symbol value)
48 "Set SYMBOL to VALUE, and update `grep-host-defaults-alist'.
49SYMBOL should be one of `grep-command', `grep-template',
50`grep-use-null-device', `grep-find-command',
51`grep-find-template', `grep-find-use-xargs', or
52`grep-highlight-matches'."
53 (when grep-host-defaults-alist
54 (let* ((host-id
55 (intern (or (file-remote-p default-directory) "localhost")))
56 (host-defaults (assq host-id grep-host-defaults-alist))
57 (defaults (assq nil grep-host-defaults-alist)))
58 (setcar (cdr (assq symbol host-defaults)) value)
59 (setcar (cdr (assq symbol defaults)) value)))
60 (set-default symbol value))
318e2976
KS
61
62;;;###autoload
63(defcustom grep-window-height nil
64 "*Number of lines in a grep window. If nil, use `compilation-window-height'."
65 :type '(choice (const :tag "Default" nil)
66 integer)
bf247b6e 67 :version "22.1"
318e2976
KS
68 :group 'grep)
69
00889cf9 70(defcustom grep-highlight-matches 'auto-detect
a601d313 71 "Use special markers to highlight grep matches.
277df088
JL
72
73Some grep programs are able to surround matches with special
74markers in grep output. Such markers can be used to highlight
a915d7a1
GM
75matches in grep mode. This requires `font-lock-mode' to be active
76in grep buffers, so if you have globally disabled font-lock-mode,
77you will not get highlighting.
277df088 78
a601d313 79This option sets the environment variable GREP_COLORS to specify
277df088
JL
80markers for highlighting and GREP_OPTIONS to add the --color
81option in front of any explicit grep options before starting
a58c94a2
JL
82the grep.
83
a601d313
JL
84When this option is `auto', grep uses `--color=auto' to highlight
85matches only when it outputs to a terminal (when `grep' is the last
86command in the pipe), thus avoiding the use of any potentially-harmful
87escape sequences when standard output goes to a file or pipe.
88
89To make grep highlight matches even into a pipe, you need the option
90`always' that forces grep to use `--color=always' to unconditionally
91output escape sequences.
92
d4bbd646 93In interactive usage, the actual value of this variable is set up
a601d313
JL
94by `grep-compute-defaults' when the default value is `auto-detect'.
95To change the default value, use Customize or call the function
96`grep-apply-setting'."
00889cf9
JL
97 :type '(choice (const :tag "Do not highlight matches with grep markers" nil)
98 (const :tag "Highlight matches with grep markers" t)
a601d313
JL
99 (const :tag "Use --color=always" always)
100 (const :tag "Use --color=auto" auto)
00889cf9 101 (other :tag "Not Set" auto-detect))
d4bbd646 102 :set 'grep-apply-setting
bf247b6e 103 :version "22.1"
277df088
JL
104 :group 'grep)
105
318e2976
KS
106(defcustom grep-scroll-output nil
107 "*Non-nil to scroll the *grep* buffer window as output appears.
108
109Setting it causes the grep commands to put point at the end of their
110output window so that the end of the output is always visible rather
111than the begining."
112 :type 'boolean
bf247b6e 113 :version "22.1"
318e2976
KS
114 :group 'grep)
115
9b19858e 116;;;###autoload
318e2976
KS
117(defcustom grep-command nil
118 "The default grep command for \\[grep].
119If the grep program used supports an option to always include file names
120in its output (such as the `-H' option to GNU grep), it's a good idea to
121include it when specifying `grep-command'.
122
d4bbd646
CY
123In interactive usage, the actual value of this variable is set up
124by `grep-compute-defaults'; to change the default value, use
125Customize or call the function `grep-apply-setting'."
318e2976
KS
126 :type '(choice string
127 (const :tag "Not Set" nil))
d4bbd646 128 :set 'grep-apply-setting
318e2976
KS
129 :group 'grep)
130
0acfb7ce
KS
131(defcustom grep-template nil
132 "The default command to run for \\[lgrep].
0acfb7ce
KS
133The following place holders should be present in the string:
134 <C> - place to put -i if case insensitive grep.
135 <F> - file names and wildcards to search.
7ae62430 136 <X> - file names and wildcards to exclude.
0acfb7ce 137 <R> - the regular expression searched for.
d4bbd646
CY
138 <N> - place to insert null-device.
139
140In interactive usage, the actual value of this variable is set up
141by `grep-compute-defaults'; to change the default value, use
142Customize or call the function `grep-apply-setting'."
0acfb7ce
KS
143 :type '(choice string
144 (const :tag "Not Set" nil))
d4bbd646 145 :set 'grep-apply-setting
0acfb7ce
KS
146 :version "22.1"
147 :group 'grep)
148
318e2976
KS
149(defcustom grep-use-null-device 'auto-detect
150 "If t, append the value of `null-device' to `grep' commands.
151This is done to ensure that the output of grep includes the filename of
152any match in the case where only a single file is searched, and is not
153necessary if the grep program used supports the `-H' option.
154
d4bbd646
CY
155In interactive usage, the actual value of this variable is set up
156by `grep-compute-defaults'; to change the default value, use
157Customize or call the function `grep-apply-setting'."
318e2976
KS
158 :type '(choice (const :tag "Do Not Append Null Device" nil)
159 (const :tag "Append Null Device" t)
160 (other :tag "Not Set" auto-detect))
d4bbd646 161 :set 'grep-apply-setting
318e2976
KS
162 :group 'grep)
163
9b19858e 164;;;###autoload
318e2976
KS
165(defcustom grep-find-command nil
166 "The default find command for \\[grep-find].
d4bbd646
CY
167In interactive usage, the actual value of this variable is set up
168by `grep-compute-defaults'; to change the default value, use
169Customize or call the function `grep-apply-setting'."
318e2976
KS
170 :type '(choice string
171 (const :tag "Not Set" nil))
d4bbd646 172 :set 'grep-apply-setting
318e2976
KS
173 :group 'grep)
174
0acfb7ce
KS
175(defcustom grep-find-template nil
176 "The default command to run for \\[rgrep].
318e2976
KS
177The following place holders should be present in the string:
178 <D> - base directory for find
179 <X> - find options to restrict or expand the directory list
180 <F> - find options to limit the files matched
181 <C> - place to put -i if case insensitive grep
d4bbd646
CY
182 <R> - the regular expression searched for.
183In interactive usage, the actual value of this variable is set up
184by `grep-compute-defaults'; to change the default value, use
185Customize or call the function `grep-apply-setting'."
318e2976
KS
186 :type '(choice string
187 (const :tag "Not Set" nil))
d4bbd646 188 :set 'grep-apply-setting
bf247b6e 189 :version "22.1"
318e2976
KS
190 :group 'grep)
191
2796180f 192(defcustom grep-files-aliases
7ae62430
JL
193 '(("all" . "* .*")
194 ("el" . "*.el")
195 ("ch" . "*.[ch]")
2796180f 196 ("c" . "*.c")
01623c28 197 ("cc" . "*.cc *.cxx *.cpp *.C *.CC *.c++")
7ae62430 198 ("cchh" . "*.cc *.[ch]xx *.[ch]pp *.[CHh] *.CC *.HH *.[ch]++")
01623c28 199 ("hh" . "*.hxx *.hpp *.[Hh] *.HH *.h++")
2796180f 200 ("h" . "*.h")
7ae62430 201 ("l" . "[Cc]hange[Ll]og*")
2796180f 202 ("m" . "[Mm]akefile*")
7ae62430
JL
203 ("tex" . "*.tex")
204 ("texi" . "*.texi")
205 ("asm" . "*.[sS]"))
0acfb7ce 206 "*Alist of aliases for the FILES argument to `lgrep' and `rgrep'."
318e2976
KS
207 :type 'alist
208 :group 'grep)
209
a2e548a9 210(defcustom grep-find-ignored-directories
1f0bee0a 211 vc-directory-exclusion-list
49405d0e
SS
212 "*List of names of sub-directories which `rgrep' shall not recurse into.
213If an element is a cons cell, the car is called on the search directory
214to determine whether cdr should not be recursed into."
7ae62430
JL
215 :type '(choice (repeat :tag "Ignored directories" string)
216 (const :tag "No ignored directories" nil))
217 :group 'grep)
218
219(defcustom grep-find-ignored-files
220 (cons ".#*" (delq nil (mapcar (lambda (s)
221 (unless (string-match-p "/\\'" s)
222 (concat "*" s)))
223 completion-ignored-extensions)))
224 "*List of file names which `rgrep' and `lgrep' shall exclude.
225If an element is a cons cell, the car is called on the search directory
226to determine whether cdr should not be excluded."
227 :type '(choice (repeat :tag "Ignored file" string)
228 (const :tag "No ignored files" nil))
318e2976
KS
229 :group 'grep)
230
bb72b9d0
DP
231(defcustom grep-error-screen-columns nil
232 "*If non-nil, column numbers in grep hits are screen columns.
233See `compilation-error-screen-columns'"
234 :type '(choice (const :tag "Default" nil)
235 integer)
bf247b6e 236 :version "22.1"
bb72b9d0
DP
237 :group 'grep)
238
318e2976
KS
239;;;###autoload
240(defcustom grep-setup-hook nil
241 "List of hook functions run by `grep-process-setup' (see `run-hooks')."
242 :type 'hook
243 :group 'grep)
244
245(defvar grep-mode-map
86c7460f
SS
246 (let ((map (make-sparse-keymap)))
247 (set-keymap-parent map compilation-minor-mode-map)
318e2976
KS
248 (define-key map " " 'scroll-up)
249 (define-key map "\^?" 'scroll-down)
0443d889 250 (define-key map "\C-c\C-f" 'next-error-follow-minor-mode)
318e2976 251
318e2976
KS
252 (define-key map "\r" 'compile-goto-error) ;; ?
253 (define-key map "n" 'next-error-no-select)
254 (define-key map "p" 'previous-error-no-select)
255 (define-key map "{" 'compilation-previous-file)
256 (define-key map "}" 'compilation-next-file)
94c713b2
JL
257 (define-key map "\t" 'compilation-next-error)
258 (define-key map [backtab] 'compilation-previous-error)
318e2976
KS
259
260 ;; Set up the menu-bar
261 (define-key map [menu-bar grep]
262 (cons "Grep" (make-sparse-keymap "Grep")))
263
264 (define-key map [menu-bar grep compilation-kill-compilation]
38805987
DN
265 '(menu-item "Kill Grep" kill-compilation
266 :help "Kill the currently running grep process"))
267 (define-key map [menu-bar grep compilation-separator2] '("----"))
318e2976 268 (define-key map [menu-bar grep compilation-compile]
38805987
DN
269 '(menu-item "Compile..." compile
270 :help "Compile the program including the current buffer. Default: run `make'"))
5d91db30
JL
271 (define-key map [menu-bar grep compilation-rgrep]
272 '(menu-item "Recursive grep..." rgrep
273 :help "User-friendly recursive grep in directory tree"))
274 (define-key map [menu-bar grep compilation-lgrep]
275 '(menu-item "Local grep..." lgrep
276 :help "User-friendly grep in a directory"))
277 (define-key map [menu-bar grep compilation-grep-find]
278 '(menu-item "Grep via Find..." grep-find
279 :help "Run grep via find, with user-specified args"))
318e2976 280 (define-key map [menu-bar grep compilation-grep]
38805987
DN
281 '(menu-item "Another grep..." grep
282 :help "Run grep, with user-specified args, and collect output in a buffer."))
318e2976 283 (define-key map [menu-bar grep compilation-recompile]
38805987
DN
284 '(menu-item "Repeat grep" recompile
285 :help "Run grep again"))
286 (define-key map [menu-bar grep compilation-separator2] '("----"))
318e2976 287 (define-key map [menu-bar grep compilation-first-error]
38805987
DN
288 '(menu-item "First Match" first-error
289 :help "Restart at the first match, visit corresponding location"))
318e2976 290 (define-key map [menu-bar grep compilation-previous-error]
38805987
DN
291 '(menu-item "Previous Match" previous-error
292 :help "Visit the previous match and corresponding location"))
318e2976 293 (define-key map [menu-bar grep compilation-next-error]
38805987
DN
294 '(menu-item "Next Match" next-error
295 :help "Visit the next match and corresponding location"))
318e2976
KS
296 map)
297 "Keymap for grep buffers.
298`compilation-minor-mode-map' is a cdr of this.")
299
38cd9f17 300(defvar grep-mode-tool-bar-map
30b72491
CY
301 ;; When bootstrapping, tool-bar-map is not properly initialized yet,
302 ;; so don't do anything.
303 (when (keymapp (butlast tool-bar-map))
304 (let ((map (butlast (copy-keymap tool-bar-map)))
305 (help (last tool-bar-map))) ;; Keep Help last in tool bar
306 (tool-bar-local-item
307 "left-arrow" 'previous-error-no-select 'previous-error-no-select map
308 :rtl "right-arrow"
309 :help "Goto previous match")
310 (tool-bar-local-item
311 "right-arrow" 'next-error-no-select 'next-error-no-select map
312 :rtl "left-arrow"
313 :help "Goto next match")
314 (tool-bar-local-item
315 "cancel" 'kill-compilation 'kill-compilation map
316 :enable '(let ((buffer (compilation-find-buffer)))
317 (get-buffer-process buffer))
318 :help "Stop grep")
319 (tool-bar-local-item
320 "refresh" 'recompile 'recompile map
321 :help "Restart grep")
322 (append map help))))
38cd9f17 323
ab55f76f
SM
324(defalias 'kill-grep 'kill-compilation)
325
318e2976
KS
326;;;; TODO --- refine this!!
327
6b3a84f2
SM
328;; (defcustom grep-use-compilation-buffer t
329;; "When non-nil, grep specific commands update `compilation-last-buffer'.
330;; This means that standard compile commands like \\[next-error] and \\[compile-goto-error]
331;; can be used to navigate between grep matches (the default).
332;; Otherwise, the grep specific commands like \\[grep-next-match] must
333;; be used to navigate between grep matches."
334;; :type 'boolean
335;; :group 'grep)
318e2976
KS
336
337;; override compilation-last-buffer
338(defvar grep-last-buffer nil
339 "The most recent grep buffer.
f911a445 340A grep buffer becomes most recent when you select Grep mode in it.
318e2976
KS
341Notice that using \\[next-error] or \\[compile-goto-error] modifies
342`complation-last-buffer' rather than `grep-last-buffer'.")
343
9b19858e 344;;;###autoload
2f7f4bee 345(defconst grep-regexp-alist
07b741a7 346 '(("^\\(.+?\\)\\(:[ \t]*\\)\\([1-9][0-9]*\\)\\2"
35952129
JL
347 1 3)
348 ;; Rule to match column numbers is commented out since no known grep
349 ;; produces them
7462142d 350 ;; ("^\\(.+?\\)\\(:[ \t]*\\)\\([0-9]+\\)\\2\\(?:\\([0-9]+\\)\\(?:-\\([0-9]+\\)\\)?\\2\\)?"
35952129 351 ;; 1 3 (4 . 5))
c04f2ac0
SM
352 ;; Note that we want to use as tight a regexp as we can to try and
353 ;; handle weird file names (with colons in them) as well as possible.
354 ;; E.g. we use [1-9][0-9]* rather than [0-9]+ so as to accept ":034:" in
355 ;; file names.
356 ("^\\(\\(.+?\\):\\([1-9][0-9]*\\):\\).*?\
983203ee 357\\(\033\\[01;31m\\(?:\033\\[K\\)?\\)\\(.*?\\)\\(\033\\[[0-9]*m\\)"
f04a8969 358 2 3
1bcd42e2 359 ;; Calculate column positions (beg . end) of first grep match on a line
277df088 360 ((lambda ()
983203ee
JL
361 (setq compilation-error-screen-columns nil)
362 (- (match-beginning 4) (match-end 1)))
277df088 363 .
983203ee 364 (lambda () (- (match-end 5) (match-end 1)
c04f2ac0 365 (- (match-end 4) (match-beginning 4)))))
f04a8969 366 nil 1)
ba65be24 367 ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
318e2976
KS
368 "Regexp used to match grep hits. See `compilation-error-regexp-alist'.")
369
ab55f76f
SM
370(defvar grep-error "grep hit"
371 "Message to print when no matches are found.")
372
373;; Reverse the colors because grep hits are not errors (though we jump there
374;; with `next-error'), and unreadable files can't be gone to.
375(defvar grep-hit-face compilation-info-face
376 "Face name to use for grep hits.")
377
7462142d 378(defvar grep-error-face 'compilation-error
ab55f76f
SM
379 "Face name to use for grep error messages.")
380
f30c45e1
JL
381(defvar grep-match-face 'match
382 "Face name to use for grep matches.")
383
35952129
JL
384(defvar grep-context-face 'shadow
385 "Face name to use for grep context lines.")
386
ab55f76f
SM
387(defvar grep-mode-font-lock-keywords
388 '(;; Command output lines.
ab55f76f
SM
389 (": \\(.+\\): \\(?:Permission denied\\|No such \\(?:file or directory\\|device or address\\)\\)$"
390 1 grep-error-face)
391 ;; remove match from grep-regexp-alist before fontifying
c2c04c28 392 ("^Grep[/a-zA-z]* started.*"
1a0a6cef 393 (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
c2c04c28 394 ("^Grep[/a-zA-z]* finished \\(?:(\\(matches found\\))\\|with \\(no matches found\\)\\).*"
1a0a6cef 395 (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
7462142d
JL
396 (1 compilation-info-face nil t)
397 (2 compilation-warning-face nil t))
c2c04c28 398 ("^Grep[/a-zA-z]* \\(exited abnormally\\|interrupt\\|killed\\|terminated\\)\\(?:.*with code \\([0-9]+\\)\\)?.*"
1a0a6cef 399 (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
7462142d 400 (1 grep-error-face)
cf115520 401 (2 grep-error-face nil t))
d9c54a06 402 ("^.+?-[0-9]+-.*\n" (0 grep-context-face)))
ab55f76f
SM
403 "Additional things to highlight in grep output.
404This gets tacked on the end of the generated expressions.")
405
9b19858e 406;;;###autoload
6bdad9ae 407(defvar grep-program (purecopy "grep")
318e2976
KS
408 "The default grep program for `grep-command' and `grep-find-command'.
409This variable's value takes effect when `grep-compute-defaults' is called.")
410
9b19858e 411;;;###autoload
6bdad9ae 412(defvar find-program (purecopy "find")
318e2976
KS
413 "The default find program for `grep-find-command'.
414This variable's value takes effect when `grep-compute-defaults' is called.")
415
1571d112 416;;;###autoload
6bdad9ae 417(defvar xargs-program (purecopy "xargs")
1571d112
JB
418 "The default xargs program for `grep-find-command'.
419See `grep-find-use-xargs'.
420This variable's value takes effect when `grep-compute-defaults' is called.")
421
9b19858e 422;;;###autoload
318e2976 423(defvar grep-find-use-xargs nil
f3ca7378
GM
424 "How to invoke find and grep.
425If `exec', use `find -exec {} ;'.
426If `exec-plus' use `find -exec {} +'.
7f3afa3d 427If `gnu', use `find -print0' and `xargs -0'.
f3ca7378 428Any other value means to use `find -print' and `xargs'.
318e2976
KS
429
430This variable's value takes effect when `grep-compute-defaults' is called.")
431
432;; History of grep commands.
9b19858e 433;;;###autoload
318e2976 434(defvar grep-history nil)
9b19858e 435;;;###autoload
318e2976
KS
436(defvar grep-find-history nil)
437
0acfb7ce
KS
438;; History of lgrep and rgrep regexp and files args.
439(defvar grep-regexp-history nil)
7ae62430 440(defvar grep-files-history nil)
0acfb7ce 441
9b19858e 442;;;###autoload
318e2976
KS
443(defun grep-process-setup ()
444 "Setup compilation variables and buffer for `grep'.
ab55f76f 445Set up `compilation-exit-message-function' and run `grep-setup-hook'."
a601d313 446 (when (eq grep-highlight-matches 'auto-detect)
a58c94a2 447 (grep-compute-defaults))
a601d313 448 (unless (or (eq grep-highlight-matches 'auto-detect)
a915d7a1
GM
449 ;; Uses font-lock to parse color escapes. (Bug#8084)
450 (null font-lock-mode)
a601d313 451 (null grep-highlight-matches))
6b8d0852
JL
452 ;; `setenv' modifies `process-environment' let-bound in `compilation-start'
453 ;; Any TERM except "dumb" allows GNU grep to use `--color=auto'
454 (setenv "TERM" "emacs-grep")
8f0e19af
EZ
455 (setenv "GREP_OPTIONS"
456 (concat (getenv "GREP_OPTIONS")
a601d313 457 " --color=" (if (eq grep-highlight-matches 'always)
8f0e19af 458 "always" "auto")))
6b8d0852 459 ;; GREP_COLOR is used in GNU grep 2.5.1, but deprecated in later versions
983203ee 460 (setenv "GREP_COLOR" "01;31")
6b8d0852 461 ;; GREP_COLORS is used in GNU grep 2.5.2 and later versions
983203ee 462 (setenv "GREP_COLORS" "mt=01;31:fn=:ln=:bn=:se=:ml=:cx=:ne"))
318e2976
KS
463 (set (make-local-variable 'compilation-exit-message-function)
464 (lambda (status code msg)
465 (if (eq status 'exit)
466 (cond ((zerop code)
467 '("finished (matches found)\n" . "matched"))
468 ((= code 1)
469 '("finished with no matches found\n" . "no match"))
470 (t
471 (cons msg code)))
472 (cons msg code))))
318e2976
KS
473 (run-hooks 'grep-setup-hook))
474
d9c54a06
CY
475(defun grep-filter ()
476 "Handle match highlighting escape sequences inserted by the grep process.
477This function is called from `compilation-filter-hook'."
478 (save-excursion
c89be45f
SM
479 (forward-line 0)
480 (let ((end (point)))
d9c54a06 481 (goto-char compilation-filter-start)
c89be45f
SM
482 (forward-line 0)
483 ;; Only operate on whole lines so we don't get caught with part of an
484 ;; escape sequence in one chunk and the rest in another.
485 (when (< (point) end)
486 (setq end (copy-marker end))
487 ;; Highlight grep matches and delete marking sequences.
488 (while (re-search-forward "\033\\[01;31m\\(.*?\\)\033\\[[0-9]*m" end 1)
489 (replace-match (propertize (match-string 1)
490 'face nil 'font-lock-face grep-match-face)
491 t t))
492 ;; Delete all remaining escape sequences
493 (goto-char compilation-filter-start)
494 (while (re-search-forward "\033\\[[0-9;]*[mK]" end 1)
495 (replace-match "" t t))))))
d9c54a06 496
0acfb7ce 497(defun grep-probe (command args &optional func result)
458c8d31
MA
498 (let (process-file-side-effects)
499 (equal (condition-case nil
500 (apply (or func 'process-file) command args)
501 (error nil))
502 (or result 0))))
0acfb7ce 503
9b19858e 504;;;###autoload
318e2976 505(defun grep-compute-defaults ()
2e2eead3
MA
506 ;; Keep default values.
507 (unless grep-host-defaults-alist
508 (add-to-list
509 'grep-host-defaults-alist
510 (cons nil
511 `((grep-command ,grep-command)
512 (grep-template ,grep-template)
513 (grep-use-null-device ,grep-use-null-device)
514 (grep-find-command ,grep-find-command)
515 (grep-find-template ,grep-find-template)
516 (grep-find-use-xargs ,grep-find-use-xargs)
517 (grep-highlight-matches ,grep-highlight-matches)))))
518 (let* ((host-id
85e7298f 519 (intern (or (file-remote-p default-directory) "localhost")))
2e2eead3
MA
520 (host-defaults (assq host-id grep-host-defaults-alist))
521 (defaults (assq nil grep-host-defaults-alist)))
05c7c7b1 522 ;; There are different defaults on different hosts. They must be
2e2eead3 523 ;; computed for every host once.
d4bbd646
CY
524 (dolist (setting '(grep-command grep-template
525 grep-use-null-device grep-find-command
526 grep-find-template grep-find-use-xargs
527 grep-highlight-matches))
528 (set setting
7860d2e3
CY
529 (cadr (or (assq setting host-defaults)
530 (assq setting defaults)))))
05c7c7b1
MA
531
532 (unless (or (not grep-use-null-device) (eq grep-use-null-device t))
533 (setq grep-use-null-device
534 (with-temp-buffer
535 (let ((hello-file (expand-file-name "HELLO" data-directory)))
536 (not
537 (and (if grep-command
538 ;; `grep-command' is already set, so
539 ;; use that for testing.
540 (grep-probe grep-command
541 `(nil t nil "^English" ,hello-file)
542 #'call-process-shell-command)
543 ;; otherwise use `grep-program'
544 (grep-probe grep-program
545 `(nil t nil "-nH" "^English" ,hello-file)))
546 (progn
547 (goto-char (point-min))
548 (looking-at
549 (concat (regexp-quote hello-file)
550 ":[0-9]+:English")))))))))
551 (unless (and grep-command grep-find-command
552 grep-template grep-find-template)
553 (let ((grep-options
554 (concat (if grep-use-null-device "-n" "-nH")
555 (if (grep-probe grep-program
556 `(nil nil nil "-e" "foo" ,null-device)
557 nil 1)
558 " -e"))))
559 (unless grep-command
560 (setq grep-command
561 (format "%s %s " grep-program grep-options)))
562 (unless grep-template
563 (setq grep-template
7ae62430 564 (format "%s <X> <C> %s <R> <F>" grep-program grep-options)))
05c7c7b1
MA
565 (unless grep-find-use-xargs
566 (setq grep-find-use-xargs
567 (cond
f3ca7378
GM
568 ((grep-probe find-program
569 `(nil nil nil ,null-device "-exec" "echo"
570 "{}" "+"))
571 'exec-plus)
05c7c7b1
MA
572 ((and
573 (grep-probe find-program `(nil nil nil ,null-device "-print0"))
1571d112 574 (grep-probe xargs-program `(nil nil nil "-0" "-e" "echo")))
05c7c7b1
MA
575 'gnu)
576 (t
577 'exec))))
578 (unless grep-find-command
579 (setq grep-find-command
0acfb7ce 580 (cond ((eq grep-find-use-xargs 'gnu)
362b9d48
GM
581 ;; Windows shells need the program file name
582 ;; after the pipe symbol be quoted if they use
583 ;; forward slashes as directory separators.
584 (format "%s . -type f -print0 | \"%s\" -0 -e %s"
1571d112 585 find-program xargs-program grep-command))
f3ca7378 586 ((memq grep-find-use-xargs '(exec exec-plus))
05c7c7b1 587 (let ((cmd0 (format "%s . -type f -exec %s"
f3ca7378
GM
588 find-program grep-command))
589 (null (if grep-use-null-device
590 (format "%s " null-device)
591 "")))
05c7c7b1 592 (cons
f3ca7378
GM
593 (if (eq grep-find-use-xargs 'exec-plus)
594 (format "%s %s{} +" cmd0 null)
595 (format "%s {} %s%s" cmd0 null
596 (shell-quote-argument ";")))
05c7c7b1 597 (1+ (length cmd0)))))
84d797c9 598 (t
362b9d48 599 (format "%s . -type f -print | \"%s\" %s"
1571d112 600 find-program xargs-program grep-command)))))
05c7c7b1
MA
601 (unless grep-find-template
602 (setq grep-find-template
603 (let ((gcmd (format "%s <C> %s <R>"
f3ca7378
GM
604 grep-program grep-options))
605 (null (if grep-use-null-device
606 (format "%s " null-device)
607 "")))
05c7c7b1 608 (cond ((eq grep-find-use-xargs 'gnu)
362b9d48 609 (format "%s . <X> -type f <F> -print0 | \"%s\" -0 -e %s"
1571d112 610 find-program xargs-program gcmd))
05c7c7b1 611 ((eq grep-find-use-xargs 'exec)
f3ca7378
GM
612 (format "%s . <X> -type f <F> -exec %s {} %s%s"
613 find-program gcmd null
05c7c7b1 614 (shell-quote-argument ";")))
f3ca7378
GM
615 ((eq grep-find-use-xargs 'exec-plus)
616 (format "%s . <X> -type f <F> -exec %s %s{} +"
617 find-program gcmd null))
05c7c7b1 618 (t
362b9d48 619 (format "%s . <X> -type f <F> -print | \"%s\" %s"
1571d112 620 find-program xargs-program gcmd))))))))
a601d313 621 (when (eq grep-highlight-matches 'auto-detect)
05c7c7b1
MA
622 (setq grep-highlight-matches
623 (with-temp-buffer
624 (and (grep-probe grep-program '(nil t nil "--help"))
625 (progn
626 (goto-char (point-min))
627 (search-forward "--color" nil t))
a601d313
JL
628 ;; Windows and DOS pipes fail `isatty' detection in Grep.
629 (if (memq system-type '(windows-nt ms-dos))
630 'always 'auto)))))
05c7c7b1
MA
631
632 ;; Save defaults for this host.
6e3aa3f5
MA
633 (setq grep-host-defaults-alist
634 (delete (assq host-id grep-host-defaults-alist)
635 grep-host-defaults-alist))
636 (add-to-list
637 'grep-host-defaults-alist
638 (cons host-id
639 `((grep-command ,grep-command)
640 (grep-template ,grep-template)
641 (grep-use-null-device ,grep-use-null-device)
642 (grep-find-command ,grep-find-command)
643 (grep-find-template ,grep-find-template)
644 (grep-find-use-xargs ,grep-find-use-xargs)
645 (grep-highlight-matches ,grep-highlight-matches))))))
318e2976 646
7cb0d0ef
KS
647(defun grep-tag-default ()
648 (or (and transient-mark-mode mark-active
649 (/= (point) (mark))
650 (buffer-substring-no-properties (point) (mark)))
651 (funcall (or find-tag-default-function
652 (get major-mode 'find-tag-default-function)
653 'find-tag-default))
654 ""))
655
318e2976 656(defun grep-default-command ()
1571d112 657 "Compute the default grep command for \\[universal-argument] \\[grep] to offer."
7cb0d0ef 658 (let ((tag-default (shell-quote-argument (grep-tag-default)))
13eb1bde
RS
659 ;; This a regexp to match single shell arguments.
660 ;; Could someone please add comments explaining it?
318e2976
KS
661 (sh-arg-re "\\(\\(?:\"\\(?:[^\"]\\|\\\\\"\\)+\"\\|'[^']+'\\|[^\"' \t\n]\\)+\\)")
662 (grep-default (or (car grep-history) grep-command)))
13eb1bde 663 ;; In the default command, find the arg that specifies the pattern.
318e2976
KS
664 (when (or (string-match
665 (concat "[^ ]+\\s +\\(?:-[^ ]+\\s +\\)*"
666 sh-arg-re "\\(\\s +\\(\\S +\\)\\)?")
667 grep-default)
668 ;; If the string is not yet complete.
669 (string-match "\\(\\)\\'" grep-default))
13eb1bde
RS
670 ;; Maybe we will replace the pattern with the default tag.
671 ;; But first, maybe replace the file name pattern.
672 (condition-case nil
673 (unless (or (not (stringp buffer-file-name))
674 (when (match-beginning 2)
675 (save-match-data
676 (string-match
677 (wildcard-to-regexp
678 (file-name-nondirectory
679 (match-string 3 grep-default)))
680 (file-name-nondirectory buffer-file-name)))))
681 (setq grep-default (concat (substring grep-default
682 0 (match-beginning 2))
683 " *."
684 (file-name-extension buffer-file-name))))
685 ;; In case wildcard-to-regexp gets an error
686 ;; from invalid data.
687 (error nil))
688 ;; Now replace the pattern with the default tag.
02b73b97 689 (replace-match tag-default t t grep-default 1))))
318e2976 690
0acfb7ce 691
318e2976 692;;;###autoload
0acfb7ce
KS
693(define-compilation-mode grep-mode "Grep"
694 "Sets `grep-last-buffer' and `compilation-window-height'."
695 (setq grep-last-buffer (current-buffer))
38cd9f17 696 (set (make-local-variable 'tool-bar-map) grep-mode-tool-bar-map)
0acfb7ce
KS
697 (set (make-local-variable 'compilation-error-face)
698 grep-hit-face)
699 (set (make-local-variable 'compilation-error-regexp-alist)
700 grep-regexp-alist)
b7cf2c79
SM
701 ;; compilation-directory-matcher can't be nil, so we set it to a regexp that
702 ;; can never match.
79106a44 703 (set (make-local-variable 'compilation-directory-matcher) '("\\`a\\`"))
0acfb7ce
KS
704 (set (make-local-variable 'compilation-process-setup-function)
705 'grep-process-setup)
d9c54a06
CY
706 (set (make-local-variable 'compilation-disable-input) t)
707 (add-hook 'compilation-filter-hook 'grep-filter nil t))
0acfb7ce
KS
708
709
710;;;###autoload
711(defun grep (command-args)
318e2976
KS
712 "Run grep, with user-specified args, and collect output in a buffer.
713While grep runs asynchronously, you can use \\[next-error] (M-x next-error),
c426452f 714or \\<grep-mode-map>\\[compile-goto-error] in the grep \
1571d112
JB
715output buffer, to go to the lines where grep
716found matches.
318e2976 717
215c3847 718For doing a recursive `grep', see the `rgrep' command. For running
9d4a3d39 719`grep' in a specific directory, see `lgrep'.
215c3847 720
1571d112
JB
721This command uses a special history list for its COMMAND-ARGS, so you
722can easily repeat a grep command.
318e2976
KS
723
724A prefix argument says to default the argument based upon the current
725tag the cursor is over, substituting it into the last grep command
1571d112
JB
726in the grep command history (or into `grep-command' if that history
727list is empty)."
318e2976
KS
728 (interactive
729 (progn
0acfb7ce 730 (grep-compute-defaults)
318e2976 731 (let ((default (grep-default-command)))
286d4b3b
SM
732 (list (read-shell-command "Run grep (like this): "
733 (if current-prefix-arg default grep-command)
734 'grep-history
735 (if current-prefix-arg nil default))))))
318e2976
KS
736
737 ;; Setting process-setup-function makes exit-message-function work
738 ;; even when async processes aren't supported.
19b3905f
JL
739 (compilation-start (if (and grep-use-null-device null-device)
740 (concat command-args " " null-device)
741 command-args)
0acfb7ce 742 'grep-mode))
ab55f76f 743
318e2976 744
318e2976
KS
745;;;###autoload
746(defun grep-find (command-args)
747 "Run grep via find, with user-specified args COMMAND-ARGS.
748Collect output in a buffer.
749While find runs asynchronously, you can use the \\[next-error] command
750to find the text that grep hits refer to.
751
752This command uses a special history list for its arguments, so you can
753easily repeat a find command."
754 (interactive
755 (progn
0acfb7ce 756 (grep-compute-defaults)
87f54c05 757 (if grep-find-command
286d4b3b
SM
758 (list (read-shell-command "Run find (like this): "
759 grep-find-command 'grep-find-history))
87f54c05
RS
760 ;; No default was set
761 (read-string
762 "compile.el: No `grep-find-command' command available. Press RET.")
763 (list nil))))
a34f7eb1 764 (when command-args
87f54c05
RS
765 (let ((null-device nil)) ; see grep
766 (grep command-args))))
318e2976 767
3d4d788a
DK
768;;;###autoload
769(defalias 'find-grep 'grep-find)
770
0acfb7ce
KS
771
772;; User-friendly interactive API.
773
774(defconst grep-expand-keywords
775 '(("<C>" . (and cf (isearch-no-upper-case-p regexp t) "-i"))
776 ("<D>" . dir)
777 ("<F>" . files)
778 ("<N>" . null-device)
779 ("<X>" . excl)
780 ("<R>" . (shell-quote-argument (or regexp ""))))
781 "List of substitutions performed by `grep-expand-template'.
782If car of an element matches, the cdr is evalled in to get the
783substitution string. Note dynamic scoping of variables.")
784
785(defun grep-expand-template (template &optional regexp files dir excl)
786 "Patch grep COMMAND string replacing <C>, <D>, <F>, <R>, and <X>."
787 (let ((command template)
788 (cf case-fold-search)
789 (case-fold-search nil))
790 (dolist (kw grep-expand-keywords command)
791 (if (string-match (car kw) command)
d0afff34
KS
792 (setq command
793 (replace-match
794 (or (if (symbolp (cdr kw))
41a2f8ba 795 (symbol-value (cdr kw))
d0afff34
KS
796 (save-match-data (eval (cdr kw))))
797 "")
798 t t command))))))
0acfb7ce
KS
799
800(defun grep-read-regexp ()
801 "Read regexp arg for interactive grep."
7cb0d0ef 802 (let ((default (grep-tag-default)))
0acfb7ce
KS
803 (read-string
804 (concat "Search for"
805 (if (and default (> (length default) 0))
7cb0d0ef 806 (format " (default \"%s\"): " default) ": "))
0acfb7ce
KS
807 nil 'grep-regexp-history default)))
808
809(defun grep-read-files (regexp)
810 "Read files arg for interactive grep."
6830f449
JL
811 (let* ((bn (or (buffer-file-name)
812 (replace-regexp-in-string "<[0-9]+>\\'" "" (buffer-name))))
208cc91f
KS
813 (fn (and bn
814 (stringp bn)
815 (file-name-nondirectory bn)))
7ae62430
JL
816 (default-alias
817 (and fn
df9db151
JL
818 (let ((aliases (remove (assoc "all" grep-files-aliases)
819 grep-files-aliases))
7ae62430
JL
820 alias)
821 (while aliases
822 (setq alias (car aliases)
823 aliases (cdr aliases))
df9db151
JL
824 (if (string-match (mapconcat
825 'wildcard-to-regexp
826 (split-string (cdr alias) nil t)
827 "\\|")
828 fn)
7ae62430
JL
829 (setq aliases nil)
830 (setq alias nil)))
831 (cdr alias))))
832 (default-extension
833 (and fn
834 (let ((ext (file-name-extension fn)))
835 (and ext (concat "*." ext)))))
208cc91f 836 (default
7ae62430
JL
837 (or default-alias
838 default-extension
bcdf86fb
KS
839 (car grep-files-history)
840 (car (car grep-files-aliases))))
9136e895 841 (files (completing-read
0acfb7ce 842 (concat "Search for \"" regexp
208cc91f
KS
843 "\" in files"
844 (if default (concat " (default " default ")"))
845 ": ")
9136e895
JL
846 'read-file-name-internal
847 nil nil nil 'grep-files-history
7ae62430
JL
848 (delete-dups
849 (delq nil (append (list default default-alias default-extension)
850 (mapcar 'car grep-files-aliases)))))))
0acfb7ce
KS
851 (and files
852 (or (cdr (assoc files grep-files-aliases))
853 files))))
318e2976
KS
854
855;;;###autoload
32a2cf25 856(defun lgrep (regexp &optional files dir confirm)
9d4a3d39 857 "Run grep, searching for REGEXP in FILES in directory DIR.
318e2976 858The search is limited to file names matching shell pattern FILES.
0acfb7ce 859FILES may use abbreviations defined in `grep-files-aliases', e.g.
318e2976
KS
860entering `ch' is equivalent to `*.[ch]'.
861
6e7c574f
KS
862With \\[universal-argument] prefix, you can edit the constructed shell command line
863before it is executed.
864With two \\[universal-argument] prefixes, directly edit and run `grep-command'.
318e2976 865
0acfb7ce 866Collect output in a buffer. While grep runs asynchronously, you
1571d112
JB
867can use \\[next-error] (M-x next-error), or \\<grep-mode-map>\\[compile-goto-error] \
868in the grep output buffer,
869to go to the lines where grep found matches.
318e2976 870
0acfb7ce 871This command shares argument histories with \\[rgrep] and \\[grep]."
318e2976 872 (interactive
0acfb7ce
KS
873 (progn
874 (grep-compute-defaults)
875 (cond
876 ((and grep-command (equal current-prefix-arg '(16)))
877 (list (read-from-minibuffer "Run: " grep-command
32a2cf25 878 nil nil 'grep-history)))
0acfb7ce 879 ((not grep-template)
5a0c3f56 880 (error "grep.el: No `grep-template' available"))
0acfb7ce 881 (t (let* ((regexp (grep-read-regexp))
9d4a3d39
KS
882 (files (grep-read-files regexp))
883 (dir (read-directory-name "In directory: "
32a2cf25
JL
884 nil default-directory t))
885 (confirm (equal current-prefix-arg '(4))))
886 (list regexp files dir confirm))))))
0acfb7ce 887 (when (and (stringp regexp) (> (length regexp) 0))
32a2cf25
JL
888 (unless (and dir (file-directory-p dir) (file-readable-p dir))
889 (setq dir default-directory))
0acfb7ce
KS
890 (let ((command regexp))
891 (if (null files)
892 (if (string= command grep-command)
893 (setq command nil))
9d4a3d39 894 (setq dir (file-name-as-directory (expand-file-name dir)))
0acfb7ce
KS
895 (setq command (grep-expand-template
896 grep-template
897 regexp
7ae62430
JL
898 files
899 nil
900 (and grep-find-ignored-files
901 (concat " --exclude="
902 (mapconcat
903 #'(lambda (ignore)
904 (cond ((stringp ignore)
905 (shell-quote-argument ignore))
906 ((consp ignore)
907 (and (funcall (car ignore) dir)
908 (shell-quote-argument
909 (cdr ignore))))))
910 grep-find-ignored-files
911 " --exclude=")))))
0acfb7ce 912 (when command
32a2cf25 913 (if confirm
0acfb7ce
KS
914 (setq command
915 (read-from-minibuffer "Confirm: "
916 command nil nil 'grep-history))
c3e9438b 917 (add-to-history 'grep-history command))))
0acfb7ce 918 (when command
32a2cf25 919 (let ((default-directory dir))
9d4a3d39
KS
920 ;; Setting process-setup-function makes exit-message-function work
921 ;; even when async processes aren't supported.
922 (compilation-start (if (and grep-use-null-device null-device)
923 (concat command " " null-device)
c60c6d91
RS
924 command)
925 'grep-mode))
9d4a3d39
KS
926 (if (eq next-error-last-buffer (current-buffer))
927 (setq default-directory dir))))))
928
0acfb7ce 929
da205913 930(defvar find-name-arg) ; not autoloaded but defined in find-dired
0acfb7ce
KS
931
932;;;###autoload
32a2cf25 933(defun rgrep (regexp &optional files dir confirm)
6e7c574f 934 "Recursively grep for REGEXP in FILES in directory tree rooted at DIR.
0acfb7ce
KS
935The search is limited to file names matching shell pattern FILES.
936FILES may use abbreviations defined in `grep-files-aliases', e.g.
937entering `ch' is equivalent to `*.[ch]'.
938
6e7c574f
KS
939With \\[universal-argument] prefix, you can edit the constructed shell command line
940before it is executed.
941With two \\[universal-argument] prefixes, directly edit and run `grep-find-command'.
0acfb7ce
KS
942
943Collect output in a buffer. While find runs asynchronously, you
1571d112
JB
944can use \\[next-error] (M-x next-error), or \\<grep-mode-map>\\[compile-goto-error] \
945in the grep output buffer,
946to go to the lines where grep found matches.
0acfb7ce
KS
947
948This command shares argument histories with \\[lgrep] and \\[grep-find]."
949 (interactive
950 (progn
951 (grep-compute-defaults)
952 (cond
953 ((and grep-find-command (equal current-prefix-arg '(16)))
954 (list (read-from-minibuffer "Run: " grep-find-command
32a2cf25 955 nil nil 'grep-find-history)))
0acfb7ce 956 ((not grep-find-template)
5a0c3f56 957 (error "grep.el: No `grep-find-template' available"))
0acfb7ce
KS
958 (t (let* ((regexp (grep-read-regexp))
959 (files (grep-read-files regexp))
960 (dir (read-directory-name "Base directory: "
32a2cf25
JL
961 nil default-directory t))
962 (confirm (equal current-prefix-arg '(4))))
963 (list regexp files dir confirm))))))
0acfb7ce 964 (when (and (stringp regexp) (> (length regexp) 0))
32a2cf25
JL
965 (unless (and dir (file-directory-p dir) (file-readable-p dir))
966 (setq dir default-directory))
0acfb7ce
KS
967 (if (null files)
968 (if (not (string= regexp grep-find-command))
12b16734 969 (compilation-start regexp 'grep-mode))
c0b87c3f 970 (setq dir (file-name-as-directory (expand-file-name dir)))
da205913 971 (require 'find-dired) ; for `find-name-arg'
c0b87c3f
KS
972 (let ((command (grep-expand-template
973 grep-find-template
974 regexp
84d797c9 975 (concat (shell-quote-argument "(")
34fac407 976 " " find-name-arg " "
c0b87c3f
KS
977 (mapconcat #'shell-quote-argument
978 (split-string files)
ea7ac2eb 979 (concat " -o " find-name-arg " "))
84d797c9
KS
980 " "
981 (shell-quote-argument ")"))
7ae62430
JL
982 dir
983 (concat
0acfb7ce 984 (and grep-find-ignored-directories
84d797c9
KS
985 (concat (shell-quote-argument "(")
986 ;; we should use shell-quote-argument here
987 " -path "
49405d0e 988 (mapconcat
7ae62430
JL
989 #'(lambda (ignore)
990 (cond ((stringp ignore)
991 (shell-quote-argument
992 (concat "*/" ignore)))
993 ((consp ignore)
994 (and (funcall (car ignore) dir)
995 (shell-quote-argument
996 (concat "*/"
997 (cdr ignore)))))))
998 grep-find-ignored-directories
999 " -o -path ")
1000 " "
1001 (shell-quote-argument ")")
1002 " -prune -o "))
1003 (and grep-find-ignored-files
1004 (concat (shell-quote-argument "(")
1005 ;; we should use shell-quote-argument here
1006 " -name "
1007 (mapconcat
1008 #'(lambda (ignore)
1009 (cond ((stringp ignore)
1010 (shell-quote-argument ignore))
1011 ((consp ignore)
1012 (and (funcall (car ignore) dir)
1013 (shell-quote-argument
1014 (cdr ignore))))))
1015 grep-find-ignored-files
1016 " -o -name ")
84d797c9
KS
1017 " "
1018 (shell-quote-argument ")")
7ae62430 1019 " -prune -o "))))))
0acfb7ce 1020 (when command
32a2cf25 1021 (if confirm
0acfb7ce
KS
1022 (setq command
1023 (read-from-minibuffer "Confirm: "
1024 command nil nil 'grep-find-history))
c3e9438b 1025 (add-to-history 'grep-find-history command))
bb617717
LMI
1026 (let ((default-directory dir)
1027 (process-connection-type nil))
c0b87c3f
KS
1028 (compilation-start command 'grep-mode))
1029 ;; Set default-directory if we started rgrep in the *grep* buffer.
1030 (if (eq next-error-last-buffer (current-buffer))
1031 (setq default-directory dir)))))))
318e2976 1032
a601d313
JL
1033;;;###autoload
1034(defun zrgrep (regexp &optional files dir confirm grep-find-template)
1035 "Recursively grep for REGEXP in gzipped FILES in tree rooted at DIR.
1036Like `rgrep' but uses `zgrep' for `grep-program', sets the default
1037file name to `*.gz', and sets `grep-highlight-matches' to `always'."
1038 (interactive
ad6fc8f4
JL
1039 (progn
1040 ;; Compute standard default values.
a601d313 1041 (grep-compute-defaults)
ad6fc8f4
JL
1042 ;; Compute the default zrgrep command by running `grep-compute-defaults'
1043 ;; for grep program "zgrep", but not changing global values.
1044 (let ((grep-program "zgrep")
1045 ;; Don't change global values for variables computed
1046 ;; by `grep-compute-defaults'.
1047 (grep-find-template nil)
1048 (grep-find-command nil)
1049 (grep-host-defaults-alist nil)
1050 ;; Use for `grep-read-files'
1051 (grep-files-aliases '(("all" . "* .*")
1052 ("gz" . "*.gz"))))
1053 ;; Recompute defaults using let-bound values above.
1054 (grep-compute-defaults)
1055 (cond
1056 ((and grep-find-command (equal current-prefix-arg '(16)))
1057 (list (read-from-minibuffer "Run: " grep-find-command
1058 nil nil 'grep-find-history)))
1059 ((not grep-find-template)
1060 (error "grep.el: No `grep-find-template' available"))
1061 (t (let* ((regexp (grep-read-regexp))
1062 (files (grep-read-files regexp))
1063 (dir (read-directory-name "Base directory: "
1064 nil default-directory t))
1065 (confirm (equal current-prefix-arg '(4))))
1066 (list regexp files dir confirm grep-find-template)))))))
a601d313
JL
1067 ;; Set `grep-highlight-matches' to `always'
1068 ;; since `zgrep' puts filters in the grep output.
1069 (let ((grep-highlight-matches 'always))
1070 ;; `rgrep' uses the dynamically bound value `grep-find-template'
1071 ;; from the argument `grep-find-template' whose value is computed
1072 ;; in the `interactive' spec.
1073 (rgrep regexp files dir confirm)))
1074
1075;;;###autoload
1076(defalias 'rzgrep 'zrgrep)
318e2976
KS
1077
1078(provide 'grep)
1079
06626cf2 1080;;; grep.el ends here