Jens Petersen a0ad7c
;;; igrep.el --- An improved interface to `grep` and `find`
Jens Petersen a0ad7c
;;; -*-unibyte: t;-*-
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Copyright © 1993-1998,2000-2004 Kevin Rodgers
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Author: Kevin Rodgers <ihs_4664@yahoo.com>
Jens Petersen a0ad7c
;; Created:  22 Jun 1993
Jens Petersen a0ad7c
;; Version: 2.112
Jens Petersen a0ad7c
;; Keywords: tools, processes, search
Jens Petersen a0ad7c
;; SCCS: @(#)igrep.el	2.112
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; This program is free software; you can redistribute it and/or
Jens Petersen a0ad7c
;; modify it under the terms of the GNU General Public License as
Jens Petersen a0ad7c
;; published by the Free Software Foundation; either version 2 of
Jens Petersen a0ad7c
;; the License, or (at your option) any later version.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; This program is distributed in the hope that it will be
Jens Petersen a0ad7c
;; useful, but WITHOUT ANY WARRANTY; without even the implied
Jens Petersen a0ad7c
;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
Jens Petersen a0ad7c
;; PURPOSE.  See the GNU General Public License for more details.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; You should have received a copy of the GNU General Public
Jens Petersen a0ad7c
;; License along with this program; if not, write to the Free
Jens Petersen a0ad7c
;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
Jens Petersen a0ad7c
;; MA 02111-1307 USA
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;;; Commentary:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; The `igrep' command is like `grep' except that it takes three
Jens Petersen a0ad7c
;; required arguments (PROGRAM, REGEX, and FILES) and an optional
Jens Petersen a0ad7c
;; argument (OPTIONS) instead of just one argument (COMMAND).  The
Jens Petersen a0ad7c
;; analogous `egrep' and `fgrep' commands are also defined for
Jens Petersen a0ad7c
;; convenience.
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; The `igrep-find' command is like `igrep' except that it uses `find`
Jens Petersen a0ad7c
;; to recursively `grep` a directory.  The analogous `egrep-find' and
Jens Petersen a0ad7c
;; `fgrep-find' commands are also defined for convenience.
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; When called interactively, `igrep' and `igrep-find' (and their
Jens Petersen a0ad7c
;; analogues) provide defaults for the REGEX and FILES arguments based
Jens Petersen a0ad7c
;; on the current word and the visited file name (if the `igrep-regex-
Jens Petersen a0ad7c
;; default' and `igrep-files-default' options are set, respectively).
Jens Petersen a0ad7c
;; The `igrep-insert-default-key' option allows the default value to be
Jens Petersen a0ad7c
;; inserted into the minibuffer for editing; since Emacs 20 provides
Jens Petersen a0ad7c
;; that via the minibuffer history, it's only enabled for older
Jens Petersen a0ad7c
;; versions by default. Other options that control the user interface
Jens Petersen a0ad7c
;; are `igrep-insert-default-directory', `igrep-read-options', `igrep-
Jens Petersen a0ad7c
;; read-multiple-files', `igrep-verbose-prompts', `igrep-save-buffers',
Jens Petersen a0ad7c
;; and `igrep-menu-bar'.
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; Besides the basic `igrep-program' and `igrep-find-program' global
Jens Petersen a0ad7c
;; variables, other variables control the syntax of the `grep` and
Jens Petersen a0ad7c
;; `find` shell commands that are executed: `igrep-options', `igrep-
Jens Petersen a0ad7c
;; regex-option', `igrep-case-fold-search', `igrep-find-prune-clause',
Jens Petersen a0ad7c
;; `igrep-find-file-clause', and `igrep-find-use-xargs'.
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; The `igrep-use-zgrep' user option controls whether the corresponding
Jens Petersen a0ad7c
;; GNU (gzip) "zPROGRAM" script is used, to `grep` compressed files.
Jens Petersen a0ad7c
;; Special minibuffer history lists are maintained for the REGEX and
Jens Petersen a0ad7c
;; FILES arguments.
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; The `agrep' and `agrep-find' commands are interfaces to the
Jens Petersen a0ad7c
;; approximate `grep` utility, which is distributed with the `glimpse'
Jens Petersen a0ad7c
;; indexing and query tool (available from http://www.tgries.de/agrep/).
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; `grep' itself can be advised to provide the `igrep' interface when
Jens Petersen a0ad7c
;; it is invoked interactively (but still use the original argument
Jens Petersen a0ad7c
;; list when it is called from Emacs Lisp), via the `igrep-insinuate'
Jens Petersen a0ad7c
;; command.  `igrep-insinuate' also defines `grep-find' as an alias for
Jens Petersen a0ad7c
;; `igrep-find', `dired-do-grep' and `dired-do-grep-find' as aliases
Jens Petersen a0ad7c
;; for `dired-do-igrep' and `dired-do-igrep-find', and `Buffer-menu-
Jens Petersen a0ad7c
;; grep' as an alias for `Buffer-menu-igrep'.
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; When run interactively from Dired mode, the various `igrep' commands
Jens Petersen a0ad7c
;; provide defaults for the REGEX and FILES arguments that are based on
Jens Petersen a0ad7c
;; the visited directory (including any inserted subdirectories) and
Jens Petersen a0ad7c
;; the current file.  The alternative `dired-do-igrep' and `dired-do-
Jens Petersen a0ad7c
;; igrep-find' commands respect the `dired-do-*' command conventions: a
Jens Petersen a0ad7c
;; prefix argument is interpreted as the number of succeeding files to
Jens Petersen a0ad7c
;; `grep`, otherwise all the marked files are `grep`ed.
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; The `igrep-visited-files' command provides a simple way to `grep`
Jens Petersen a0ad7c
;; just those files that are being visited in buffers.  The `Buffer-
Jens Petersen a0ad7c
;; menu-igrep' command does the same thing, for buffers marked for
Jens Petersen a0ad7c
;; selection in Buffer Menu mode.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Installation:
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; 1. Put this file in a directory that is a member of load-path, and
Jens Petersen a0ad7c
;;    byte-compile it (e.g. with `M-x byte-compile-file') for better
Jens Petersen a0ad7c
;;    performance.  You can ignore any warnings about references to free
Jens Petersen a0ad7c
;;    variables and "not known to be defined" functions.
Jens Petersen a0ad7c
;; 2. Put these forms in default.el or ~/.emacs:
Jens Petersen a0ad7c
;;    (autoload 'igrep "igrep"
Jens Petersen a0ad7c
;;       "*Run `grep` PROGRAM to match REGEX in FILES..." t)
Jens Petersen a0ad7c
;;    (autoload 'igrep-find "igrep"
Jens Petersen a0ad7c
;;       "*Run `grep` via `find`..." t)
Jens Petersen a0ad7c
;;    (autoload 'igrep-visited-files "igrep"
Jens Petersen a0ad7c
;;       "*Run `grep` ... on all visited files." t)
Jens Petersen a0ad7c
;;    (autoload 'dired-do-igrep "igrep"
Jens Petersen a0ad7c
;;       "*Run `grep` on the marked (or next prefix ARG) files." t)
Jens Petersen a0ad7c
;;    (autoload 'dired-do-igrep-find "igrep"
Jens Petersen a0ad7c
;;       "*Run `grep` via `find` on the marked (or next prefix ARG) directories." t)
Jens Petersen a0ad7c
;;    (autoload 'Buffer-menu-igrep "igrep"
Jens Petersen a0ad7c
;;      "*Run `grep` on the files visited in buffers marked with '>'." t)
Jens Petersen a0ad7c
;;    (autoload 'igrep-insinuate "igrep"
Jens Petersen a0ad7c
;;      "Define `grep' aliases for the corresponding `igrep' commands." t)
Jens Petersen a0ad7c
;; 2. a. For completeness, you can add these forms as well:
Jens Petersen a0ad7c
;;    (autoload 'grep "igrep"
Jens Petersen a0ad7c
;;       "*Run `grep` PROGRAM to match REGEX in FILES..." t)
Jens Petersen a0ad7c
;;    (autoload 'egrep "igrep"
Jens Petersen a0ad7c
;;       "*Run `egrep`..." t)
Jens Petersen a0ad7c
;;    (autoload 'fgrep "igrep"
Jens Petersen a0ad7c
;;       "*Run `fgrep`..." t)
Jens Petersen a0ad7c
;;    (autoload 'agrep "igrep"
Jens Petersen a0ad7c
;;       "*Run `agrep`..." t)
Jens Petersen a0ad7c
;;    (autoload 'grep-find "igrep"
Jens Petersen a0ad7c
;;       "*Run `grep` via `find`..." t)
Jens Petersen a0ad7c
;;    (autoload 'egrep-find "igrep"
Jens Petersen a0ad7c
;;       "*Run `egrep` via `find`..." t)
Jens Petersen a0ad7c
;;    (autoload 'fgrep-find "igrep"
Jens Petersen a0ad7c
;;       "*Run `fgrep` via `find`..." t)
Jens Petersen a0ad7c
;;    (autoload 'agrep-find "igrep"
Jens Petersen a0ad7c
;;       "*Run `agrep` via `find`..." t)
Jens Petersen a0ad7c
;; 3. If you are running Windows 95/NT, you should install findutils
Jens Petersen a0ad7c
;;    and grep from release 17.1 (or higher) of the Cygnus GNU-Win32
Jens Petersen a0ad7c
;;    distribution (http://www.cygnus.com/misc/gnu-win32/).
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Usage:
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; These igrep commands accept 1, 2, or 3 `C-u' prefix arguments:
Jens Petersen a0ad7c
;; 	M-x igrep		M-x igrep-find
Jens Petersen a0ad7c
;; 	M-x  grep		M-x  grep-find	[after `M-x igrep-insinuate']
Jens Petersen a0ad7c
;; 	M-x egrep		M-x egrep-find
Jens Petersen a0ad7c
;; 	M-x fgrep		M-x fgrep-find
Jens Petersen a0ad7c
;; 	M-x agrep		M-x agrep-find
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; These igrep commands accept a single `C-u' prefix argument:
Jens Petersen a0ad7c
;; 	M-x igrep-visited-files
Jens Petersen a0ad7c
;; 	M-x Buffer-menu-igrep	[in the *Buffer List* buffer]
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; These igrep commands interpret a prefix argument like the Emacs
Jens Petersen a0ad7c
;; `dired-do-*' commands:
Jens Petersen a0ad7c
;; 	M-x dired-do-igrep	M-x dired-do-igrep-find
Jens Petersen a0ad7c
;; 	M-x  dired-do-grep	M-x  dired-do-grep-find	[after `M-x
Jens Petersen a0ad7c
;; 							 igrep-insinuate']
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; These Emacs commands can be used after any igrep command:
Jens Petersen a0ad7c
;; 	C-x ` (M-x next-error)
Jens Petersen a0ad7c
;; 	C-c C-c (M-x compile-goto-error)	[in the *igrep* buffer]
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Customization examples:
Jens Petersen a0ad7c
;; 
Jens Petersen a0ad7c
;; To ignore case by default:
Jens Petersen a0ad7c
;; 	(setq igrep-options "-i")
Jens Petersen a0ad7c
;; or:
Jens Petersen a0ad7c
;; 	(setq igrep-case-fold-search t)
Jens Petersen a0ad7c
;; To search subdirectories by default:
Jens Petersen a0ad7c
;; 	(setq igrep-find t)
Jens Petersen a0ad7c
;; To search files with the GNU (gzip) zgrep script:
Jens Petersen a0ad7c
;; 	(setq igrep-use-zgrep t)
Jens Petersen a0ad7c
;; or define new igrep commands (this works for zegrep and zfgrep as well):
Jens Petersen a0ad7c
;; 	(igrep-define zgrep)		; M-x zgrep
Jens Petersen a0ad7c
;; 	(igrep-find-define zgrep)	; M-x zgrep-find
Jens Petersen a0ad7c
;; To search "*.[ch]" files by default in C mode:
Jens Petersen a0ad7c
;; 	(put 'igrep-files-default 'c-mode
Jens Petersen a0ad7c
;; 	     (lambda () "*.[ch]"))
Jens Petersen a0ad7c
;; To disable the default search regex and/or files pattern, except for
Jens Petersen a0ad7c
;; specific modes:
Jens Petersen a0ad7c
;; 	(setq igrep-regex-default 'ignore)
Jens Petersen a0ad7c
;; 	(setq igrep-files-default 'ignore)
Jens Petersen a0ad7c
;; To avoid exceeding some shells' limit on command argument length
Jens Petersen a0ad7c
;; (this only searches files in the current directory):
Jens Petersen a0ad7c
;; 	(setq igrep-find t
Jens Petersen a0ad7c
;; 	      igrep-find-prune-clause "-type d \\! -name .")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; To do:
Jens Petersen a0ad7c
;; 1. Replace igrep-options with a table that maps igrep-program
Jens Petersen a0ad7c
;;    to the appropriate options, and/or support POSIX (egrep -> `grep -E`).
Jens Petersen a0ad7c
;; 2. Generalize support for the -prune find clause (e.g. -fstype nfs).
Jens Petersen a0ad7c
;; 3. Provide support for `glimpse`.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;;; Code:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Package interface:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(require 'custom)			; defgroup, defcustom
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(require 'easymenu)			; easy-menu-define, easy-menu-add-item
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(or (condition-case nil
Jens Petersen a0ad7c
	(require 'grep)			; CVS Emacs (21.3.50/21.4)
Jens Petersen a0ad7c
      (error nil))
Jens Petersen a0ad7c
    (require 'compile))			; compile-internal, grep-regexp-alist,
Jens Petersen a0ad7c
					; grep-null-device
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(eval-when-compile
Jens Petersen a0ad7c
  (require 'dired)			; dired-directory,
Jens Petersen a0ad7c
					; dired-get-filename,
Jens Petersen a0ad7c
					; dired-current-directory,
Jens Petersen a0ad7c
					; dired-get-marked-files,
Jens Petersen a0ad7c
					; dired-mark-get-files
Jens Petersen a0ad7c
  (or (featurep 'ange-ftp)
Jens Petersen a0ad7c
      (featurep 'efs)
Jens Petersen a0ad7c
      (condition-case nil
Jens Petersen a0ad7c
	  (load-library "ange-ftp")	; ange-ftp-ftp-name
Jens Petersen a0ad7c
	(error nil))
Jens Petersen a0ad7c
      (condition-case nil
Jens Petersen a0ad7c
	  (load-library "efs")		; efs-ftp-path
Jens Petersen a0ad7c
	(error nil)))
Jens Petersen a0ad7c
  )
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defconst igrep-version "2.112"
Jens Petersen a0ad7c
  "This version of igrep.el.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defgroup igrep nil
Jens Petersen a0ad7c
  "An improved interface to `grep` and `find`."
Jens Petersen a0ad7c
  :group 'compilation)
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; User options:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defcustom igrep-options nil
Jens Petersen a0ad7c
  "*The options passed by `\\[igrep]' to `igrep-program', or nil.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
\"-n\" will automatically be passed to `igrep-program', to generate the
Jens Petersen a0ad7c
output expected by `\\[next-error]' and `\\[compile-goto-error]'.
Jens Petersen a0ad7c
\"-e\" will automatically be passed to `igrep-program', if it supports
Jens Petersen a0ad7c
that option."
Jens Petersen a0ad7c
  :group 'igrep
Jens Petersen a0ad7c
  :type '(choice (const nil) (string)))
Jens Petersen a0ad7c
(put 'igrep-options 'variable-interactive
Jens Petersen a0ad7c
     "xOptions (\"-xyz\" or nil): ")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defcustom igrep-case-fold-search nil
Jens Petersen a0ad7c
  "*If non-nil, `\\[igrep]' ignores case unless REGEX has uppercase letters."
Jens Petersen a0ad7c
  :group 'igrep
Jens Petersen a0ad7c
  :type '(boolean))
Jens Petersen a0ad7c
(put 'igrep-case-fold-search 'variable-interactive
Jens Petersen a0ad7c
     "XIgnore case? (t or nil): ")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defcustom igrep-read-options nil
Jens Petersen a0ad7c
  "*If non-nil, `\\[igrep]' always prompts for options;
Jens Petersen a0ad7c
otherwise, it only prompts when 1 or 3 `C-u's are given as a prefix arg."
Jens Petersen a0ad7c
  :group 'igrep
Jens Petersen a0ad7c
  :type '(boolean))
Jens Petersen a0ad7c
(put 'igrep-read-options 'variable-interactive
Jens Petersen a0ad7c
     "XAlways prompt for options? (t or nil): ")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defcustom igrep-read-multiple-files nil
Jens Petersen a0ad7c
  "*If non-nil, `\\[igrep]' always prompts for multiple-files;
Jens Petersen a0ad7c
otherwise, it only prompts when 2 or 3 `C-u's are given as a prefix arg."
Jens Petersen a0ad7c
  :group 'igrep
Jens Petersen a0ad7c
  :type '(boolean))
Jens Petersen a0ad7c
(put 'igrep-read-multiple-files 'variable-interactive
Jens Petersen a0ad7c
     "XAlways prompt for multiple files? (t or nil): ")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defcustom igrep-regex-default 'current-word
Jens Petersen a0ad7c
  "*If non-nil, a function that returns a default REGEX for `\\[igrep]'.
Jens Petersen a0ad7c
The function is called with no arguments and should return a string (or nil).
Jens Petersen a0ad7c

Jens Petersen a0ad7c
A different function can be specified for any particular mode by specifying
Jens Petersen a0ad7c
a value for that `major-mode' property; for example:
Jens Petersen a0ad7c
	(put 'igrep-regex-default 'dired-mode
Jens Petersen a0ad7c
	     'igrep-dired-file-current-word)"
Jens Petersen a0ad7c
  :group 'igrep
Jens Petersen a0ad7c
  :type '(choice (const nil) (function)))
Jens Petersen a0ad7c
(put 'igrep-regex-default 'variable-interactive
Jens Petersen a0ad7c
     "SProvide a default regex? (function or nil): ")
Jens Petersen a0ad7c
(put 'igrep-regex-default 'dired-mode
Jens Petersen a0ad7c
     'igrep-dired-file-current-word)
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defcustom igrep-files-default 'igrep-buffer-file-name-pattern
Jens Petersen a0ad7c
  "*If non-nil, a function that returns the default FILES for `\\[igrep]'.
Jens Petersen a0ad7c
The function is called with no arguments and should return a string,
Jens Petersen a0ad7c
or a list of strings (or nil).
Jens Petersen a0ad7c

Jens Petersen a0ad7c
A different function can be specified for any particular mode by specifying
Jens Petersen a0ad7c
a value for that `major-mode' property; for example:
Jens Petersen a0ad7c
	(put 'igrep-files-default 'dired-mode
Jens Petersen a0ad7c
	     'igrep-dired-directory-file-pattern)"
Jens Petersen a0ad7c
  :group 'igrep
Jens Petersen a0ad7c
  :type '(choice (const nil) (function)))
Jens Petersen a0ad7c
(put 'igrep-files-default 'variable-interactive
Jens Petersen a0ad7c
     "SProvide a default file name pattern? (function or nil): ")
Jens Petersen a0ad7c
(put 'igrep-files-default 'dired-mode
Jens Petersen a0ad7c
     'igrep-dired-directory-file-pattern)
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defcustom igrep-verbose-prompts t
Jens Petersen a0ad7c
  "*If t, `\\[igrep]' prompts for arguments verbosely;
Jens Petersen a0ad7c
if not t but non-nil, `\\[igrep]' prompts for arguments semi-verbosely;
Jens Petersen a0ad7c
if nil, `\\[igrep]' prompts for arguments tersely."
Jens Petersen a0ad7c
  :group 'igrep
Jens Petersen a0ad7c
  :type '(choice (const :tag "Verbose" t)
Jens Petersen a0ad7c
		 (other :tag "Semi-verbose" semi)
Jens Petersen a0ad7c
		 (const :tag "Terse" nil)))
Jens Petersen a0ad7c
(put 'igrep-verbose-prompts 'variable-interactive
Jens Petersen a0ad7c
     "XPrompt verbosely? (t, 'semi, or nil): ")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defcustom igrep-insert-default-directory nil
Jens Petersen a0ad7c
  "*The value of `insert-default-directory' for `\\[igrep]'."
Jens Petersen a0ad7c
  :group 'igrep
Jens Petersen a0ad7c
  :type '(boolean))
Jens Petersen a0ad7c
(put 'igrep-insert-default-directory 'variable-interactive
Jens Petersen a0ad7c
     "XPrompt with directory in the minibuffer? (t or nil): ")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defcustom igrep-insert-default-key
Jens Petersen a0ad7c
  (if (< emacs-major-version 20) "\C-c\C-e")
Jens Petersen a0ad7c
  "*The key used to insert the default argument in the minibuffer.
Jens Petersen a0ad7c
In Emacs 20, the default is available via the minibuffer history \
Jens Petersen a0ad7c
\(\\<minibuffer-local-map>\\[next-history-element])."
Jens Petersen a0ad7c
  :group 'igrep
Jens Petersen a0ad7c
  :type '(choice (const nil) (string) (vector))) ; key-binding
Jens Petersen a0ad7c
(put 'igrep-insert-default-key 'variable-interactive
Jens Petersen a0ad7c
     "kSet key to insert the default `\\[igrep]' argument in the minibuffer: ")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defcustom igrep-save-buffers 'query
Jens Petersen a0ad7c
  "*If t, `\\[igrep]' first saves each modified file buffer;
Jens Petersen a0ad7c
if not t but non-nil, `\\[igrep]' offers to save each modified file buffer."
Jens Petersen a0ad7c
  :group 'igrep
Jens Petersen a0ad7c
  :type '(choice (const :tag "Save" t)
Jens Petersen a0ad7c
		 (other :tag "Query" query)
Jens Petersen a0ad7c
		 (const :tag "Don't Save" nil)))
Jens Petersen a0ad7c
(put 'igrep-save-buffers 'variable-interactive
Jens Petersen a0ad7c
     "XSave modified buffers? (t, 'query, or nil): ")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defcustom igrep-menu-bar t
Jens Petersen a0ad7c
  "*If non-nil, enable the `igrep-menu' submenu on the \"Tools\" menu bar."
Jens Petersen a0ad7c
  :group 'igrep
Jens Petersen a0ad7c
  :type '(boolean))
Jens Petersen a0ad7c
(put 'igrep-menu-bar 'variable-interactive
Jens Petersen a0ad7c
     "XEnable menu bar? (t or nil): ")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; User variables:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defsubst igrep-easy-menu-item (name callback help-keyword help-text)
Jens Petersen a0ad7c
  "Return a [NAME CALLBACK HELP-KEYWORD HELP-TEXT] menu item.
Jens Petersen a0ad7c
See `easy-menu-define'."
Jens Petersen a0ad7c
  (if (featurep 'xemacs)                ; no :help keyword
Jens Petersen a0ad7c
      (vector name callback)
Jens Petersen a0ad7c
    (vector name callback help-keyword help-text)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar :help ':help)			; Emacs 19
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-easy-menu
Jens Petersen a0ad7c
  `("Search Files and Directories (igrep)"
Jens Petersen a0ad7c
    ,@(cond ((featurep 'xemacs) '(:included igrep-menu-bar))
Jens Petersen a0ad7c
	    ((>= emacs-major-version 20) '(:active igrep-menu-bar))
Jens Petersen a0ad7c
	    (t ()))
Jens Petersen a0ad7c
    ("Search files"
Jens Petersen a0ad7c
     ,(igrep-easy-menu-item "`grep` files..." 'igrep
Jens Petersen a0ad7c
                            :help "Search files for basic regex(5)s")
Jens Petersen a0ad7c
     ,(igrep-easy-menu-item "`egrep` files..." 'egrep
Jens Petersen a0ad7c
                            :help "Search files for extended regex(5)s")
Jens Petersen a0ad7c
     ,(igrep-easy-menu-item "`fgrep` files..." 'fgrep
Jens Petersen a0ad7c
                            :help "Search files for strings"))
Jens Petersen a0ad7c
    ("Search directories"
Jens Petersen a0ad7c
     ,(igrep-easy-menu-item "`find | grep` directories..." 'igrep-find
Jens Petersen a0ad7c
                            :help "Search directories for basic regex(5)s")
Jens Petersen a0ad7c
     ,(igrep-easy-menu-item "`find | egrep` directories..." 'egrep-find
Jens Petersen a0ad7c
                            :help "Search directories for extended regex(5)s")
Jens Petersen a0ad7c
     ,(igrep-easy-menu-item "`find | fgrep` directories..." 'fgrep-find
Jens Petersen a0ad7c
                            :help "Search directories for strings"))
Jens Petersen a0ad7c
    "--"
Jens Petersen a0ad7c
    ,(igrep-easy-menu-item "Search visited files..." 'igrep-visited-files
Jens Petersen a0ad7c
                           :help "Search visited files for basic regex(5)s"))
Jens Petersen a0ad7c
  "If non-nil, the menu bar submenu of `igrep' commands.
Jens Petersen a0ad7c
See `easy-menu-define'.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-null-device
Jens Petersen a0ad7c
  (cond ((boundp 'null-device) null-device) ; Emacs 20
Jens Petersen a0ad7c
	((boundp 'grep-null-device) grep-null-device)) ; Emacs 19
Jens Petersen a0ad7c
  "The system null device.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-program "grep"
Jens Petersen a0ad7c
  "The default program run by `\\[igrep]' and `\\[igrep-find]'.
Jens Petersen a0ad7c
It must accept a `grep` regex argument and one or more file names, plus
Jens Petersen a0ad7c
the \"-n\" option.  If nil, `\\[igrep]' prompts for the program to run.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-regex-option
Jens Petersen a0ad7c
  (if (equal (call-process igrep-program nil nil nil
Jens Petersen a0ad7c
			   "-e" "foo" igrep-null-device)
Jens Petersen a0ad7c
	     1)
Jens Petersen a0ad7c
      "-e")
Jens Petersen a0ad7c
  "If non-nil, the option used to specify the REGEX argument to `\\[igrep]'.
Jens Petersen a0ad7c
This protects an initial \"-\" from option processing.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-program-table		; referenced by igrep-use-zgrep
Jens Petersen a0ad7c
  (let ((exec-directories exec-path)
Jens Petersen a0ad7c
	(program-obarray (make-vector 11 0)))
Jens Petersen a0ad7c
    (while exec-directories
Jens Petersen a0ad7c
      (if (and (car exec-directories)
Jens Petersen a0ad7c
	       (file-directory-p (car exec-directories))
Jens Petersen a0ad7c
	       (file-readable-p (car exec-directories)))
Jens Petersen a0ad7c
	  (let ((grep-programs
Jens Petersen a0ad7c
		 (directory-files (car exec-directories)
Jens Petersen a0ad7c
				  nil "grep\\(\\.exe\\)?\\'")))
Jens Petersen a0ad7c
	    (while grep-programs
Jens Petersen a0ad7c
	      ;; Check `(file-executable-p (car grep-programs))'?
Jens Petersen a0ad7c
	      (if (save-match-data
Jens Petersen a0ad7c
		    (string-match "\\.exe\\'" (car grep-programs)))
Jens Petersen a0ad7c
		  (intern (substring (car grep-programs) 0 -4) program-obarray)
Jens Petersen a0ad7c
		(intern (car grep-programs) program-obarray))
Jens Petersen a0ad7c
	      (setq grep-programs (cdr grep-programs)))))
Jens Petersen a0ad7c
      (setq exec-directories (cdr exec-directories)))
Jens Petersen a0ad7c
    program-obarray)
Jens Petersen a0ad7c
  "An obarray of available `grep` programs.
Jens Petersen a0ad7c
This is passed by `igrep-read-program' to `completing-read' when
Jens Petersen a0ad7c
`igrep-program' is nil.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-use-zgrep
Jens Petersen a0ad7c
  (if (intern-soft "zgrep" igrep-program-table)
Jens Petersen a0ad7c
      'files)
Jens Petersen a0ad7c
  "If t, `\\[igrep]' searches files using the GNU (gzip) `zPROGRAM` script;
Jens Petersen a0ad7c
If not t but non-nil, `\\[igrep]' searches compressed FILES using `zPROGRAM`;
Jens Petersen a0ad7c
if nil, `\\[igrep]' searches files with `PROGRAM`.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-find nil
Jens Petersen a0ad7c
  "If non-nil, `\\[igrep]' searches directories using `find`.
Jens Petersen a0ad7c
See `igrep-find'.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-find-program "find"
Jens Petersen a0ad7c
  "The program run by `\\[igrep-find]'.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-find-prune-clause
Jens Petersen a0ad7c
  (if (equal (call-process igrep-find-program nil nil nil
Jens Petersen a0ad7c
			   igrep-null-device "-prune")
Jens Petersen a0ad7c
	     0)
Jens Petersen a0ad7c
      (format "-type d %s -name RCS -o -name CVS -o -name SCCS %s"
Jens Petersen a0ad7c
	      (shell-quote-argument "(")
Jens Petersen a0ad7c
	      (shell-quote-argument ")")))
Jens Petersen a0ad7c
  "The `find` clause used to prune directories, or nil;
Jens Petersen a0ad7c
see `igrep-find'.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-find-file-clause
Jens Petersen a0ad7c
  (format "-type f %s -name %s %s -name %s %s -name %s %s -name %s" ; -type l
Jens Petersen a0ad7c
	  (shell-quote-argument "!")
Jens Petersen a0ad7c
	  (shell-quote-argument "*~")	; Emacs backup
Jens Petersen a0ad7c
	  (shell-quote-argument "!")
Jens Petersen a0ad7c
	  (shell-quote-argument "*,v")	; RCS file
Jens Petersen a0ad7c
	  (shell-quote-argument "!")
Jens Petersen a0ad7c
	  (shell-quote-argument "s.*")	; SCCS file
Jens Petersen a0ad7c
	  (shell-quote-argument "!")
Jens Petersen a0ad7c
	  (shell-quote-argument ".#*"))	; CVS file
Jens Petersen a0ad7c
  "The `find` clause used to filter files passed to `grep`, or nil;
Jens Petersen a0ad7c
see `igrep-find'.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-find-use-xargs
Jens Petersen a0ad7c
  (cond ((equal (call-process igrep-find-program nil nil nil
Jens Petersen a0ad7c
			      igrep-null-device "-print0")
Jens Petersen a0ad7c
		0)
Jens Petersen a0ad7c
	 'gnu)
Jens Petersen a0ad7c
	((not (equal system-type 'darwin)))) ; not MacOS
Jens Petersen a0ad7c
  "Whether `\\[igrep-find]' uses the `xargs` program or not.
Jens Petersen a0ad7c
If `gnu', it executes
Jens Petersen a0ad7c
	`find ... -print0 | xargs -0 -e grep ...`;
Jens Petersen a0ad7c
if not `gnu' but non-nil, it executes
Jens Petersen a0ad7c
	`find ... -print | xargs -e grep ...`;
Jens Petersen a0ad7c
if nil, it executes
Jens Petersen a0ad7c
	`find ... -exec grep ...`.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-program-default "grep"
Jens Petersen a0ad7c
  "The default `grep` program.
Jens Petersen a0ad7c
This is passed by `igrep-read-program' to `completing-read' when
Jens Petersen a0ad7c
`igrep-program' is nil.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Internal variables:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-regex-history '()
Jens Petersen a0ad7c
  "The minibuffer history list for `\\[igrep]'s REGEX argument.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defvar igrep-files-history '()
Jens Petersen a0ad7c
  "The minibuffer history list for `\\[igrep]'s FILES argument.")
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Commands:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;;;###autoload
Jens Petersen a0ad7c
(defun igrep-insinuate (&optional override)
Jens Petersen a0ad7c
  "Define `grep' aliases for the corresponding `igrep' commands.
Jens Petersen a0ad7c
With a prefix arg, OVERRIDE the current `grep' command definitions."
Jens Petersen a0ad7c
  (interactive "P")
Jens Petersen a0ad7c
  (if override
Jens Petersen a0ad7c
      (defalias 'grep 'igrep)
Jens Petersen a0ad7c
    (defadvice grep (around igrep-interactive first (&rest command-args)
Jens Petersen a0ad7c
			    activate)
Jens Petersen a0ad7c
      "If called interactively, use the `\\[igrep]' interface instead,
Jens Petersen a0ad7c
where COMMAND-ARGS is (PROGRAM REGEX FILES [OPTIONS]); if called
Jens Petersen a0ad7c
programmatically, COMMAND-ARGS is still (COMMAND)."
Jens Petersen a0ad7c
      (interactive (igrep-read-args))
Jens Petersen a0ad7c
      (if (interactive-p)
Jens Petersen a0ad7c
	  (apply 'igrep command-args)
Jens Petersen a0ad7c
	ad-do-it)))
Jens Petersen a0ad7c
  (if (or (not (fboundp 'grep-find))
Jens Petersen a0ad7c
	  override)
Jens Petersen a0ad7c
      (defalias 'grep-find 'igrep-find))
Jens Petersen a0ad7c
  (if (or (not (fboundp 'dired-do-grep))
Jens Petersen a0ad7c
	  override)
Jens Petersen a0ad7c
      (defalias 'dired-do-grep 'dired-do-igrep))
Jens Petersen a0ad7c
  (if (or (not (fboundp 'dired-do-grep-find))
Jens Petersen a0ad7c
	  override)
Jens Petersen a0ad7c
      (defalias 'dired-do-grep-find 'dired-do-igrep-find))
Jens Petersen a0ad7c
  (if (or (not (fboundp 'Buffer-menu-grep))
Jens Petersen a0ad7c
	  override)
Jens Petersen a0ad7c
      (defalias 'Buffer-menu-grep 'Buffer-menu-igrep)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defsubst igrep-quote-file-name (file)
Jens Petersen a0ad7c
  "Quote FILE name pattern for `shell-file-name'."
Jens Petersen a0ad7c
  (if (fboundp 'shell-quote-wildcard-pattern) ; Emacs 21
Jens Petersen a0ad7c
      (shell-quote-wildcard-pattern file)
Jens Petersen a0ad7c
    (shell-quote-argument file)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;;;###autoload
Jens Petersen a0ad7c
(defun igrep (program regex files &optional options)
Jens Petersen a0ad7c
  "*Run `grep` PROGRAM to match REGEX in FILES.
Jens Petersen a0ad7c
The output is displayed in the *igrep* buffer, which `\\[next-error]' and
Jens Petersen a0ad7c
`\\[compile-goto-error]' parse to find each line of matched text.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
PROGRAM may be nil, in which case it defaults to `igrep-program'.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
REGEX is automatically quoted by `shell-quote-argument'.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
FILES is either a file name pattern (automatically quoted by
Jens Petersen a0ad7c
`shell-quote-wildcard-pattern', then expanded by the `shell-file-name' shell),
Jens Petersen a0ad7c
or a list of file name patterns.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
Optional OPTIONS is also passed to PROGRAM; it defaults to `igrep-options'.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
If a prefix argument \
Jens Petersen a0ad7c
\(`\\[universal-argument]') \
Jens Petersen a0ad7c
is given when called interactively,
Jens Petersen a0ad7c
or if `igrep-read-options' is set, OPTIONS is read from the minibuffer.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
If two prefix arguments \
Jens Petersen a0ad7c
\(`\\[universal-argument] \\[universal-argument]') \
Jens Petersen a0ad7c
are given when called interactively,
Jens Petersen a0ad7c
or if `igrep-read-multiple-files' is set, FILES is read from the minibuffer
Jens Petersen a0ad7c
multiple times.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
If three prefix arguments \
Jens Petersen a0ad7c
\(`\\[universal-argument] \\[universal-argument] \\[universal-argument]') \
Jens Petersen a0ad7c
are given when called interactively,
Jens Petersen a0ad7c
or if `igrep-read-options' and `igrep-read-multiple-files' are set,
Jens Petersen a0ad7c
OPTIONS is read and FILES is read multiple times.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
If `igrep-find' is non-nil, the directory or directories
Jens Petersen a0ad7c
containing FILES is recursively searched for files whose name matches
Jens Petersen a0ad7c
the file name component of FILES (and whose contents match REGEX)."
Jens Petersen a0ad7c
  (interactive
Jens Petersen a0ad7c
   (igrep-read-args))
Jens Petersen a0ad7c
  (if (null program)
Jens Petersen a0ad7c
      (setq program (or igrep-program "grep")))
Jens Petersen a0ad7c
  (if (null options)
Jens Petersen a0ad7c
      (setq options igrep-options))
Jens Petersen a0ad7c
  (if (not (listp files))		; (stringp files)
Jens Petersen a0ad7c
      (setq files (list files)))
Jens Petersen a0ad7c
  (if (and (member ?~ (mapcar 'string-to-char files))
Jens Petersen a0ad7c
	   (save-match-data
Jens Petersen a0ad7c
	     (string-match "\\`[rj]?sh\\(\\.exe\\)?\\'"
Jens Petersen a0ad7c
			   (file-name-nondirectory shell-file-name))))
Jens Petersen a0ad7c
      ;; (restricted, job-control, or standard) Bourne shell doesn't expand ~:
Jens Petersen a0ad7c
      (setq files
Jens Petersen a0ad7c
	    (mapcar 'expand-file-name files)))
Jens Petersen a0ad7c
  (let* ((use-zgrep (cond ((eq igrep-use-zgrep t))
Jens Petersen a0ad7c
			  (igrep-use-zgrep
Jens Petersen a0ad7c
			   (let ((files files)
Jens Petersen a0ad7c
				 (compressed-p nil))
Jens Petersen a0ad7c
			     (while (and files (not compressed-p))
Jens Petersen a0ad7c
			       (if (save-match-data
Jens Petersen a0ad7c
				     (string-match "\\.g?[zZ]\\'" (car files)))
Jens Petersen a0ad7c
				   (setq compressed-p t))
Jens Petersen a0ad7c
			       (setq files (cdr files)))
Jens Petersen a0ad7c
			     compressed-p))
Jens Petersen a0ad7c
			  (t nil)))
Jens Petersen a0ad7c
	 (command (format "%s -n %s %s %s %s %s"
Jens Petersen a0ad7c
			  (if (and use-zgrep
Jens Petersen a0ad7c
				   (save-match-data
Jens Petersen a0ad7c
				     (not (string-match "\\`z" program))))
Jens Petersen a0ad7c
			      (setq program (concat "z" program))
Jens Petersen a0ad7c
			    program)
Jens Petersen a0ad7c
			  (or options
Jens Petersen a0ad7c
			      (and igrep-case-fold-search
Jens Petersen a0ad7c
				   (equal regex (downcase regex))
Jens Petersen a0ad7c
				   "-i")
Jens Petersen a0ad7c
			      "")
Jens Petersen a0ad7c
			  (or igrep-regex-option
Jens Petersen a0ad7c
			      (progn
Jens Petersen a0ad7c
				(if (save-match-data
Jens Petersen a0ad7c
				      (string-match "\\`-" regex))
Jens Petersen a0ad7c
				    (setq regex (concat "\\" regex)))
Jens Petersen a0ad7c
				""))
Jens Petersen a0ad7c
			  (shell-quote-argument regex)
Jens Petersen a0ad7c
			  (if igrep-find
Jens Petersen a0ad7c
			      (if igrep-find-use-xargs
Jens Petersen a0ad7c
				  ""
Jens Petersen a0ad7c
				(shell-quote-argument "{}"))
Jens Petersen a0ad7c
			    (mapconcat (lambda (file)
Jens Petersen a0ad7c
					 (let ((dir (file-name-directory file)))
Jens Petersen a0ad7c
					   (if dir
Jens Petersen a0ad7c
					       (expand-file-name
Jens Petersen a0ad7c
						(file-name-nondirectory file)
Jens Petersen a0ad7c
						(igrep-quote-file-name dir))
Jens Petersen a0ad7c
					     file)))
Jens Petersen a0ad7c
				       files " "))
Jens Petersen a0ad7c
			  igrep-null-device)))
Jens Petersen a0ad7c
    (if igrep-find
Jens Petersen a0ad7c
	(setq command
Jens Petersen a0ad7c
	      (igrep-format-find-command command files)))
Jens Petersen a0ad7c
    (cond ((eq igrep-save-buffers t) (save-some-buffers t))
Jens Petersen a0ad7c
	  (igrep-save-buffers (save-some-buffers)))
Jens Petersen a0ad7c
    (if (fboundp 'compilation-start)    ; CVS Emacs (21.3.50/21.4)
Jens Petersen a0ad7c
        (let ((compilation-process-setup-function 'grep-process-setup))
Jens Petersen a0ad7c
          (or (fboundp 'igrep-mode)
Jens Petersen a0ad7c
              (define-derived-mode igrep-mode grep-mode "Igrep"))
Jens Petersen a0ad7c
          (compilation-start command
Jens Petersen a0ad7c
                             'igrep-mode
Jens Petersen a0ad7c
                             nil
Jens Petersen a0ad7c
                             (cond ((eq compilation-highlight-regexp t))
Jens Petersen a0ad7c
                                   (compilation-highlight-regexp
Jens Petersen a0ad7c
                                    (if (eq program "fgrep")
Jens Petersen a0ad7c
                                        (regexp-quote regex)
Jens Petersen a0ad7c
                                      regex)))))
Jens Petersen a0ad7c
      (compile-internal command (format "No more %s matches" program)
Jens Petersen a0ad7c
                        "Igrep" nil grep-regexp-alist))))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Analogue commands:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defmacro igrep-define (analogue-command &rest igrep-bindings)
Jens Petersen a0ad7c
  "Define ANALOGUE-COMMAND as an `igrep' analogue command.
Jens Petersen a0ad7c
Optional (VARIABLE VALUE) arguments specify the temporary IGREP-BINDINGS
Jens Petersen a0ad7c
for the command."
Jens Petersen a0ad7c
  ;; (interactive "SCommand: ") ; C-u => read bindings?
Jens Petersen a0ad7c
  (let ((analogue-program (symbol-name analogue-command)))
Jens Petersen a0ad7c
    `(defun ,analogue-command (&rest igrep-args)
Jens Petersen a0ad7c
       ,(format "*Run `%s` via `\\[igrep]'.
Jens Petersen a0ad7c
All arguments (including prefix arguments, when called interactively)
Jens Petersen a0ad7c
are handled by `igrep'."
Jens Petersen a0ad7c
		analogue-program)
Jens Petersen a0ad7c
       (interactive
Jens Petersen a0ad7c
	(let ((igrep-program (if igrep-program ,analogue-program))
Jens Petersen a0ad7c
	      (igrep-program-default ,analogue-program))
Jens Petersen a0ad7c
	  (igrep-read-args)))
Jens Petersen a0ad7c
       (let (,@ igrep-bindings)
Jens Petersen a0ad7c
	 (apply 'igrep
Jens Petersen a0ad7c
		(cond ((interactive-p) (car igrep-args))
Jens Petersen a0ad7c
		      ((car igrep-args))
Jens Petersen a0ad7c
		      (t ,analogue-program))
Jens Petersen a0ad7c
		(cdr igrep-args))))))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(igrep-define egrep)
Jens Petersen a0ad7c
(igrep-define fgrep)
Jens Petersen a0ad7c
(igrep-define agrep
Jens Petersen a0ad7c
  (igrep-use-zgrep nil)
Jens Petersen a0ad7c
  (igrep-regex-option "-e"))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Recursive (`find`) commands:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;;;###autoload
Jens Petersen a0ad7c
(defun igrep-find (&rest igrep-args)
Jens Petersen a0ad7c
  "*Run `grep` via `find`; see `igrep' and `igrep-find'.
Jens Petersen a0ad7c
All IGREP-ARGS (including prefix arguments, when called interactively)
Jens Petersen a0ad7c
are handled by `igrep'."
Jens Petersen a0ad7c
  (interactive
Jens Petersen a0ad7c
   (let ((igrep-find t))
Jens Petersen a0ad7c
     (igrep-read-args)))
Jens Petersen a0ad7c
  (let ((igrep-find t))
Jens Petersen a0ad7c
    (apply 'igrep igrep-args)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Analogue recursive (`find`) commands:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defmacro igrep-find-define (analogue-command &rest igrep-bindings)
Jens Petersen a0ad7c
  "Define ANALOGUE-COMMAND-find as an `igrep' analogue `find` command.
Jens Petersen a0ad7c
Optional (VARIABLE VALUE) arguments specify the temporary IGREP-BINDINGS
Jens Petersen a0ad7c
for the command."
Jens Petersen a0ad7c
  ;; (interactive "SCommand: ") ; C-u => read bindings?
Jens Petersen a0ad7c
  (let ((analogue-program (symbol-name analogue-command)))
Jens Petersen a0ad7c
    (setq analogue-command
Jens Petersen a0ad7c
	  (intern (format "%s-find" analogue-command)))
Jens Petersen a0ad7c
    `(defun ,analogue-command (&rest igrep-args)
Jens Petersen a0ad7c
       ,(format "*Run `%s` via `\\[igrep-find]'.
Jens Petersen a0ad7c
All arguments (including prefix arguments, when called interactively)
Jens Petersen a0ad7c
are handled by `igrep'."
Jens Petersen a0ad7c
		analogue-program)
Jens Petersen a0ad7c
       (interactive
Jens Petersen a0ad7c
	(let ((igrep-program (if igrep-program ,analogue-program))
Jens Petersen a0ad7c
	      (igrep-program-default ,analogue-program)
Jens Petersen a0ad7c
	      (igrep-find t))
Jens Petersen a0ad7c
	  (igrep-read-args)))
Jens Petersen a0ad7c
       (let (,@ igrep-bindings)
Jens Petersen a0ad7c
	 (apply 'igrep-find
Jens Petersen a0ad7c
		(cond ((interactive-p) (car igrep-args))
Jens Petersen a0ad7c
		      ((car igrep-args))
Jens Petersen a0ad7c
		      (t ,analogue-program))
Jens Petersen a0ad7c
		(cdr igrep-args))))))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(igrep-find-define egrep)
Jens Petersen a0ad7c
(igrep-find-define fgrep)
Jens Petersen a0ad7c
(igrep-find-define agrep
Jens Petersen a0ad7c
  (igrep-use-zgrep nil)
Jens Petersen a0ad7c
  (igrep-regex-option "-e"))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;;;###autoload
Jens Petersen a0ad7c
(defun igrep-visited-files (program regex &optional options)
Jens Petersen a0ad7c
  "*Run `grep` PROGRAM to match REGEX (with optional OPTIONS) \
Jens Petersen a0ad7c
on all visited files.
Jens Petersen a0ad7c
See `\\[igrep]'."
Jens Petersen a0ad7c
  (interactive
Jens Petersen a0ad7c
   (let ((igrep-args (igrep-read-args 'no-files)))
Jens Petersen a0ad7c
     ;; Delete FILES:
Jens Petersen a0ad7c
     (setcdr (nthcdr 1 igrep-args) (nthcdr 3 igrep-args))
Jens Petersen a0ad7c
     igrep-args))
Jens Petersen a0ad7c
  (igrep program regex
Jens Petersen a0ad7c
	 (let ((directory-abbrev-alist
Jens Petersen a0ad7c
		(cons (cons (regexp-quote (expand-file-name default-directory))
Jens Petersen a0ad7c
			    "./")	; or even ""
Jens Petersen a0ad7c
		      directory-abbrev-alist)))
Jens Petersen a0ad7c
	   (mapcar 'abbreviate-file-name
Jens Petersen a0ad7c
		   (apply 'nconc
Jens Petersen a0ad7c
			  (mapcar (lambda (buffer)
Jens Petersen a0ad7c
				    (let ((file (buffer-file-name buffer)))
Jens Petersen a0ad7c
				      (if (and file
Jens Petersen a0ad7c
					       (cond ((featurep 'ange-ftp)
Jens Petersen a0ad7c
						      (not (ange-ftp-ftp-name file)))
Jens Petersen a0ad7c
						     ((featurep 'efs)
Jens Petersen a0ad7c
						      (not (efs-ftp-path file)))
Jens Petersen a0ad7c
						     (t t))
Jens Petersen a0ad7c
					       ;; (file-exists-p file)
Jens Petersen a0ad7c
					       )
Jens Petersen a0ad7c
					  (list file))))
Jens Petersen a0ad7c
				  (buffer-list)))))
Jens Petersen a0ad7c
	 options))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Dired commands:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;;;###autoload
Jens Petersen a0ad7c
(defun dired-do-igrep (program regex &optional options arg)
Jens Petersen a0ad7c
  "*Search the marked (or next prefix ARG) files.
Jens Petersen a0ad7c
See `\\[igrep]' for a description of PROGRAM, REGEX, and OPTIONS."
Jens Petersen a0ad7c
  (interactive
Jens Petersen a0ad7c
   (let ((igrep-args
Jens Petersen a0ad7c
	  (let ((current-prefix-arg nil))
Jens Petersen a0ad7c
	    (igrep-read-args 'no-files))))
Jens Petersen a0ad7c
     ;; Delete FILES:
Jens Petersen a0ad7c
     (setcdr (nthcdr 1 igrep-args) (nthcdr 3 igrep-args))
Jens Petersen a0ad7c
     ;; Append ARG:
Jens Petersen a0ad7c
     (nconc igrep-args (list current-prefix-arg))))
Jens Petersen a0ad7c
  (igrep program regex
Jens Petersen a0ad7c
	 (funcall (cond ((fboundp 'dired-get-marked-files) ; GNU Emacs
Jens Petersen a0ad7c
			 'dired-get-marked-files)
Jens Petersen a0ad7c
			((fboundp 'dired-mark-get-files) ; XEmacs
Jens Petersen a0ad7c
			 'dired-mark-get-files))
Jens Petersen a0ad7c
		  t arg)
Jens Petersen a0ad7c
	 options))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Dired recursive (`find`) commands:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;;;###autoload
Jens Petersen a0ad7c
(defun dired-do-igrep-find (program regex &optional options arg)
Jens Petersen a0ad7c
  "*Run `grep` on the marked (or next prefix ARG) directories.
Jens Petersen a0ad7c
See `\\[igrep]' for a description of PROGRAM, REGEX, and OPTIONS."
Jens Petersen a0ad7c
  (interactive
Jens Petersen a0ad7c
   (let ((igrep-args
Jens Petersen a0ad7c
	  (let ((current-prefix-arg nil)
Jens Petersen a0ad7c
		(igrep-find t))
Jens Petersen a0ad7c
	    (igrep-read-args 'no-files))))
Jens Petersen a0ad7c
     ;; Delete FILES:
Jens Petersen a0ad7c
     (setcdr (nthcdr 1 igrep-args) (nthcdr 3 igrep-args))
Jens Petersen a0ad7c
     ;; Append ARG:
Jens Petersen a0ad7c
     (nconc igrep-args (list current-prefix-arg))))
Jens Petersen a0ad7c
  (let ((igrep-find t))
Jens Petersen a0ad7c
    (dired-do-igrep program regex options arg)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Buffer menu commands:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;;;###autoload
Jens Petersen a0ad7c
(defun Buffer-menu-igrep (program regex &optional options)
Jens Petersen a0ad7c
  "*Run `grep` on the files visited in buffers marked with '>'.
Jens Petersen a0ad7c
See `\\[igrep]' for a description of PROGRAM, REGEX, and OPTIONS."
Jens Petersen a0ad7c
  (interactive
Jens Petersen a0ad7c
   (let ((igrep-args (igrep-read-args 'no-files)))
Jens Petersen a0ad7c
     ;; Delete FILES:
Jens Petersen a0ad7c
     (setcdr (nthcdr 1 igrep-args) (nthcdr 3 igrep-args))
Jens Petersen a0ad7c
     igrep-args))
Jens Petersen a0ad7c
  ;; See Buffer-menu-select:
Jens Petersen a0ad7c
  (let ((marked-files '())
Jens Petersen a0ad7c
	marked-buffer
Jens Petersen a0ad7c
	file)
Jens Petersen a0ad7c
    (goto-char (point-min))
Jens Petersen a0ad7c
    (while (search-forward "\n>" nil t)
Jens Petersen a0ad7c
      (setq marked-buffer (Buffer-menu-buffer t)
Jens Petersen a0ad7c
	    file (buffer-file-name marked-buffer))
Jens Petersen a0ad7c
      (if (and file
Jens Petersen a0ad7c
	       ;; local:
Jens Petersen a0ad7c
	       (cond ((featurep 'ange-ftp)
Jens Petersen a0ad7c
		      (not (ange-ftp-ftp-name file)))
Jens Petersen a0ad7c
		     ((featurep 'efs)
Jens Petersen a0ad7c
		      (not (efs-ftp-path file)))
Jens Petersen a0ad7c
		     (t t)))
Jens Petersen a0ad7c
	  (setq marked-files (cons file marked-files)))
Jens Petersen a0ad7c
;;;    (let ((buffer-read-only nil))
Jens Petersen a0ad7c
;;;      (delete-char -1)
Jens Petersen a0ad7c
;;;      (insert ?\ ))
Jens Petersen a0ad7c
      )
Jens Petersen a0ad7c
    (setq marked-files (nreverse marked-files))
Jens Petersen a0ad7c
    (igrep program regex
Jens Petersen a0ad7c
	   (let ((directory-abbrev-alist
Jens Petersen a0ad7c
		  (cons (cons (regexp-quote (expand-file-name default-directory))
Jens Petersen a0ad7c
			      "./")	; or even ""
Jens Petersen a0ad7c
			directory-abbrev-alist)))
Jens Petersen a0ad7c
	     (mapcar 'abbreviate-file-name marked-files))
Jens Petersen a0ad7c
	   options)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; User functions:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-dired-file-current-word ()
Jens Petersen a0ad7c
  "Return the current word in the file on this line, if it is visible;
Jens Petersen a0ad7c
else, return the file name on this line, if there is one;
Jens Petersen a0ad7c
otherwise, return the current word."
Jens Petersen a0ad7c
  (let* ((dired-file
Jens Petersen a0ad7c
	  (dired-get-filename t t))
Jens Petersen a0ad7c
	 (dired-file-buffer
Jens Petersen a0ad7c
	  (if dired-file
Jens Petersen a0ad7c
	      (get-file-buffer (expand-file-name dired-file))))
Jens Petersen a0ad7c
	 (dired-file-buffer-window
Jens Petersen a0ad7c
	  (if dired-file-buffer
Jens Petersen a0ad7c
	      (get-buffer-window dired-file-buffer))))
Jens Petersen a0ad7c
    (cond (dired-file-buffer-window (save-excursion
Jens Petersen a0ad7c
				      (set-buffer dired-file-buffer)
Jens Petersen a0ad7c
				      (current-word)))
Jens Petersen a0ad7c
	  (dired-file)
Jens Petersen a0ad7c
	  (t (current-word)))))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-buffer-file-name-pattern ()
Jens Petersen a0ad7c
  "Return a shell file name pattern based on the visited file name.
Jens Petersen a0ad7c
If the `buffer-file-name' variable is nil, return \"*\"."
Jens Petersen a0ad7c
  ;; (Based on other-possibly-interesting-files in ~/as-is/unix.el, by
Jens Petersen a0ad7c
  ;; Wolfgang Rupprecht <wolfgang@mgm.mit.edu>.)
Jens Petersen a0ad7c
  (if buffer-file-name
Jens Petersen a0ad7c
      (let ((file-name (file-name-nondirectory buffer-file-name)))
Jens Petersen a0ad7c
	(concat "*"
Jens Petersen a0ad7c
		(save-match-data
Jens Petersen a0ad7c
		  (if (string-match "\\.[^.]+\\(\\.g?[zZ]\\)?\\'"
Jens Petersen a0ad7c
				    file-name)
Jens Petersen a0ad7c
		      (substring file-name (match-beginning 0)
Jens Petersen a0ad7c
				 (match-end 0))))))
Jens Petersen a0ad7c
    "*"))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-dired-directory-file-pattern ()
Jens Petersen a0ad7c
  "Return a shell file name pattern based on `dired-directory', or \"*\"."
Jens Petersen a0ad7c
  (cond ((stringp dired-directory)
Jens Petersen a0ad7c
	 (if (file-directory-p dired-directory)
Jens Petersen a0ad7c
	     "*"
Jens Petersen a0ad7c
	   (file-name-nondirectory dired-directory))) ; wildcard
Jens Petersen a0ad7c
	((consp dired-directory)	; (DIR FILE ...)
Jens Petersen a0ad7c
	 (mapconcat 'identity (cdr dired-directory) " "))))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Utilities:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defsubst igrep-file-directory (name)
Jens Petersen a0ad7c
  "Return the directory component of NAME, or \".\" if it has none."
Jens Petersen a0ad7c
  (directory-file-name (or (file-name-directory name)
Jens Petersen a0ad7c
			   (file-name-as-directory "."))))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defsubst igrep-file-pattern (name)
Jens Petersen a0ad7c
  "Return the file component of NAME, or \"*\" if it has none."
Jens Petersen a0ad7c
  (let ((pattern (file-name-nondirectory name)))
Jens Petersen a0ad7c
       (if (string= pattern "")
Jens Petersen a0ad7c
	   "*"
Jens Petersen a0ad7c
	 pattern)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-format-find-command (command files)
Jens Petersen a0ad7c
  "Format `grep` COMMAND to be invoked via `find` on FILES."
Jens Petersen a0ad7c
  (let ((directories '())
Jens Petersen a0ad7c
	(patterns '()))
Jens Petersen a0ad7c
    (while files
Jens Petersen a0ad7c
      (let ((dir (igrep-file-directory (car files)))
Jens Petersen a0ad7c
	    (pat (igrep-file-pattern (car files))))
Jens Petersen a0ad7c
	(if (and (not (string= dir "."))
Jens Petersen a0ad7c
		 (file-symlink-p dir))
Jens Petersen a0ad7c
	    (setq dir (concat dir "/.")))
Jens Petersen a0ad7c
	(if (not (member dir directories))
Jens Petersen a0ad7c
	    (setq directories (cons dir directories)))
Jens Petersen a0ad7c
	(cond ((equal pat "*")
Jens Petersen a0ad7c
	       (setq patterns t))
Jens Petersen a0ad7c
	      ((and (listp patterns)
Jens Petersen a0ad7c
		    (not (member pat patterns)))
Jens Petersen a0ad7c
	       (setq patterns (cons pat patterns)))))
Jens Petersen a0ad7c
      (setq files (cdr files)))
Jens Petersen a0ad7c
    (format (cond ((eq igrep-find-use-xargs 'gnu)
Jens Petersen a0ad7c
		   ;; | \\\n
Jens Petersen a0ad7c
		   "%s %s %s %s %s -print0 | xargs -0 -e %s")
Jens Petersen a0ad7c
		  (igrep-find-use-xargs
Jens Petersen a0ad7c
		   ;; | \\\n
Jens Petersen a0ad7c
		   "%s %s %s %s %s -print | xargs -e %s")
Jens Petersen a0ad7c
		  (t
Jens Petersen a0ad7c
		   "%s %s %s %s %s -exec %s %s"))
Jens Petersen a0ad7c
	    igrep-find-program
Jens Petersen a0ad7c
	    (mapconcat 'igrep-quote-file-name (nreverse directories)
Jens Petersen a0ad7c
		       " ")
Jens Petersen a0ad7c
	    (if igrep-find-prune-clause
Jens Petersen a0ad7c
		(format "%s -prune -o" igrep-find-prune-clause)
Jens Petersen a0ad7c
	      "")
Jens Petersen a0ad7c
	    (or igrep-find-file-clause "")
Jens Petersen a0ad7c
	    (if (listp patterns)
Jens Petersen a0ad7c
		(if (cdr patterns)	; (> (length patterns) 1)
Jens Petersen a0ad7c
		    (format "%s %s %s"
Jens Petersen a0ad7c
			    (shell-quote-argument "(")
Jens Petersen a0ad7c
			    (mapconcat (lambda (pat)
Jens Petersen a0ad7c
					 (format "-name %s"
Jens Petersen a0ad7c
						 (shell-quote-argument pat)))
Jens Petersen a0ad7c
				       (nreverse patterns)
Jens Petersen a0ad7c
				       " -o ")
Jens Petersen a0ad7c
			    (shell-quote-argument ")"))
Jens Petersen a0ad7c
		  (format "-name %s" (shell-quote-argument (car patterns))))
Jens Petersen a0ad7c
	      "")
Jens Petersen a0ad7c
	    command
Jens Petersen a0ad7c
	    (shell-quote-argument ";")
Jens Petersen a0ad7c
	    )))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defmacro igrep-default-arg (variable)
Jens Petersen a0ad7c
  "Return the default arg based on VARIABLE."
Jens Petersen a0ad7c
  `(if ,variable
Jens Petersen a0ad7c
       (cond ((get (quote ,variable) major-mode)
Jens Petersen a0ad7c
	      (funcall (get (quote ,variable) major-mode)))
Jens Petersen a0ad7c
	     (t (funcall ,variable)))))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-default-regex ()
Jens Petersen a0ad7c
  "Return the default REGEX for `\\[igrep]'."
Jens Petersen a0ad7c
  (let ((default-regex (igrep-default-arg igrep-regex-default)))
Jens Petersen a0ad7c
    (if (not (equal default-regex ""))
Jens Petersen a0ad7c
	default-regex)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-default-files ()
Jens Petersen a0ad7c
  "Return the default FILES for `\\[igrep]'."
Jens Petersen a0ad7c
  (let* ((dired-subdirectory (if (cond ((fboundp 'derived-mode-p) ; Emacs 21
Jens Petersen a0ad7c
					(derived-mode-p 'dired-mode))
Jens Petersen a0ad7c
				       (t (eq major-mode 'dired-mode)))
Jens Petersen a0ad7c
				 (dired-current-directory t)))
Jens Petersen a0ad7c
	 (default-files (igrep-default-arg igrep-files-default)))
Jens Petersen a0ad7c
    (if (not (listp default-files))	; stringp
Jens Petersen a0ad7c
	(setq default-files (list default-files)))
Jens Petersen a0ad7c
    (if dired-subdirectory
Jens Petersen a0ad7c
	(mapcar (lambda (file)
Jens Petersen a0ad7c
		  (concat dired-subdirectory file))
Jens Petersen a0ad7c
		default-files)
Jens Petersen a0ad7c
      default-files)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defsubst igrep-prefix (prefix string &rest strings)
Jens Petersen a0ad7c
  "Concatenate PREFIX (if non-nil), STRING, and any other STRINGS."
Jens Petersen a0ad7c
  (if (or prefix strings)
Jens Petersen a0ad7c
      (apply 'concat prefix string strings)
Jens Petersen a0ad7c
    string))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-read-args (&optional no-files)
Jens Petersen a0ad7c
  "Read and return a list: (PROGRAM REGEX FILES OPTIONS).
Jens Petersen a0ad7c
If NO-FILES is non-nil, then FILES is not read and nil is returned
Jens Petersen a0ad7c
in its place."
Jens Petersen a0ad7c
  (let* ((pre-prefix (if (and igrep-find (eq igrep-verbose-prompts t))
Jens Petersen a0ad7c
			 "[find] "))
Jens Petersen a0ad7c
	 (program
Jens Petersen a0ad7c
	  (igrep-read-program pre-prefix))
Jens Petersen a0ad7c
	 (prefix (if (and program (eq igrep-verbose-prompts t))
Jens Petersen a0ad7c
		     (igrep-prefix pre-prefix program " ")
Jens Petersen a0ad7c
		   pre-prefix))
Jens Petersen a0ad7c
	 (options
Jens Petersen a0ad7c
	  (igrep-read-options prefix))
Jens Petersen a0ad7c
	 (post-prefix (if (and options (eq igrep-verbose-prompts t))
Jens Petersen a0ad7c
			    (igrep-prefix prefix options " ")
Jens Petersen a0ad7c
			  prefix)))
Jens Petersen a0ad7c
    (list program
Jens Petersen a0ad7c
	  (igrep-read-regex post-prefix)
Jens Petersen a0ad7c
	  (if (not no-files)
Jens Petersen a0ad7c
	      (igrep-read-files post-prefix))
Jens Petersen a0ad7c
	  options)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-read-program (&optional prompt-prefix)
Jens Petersen a0ad7c
  "Read and return a `grep` program name from the minibuffer.
Jens Petersen a0ad7c
If `igrep-program' is non-nil, it.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
Optional PROMPT-PREFIX is prepended to the \"Program: \" prompt."
Jens Petersen a0ad7c
  (or igrep-program
Jens Petersen a0ad7c
      (let ((prompt "Program: "))
Jens Petersen a0ad7c
	(completing-read (igrep-prefix prompt-prefix prompt) igrep-program-table
Jens Petersen a0ad7c
			 nil t igrep-program-default))))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-read-options (&optional prompt-prefix)
Jens Petersen a0ad7c
  "Read and return an options string from the minibuffer.
Jens Petersen a0ad7c
If `current-prefix-arg' is '(4) or '(64), return `igrep-options'.
Jens Petersen a0ad7c

Jens Petersen a0ad7c
Optional PROMPT-PREFIX is prepended to the \"Options: \" prompt."
Jens Petersen a0ad7c
  (if (or igrep-read-options
Jens Petersen a0ad7c
	  (and (consp current-prefix-arg)
Jens Petersen a0ad7c
	       (memq (prefix-numeric-value current-prefix-arg)
Jens Petersen a0ad7c
		     '(4 64))))
Jens Petersen a0ad7c
      (let ((prompt "Options: "))
Jens Petersen a0ad7c
	(read-string (igrep-prefix prompt-prefix prompt)
Jens Petersen a0ad7c
		     (or igrep-options "-")))
Jens Petersen a0ad7c
    igrep-options))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-read-regex (&optional prompt-prefix)
Jens Petersen a0ad7c
  "Read and return a `grep` regex(5) string from the minibuffer.
Jens Petersen a0ad7c
Optional PROMPT-PREFIX is prepended to the \"Regex: \" prompt."
Jens Petersen a0ad7c
  (if igrep-insert-default-key
Jens Petersen a0ad7c
      (define-key minibuffer-local-map igrep-insert-default-key
Jens Petersen a0ad7c
	'igrep-insert-default-regex))
Jens Petersen a0ad7c
  (let* ((default-regex (igrep-default-regex))
Jens Petersen a0ad7c
	 (prompt (igrep-prefix prompt-prefix
Jens Petersen a0ad7c
			       (if default-regex
Jens Petersen a0ad7c
				   (format "Regex [default: %s]: "
Jens Petersen a0ad7c
					   default-regex)
Jens Petersen a0ad7c
				 "Regex: ")))
Jens Petersen a0ad7c
	 (regex (cond ((featurep 'xemacs) ; incompatible
Jens Petersen a0ad7c
                       ;; DEFAULT-VALUE is the 7th arg in 21.4 (but 21.1
Jens Petersen a0ad7c
                       ;; only accepts 6 args):
Jens Petersen a0ad7c
		       (read-from-minibuffer prompt
Jens Petersen a0ad7c
					     nil nil nil
Jens Petersen a0ad7c
					     'igrep-regex-history
Jens Petersen a0ad7c
					     nil)) ; ABBREV-TABLE
Jens Petersen a0ad7c
		      ((>= emacs-major-version 20)
Jens Petersen a0ad7c
		       (read-from-minibuffer prompt
Jens Petersen a0ad7c
					     nil nil nil
Jens Petersen a0ad7c
					     'igrep-regex-history
Jens Petersen a0ad7c
					     default-regex))
Jens Petersen a0ad7c
		      (t
Jens Petersen a0ad7c
		       (read-from-minibuffer prompt
Jens Petersen a0ad7c
					     nil nil nil
Jens Petersen a0ad7c
					     'igrep-regex-history)))))
Jens Petersen a0ad7c
    (if (equal regex "")
Jens Petersen a0ad7c
	(progn
Jens Petersen a0ad7c
	  (or (equal default-regex (car igrep-regex-history))
Jens Petersen a0ad7c
	      (setq igrep-regex-history
Jens Petersen a0ad7c
		    (cons default-regex igrep-regex-history)))
Jens Petersen a0ad7c
	  default-regex)
Jens Petersen a0ad7c
      regex)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-insert-default-regex (&optional clear-minibuffer)
Jens Petersen a0ad7c
  "*Insert the default regex in the minibuffer.
Jens Petersen a0ad7c
If a prefix argument is specified, CLEAR-MINIBUFFER contents first."
Jens Petersen a0ad7c
  (interactive "P")
Jens Petersen a0ad7c
  (if clear-minibuffer
Jens Petersen a0ad7c
      (delete-region (if (fboundp 'minibuffer-prompt-end) ; Emacs 21
Jens Petersen a0ad7c
			 (minibuffer-prompt-end)
Jens Petersen a0ad7c
		       (point-min))
Jens Petersen a0ad7c
		     (point-max)))
Jens Petersen a0ad7c
  (insert (or (save-excursion
Jens Petersen a0ad7c
		(set-buffer (window-buffer minibuffer-scroll-window))
Jens Petersen a0ad7c
		(igrep-default-regex))
Jens Petersen a0ad7c
	      "")))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-insert-default-files (&optional clear-minibuffer)
Jens Petersen a0ad7c
  "*Insert the default files in the minibuffer.
Jens Petersen a0ad7c
If a prefix argument is specified, CLEAR-MINIBUFFER contents first."
Jens Petersen a0ad7c
  (interactive "P")
Jens Petersen a0ad7c
  (if clear-minibuffer
Jens Petersen a0ad7c
      (delete-region (if (fboundp 'minibuffer-prompt-end) ; Emacs 21
Jens Petersen a0ad7c
			 (minibuffer-prompt-end)
Jens Petersen a0ad7c
		       (point-min))
Jens Petersen a0ad7c
		     (point-max)))
Jens Petersen a0ad7c
  (insert (mapconcat 'identity
Jens Petersen a0ad7c
		     (save-excursion
Jens Petersen a0ad7c
		       (set-buffer (window-buffer minibuffer-scroll-window))
Jens Petersen a0ad7c
		       (igrep-default-files))
Jens Petersen a0ad7c
		     " ")))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defsubst igrep-default-key (command &optional keymap key)
Jens Petersen a0ad7c
  "Return the key bound to COMMAND in KEYMAP, preferably KEY."
Jens Petersen a0ad7c
  (if (null keymap)
Jens Petersen a0ad7c
      (setq keymap (current-global-map)))
Jens Petersen a0ad7c
  (if (and key
Jens Petersen a0ad7c
	   (eq (lookup-key keymap key) command))
Jens Petersen a0ad7c
      key
Jens Petersen a0ad7c
    (where-is-internal command keymap t)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-read-files (&optional prompt-prefix)
Jens Petersen a0ad7c
  "Read and return a file name pattern from the minibuffer.
Jens Petersen a0ad7c
If `current-prefix-arg' is '(16) or '(64), read multiple file name
Jens Petersen a0ad7c
patterns and return them in a list.  Optional PROMPT-PREFIX is
Jens Petersen a0ad7c
prepended to the \"File(s): \" prompt."
Jens Petersen a0ad7c
  (let* ((default-files (igrep-default-files))
Jens Petersen a0ad7c
	 (default-files-string (mapconcat 'identity default-files " "))
Jens Petersen a0ad7c
	 (insert-default-directory igrep-insert-default-directory)
Jens Petersen a0ad7c
	 (file (igrep-read-file-name
Jens Petersen a0ad7c
		(igrep-prefix prompt-prefix
Jens Petersen a0ad7c
			      (if default-files
Jens Petersen a0ad7c
				  (format "File(s) [default: %s]: "
Jens Petersen a0ad7c
					  default-files-string)
Jens Petersen a0ad7c
				"File(s): "))
Jens Petersen a0ad7c
		nil (if default-files default-files-string "") nil nil
Jens Petersen a0ad7c
		'igrep-files-history))
Jens Petersen a0ad7c
	 (files (list file)))
Jens Petersen a0ad7c
    (if (or igrep-read-multiple-files
Jens Petersen a0ad7c
	    (and (consp current-prefix-arg)
Jens Petersen a0ad7c
		 (memq (prefix-numeric-value current-prefix-arg)
Jens Petersen a0ad7c
		       '(16 64))))
Jens Petersen a0ad7c
	(let* ((key (igrep-default-key 'exit-minibuffer
Jens Petersen a0ad7c
				       minibuffer-local-completion-map
Jens Petersen a0ad7c
				       "\r"))
Jens Petersen a0ad7c
	       (prompt
Jens Petersen a0ad7c
		(igrep-prefix prompt-prefix
Jens Petersen a0ad7c
			      (if igrep-verbose-prompts
Jens Petersen a0ad7c
				  (format "File(s): [Type `%s' when done] "
Jens Petersen a0ad7c
					  (key-description key))
Jens Petersen a0ad7c
				"File(s): "))))
Jens Petersen a0ad7c
	  (while (and (setq file
Jens Petersen a0ad7c
			    (igrep-read-file-name prompt
Jens Petersen a0ad7c
						  nil "" nil nil
Jens Petersen a0ad7c
						  'igrep-files-history))
Jens Petersen a0ad7c
		      (not (equal file "")))
Jens Petersen a0ad7c
	    (setq files (cons file files)))))
Jens Petersen a0ad7c
    (mapcar (lambda (file)
Jens Petersen a0ad7c
	      (if (file-directory-p file)
Jens Petersen a0ad7c
		  ;; really should map expand-file-name over default-files:
Jens Petersen a0ad7c
		  (expand-file-name (if default-files default-files-string "*")
Jens Petersen a0ad7c
				    file)
Jens Petersen a0ad7c
		file))
Jens Petersen a0ad7c
	    (nreverse files))))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(defun igrep-read-file-name (prompt
Jens Petersen a0ad7c
  &optional directory default existing initial history)
Jens Petersen a0ad7c
  "Just like `read-file-name,' but with optional HISTORY."
Jens Petersen a0ad7c
  (if igrep-insert-default-key
Jens Petersen a0ad7c
      (define-key minibuffer-local-completion-map igrep-insert-default-key
Jens Petersen a0ad7c
	'igrep-insert-default-files))
Jens Petersen a0ad7c
  (if history
Jens Petersen a0ad7c
      (let ((file-name-history (symbol-value history)))
Jens Petersen a0ad7c
	(prog1 (read-file-name prompt directory default existing initial)
Jens Petersen a0ad7c
	  (set history file-name-history)))
Jens Petersen a0ad7c
    (read-file-name prompt directory default existing initial)))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;; Menu bar:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(if igrep-easy-menu
Jens Petersen a0ad7c
    (progn
Jens Petersen a0ad7c
      (easy-menu-define igrep-menu nil
Jens Petersen a0ad7c
	"Menu keymap for igrep."
Jens Petersen a0ad7c
	igrep-easy-menu)
Jens Petersen a0ad7c
      (cond ((fboundp 'add-submenu)	; XEmacs
Jens Petersen a0ad7c
	     (add-submenu '("Tools") igrep-menu "Grep..."))
Jens Petersen a0ad7c
	    ((fboundp 'easy-menu-add-item) ; Emacs 20
Jens Petersen a0ad7c
	     (easy-menu-add-item menu-bar-tools-menu nil igrep-menu
Jens Petersen a0ad7c
				 'grep))
Jens Petersen a0ad7c
	    (t				; Emacs 19
Jens Petersen a0ad7c
	     (define-key-after menu-bar-tools-menu [igrep]
Jens Petersen a0ad7c
	       (cons (car igrep-easy-menu) igrep-menu)
Jens Petersen a0ad7c
	       (and (lookup-key menu-bar-tools-menu [grep]) 'grep))))))
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;;; Local Variables:
Jens Petersen a0ad7c
;;; eval: (put 'igrep-define 'lisp-indent-function 1)
Jens Petersen a0ad7c
;;; eval: (put 'igrep-find-define 'lisp-indent-function 1)
Jens Petersen a0ad7c
;;; eval: (put 'easy-menu-define 'lisp-indent-function 'defun)
Jens Petersen a0ad7c
;;; End:
Jens Petersen a0ad7c

Jens Petersen a0ad7c
(provide 'igrep)
Jens Petersen a0ad7c

Jens Petersen a0ad7c
;;; igrep.el ends here