-;;; grep.el --- run Grep as inferior of Emacs, parse match messages
+;;; grep.el --- run `grep' and display the results
-;; Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-;; 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+;; Copyright (C) 1985-1987, 1993-1999, 2001-2011
;; Free Software Foundation, Inc.
;; Author: Roland McGrath <roland@gnu.org>
(defgroup grep nil
- "Run grep as inferior of Emacs, parse error messages."
+ "Run `grep' and display the results."
:group 'tools
:group 'processes)
Some grep programs are able to surround matches with special
markers in grep output. Such markers can be used to highlight
-matches in grep mode.
+matches in grep mode. This requires `font-lock-mode' to be active
+in grep buffers, so if you have globally disabled font-lock-mode,
+you will not get highlighting.
This option sets the environment variable GREP_COLORS to specify
markers for highlighting and GREP_OPTIONS to add the --color
;;;###autoload
(defconst grep-regexp-alist
- '(("^\\(.+?\\)\\(:[ \t]*\\)\\([0-9]+\\)\\2"
+ '(("^\\(.+?\\)\\(:[ \t]*\\)\\([1-9][0-9]*\\)\\2"
1 3)
;; Rule to match column numbers is commented out since no known grep
;; produces them
;; ("^\\(.+?\\)\\(:[ \t]*\\)\\([0-9]+\\)\\2\\(?:\\([0-9]+\\)\\(?:-\\([0-9]+\\)\\)?\\2\\)?"
;; 1 3 (4 . 5))
- ("^\\(\\(.+?\\):\\([0-9]+\\):\\).*?\
+ ;; Note that we want to use as tight a regexp as we can to try and
+ ;; handle weird file names (with colons in them) as well as possible.
+ ;; E.g. we use [1-9][0-9]* rather than [0-9]+ so as to accept ":034:" in
+ ;; file names.
+ ("^\\(\\(.+?\\):\\([1-9][0-9]*\\):\\).*?\
\\(\033\\[01;31m\\(?:\033\\[K\\)?\\)\\(.*?\\)\\(\033\\[[0-9]*m\\)"
2 3
;; Calculate column positions (beg . end) of first grep match on a line
(- (match-beginning 4) (match-end 1)))
.
(lambda () (- (match-end 5) (match-end 1)
- (- (match-end 4) (match-beginning 4)))))
+ (- (match-end 4) (match-beginning 4)))))
nil 1)
("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
"Regexp used to match grep hits. See `compilation-error-regexp-alist'.")
(defvar grep-mode-font-lock-keywords
'(;; Command output lines.
- ("^\\([A-Za-z_0-9/\.+-]+\\)[ \t]*:" 1 font-lock-function-name-face)
(": \\(.+\\): \\(?:Permission denied\\|No such \\(?:file or directory\\|device or address\\)\\)$"
1 grep-error-face)
;; remove match from grep-regexp-alist before fontifying
("^Grep[/a-zA-z]* started.*"
- (0 '(face nil message nil help-echo nil mouse-face nil) t))
+ (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
("^Grep[/a-zA-z]* finished \\(?:(\\(matches found\\))\\|with \\(no matches found\\)\\).*"
- (0 '(face nil message nil help-echo nil mouse-face nil) t)
+ (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
(1 compilation-info-face nil t)
(2 compilation-warning-face nil t))
("^Grep[/a-zA-z]* \\(exited abnormally\\|interrupt\\|killed\\|terminated\\)\\(?:.*with code \\([0-9]+\\)\\)?.*"
- (0 '(face nil message nil help-echo nil mouse-face nil) t)
+ (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
(1 grep-error-face)
(2 grep-error-face nil t))
- ("^.+?-[0-9]+-.*\n" (0 grep-context-face))
- ;; Highlight grep matches and delete markers
- ("\\(\033\\[01;31m\\)\\(.*?\\)\\(\033\\[[0-9]*m\\)"
- ;; Refontification does not work after the markers have been
- ;; deleted. So we use the font-lock-face property here as Font
- ;; Lock does not clear that.
- (2 (list 'face nil 'font-lock-face grep-match-face))
- ((lambda (bound))
- (progn
- ;; Delete markers with `replace-match' because it updates
- ;; the match-data, whereas `delete-region' would render it obsolete.
- (replace-match "" t t nil 3)
- (replace-match "" t t nil 1))))
- ("\\(\033\\[[0-9;]*[mK]\\)"
- ;; Delete all remaining escape sequences
- ((lambda (bound))
- (replace-match "" t t nil 1))))
+ ("^.+?-[0-9]+-.*\n" (0 grep-context-face)))
"Additional things to highlight in grep output.
This gets tacked on the end of the generated expressions.")
;;;###autoload
(defvar grep-find-use-xargs nil
- "Non-nil means that `grep-find' uses the `xargs' utility by default.
-If `exec', use `find -exec'.
+ "How to invoke find and grep.
+If `exec', use `find -exec {} ;'.
+If `exec-plus' use `find -exec {} +'.
If `gnu', use `find -print0' and `xargs -0'.
-Any other non-nil value means to use `find -print' and `xargs'.
+Any other value means to use `find -print' and `xargs'.
This variable's value takes effect when `grep-compute-defaults' is called.")
(when (eq grep-highlight-matches 'auto-detect)
(grep-compute-defaults))
(unless (or (eq grep-highlight-matches 'auto-detect)
+ ;; Uses font-lock to parse color escapes. (Bug#8084)
+ (null font-lock-mode)
(null grep-highlight-matches))
;; `setenv' modifies `process-environment' let-bound in `compilation-start'
;; Any TERM except "dumb" allows GNU grep to use `--color=auto'
(cons msg code))))
(run-hooks 'grep-setup-hook))
+(defun grep-filter ()
+ "Handle match highlighting escape sequences inserted by the grep process.
+This function is called from `compilation-filter-hook'."
+ (save-excursion
+ (forward-line 0)
+ (let ((end (point)))
+ (goto-char compilation-filter-start)
+ (forward-line 0)
+ ;; Only operate on whole lines so we don't get caught with part of an
+ ;; escape sequence in one chunk and the rest in another.
+ (when (< (point) end)
+ (setq end (copy-marker end))
+ ;; Highlight grep matches and delete marking sequences.
+ (while (re-search-forward "\033\\[01;31m\\(.*?\\)\033\\[[0-9]*m" end 1)
+ (replace-match (propertize (match-string 1)
+ 'face nil 'font-lock-face grep-match-face)
+ t t))
+ ;; Delete all remaining escape sequences
+ (goto-char compilation-filter-start)
+ (while (re-search-forward "\033\\[[0-9;]*[mK]" end 1)
+ (replace-match "" t t))))))
+
(defun grep-probe (command args &optional func result)
(let (process-file-side-effects)
(equal (condition-case nil
(unless grep-find-use-xargs
(setq grep-find-use-xargs
(cond
+ ((grep-probe find-program
+ `(nil nil nil ,null-device "-exec" "echo"
+ "{}" "+"))
+ 'exec-plus)
((and
(grep-probe find-program `(nil nil nil ,null-device "-print0"))
(grep-probe xargs-program `(nil nil nil "-0" "-e" "echo")))
(unless grep-find-command
(setq grep-find-command
(cond ((eq grep-find-use-xargs 'gnu)
- (format "%s . -type f -print0 | %s -0 -e %s"
+ ;; Windows shells need the program file name
+ ;; after the pipe symbol be quoted if they use
+ ;; forward slashes as directory separators.
+ (format "%s . -type f -print0 | \"%s\" -0 -e %s"
find-program xargs-program grep-command))
- ((eq grep-find-use-xargs 'exec)
+ ((memq grep-find-use-xargs '(exec exec-plus))
(let ((cmd0 (format "%s . -type f -exec %s"
- find-program grep-command)))
+ find-program grep-command))
+ (null (if grep-use-null-device
+ (format "%s " null-device)
+ "")))
(cons
- (format "%s {} %s %s"
- cmd0 null-device
- (shell-quote-argument ";"))
+ (if (eq grep-find-use-xargs 'exec-plus)
+ (format "%s %s{} +" cmd0 null)
+ (format "%s {} %s%s" cmd0 null
+ (shell-quote-argument ";")))
(1+ (length cmd0)))))
(t
- (format "%s . -type f -print | %s %s"
+ (format "%s . -type f -print | \"%s\" %s"
find-program xargs-program grep-command)))))
(unless grep-find-template
(setq grep-find-template
(let ((gcmd (format "%s <C> %s <R>"
- grep-program grep-options)))
+ grep-program grep-options))
+ (null (if grep-use-null-device
+ (format "%s " null-device)
+ "")))
(cond ((eq grep-find-use-xargs 'gnu)
- (format "%s . <X> -type f <F> -print0 | %s -0 -e %s"
+ (format "%s . <X> -type f <F> -print0 | \"%s\" -0 -e %s"
find-program xargs-program gcmd))
((eq grep-find-use-xargs 'exec)
- (format "%s . <X> -type f <F> -exec %s {} %s %s"
- find-program gcmd null-device
+ (format "%s . <X> -type f <F> -exec %s {} %s%s"
+ find-program gcmd null
(shell-quote-argument ";")))
+ ((eq grep-find-use-xargs 'exec-plus)
+ (format "%s . <X> -type f <F> -exec %s %s{} +"
+ find-program gcmd null))
(t
- (format "%s . <X> -type f <F> -print | %s %s"
+ (format "%s . <X> -type f <F> -print | \"%s\" %s"
find-program xargs-program gcmd))))))))
(when (eq grep-highlight-matches 'auto-detect)
(setq grep-highlight-matches
grep-hit-face)
(set (make-local-variable 'compilation-error-regexp-alist)
grep-regexp-alist)
+ ;; compilation-directory-matcher can't be nil, so we set it to a regexp that
+ ;; can never match.
+ (set (make-local-variable 'compilation-directory-matcher) '("\\`a\\`"))
(set (make-local-variable 'compilation-process-setup-function)
'grep-process-setup)
- (set (make-local-variable 'compilation-disable-input) t))
+ (set (make-local-variable 'compilation-disable-input) t)
+ (add-hook 'compilation-filter-hook 'grep-filter nil t))
;;;###autoload
(file-name-nondirectory bn)))
(default-alias
(and fn
- (let ((aliases grep-files-aliases)
+ (let ((aliases (remove (assoc "all" grep-files-aliases)
+ grep-files-aliases))
alias)
(while aliases
(setq alias (car aliases)
aliases (cdr aliases))
- (if (string-match (wildcard-to-regexp (cdr alias)) fn)
+ (if (string-match (mapconcat
+ 'wildcard-to-regexp
+ (split-string (cdr alias) nil t)
+ "\\|")
+ fn)
(setq aliases nil)
(setq alias nil)))
(cdr alias))))
(provide 'grep)
-;; arch-tag: 5a5b9169-a79d-4f38-9c38-f69615f39c4d
;;; grep.el ends here