Use grep's --null option (Bug#6843)
* lisp/progmodes/grep.el (grep-use-null-filename-separator): New option. (grep--regexp-alist-column, grep--regexp-alist-bin-matcher) (grep-with-null-regexp-alist, grep-fallback-regexp-alist): New constants, replacing `grep-regexp-alist'. (grep-regex-alist): Mark the variable obsolete, add a new function of the same name to replace it. (grep-compute-defaults): Compute default for `grep-use-null-filename-separator'. (grep-mode): Set compilation-error-regexp-alist (buffer locally) to the value of `grep-with-null-regexp-alist' or `grep-fallback-regexp-alist' according to `grep-use-null-filename-separator'. * lisp/progmodes/xref.el (xref-collect-matches): Call `grep-regex-alist' instead of the obsolete variable. Don't hardcode grep-regexp-alist match groups. * etc/NEWS: Announce new use of --null. Move 'grep-save-buffers' item under "Grep" heading as well.
This commit is contained in:
parent
eda9aa0d31
commit
644cdd1aa0
3 changed files with 105 additions and 48 deletions
16
etc/NEWS
16
etc/NEWS
|
@ -705,6 +705,18 @@ this is controlled by the 'wdired-create-parent-directories' variable.
|
||||||
*** 'W' is now bound to 'browse-url-of-dired-file', and is useful for
|
*** 'W' is now bound to 'browse-url-of-dired-file', and is useful for
|
||||||
viewing HTML files and the like.
|
viewing HTML files and the like.
|
||||||
|
|
||||||
|
** Grep
|
||||||
|
|
||||||
|
---
|
||||||
|
*** Grep commands will now use GNU grep's '--null' option if
|
||||||
|
available, which allows distinguishing the filename from contents if
|
||||||
|
they contain colons. This can be controlled by the new custom option
|
||||||
|
'grep-use-null-filename-separator'.
|
||||||
|
|
||||||
|
*** The grep/rgrep/lgrep functions will now ask about saving files
|
||||||
|
before running. This is controlled by the 'grep-save-buffers'
|
||||||
|
variable.
|
||||||
|
|
||||||
** Edebug
|
** Edebug
|
||||||
|
|
||||||
*** Edebug can be prevented from pausing 1 second after reaching a
|
*** Edebug can be prevented from pausing 1 second after reaching a
|
||||||
|
@ -1053,10 +1065,6 @@ things like forward-word in readline work.
|
||||||
** hideshow mode got four key bindings that are analogous to outline
|
** hideshow mode got four key bindings that are analogous to outline
|
||||||
mode bindings: 'C-c @ C-a', 'C-c @ C-t', 'C-c @ C-d', and 'C-c @ C-e.'
|
mode bindings: 'C-c @ C-a', 'C-c @ C-t', 'C-c @ C-d', and 'C-c @ C-e.'
|
||||||
|
|
||||||
** The grep/rgrep/lgrep functions will now ask about saving files
|
|
||||||
before running. This is controlled by the 'grep-save-buffers'
|
|
||||||
variable.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
** Customizable variable 'query-replace-from-to-separator'
|
** Customizable variable 'query-replace-from-to-separator'
|
||||||
now doesn't propertize the string value of the separator.
|
now doesn't propertize the string value of the separator.
|
||||||
|
|
|
@ -47,8 +47,8 @@ to avoid computing them again.")
|
||||||
(defun grep-apply-setting (symbol value)
|
(defun grep-apply-setting (symbol value)
|
||||||
"Set SYMBOL to VALUE, and update `grep-host-defaults-alist'.
|
"Set SYMBOL to VALUE, and update `grep-host-defaults-alist'.
|
||||||
SYMBOL should be one of `grep-command', `grep-template',
|
SYMBOL should be one of `grep-command', `grep-template',
|
||||||
`grep-use-null-device', `grep-find-command',
|
`grep-use-null-device', `grep-find-command' `grep-find-template',
|
||||||
`grep-find-template', `grep-find-use-xargs', or
|
`grep-find-use-xargs', `grep-use-null-filename-separator', or
|
||||||
`grep-highlight-matches'."
|
`grep-highlight-matches'."
|
||||||
(when grep-host-defaults-alist
|
(when grep-host-defaults-alist
|
||||||
(let* ((host-id
|
(let* ((host-id
|
||||||
|
@ -160,6 +160,15 @@ Customize or call the function `grep-apply-setting'."
|
||||||
:set 'grep-apply-setting
|
:set 'grep-apply-setting
|
||||||
:group 'grep)
|
:group 'grep)
|
||||||
|
|
||||||
|
(defcustom grep-use-null-filename-separator 'auto-detect
|
||||||
|
"If non-nil, use `grep's `--null' option.
|
||||||
|
This is done to disambiguate file names in `grep's output."
|
||||||
|
:type '(choice (const :tag "Do Not Use `--null'" nil)
|
||||||
|
(const :tag "Use `--null'" t)
|
||||||
|
(other :tag "Not Set" auto-detect))
|
||||||
|
:set 'grep-apply-setting
|
||||||
|
:group 'grep)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defcustom grep-find-command nil
|
(defcustom grep-find-command nil
|
||||||
"The default find command for \\[grep-find].
|
"The default find command for \\[grep-find].
|
||||||
|
@ -357,33 +366,53 @@ A grep buffer becomes most recent when you select Grep mode in it.
|
||||||
Notice that using \\[next-error] or \\[compile-goto-error] modifies
|
Notice that using \\[next-error] or \\[compile-goto-error] modifies
|
||||||
`compilation-last-buffer' rather than `grep-last-buffer'.")
|
`compilation-last-buffer' rather than `grep-last-buffer'.")
|
||||||
|
|
||||||
;;;###autoload
|
(defconst grep--regexp-alist-column
|
||||||
(defconst grep-regexp-alist
|
;; Calculate column positions (col . end-col) of first grep match on a line
|
||||||
'(
|
(cons
|
||||||
;; Use a tight regexp to handle weird file names (with colons
|
(lambda ()
|
||||||
|
(when grep-highlight-matches
|
||||||
|
(let* ((beg (match-end 0))
|
||||||
|
(end (save-excursion (goto-char beg) (line-end-position)))
|
||||||
|
(mbeg (text-property-any beg end 'font-lock-face 'grep-match-face)))
|
||||||
|
(when mbeg
|
||||||
|
(- mbeg beg)))))
|
||||||
|
(lambda ()
|
||||||
|
(when grep-highlight-matches
|
||||||
|
(let* ((beg (match-end 0))
|
||||||
|
(end (save-excursion (goto-char beg) (line-end-position)))
|
||||||
|
(mbeg (text-property-any beg end 'font-lock-face 'grep-match-face))
|
||||||
|
(mend (and mbeg (next-single-property-change mbeg 'font-lock-face nil end))))
|
||||||
|
(when mend
|
||||||
|
(- mend beg)))))))
|
||||||
|
(defconst grep--regexp-alist-bin-matcher
|
||||||
|
'("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
|
||||||
|
(defconst grep-with-null-regexp-alist
|
||||||
|
`(("^\\([^\0]+\\)\\(\0\\)\\([0-9]+\\):" 1 3 ,grep--regexp-alist-column nil nil
|
||||||
|
(2 '(face unspecified display ":")))
|
||||||
|
,grep--regexp-alist-bin-matcher)
|
||||||
|
"Regexp used to match grep hits.
|
||||||
|
See `compilation-error-regexp-alist'.")
|
||||||
|
(defconst grep-fallback-regexp-alist
|
||||||
|
`(;; Use a tight regexp to handle weird file names (with colons
|
||||||
;; in them) as well as possible. E.g., use [1-9][0-9]* rather
|
;; in them) as well as possible. E.g., use [1-9][0-9]* rather
|
||||||
;; than [0-9]+ so as to accept ":034:" in file names.
|
;; than [0-9]+ so as to accept ":034:" in file names.
|
||||||
("^\\(.*?[^/\n]\\):[ \t]*\\([1-9][0-9]*\\)[ \t]*:"
|
("^\\(.*?[^/\n]\\):[ \t]*\\([1-9][0-9]*\\)[ \t]*:"
|
||||||
1 2
|
1 2 ,grep--regexp-alist-column)
|
||||||
;; Calculate column positions (col . end-col) of first grep match on a line
|
,grep--regexp-alist-bin-matcher)
|
||||||
((lambda ()
|
"Regexp used to match grep hits when `--null' is not supported.
|
||||||
(when grep-highlight-matches
|
See `compilation-error-regexp-alist'.")
|
||||||
(let* ((beg (match-end 0))
|
|
||||||
(end (save-excursion (goto-char beg) (line-end-position)))
|
(defvaralias 'grep-regex-alist 'grep-with-null-regexp-alist)
|
||||||
(mbeg (text-property-any beg end 'font-lock-face grep-match-face)))
|
(make-obsolete-variable
|
||||||
(when mbeg
|
'grep-regex-alist "Call `grep-regexp-alist' instead." "26.1")
|
||||||
(- mbeg beg)))))
|
|
||||||
.
|
;;;###autoload
|
||||||
(lambda ()
|
(defun grep-regexp-alist ()
|
||||||
(when grep-highlight-matches
|
"Return a regexp alist to match grep hits.
|
||||||
(let* ((beg (match-end 0))
|
The regexp used depends on `grep-use-null-filename-separator'.
|
||||||
(end (save-excursion (goto-char beg) (line-end-position)))
|
See `compilation-error-regexp-alist' for format details."
|
||||||
(mbeg (text-property-any beg end 'font-lock-face grep-match-face))
|
(if grep-use-null-filename-separator
|
||||||
(mend (and mbeg (next-single-property-change mbeg 'font-lock-face nil end))))
|
grep-with-null-regexp-alist grep-fallback-regexp-alist))
|
||||||
(when mend
|
|
||||||
(- mend beg)))))))
|
|
||||||
("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
|
|
||||||
"Regexp used to match grep hits. See `compilation-error-regexp-alist'.")
|
|
||||||
|
|
||||||
(defvar grep-first-column 0 ; bug#10594
|
(defvar grep-first-column 0 ; bug#10594
|
||||||
"Value to use for `compilation-first-column' in grep buffers.")
|
"Value to use for `compilation-first-column' in grep buffers.")
|
||||||
|
@ -538,6 +567,8 @@ This function is called from `compilation-filter-hook'."
|
||||||
(grep-use-null-device ,grep-use-null-device)
|
(grep-use-null-device ,grep-use-null-device)
|
||||||
(grep-find-command ,grep-find-command)
|
(grep-find-command ,grep-find-command)
|
||||||
(grep-find-template ,grep-find-template)
|
(grep-find-template ,grep-find-template)
|
||||||
|
(grep-use-null-filename-separator
|
||||||
|
,grep-use-null-filename-separator)
|
||||||
(grep-find-use-xargs ,grep-find-use-xargs)
|
(grep-find-use-xargs ,grep-find-use-xargs)
|
||||||
(grep-highlight-matches ,grep-highlight-matches)))))
|
(grep-highlight-matches ,grep-highlight-matches)))))
|
||||||
(let* ((host-id
|
(let* ((host-id
|
||||||
|
@ -550,7 +581,8 @@ This function is called from `compilation-filter-hook'."
|
||||||
;; computed for every host once.
|
;; computed for every host once.
|
||||||
(dolist (setting '(grep-command grep-template
|
(dolist (setting '(grep-command grep-template
|
||||||
grep-use-null-device grep-find-command
|
grep-use-null-device grep-find-command
|
||||||
grep-find-template grep-find-use-xargs
|
grep-use-null-filename-separator
|
||||||
|
grep-find-template grep-find-use-xargs
|
||||||
grep-highlight-matches))
|
grep-highlight-matches))
|
||||||
(set setting
|
(set setting
|
||||||
(cadr (or (assq setting host-defaults)
|
(cadr (or (assq setting host-defaults)
|
||||||
|
@ -576,6 +608,21 @@ This function is called from `compilation-filter-hook'."
|
||||||
(concat (regexp-quote hello-file)
|
(concat (regexp-quote hello-file)
|
||||||
":[0-9]+:English")))))))))
|
":[0-9]+:English")))))))))
|
||||||
|
|
||||||
|
(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)))
|
||||||
|
(if grep-use-null-device
|
||||||
|
(setq args (append args (list null-device)))
|
||||||
|
(push "-H" args))
|
||||||
|
(and (grep-probe grep-program `(nil t nil ,@args))
|
||||||
|
(progn
|
||||||
|
(goto-char (point-min))
|
||||||
|
(looking-at
|
||||||
|
(concat (regexp-quote hello-file)
|
||||||
|
"\0[0-9]+:English"))))))))
|
||||||
|
|
||||||
(when (eq grep-highlight-matches 'auto-detect)
|
(when (eq grep-highlight-matches 'auto-detect)
|
||||||
(setq grep-highlight-matches
|
(setq grep-highlight-matches
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
|
@ -591,6 +638,7 @@ This function is called from `compilation-filter-hook'."
|
||||||
grep-template grep-find-template)
|
grep-template grep-find-template)
|
||||||
(let ((grep-options
|
(let ((grep-options
|
||||||
(concat (if grep-use-null-device "-n" "-nH")
|
(concat (if grep-use-null-device "-n" "-nH")
|
||||||
|
(if grep-use-null-filename-separator " --null")
|
||||||
(if (grep-probe grep-program
|
(if (grep-probe grep-program
|
||||||
`(nil nil nil "-e" "foo" ,null-device)
|
`(nil nil nil "-e" "foo" ,null-device)
|
||||||
nil 1)
|
nil 1)
|
||||||
|
@ -733,7 +781,7 @@ This function is called from `compilation-filter-hook'."
|
||||||
(set (make-local-variable 'compilation-error-face)
|
(set (make-local-variable 'compilation-error-face)
|
||||||
grep-hit-face)
|
grep-hit-face)
|
||||||
(set (make-local-variable 'compilation-error-regexp-alist)
|
(set (make-local-variable 'compilation-error-regexp-alist)
|
||||||
grep-regexp-alist)
|
(grep-regexp-alist))
|
||||||
;; compilation-directory-matcher can't be nil, so we set it to a regexp that
|
;; compilation-directory-matcher can't be nil, so we set it to a regexp that
|
||||||
;; can never match.
|
;; can never match.
|
||||||
(set (make-local-variable 'compilation-directory-matcher) '("\\`a\\`"))
|
(set (make-local-variable 'compilation-directory-matcher) '("\\`a\\`"))
|
||||||
|
|
|
@ -917,20 +917,21 @@ IGNORES is a list of glob patterns."
|
||||||
(grep-compute-defaults)
|
(grep-compute-defaults)
|
||||||
(defvar grep-find-template)
|
(defvar grep-find-template)
|
||||||
(defvar grep-highlight-matches)
|
(defvar grep-highlight-matches)
|
||||||
(let* ((grep-find-template (replace-regexp-in-string "<C>" "<C> -E"
|
(pcase-let*
|
||||||
grep-find-template t t))
|
((grep-find-template (replace-regexp-in-string "<C>" "<C> -E"
|
||||||
(grep-highlight-matches nil)
|
grep-find-template t t))
|
||||||
;; TODO: Sanitize the regexp to remove Emacs-specific terms,
|
(grep-highlight-matches nil)
|
||||||
;; so that Grep can search for the "relaxed" version. Can we
|
;; TODO: Sanitize the regexp to remove Emacs-specific terms,
|
||||||
;; do that reliably enough, without creating false negatives?
|
;; so that Grep can search for the "relaxed" version. Can we
|
||||||
(command (xref--rgrep-command (xref--regexp-to-extended regexp)
|
;; do that reliably enough, without creating false negatives?
|
||||||
files
|
(command (xref--rgrep-command (xref--regexp-to-extended regexp)
|
||||||
(expand-file-name dir)
|
files
|
||||||
ignores))
|
(expand-file-name dir)
|
||||||
(buf (get-buffer-create " *xref-grep*"))
|
ignores))
|
||||||
(grep-re (caar grep-regexp-alist))
|
(buf (get-buffer-create " *xref-grep*"))
|
||||||
status
|
(`(,grep-re ,file-group ,line-group . ,_) (car (grep-regexp-alist)))
|
||||||
hits)
|
(status nil)
|
||||||
|
(hits nil))
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(setq status
|
(setq status
|
||||||
|
@ -944,8 +945,8 @@ IGNORES is a list of glob patterns."
|
||||||
(not (looking-at grep-re)))
|
(not (looking-at grep-re)))
|
||||||
(user-error "Search failed with status %d: %s" status (buffer-string)))
|
(user-error "Search failed with status %d: %s" status (buffer-string)))
|
||||||
(while (re-search-forward grep-re nil t)
|
(while (re-search-forward grep-re nil t)
|
||||||
(push (list (string-to-number (match-string 2))
|
(push (list (string-to-number (match-string line-group))
|
||||||
(match-string 1)
|
(match-string file-group)
|
||||||
(buffer-substring-no-properties (point) (line-end-position)))
|
(buffer-substring-no-properties (point) (line-end-position)))
|
||||||
hits)))
|
hits)))
|
||||||
(xref--convert-hits (nreverse hits) regexp)))
|
(xref--convert-hits (nreverse hits) regexp)))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue