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