LCOV - code coverage report
Current view: top level - lisp/progmodes - grep.el (source / functions) Hit Total Coverage
Test: tramp-tests.info Lines: 3 447 0.7 %
Date: 2017-08-27 09:44:50 Functions: 1 23 4.3 %

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

Generated by: LCOV version 1.12