emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: address@hidden: grep-tree doesn't shell-quote-argument]


From: Kim F. Storm
Subject: Re: address@hidden: grep-tree doesn't shell-quote-argument]
Date: Fri, 21 Apr 2006 10:27:12 +0200
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux)

Richard Stallman <address@hidden> writes:

>     I think at least grep-tree and grep-find could be a single command:
>     e.g., it would behave like grep-tree by default, but with a prefix
>     argument will show the full command (so that power users could tailor
>     it), like grep-find does.
>
> That sounds plausible.  Can you make a precise proposal
> for the interface?

Below is a patch which merges grep-tree into grep-find, with
the new grep-tree interface as the default API, while a C-u
prefix requests using the old grep-find interface.

If called non-interactively with one arg, it behaves like the
old grep-find (interpreting the arg as a shell command).

In the process, the grep-tree part of the code has been cleaned up,
all the related defcustoms have been suitable renamed, and proper
histories for the new-style arguments have been added.

There is a new defcustom grep-find-prompt-style to permanently
select the old-style prompting.

One question:
Why are grep-history and grep-find-history autoloaded?


*** grep.el     16 Mar 2006 09:41:13 +0100      1.51
--- grep.el     20 Apr 2006 13:59:23 +0200      
***************
*** 130,137 ****
                 (const :tag "Not Set" nil))
    :group 'grep)
  
! (defcustom grep-tree-command nil
!   "The default find command for \\[grep-tree].
  The default value of this variable is set up by `grep-compute-defaults';
  call that function before using this variable in your program.
  The following place holders should be present in the string:
--- 130,137 ----
                 (const :tag "Not Set" nil))
    :group 'grep)
  
! (defcustom grep-find-template nil
!   "The default find command for \\[grep-find].
  The default value of this variable is set up by `grep-compute-defaults';
  call that function before using this variable in your program.
  The following place holders should be present in the string:
***************
*** 145,170 ****
    :version "22.1"
    :group 'grep)
  
! (defcustom grep-tree-files-aliases '(
        ("ch" . "*.[ch]")
        ("c" .  "*.c")
        ("h" .  "*.h")
-       ("m" .  "[Mm]akefile*")
        ("asm" . "*.[sS]")
!       ("all" . "*")
!       ("el" . "*.el")
        )
!   "*Alist of aliases for the FILES argument to `grep-tree'."
    :type 'alist
    :group 'grep)
  
! (defcustom grep-tree-ignore-case t
!   "*If non-nil, `grep-tree' ignores case in matches."
    :type 'boolean
    :group 'grep)
  
! (defcustom grep-tree-ignore-CVS-directories t
!   "*If non-nil, `grep-tree' does no recurse into CVS directories."
    :type 'boolean
    :group 'grep)
  
--- 145,180 ----
    :version "22.1"
    :group 'grep)
  
! (defcustom grep-find-prompt-style nil
!   "*Prompt style used by `grep-find'.
! Nil means to prompt for regexp, files, and directory.
! Value `shell' means to prompt for shell command instead.
! Value `post' means to post-edit the final shell command."
!   :type '(choice (const :tag "Standard" nil)
!                (const :tag "Shell Command" shell)
!                (const :tag "Post-edit Command" post))
!   :version "22.1"
!   :group 'grep)
! 
! (defcustom grep-find-files-aliases '(
!       ("el" . "*.el")
        ("ch" . "*.[ch]")
        ("c" .  "*.c")
        ("h" .  "*.h")
        ("asm" . "*.[sS]")
!       ("m" .  "[Mm]akefile*")
        )
!   "*Alist of aliases for the FILES argument to `grep-find'."
    :type 'alist
    :group 'grep)
  
! (defcustom grep-find-ignore-case t
!   "*If non-nil, `grep-find' ignores case in matches."
    :type 'boolean
    :group 'grep)
  
! (defcustom grep-find-ignore-CVS-directories t
!   "*If non-nil, `grep-find' does no recurse into CVS directories."
    :type 'boolean
    :group 'grep)
  
***************
*** 318,323 ****
--- 328,337 ----
     "Additional things to highlight in grep output.
  This gets tacked on the end of the generated expressions.")
  
+ ;; grep-find regexp and files history
+ (defvar grep-find-regexp-history nil)
+ (defvar grep-find-files-history '("ch" "el"))
+ 
  ;;;###autoload
  (defvar grep-program
    ;; Currently zgrep has trouble.  It runs egrep instead of grep,
***************
*** 433,440 ****
                (t (cons (format "%s . -type f -exec %s {} %s \\;"
                                 find-program grep-command null-device)
                         (+ 22 (length grep-command)))))))
!   (unless grep-tree-command
!     (setq grep-tree-command
          (let* ((glen (length grep-program))
                 (gcmd (concat grep-program " <C>" (substring grep-command 
glen))))
            (cond ((eq grep-find-use-xargs 'gnu)
--- 447,454 ----
                (t (cons (format "%s . -type f -exec %s {} %s \\;"
                                 find-program grep-command null-device)
                         (+ 22 (length grep-command)))))))
!   (unless grep-find-template
!     (setq grep-find-template
          (let* ((glen (length grep-program))
                 (gcmd (concat grep-program " <C>" (substring grep-command 
glen))))
            (cond ((eq grep-find-use-xargs 'gnu)
***************
*** 488,501 ****
        (replace-match tag-default t t grep-default 1))))
  
  ;;;###autoload
! (defun grep (command-args &optional highlight-regexp)
    "Run grep, with user-specified args, and collect output in a buffer.
  While grep runs asynchronously, you can use \\[next-error] (M-x next-error),
  or \\<grep-mode-map>\\[compile-goto-error] in the grep \
  output buffer, to go to the lines
  where grep found matches.
  
! This command uses a special history list for its COMMAND-ARGS, so you can
  easily repeat a grep command.
  
  A prefix argument says to default the argument based upon the current
--- 502,515 ----
        (replace-match tag-default t t grep-default 1))))
  
  ;;;###autoload
! (defun grep (command &optional highlight-regexp)
    "Run grep, with user-specified args, and collect output in a buffer.
  While grep runs asynchronously, you can use \\[next-error] (M-x next-error),
  or \\<grep-mode-map>\\[compile-goto-error] in the grep \
  output buffer, to go to the lines
  where grep found matches.
  
! This command uses a special history list for its COMMAND, so you can
  easily repeat a grep command.
  
  A prefix argument says to default the argument based upon the current
***************
*** 520,527 ****
    ;; Setting process-setup-function makes exit-message-function work
    ;; even when async processes aren't supported.
    (compilation-start (if (and grep-use-null-device null-device)
!                        (concat command-args " " null-device)
!                      command-args)
                     'grep-mode nil highlight-regexp))
  
  ;;;###autoload
--- 534,541 ----
    ;; Setting process-setup-function makes exit-message-function work
    ;; even when async processes aren't supported.
    (compilation-start (if (and grep-use-null-device null-device)
!                        (concat command " " null-device)
!                      command)
                     'grep-mode nil highlight-regexp))
  
  ;;;###autoload
***************
*** 536,571 ****
         'grep-process-setup)
    (set (make-local-variable 'compilation-disable-input) t))
  
! ;;;###autoload
! (defun grep-find (command-args)
!   "Run grep via find, with user-specified args COMMAND-ARGS.
! Collect output in a buffer.
! While find runs asynchronously, you can use the \\[next-error] command
! to find the text that grep hits refer to.
! 
! This command uses a special history list for its arguments, so you can
! easily repeat a find command."
!   (interactive
!    (progn
!      (unless (and grep-command
!                 (or (not grep-use-null-device) (eq grep-use-null-device t)))
!        (grep-compute-defaults))
!      (if grep-find-command
!        (list (read-from-minibuffer "Run find (like this): "
!                                    grep-find-command nil nil
!                                      'grep-find-history))
!        ;; No default was set
!        (read-string
!         "compile.el: No `grep-find-command' command available. Press RET.")
!        (list nil))))
!   (when (and grep-find-command command-args)
!     (let ((null-device nil))          ; see grep
!       (grep command-args))))
! 
! ;;;###autoload
! (defalias 'find-grep 'grep-find)
! 
! (defun grep-expand-command-macros (command &optional regexp files dir excl 
case-fold)
    "Patch grep COMMAND replacing <D>, etc."
    (setq command
        (replace-regexp-in-string "<D>"
--- 550,556 ----
         'grep-process-setup)
    (set (make-local-variable 'compilation-disable-input) t))
  
! (defun grep-expand-template (command &optional regexp files dir excl 
case-fold)
    "Patch grep COMMAND replacing <D>, etc."
    (setq command
        (replace-regexp-in-string "<D>"
***************
*** 584,649 ****
                                  (or regexp "") command t t))
    command)
  
- (defvar grep-tree-last-regexp "")
- (defvar grep-tree-last-files (car (car grep-tree-files-aliases)))
- 
  ;;;###autoload
! (defun grep-tree (regexp files dir &optional subdirs)
!   "Grep for REGEXP in FILES in directory tree rooted at DIR.
  Collect output in a buffer.
  Interactively, prompt separately for each search parameter.
- With prefix arg, reuse previous REGEXP.
  The search is limited to file names matching shell pattern FILES.
! FILES may use abbreviations defined in `grep-tree-files-aliases', e.g.
  entering `ch' is equivalent to `*.[ch]'.
  
  While find runs asynchronously, you can use the \\[next-error] command
  to find the text that grep hits refer to.
  
  This command uses a special history list for its arguments, so you can
! easily repeat a find command.
! 
! When used non-interactively, optional arg SUBDIRS limits the search to
! those sub directories of DIR."
    (interactive
!    (let* ((regexp
!          (if current-prefix-arg
!              grep-tree-last-regexp
!            (let* ((default (current-word))
!                   (spec (read-string
!                          (concat "Search for"
!                                  (if (and default (> (length default) 0))
!                                      (format " (default %s): " default) ": 
")))))
!              (if (equal spec "") default spec))))
!         (files
!          (read-string (concat "Search for \"" regexp "\" in files (default "  
 grep-tree-last-files  "): ")))
!         (dir
!          (read-directory-name "Base directory: " nil default-directory t)))
!      (list regexp files dir)))
!   (unless grep-tree-command
!     (grep-compute-defaults))
!   (unless (and (stringp files) (> (length files) 0))
!     (setq files grep-tree-last-files))
!   (when files
!     (setq grep-tree-last-files files)
!     (let ((mf (assoc files grep-tree-files-aliases)))
!       (if mf
!         (setq files (cdr mf)))))
!   (let ((command-args (grep-expand-command-macros
!                      grep-tree-command
!                      (setq grep-tree-last-regexp regexp)
!                      (and files (concat "-name '" files "'"))
!                      (if subdirs
!                          (if (stringp subdirs)
!                              subdirs
!                            (mapconcat 'identity subdirs " "))
!                        nil)  ;; we change default-directory to dir
!                      (and grep-tree-ignore-CVS-directories "-path '*/CVS' 
-prune -o ")
!                      grep-tree-ignore-case))
!       (default-directory (file-name-as-directory (expand-file-name dir)))
!       (null-device nil))              ; see grep
!     (grep command-args regexp)))
  
  
  (provide 'grep)
  
--- 569,680 ----
                                  (or regexp "") command t t))
    command)
  
  ;;;###autoload
! (defun grep-find (regexp &optional files dir api)
!   "Recusively grep for REGEXP in FILES in directory tree rooted at DIR.
  Collect output in a buffer.
  Interactively, prompt separately for each search parameter.
  The search is limited to file names matching shell pattern FILES.
! FILES may use abbreviations defined in `grep-find-files-aliases', e.g.
  entering `ch' is equivalent to `*.[ch]'.
  
+ With \\[universal-argument] prefix, prompt for shell command instead.
+ With two \\[universal-argument] prefixes, prompt for search parameters,
+ and allow user to edit the final shell command before it is submitted.
+ Note that setting `grep-find-prompt-style' overrides any prefix arg.
+ 
  While find runs asynchronously, you can use the \\[next-error] command
  to find the text that grep hits refer to.
  
  This command uses a special history list for its arguments, so you can
! easily modify or repeat a find command."
    (interactive
!    (progn
!      (unless (and grep-command grep-find-command grep-find-template
!                 (or (not grep-use-null-device) (eq grep-use-null-device t)))
!        (grep-compute-defaults))
!      (cond
!       ((or (eq grep-find-prompt-style 'shell)
!          (equal current-prefix-arg '(4)))
!        (if grep-find-command
!          (list (read-from-minibuffer "Run find (like this): "
!                                      grep-find-command nil nil
!                                      'grep-find-history)
!                nil nil current-prefix-arg)
! 
!        ;; No default was set
!        (read-string
!         "grep.el: No `grep-find-command' available. Press RET.")
!        (list nil nil nil nil)))
!       ((not grep-find-template)
!        (read-string
!       "grep.el: No `grep-find-template' available. Press RET.")
!        (list nil nil nil nil))
!       (t
!        (let* ((default-regexp
!               (or (funcall (or find-tag-default-function
!                                (get major-mode 'find-tag-default-function)
!                                'find-tag-default))
!                   ""))
!             (regexp (read-string
!                      (concat "Search for"
!                              (if (and default-regexp
!                                       (> (length default-regexp) 0))
!                                  (format " (default %s): " default-regexp) ": 
"))
!                      nil 'grep-find-regexp-history default-regexp))
!             (default-files
!                    (or (and (stringp (buffer-file-name))
!                             (let ((fn (file-name-nondirectory 
(buffer-file-name)))
!                                   (aliases grep-find-files-aliases)
!                                   alias)
!                               (while aliases
!                                 (setq alias (car aliases)
!                                       aliases (cdr aliases))
!                                 (if (string-match (wildcard-to-regexp (cdr 
alias)) fn)
!                                     (setq aliases nil)
!                                   (setq alias nil)))
!                               (cdr alias)))
!                        (car grep-find-files-history)))
!                  (files (read-string
!                          (concat "Search for \"" regexp
!                                  "\" in files (default " default-files
!                                  "): ")
!                          nil 'grep-find-files-history default-files))
!                  (dir
!                   (read-directory-name "Base directory: " nil 
default-directory t)))
!        (list regexp files dir current-prefix-arg))))))
!   (when regexp
!     (if (or (null files)  ;; backwards compatible non-interactive call
!           (eq grep-find-prompt-style 'shell)
!           (equal current-prefix-arg '(4)))
!       (let ((null-device nil)
!             (command regexp))
!         (grep command))
!       (when files
!       (let ((mf (assoc files grep-find-files-aliases)))
!         (if mf
!             (setq files (cdr mf)))))
!       (let ((command (grep-expand-template
!                     grep-find-template
!                     (shell-quote-argument regexp)
!                     (and files (concat "-name "
!                                        (shell-quote-argument files)))
!                     nil  ;; we change default-directory to dir
!                     (and grep-find-ignore-CVS-directories "-path '*/CVS' 
-prune -o ")
!                     grep-find-ignore-case))
!           (default-directory (file-name-as-directory (expand-file-name dir)))
!           (null-device nil))          ; see grep
!       (when command
!         (if (or (eq grep-find-prompt-style 'post)
!                 (equal current-prefix-arg '(16)))
!             (setq command
!                   (read-from-minibuffer "Confirm: "
!                                         command nil nil 'grep-find-history))
!           (push command grep-find-history))
!         (grep command regexp))))))
  
+ ;;;###autoload
+ (defalias 'find-grep 'grep-find)
  
  (provide 'grep)
  

-- 
Kim F. Storm <address@hidden> http://www.cua.dk





reply via email to

[Prev in Thread] Current Thread [Next in Thread]