summaryrefslogtreecommitdiff
path: root/lisp/progmodes/grep.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/grep.el')
-rw-r--r--lisp/progmodes/grep.el136
1 files changed, 107 insertions, 29 deletions
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index 8b9a2d86c75..67222f78627 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -29,6 +29,7 @@
;;; Code:
+(eval-when-compile (require 'cl-lib))
(require 'compile)
(defgroup grep nil
@@ -286,6 +287,11 @@ See `compilation-error-screen-columns'"
(define-key map [menu-bar grep]
(cons "Grep" (make-sparse-keymap "Grep")))
+ (define-key map [menu-bar grep grep-find-toggle-abbreviation]
+ '(menu-item "Toggle command abbreviation"
+ grep-find-toggle-abbreviation
+ :help "Toggle showing verbose command options"))
+ (define-key map [menu-bar grep compilation-separator3] '("----"))
(define-key map [menu-bar grep compilation-kill-compilation]
'(menu-item "Kill Grep" kill-compilation
:help "Kill the currently running grep process"))
@@ -308,7 +314,7 @@ See `compilation-error-screen-columns'"
(define-key map [menu-bar grep compilation-recompile]
'(menu-item "Repeat grep" recompile
:help "Run grep again"))
- (define-key map [menu-bar grep compilation-separator2] '("----"))
+ (define-key map [menu-bar grep compilation-separator1] '("----"))
(define-key map [menu-bar grep compilation-first-error]
'(menu-item "First Match" first-error
:help "Restart at the first match, visit corresponding location"))
@@ -348,17 +354,6 @@ See `compilation-error-screen-columns'"
(defalias 'kill-grep 'kill-compilation)
-;;;; TODO --- refine this!!
-
-;; (defcustom grep-use-compilation-buffer t
-;; "When non-nil, grep specific commands update `compilation-last-buffer'.
-;; This means that standard compile commands like \\[next-error] and \\[compile-goto-error]
-;; can be used to navigate between grep matches (the default).
-;; Otherwise, the grep specific commands like \\[grep-next-match] must
-;; be used to navigate between grep matches."
-;; :type 'boolean
-;; :group 'grep)
-
;; override compilation-last-buffer
(defvar grep-last-buffer nil
"The most recent grep buffer.
@@ -435,26 +430,66 @@ See `compilation-error-regexp-alist' for format details.")
help-echo "Number of matches so far")
"]"))
+(defcustom grep-find-abbreviate t
+ "If non-nil, hide part of rgrep/lgrep/zrgrep command line.
+The hidden part contains a list of ignored directories and files.
+Clicking on the button-like ellipsis unhides the abbreviated part
+and reveals the entire command line. The visibility of the
+abbreviated part can also be toggled with
+`grep-find-toggle-abbreviation'."
+ :type 'boolean
+ :version "27.1"
+ :group 'grep)
+
+(defcustom grep-search-path '(nil)
+ "Search path for grep results.
+Elements should be directory names, not file names of directories.
+The value nil as an element means to try the default directory."
+ :group 'grep
+ :version "27.1"
+ :type '(repeat (choice (const :tag "Default" nil)
+ (string :tag "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)
+ `(face nil display ,ellipsis mouse-face highlight
+ help-echo "RET, mouse-2: show unabbreviated command"
+ keymap ,map abbreviated-command t))
+ "Properties of button-like ellipsis on part of rgrep command line.")
+
(defvar grep-mode-font-lock-keywords
'(;; Command output lines.
(": \\(.+\\): \\(?: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.*"
+ ("^Grep[/a-zA-Z]* started.*"
(0 '(face nil compilation-message nil help-echo nil mouse-face nil) t))
- ("^Grep[/a-zA-z]* finished with \\(?:\\(\\(?:[0-9]+ \\)?matches found\\)\\|\\(no matches found\\)\\).*"
+ ("^Grep[/a-zA-Z]* finished with \\(?:\\(\\(?:[0-9]+ \\)?match\\(?:es\\)? found\\)\\|\\(no matches found\\)\\).*"
(0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
(1 compilation-info-face nil t)
(2 compilation-warning-face nil t))
- ("^Grep[/a-zA-z]* \\(exited abnormally\\|interrupt\\|killed\\|terminated\\)\\(?:.*with code \\([0-9]+\\)\\)?.*"
+ ("^Grep[/a-zA-Z]* \\(exited abnormally\\|interrupt\\|killed\\|terminated\\)\\(?:.*with code \\([0-9]+\\)\\)?.*"
(0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
(1 grep-error-face)
(2 grep-error-face nil t))
;; "filename-linenumber-" format is used for context lines in GNU grep,
;; "filename=linenumber=" for lines with function names in "git grep -p".
- ("^.+?\\([-=\0]\\)[0-9]+\\([-=]\\).*\n" (0 grep-context-face)
+ ("^.+?\\([-=\0]\\)[0-9]+\\([-=]\\).*\n"
+ (0 grep-context-face)
(1 (if (eq (char-after (match-beginning 1)) ?\0)
- `(face nil display ,(match-string 2))))))
+ `(face nil display ,(match-string 2)))))
+ ;; Hide excessive part of rgrep command
+ ("^find \\(\\. -type d .*\\\\)\\)"
+ (1 (if grep-find-abbreviate grep-find-abbreviate-properties
+ '(face nil abbreviated-command t))))
+ ;; Hide excessive part of lgrep command
+ ("^grep \\( *--exclude.*--exclude[^ ]+\\)"
+ (1 (if grep-find-abbreviate grep-find-abbreviate-properties
+ '(face nil abbreviated-command t)))))
"Additional things to highlight in grep output.
This gets tacked on the end of the generated expressions.")
@@ -476,14 +511,24 @@ See `grep-find-use-xargs'.
This variable's value takes effect when `grep-compute-defaults' is called.")
;;;###autoload
-(defvar grep-find-use-xargs nil
+(defcustom grep-find-use-xargs nil
"How to invoke find and grep.
If `exec', use `find -exec {} ;'.
If `exec-plus' use `find -exec {} +'.
If `gnu', use `find -print0' and `xargs -0'.
+If `gnu-sort', use `find -print0', `sort -z' and `xargs -0'.
Any other value means to use `find -print' and `xargs'.
-This variable's value takes effect when `grep-compute-defaults' is called.")
+This variable's value takes effect when `grep-compute-defaults' is called."
+ :type '(choice (const :tag "find -exec {} ;" exec)
+ (const :tag "find -exec {} +" exec-plus)
+ (const :tag "find -print0 | xargs -0" gnu)
+ (const :tag "find -print0 | sort -z | xargs -0'" gnu-sort)
+ string
+ (const :tag "Not Set" nil))
+ :set 'grep-apply-setting
+ :version "27.1"
+ :group 'grep)
;; History of grep commands.
;;;###autoload
@@ -526,7 +571,10 @@ Set up `compilation-exit-message-function' and run `grep-setup-hook'."
;; so the buffer is still unmodified if there is no output.
(cond ((and (zerop code) (buffer-modified-p))
(if (> grep-num-matches-found 0)
- (cons (format "finished with %d matches found\n" grep-num-matches-found)
+ (cons (format (ngettext "finished with %d match found\n"
+ "finished with %d matches found\n"
+ grep-num-matches-found)
+ grep-num-matches-found)
"matched")
'("finished with matches found\n" . "matched")))
((not (buffer-modified-p))
@@ -608,22 +656,22 @@ This function is called from `compilation-filter-hook'."
;; `grep-command' is already set, so
;; use that for testing.
(grep-probe grep-command
- `(nil t nil "^English" ,hello-file)
+ `(nil t nil "^Copyright" ,hello-file)
#'call-process-shell-command)
;; otherwise use `grep-program'
(grep-probe grep-program
- `(nil t nil "-nH" "^English" ,hello-file)))
+ `(nil t nil "-nH" "^Copyright" ,hello-file)))
(progn
(goto-char (point-min))
(looking-at
(concat (regexp-quote hello-file)
- ":[0-9]+:English")))))))))
+ ":[0-9]+:Copyright")))))))))
(when (eq grep-use-null-filename-separator 'auto-detect)
(setq grep-use-null-filename-separator
(with-temp-buffer
(let* ((hello-file (expand-file-name "HELLO" data-directory))
- (args `("--null" "-ne" "^English" ,hello-file)))
+ (args `("--null" "-ne" "^Copyright" ,hello-file)))
(if grep-use-null-device
(setq args (append args (list null-device)))
(push "-H" args))
@@ -632,7 +680,7 @@ This function is called from `compilation-filter-hook'."
(goto-char (point-min))
(looking-at
(concat (regexp-quote hello-file)
- "\0[0-9]+:English"))))))))
+ "\0[0-9]+:Copyright"))))))))
(when (eq grep-highlight-matches 'auto-detect)
(setq grep-highlight-matches
@@ -678,7 +726,7 @@ This function is called from `compilation-filter-hook'."
'exec-plus)
((and
(grep-probe find-program `(nil nil nil ,null-device "-print0"))
- (grep-probe xargs-program `(nil nil nil "-0" "echo")))
+ (grep-probe xargs-program '(nil nil nil "-0" "echo")))
'gnu)
(t
'exec))))
@@ -690,6 +738,9 @@ This function is called from `compilation-filter-hook'."
;; forward slashes as directory separators.
(format "%s . -type f -print0 | \"%s\" -0 %s"
find-program xargs-program grep-command))
+ ((eq grep-find-use-xargs 'gnu-sort)
+ (format "%s . -type f -print0 | sort -z | \"%s\" -0 %s"
+ find-program xargs-program grep-command))
((memq grep-find-use-xargs '(exec exec-plus))
(let ((cmd0 (format "%s . -type f -exec %s"
find-program grep-command))
@@ -714,6 +765,9 @@ This function is called from `compilation-filter-hook'."
(cond ((eq grep-find-use-xargs 'gnu)
(format "%s <D> <X> -type f <F> -print0 | \"%s\" -0 %s"
find-program xargs-program gcmd))
+ ((eq grep-find-use-xargs 'gnu-sort)
+ (format "%s <D> <X> -type f <F> -print0 | sort -z | \"%s\" -0 %s"
+ find-program xargs-program gcmd))
((eq grep-find-use-xargs 'exec)
(format "%s <D> <X> -type f <F> -exec %s %s %s%s"
find-program gcmd quot-braces null quot-scolon))
@@ -799,7 +853,8 @@ This function is called from `compilation-filter-hook'."
grep-mode-line-matches)
;; compilation-directory-matcher can't be nil, so we set it to a regexp that
;; can never match.
- (set (make-local-variable 'compilation-directory-matcher) '("\\`a\\`"))
+ (set (make-local-variable 'compilation-directory-matcher)
+ (list regexp-unmatchable))
(set (make-local-variable 'compilation-process-setup-function)
'grep-process-setup)
(set (make-local-variable 'compilation-disable-input) t)
@@ -930,8 +985,16 @@ substitution string. Note dynamic scoping of variables.")
The pattern can include shell wildcards. As whitespace triggers
completion when entering a pattern, including it requires
quoting, e.g. `\\[quoted-insert]<space>'."
- (let* ((bn (or (buffer-file-name)
- (replace-regexp-in-string "<[0-9]+>\\'" "" (buffer-name))))
+ (let* ((grep-read-files-function (get major-mode 'grep-read-files))
+ (file-name-at-point
+ (run-hook-with-args-until-success 'file-name-at-point-functions))
+ (bn (if grep-read-files-function
+ (funcall grep-read-files-function)
+ (or (if (and (stringp file-name-at-point)
+ (not (file-directory-p file-name-at-point)))
+ file-name-at-point)
+ (buffer-file-name)
+ (replace-regexp-in-string "<[0-9]+>\\'" "" (buffer-name)))))
(fn (and bn
(stringp bn)
(file-name-nondirectory bn)))
@@ -1048,6 +1111,7 @@ This command shares argument histories with \\[rgrep] and \\[grep]."
(concat command " " null-device)
command)
'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))))))
@@ -1170,6 +1234,20 @@ to specify a command to run."
(shell-quote-argument ")")
" -prune -o ")))))
+(defun grep-find-toggle-abbreviation ()
+ "Toggle showing the hidden part of rgrep/lgrep/zrgrep command line."
+ (interactive)
+ (with-silent-modifications
+ (let* ((beg (next-single-property-change (point-min) 'abbreviated-command))
+ (end (when beg
+ (next-single-property-change beg 'abbreviated-command))))
+ (if end
+ (if (get-text-property beg 'display)
+ (remove-list-of-text-properties
+ beg end '(display help-echo mouse-face help-echo keymap))
+ (add-text-properties beg end grep-find-abbreviate-properties))
+ (user-error "No abbreviated part to hide/show")))))
+
;;;###autoload
(defun zrgrep (regexp &optional files dir confirm template)
"Recursively grep for REGEXP in gzipped FILES in tree rooted at DIR.