diff options
Diffstat (limited to 'lisp/progmodes/grep.el')
-rw-r--r-- | lisp/progmodes/grep.el | 175 |
1 files changed, 105 insertions, 70 deletions
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el index bbcb644b73f..4c1f801980a 100644 --- a/lisp/progmodes/grep.el +++ b/lisp/progmodes/grep.el @@ -48,8 +48,8 @@ to avoid computing them again.") "Set SYMBOL to VALUE, and update `grep-host-defaults-alist'. SYMBOL should be one of `grep-command', `grep-template', `grep-use-null-device', `grep-find-command' `grep-find-template', -`grep-find-use-xargs', `grep-use-null-filename-separator', or -`grep-highlight-matches'." +`grep-find-use-xargs', `grep-use-null-filename-separator', +`grep-highlight-matches', or `grep-quoting-style'." (when grep-host-defaults-alist (let* ((host-id (intern (or (file-remote-p default-directory) "localhost"))) @@ -66,6 +66,7 @@ SYMBOL should be one of `grep-command', `grep-template', integer) :version "22.1") +;;;###autoload (defcustom grep-highlight-matches 'auto-detect "Use special markers to highlight grep matches. @@ -202,6 +203,9 @@ by `grep-compute-defaults'; to change the default value, use :set #'grep-apply-setting :version "22.1") +(defvar grep-quoting-style nil + "Whether to use POSIX-like shell argument quoting.") + (defcustom grep-files-aliases '(("all" . "* .*") ("el" . "*.el") @@ -212,6 +216,7 @@ by `grep-compute-defaults'; to change the default value, use ("hh" . "*.hxx *.hpp *.[Hh] *.HH *.h++") ("h" . "*.h") ("l" . "[Cc]hange[Ll]og*") + ("am" . "Makefile.am GNUmakefile *.mk") ("m" . "[Mm]akefile*") ("tex" . "*.tex") ("texi" . "*.texi") @@ -269,16 +274,16 @@ See `compilation-error-screen-columns'." (defvar grep-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map compilation-minor-mode-map) - (define-key map " " 'scroll-up-command) - (define-key map [?\S-\ ] 'scroll-down-command) - (define-key map "\^?" 'scroll-down-command) - (define-key map "\C-c\C-f" 'next-error-follow-minor-mode) - - (define-key map "\r" 'compile-goto-error) ;; ? - (define-key map "{" 'compilation-previous-file) - (define-key map "}" 'compilation-next-file) - (define-key map "\t" 'compilation-next-error) - (define-key map [backtab] 'compilation-previous-error) + (define-key map " " #'scroll-up-command) + (define-key map [?\S-\ ] #'scroll-down-command) + (define-key map "\^?" #'scroll-down-command) + (define-key map "\C-c\C-f" #'next-error-follow-minor-mode) + + (define-key map "\r" #'compile-goto-error) ;; ? + (define-key map "{" #'compilation-previous-file) + (define-key map "}" #'compilation-next-file) + (define-key map "\t" #'compilation-next-error) + (define-key map [backtab] #'compilation-previous-error) map) "Keymap for grep buffers. `compilation-minor-mode-map' is a cdr of this.") @@ -322,32 +327,33 @@ See `compilation-error-screen-columns'." ;; FIXME: Nowadays the last button is not "help" but "search"! (help (last tool-bar-map))) ;; Keep Help last in tool bar (tool-bar-local-item - "left-arrow" 'previous-error-no-select 'previous-error-no-select map + "left-arrow" #'previous-error-no-select #'previous-error-no-select map :rtl "right-arrow" :help "Goto previous match") (tool-bar-local-item - "right-arrow" 'next-error-no-select 'next-error-no-select map + "right-arrow" #'next-error-no-select #'next-error-no-select map :rtl "left-arrow" :help "Goto next match") (tool-bar-local-item - "cancel" 'kill-compilation 'kill-compilation map + "cancel" #'kill-compilation #'kill-compilation map :enable '(let ((buffer (compilation-find-buffer))) (get-buffer-process buffer)) :help "Stop grep") (tool-bar-local-item - "refresh" 'recompile 'recompile map + "refresh" #'recompile #'recompile map :help "Restart grep") (append map help)))) -(defalias 'kill-grep 'kill-compilation) +(defalias 'kill-grep #'kill-compilation) -;; override compilation-last-buffer +;; override next-error-last-buffer (defvar grep-last-buffer nil "The most recent grep buffer. A grep buffer becomes most recent when you select Grep mode in it. Notice that using \\[next-error] or \\[compile-goto-error] modifies -`compilation-last-buffer' rather than `grep-last-buffer'.") +`next-error-last-buffer' rather than `grep-last-buffer'.") +;;;###autoload (defvar grep-match-face 'match "Face name to use for grep matches.") @@ -443,9 +449,9 @@ buffer `default-directory'." (defvar grep-find-abbreviate-properties (let ((ellipsis (if (char-displayable-p ?…) "[…]" "[...]")) (map (make-sparse-keymap))) - (define-key map [down-mouse-2] 'mouse-set-point) - (define-key map [mouse-2] 'grep-find-toggle-abbreviation) - (define-key map "\C-m" 'grep-find-toggle-abbreviation) + (define-key map [down-mouse-2] #'mouse-set-point) + (define-key map [mouse-2] #'grep-find-toggle-abbreviation) + (define-key map "\C-m" #'grep-find-toggle-abbreviation) `(face nil display ,ellipsis mouse-face highlight help-echo "RET, mouse-2: show unabbreviated command" keymap ,map abbreviated-command t)) @@ -453,7 +459,7 @@ buffer `default-directory'." (defvar grep-mode-font-lock-keywords '(;; Command output lines. - (": \\(.+\\): \\(?:Permission denied\\|No such \\(?:file or directory\\|device or address\\)\\)$" + (": \\(.\\{,200\\}\\): \\(?:Permission denied\\|No such \\(?:file or directory\\|device or address\\)\\)$" 1 grep-error-face) ;; remove match from grep-regexp-alist before fontifying ("^Grep[/a-zA-Z]* started.*" @@ -616,8 +622,8 @@ This function is called from `compilation-filter-hook'." "Compute the defaults for the `grep' command. The value depends on `grep-command', `grep-template', `grep-use-null-device', `grep-find-command', `grep-find-template', -`grep-use-null-filename-separator', `grep-find-use-xargs' and -`grep-highlight-matches'." +`grep-use-null-filename-separator', `grep-find-use-xargs', +`grep-highlight-matches', and `grep-quoting-style'." ;; Keep default values. (unless grep-host-defaults-alist (add-to-list @@ -631,13 +637,14 @@ The value depends on `grep-command', `grep-template', (grep-use-null-filename-separator ,grep-use-null-filename-separator) (grep-find-use-xargs ,grep-find-use-xargs) - (grep-highlight-matches ,grep-highlight-matches))))) - (let* ((host-id - (intern (or (file-remote-p default-directory) "localhost"))) + (grep-highlight-matches ,grep-highlight-matches) + (grep-quoting-style ,grep-quoting-style))))) + (let* ((remote (file-remote-p default-directory)) + (host-id (intern (or remote "localhost"))) (host-defaults (assq host-id grep-host-defaults-alist)) (defaults (assq nil grep-host-defaults-alist)) - (quot-braces (shell-quote-argument "{}")) - (quot-scolon (shell-quote-argument ";"))) + (quot-braces (shell-quote-argument "{}" remote)) + (quot-scolon (shell-quote-argument ";" remote))) ;; There are different defaults on different hosts. They must be ;; computed for every host once. (dolist (setting '(grep-command grep-template @@ -791,8 +798,11 @@ The value depends on `grep-command', `grep-template', find-program gcmd null quot-braces)) (t (format "%s -H <D> <X> -type f <F> -print | \"%s\" %s" - find-program xargs-program gcmd)))))))) - ;; Save defaults for this host. + find-program xargs-program gcmd)))))) + + (setq grep-quoting-style (and remote 'posix)))) + + ;; Save defaults for this host. (setq grep-host-defaults-alist (delete (assq host-id grep-host-defaults-alist) grep-host-defaults-alist)) @@ -807,7 +817,8 @@ The value depends on `grep-command', `grep-template', (grep-use-null-filename-separator ,grep-use-null-filename-separator) (grep-find-use-xargs ,grep-find-use-xargs) - (grep-highlight-matches ,grep-highlight-matches)))))) + (grep-highlight-matches ,grep-highlight-matches) + (grep-quoting-style ,grep-quoting-style)))))) (defun grep-tag-default () (or (and transient-mark-mode mark-active @@ -820,7 +831,8 @@ The value depends on `grep-command', `grep-template', (defun grep-default-command () "Compute the default grep command for \\[universal-argument] \\[grep] to offer." - (let ((tag-default (shell-quote-argument (grep-tag-default))) + (let ((tag-default + (shell-quote-argument (grep-tag-default) grep-quoting-style)) ;; This a regexp to match single shell arguments. ;; Could someone please add comments explaining it? (sh-arg-re @@ -875,6 +887,14 @@ The value depends on `grep-command', `grep-template', (setq-local compilation-disable-input t) (setq-local compilation-error-screen-columns grep-error-screen-columns) + ;; We normally use a nul byte to separate the file name from the + ;; contents, but display it as ":". That's fine, but when yanking + ;; to other buffers, it's annoying to have the nul byte there. + (unless kill-transform-function + (setq-local kill-transform-function #'identity)) + (add-function :filter-return (local 'kill-transform-function) + (lambda (string) + (string-replace "\0" ":" string))) (add-hook 'compilation-filter-hook #'grep-filter nil t)) (defun grep--save-buffers () @@ -952,8 +972,7 @@ easily repeat a find command." (grep command-args)))) ;;;###autoload -(defalias 'find-grep 'grep-find) - +(defalias 'find-grep #'grep-find) ;; User-friendly interactive API. @@ -963,7 +982,7 @@ easily repeat a find command." ("<F>" . files) ("<N>" . (null-device)) ("<X>" . excl) - ("<R>" . (shell-quote-argument (or regexp "")))) + ("<R>" . (shell-quote-argument (or regexp "") grep-quoting-style))) "List of substitutions performed by `grep-expand-template'. If car of an element matches, the cdr is evalled in order to get the substitution string. @@ -1010,7 +1029,7 @@ these include `opts', `dir', `files', `null-device', `excl' and ;; Instead of a `grep-read-files-function' variable, we used to lookup ;; mode-specific functions in the major mode's symbol properties, so preserve ;; this behavior for backward compatibility. - (let ((old-function (get major-mode 'grep-read-files))) ;Obsolete since 28.1 + (let ((old-function (get major-mode #'grep-read-files))) ;Obsolete since 28.1 (if old-function (funcall old-function) (let ((file-name-at-point @@ -1057,17 +1076,18 @@ REGEXP is used as a string in the prompt." default-extension (car grep-files-history) (car (car grep-files-aliases)))) - (files (completing-read - (concat "Search for \"" regexp - "\" in files matching wildcard" - (if default (concat " (default " default ")")) - ": ") - #'read-file-name-internal - nil nil nil 'grep-files-history - (delete-dups - (delq nil - (append (list default default-alias default-extension) - (mapcar #'car grep-files-aliases))))))) + (defaults + (delete-dups + (delq nil + (append (list default default-alias default-extension) + (mapcar #'car grep-files-aliases))))) + (files (completing-read + (format-prompt "Search for \"%s\" in files matching wildcard" + default regexp) + (completion-table-merge + (lambda (_string _pred _action) defaults) + #'read-file-name-internal) + nil nil nil 'grep-files-history defaults))) (and files (or (cdr (assoc files grep-files-aliases)) files)))) @@ -1114,6 +1134,9 @@ command before it's run." (when (and (stringp regexp) (> (length regexp) 0)) (unless (and dir (file-accessible-directory-p dir)) (setq dir default-directory)) + (unless (string-equal (file-remote-p dir) (file-remote-p default-directory)) + (let ((default-directory dir)) + (grep-compute-defaults))) (let ((command regexp)) (if (null files) (if (string= command grep-command) @@ -1136,11 +1159,13 @@ command before it's run." (mapconcat (lambda (ignore) (cond ((stringp ignore) - (shell-quote-argument ignore)) + (shell-quote-argument + ignore grep-quoting-style)) ((consp ignore) (and (funcall (car ignore) dir) (shell-quote-argument - (cdr ignore)))))) + (cdr ignore) + grep-quoting-style))))) grep-find-ignored-files " --exclude="))) (and (eq grep-use-directories-skip t) @@ -1160,7 +1185,7 @@ command before it's run." (if (and grep-use-null-device null-device (null-device)) (concat command " " (null-device)) command) - 'grep-mode)) + #'grep-mode)) ;; Set default-directory if we started lgrep in the *grep* buffer. (if (eq next-error-last-buffer (current-buffer)) (setq default-directory dir)))))) @@ -1193,7 +1218,11 @@ When called programmatically and FILES is nil, REGEXP is expected to specify a command to run. If CONFIRM is non-nil, the user will be given an opportunity to edit the -command before it's run." +command before it's run. + +Interactively, the user can use the \\`M-c' command while entering +the regexp to indicate whether the grep should be case sensitive +or not." (interactive (progn (grep-compute-defaults) @@ -1212,13 +1241,17 @@ command before it's run." (when (and (stringp regexp) (> (length regexp) 0)) (unless (and dir (file-accessible-directory-p dir)) (setq dir default-directory)) + (unless (string-equal (file-remote-p dir) (file-remote-p default-directory)) + (let ((default-directory dir)) + (grep-compute-defaults))) (if (null files) (if (not (string= regexp (if (consp grep-find-command) (car grep-find-command) grep-find-command))) - (compilation-start regexp 'grep-mode)) + (compilation-start regexp #'grep-mode)) (setq dir (file-name-as-directory (expand-file-name dir))) - (let ((command (rgrep-default-command regexp files nil))) + (let* ((case-fold-search (read-regexp-case-fold-search regexp)) + (command (rgrep-default-command regexp files nil))) (when command (if confirm (setq command @@ -1227,7 +1260,7 @@ command before it's run." (add-to-history 'grep-find-history command)) (grep--save-buffers) (let ((default-directory dir)) - (compilation-start command 'grep-mode)) + (compilation-start command #'grep-mode)) ;; Set default-directory if we started rgrep in the *grep* buffer. (if (eq next-error-last-buffer (current-buffer)) (setq default-directory dir))))))) @@ -1247,44 +1280,46 @@ command before it's run." (grep-expand-template grep-find-template regexp - (concat (shell-quote-argument "(") + (concat (shell-quote-argument "(" grep-quoting-style) " " find-name-arg " " (mapconcat - #'shell-quote-argument + (lambda (x) (shell-quote-argument x grep-quoting-style)) (split-string files) (concat " -o " find-name-arg " ")) " " - (shell-quote-argument ")")) + (shell-quote-argument ")" grep-quoting-style)) dir (concat (and grep-find-ignored-directories (concat "-type d " - (shell-quote-argument "(") + (shell-quote-argument "(" grep-quoting-style) ;; we should use shell-quote-argument here " -path " - (mapconcat (lambda (d) (shell-quote-argument (concat "*/" d))) - (rgrep-find-ignored-directories dir) - " -o -path ") + (mapconcat + (lambda (d) + (shell-quote-argument (concat "*/" d) grep-quoting-style)) + (rgrep-find-ignored-directories dir) + " -o -path ") " " - (shell-quote-argument ")") + (shell-quote-argument ")" grep-quoting-style) " -prune -o ")) (and grep-find-ignored-files - (concat (shell-quote-argument "!") " -type d " - (shell-quote-argument "(") + (concat (shell-quote-argument "!" grep-quoting-style) " -type d " + (shell-quote-argument "(" grep-quoting-style) ;; we should use shell-quote-argument here " -name " (mapconcat (lambda (ignore) (cond ((stringp ignore) - (shell-quote-argument ignore)) + (shell-quote-argument ignore grep-quoting-style)) ((consp ignore) (and (funcall (car ignore) dir) (shell-quote-argument - (cdr ignore)))))) + (cdr ignore) grep-quoting-style))))) grep-find-ignored-files " -o -name ") " " - (shell-quote-argument ")") + (shell-quote-argument ")" grep-quoting-style) " -prune -o "))))) (defun grep-find-toggle-abbreviation () @@ -1354,7 +1389,7 @@ The returned file name is relative." (caar (compilation--loc->file-struct loc)))) ;;;###autoload -(defalias 'rzgrep 'zrgrep) +(defalias 'rzgrep #'zrgrep) (provide 'grep) |