aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNoam Postavsky2016-09-13 20:48:09 -0400
committerNoam Postavsky2017-07-19 20:03:00 -0400
commit644cdd1aa0a10dbfffa3b9b4c7a97f8cddded0b8 (patch)
treee32e53f267c7607806d0a88d239fd4e79ba2f965
parenteda9aa0d314ca8e8919d4c17927aa86290449f8d (diff)
downloademacs-644cdd1aa0a10dbfffa3b9b4c7a97f8cddded0b8.tar.gz
emacs-644cdd1aa0a10dbfffa3b9b4c7a97f8cddded0b8.zip
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.
-rw-r--r--etc/NEWS16
-rw-r--r--lisp/progmodes/grep.el104
-rw-r--r--lisp/progmodes/xref.el33
3 files changed, 105 insertions, 48 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 0c2db0c398b..954fe0d547e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -705,6 +705,18 @@ this is controlled by the 'wdired-create-parent-directories' variable.
705*** 'W' is now bound to 'browse-url-of-dired-file', and is useful for 705*** 'W' is now bound to 'browse-url-of-dired-file', and is useful for
706viewing HTML files and the like. 706viewing HTML files and the like.
707 707
708** Grep
709
710---
711*** Grep commands will now use GNU grep's '--null' option if
712available, which allows distinguishing the filename from contents if
713they contain colons. This can be controlled by the new custom option
714'grep-use-null-filename-separator'.
715
716*** The grep/rgrep/lgrep functions will now ask about saving files
717before running. This is controlled by the 'grep-save-buffers'
718variable.
719
708** Edebug 720** Edebug
709 721
710*** Edebug can be prevented from pausing 1 second after reaching a 722*** Edebug can be prevented from pausing 1 second after reaching a
@@ -1053,10 +1065,6 @@ things like forward-word in readline work.
1053** hideshow mode got four key bindings that are analogous to outline 1065** hideshow mode got four key bindings that are analogous to outline
1054mode bindings: 'C-c @ C-a', 'C-c @ C-t', 'C-c @ C-d', and 'C-c @ C-e.' 1066mode bindings: 'C-c @ C-a', 'C-c @ C-t', 'C-c @ C-d', and 'C-c @ C-e.'
1055 1067
1056** The grep/rgrep/lgrep functions will now ask about saving files
1057before running. This is controlled by the 'grep-save-buffers'
1058variable.
1059
1060--- 1068---
1061** Customizable variable 'query-replace-from-to-separator' 1069** Customizable variable 'query-replace-from-to-separator'
1062now doesn't propertize the string value of the separator. 1070now doesn't propertize the string value of the separator.
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index b3d8a51ceeb..2ddaf884bce 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -47,8 +47,8 @@ to avoid computing them again.")
47(defun grep-apply-setting (symbol value) 47(defun grep-apply-setting (symbol value)
48 "Set SYMBOL to VALUE, and update `grep-host-defaults-alist'. 48 "Set SYMBOL to VALUE, and update `grep-host-defaults-alist'.
49SYMBOL should be one of `grep-command', `grep-template', 49SYMBOL should be one of `grep-command', `grep-template',
50`grep-use-null-device', `grep-find-command', 50`grep-use-null-device', `grep-find-command' `grep-find-template',
51`grep-find-template', `grep-find-use-xargs', or 51`grep-find-use-xargs', `grep-use-null-filename-separator', or
52`grep-highlight-matches'." 52`grep-highlight-matches'."
53 (when grep-host-defaults-alist 53 (when grep-host-defaults-alist
54 (let* ((host-id 54 (let* ((host-id
@@ -160,6 +160,15 @@ Customize or call the function `grep-apply-setting'."
160 :set 'grep-apply-setting 160 :set 'grep-apply-setting
161 :group 'grep) 161 :group 'grep)
162 162
163(defcustom grep-use-null-filename-separator 'auto-detect
164 "If non-nil, use `grep's `--null' option.
165This is done to disambiguate file names in `grep's output."
166 :type '(choice (const :tag "Do Not Use `--null'" nil)
167 (const :tag "Use `--null'" t)
168 (other :tag "Not Set" auto-detect))
169 :set 'grep-apply-setting
170 :group 'grep)
171
163;;;###autoload 172;;;###autoload
164(defcustom grep-find-command nil 173(defcustom grep-find-command nil
165 "The default find command for \\[grep-find]. 174 "The default find command for \\[grep-find].
@@ -357,33 +366,53 @@ A grep buffer becomes most recent when you select Grep mode in it.
357Notice that using \\[next-error] or \\[compile-goto-error] modifies 366Notice that using \\[next-error] or \\[compile-goto-error] modifies
358`compilation-last-buffer' rather than `grep-last-buffer'.") 367`compilation-last-buffer' rather than `grep-last-buffer'.")
359 368
360;;;###autoload 369(defconst grep--regexp-alist-column
361(defconst grep-regexp-alist 370 ;; Calculate column positions (col . end-col) of first grep match on a line
362 '( 371 (cons
363 ;; Use a tight regexp to handle weird file names (with colons 372 (lambda ()
373 (when grep-highlight-matches
374 (let* ((beg (match-end 0))
375 (end (save-excursion (goto-char beg) (line-end-position)))
376 (mbeg (text-property-any beg end 'font-lock-face 'grep-match-face)))
377 (when mbeg
378 (- mbeg beg)))))
379 (lambda ()
380 (when grep-highlight-matches
381 (let* ((beg (match-end 0))
382 (end (save-excursion (goto-char beg) (line-end-position)))
383 (mbeg (text-property-any beg end 'font-lock-face 'grep-match-face))
384 (mend (and mbeg (next-single-property-change mbeg 'font-lock-face nil end))))
385 (when mend
386 (- mend beg)))))))
387(defconst grep--regexp-alist-bin-matcher
388 '("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
389(defconst grep-with-null-regexp-alist
390 `(("^\\([^\0]+\\)\\(\0\\)\\([0-9]+\\):" 1 3 ,grep--regexp-alist-column nil nil
391 (2 '(face unspecified display ":")))
392 ,grep--regexp-alist-bin-matcher)
393 "Regexp used to match grep hits.
394See `compilation-error-regexp-alist'.")
395(defconst grep-fallback-regexp-alist
396 `(;; Use a tight regexp to handle weird file names (with colons
364 ;; in them) as well as possible. E.g., use [1-9][0-9]* rather 397 ;; in them) as well as possible. E.g., use [1-9][0-9]* rather
365 ;; than [0-9]+ so as to accept ":034:" in file names. 398 ;; than [0-9]+ so as to accept ":034:" in file names.
366 ("^\\(.*?[^/\n]\\):[ \t]*\\([1-9][0-9]*\\)[ \t]*:" 399 ("^\\(.*?[^/\n]\\):[ \t]*\\([1-9][0-9]*\\)[ \t]*:"
367 1 2 400 1 2 ,grep--regexp-alist-column)
368 ;; Calculate column positions (col . end-col) of first grep match on a line 401 ,grep--regexp-alist-bin-matcher)
369 ((lambda () 402 "Regexp used to match grep hits when `--null' is not supported.
370 (when grep-highlight-matches 403See `compilation-error-regexp-alist'.")
371 (let* ((beg (match-end 0)) 404
372 (end (save-excursion (goto-char beg) (line-end-position))) 405(defvaralias 'grep-regex-alist 'grep-with-null-regexp-alist)
373 (mbeg (text-property-any beg end 'font-lock-face grep-match-face))) 406(make-obsolete-variable
374 (when mbeg 407 'grep-regex-alist "Call `grep-regexp-alist' instead." "26.1")
375 (- mbeg beg))))) 408
376 . 409;;;###autoload
377 (lambda () 410(defun grep-regexp-alist ()
378 (when grep-highlight-matches 411 "Return a regexp alist to match grep hits.
379 (let* ((beg (match-end 0)) 412The regexp used depends on `grep-use-null-filename-separator'.
380 (end (save-excursion (goto-char beg) (line-end-position))) 413See `compilation-error-regexp-alist' for format details."
381 (mbeg (text-property-any beg end 'font-lock-face grep-match-face)) 414 (if grep-use-null-filename-separator
382 (mend (and mbeg (next-single-property-change mbeg 'font-lock-face nil end)))) 415 grep-with-null-regexp-alist grep-fallback-regexp-alist))
383 (when mend
384 (- mend beg)))))))
385 ("^Binary file \\(.+\\) matches$" 1 nil nil 0 1))
386 "Regexp used to match grep hits. See `compilation-error-regexp-alist'.")
387 416
388(defvar grep-first-column 0 ; bug#10594 417(defvar grep-first-column 0 ; bug#10594
389 "Value to use for `compilation-first-column' in grep buffers.") 418 "Value to use for `compilation-first-column' in grep buffers.")
@@ -538,6 +567,8 @@ This function is called from `compilation-filter-hook'."
538 (grep-use-null-device ,grep-use-null-device) 567 (grep-use-null-device ,grep-use-null-device)
539 (grep-find-command ,grep-find-command) 568 (grep-find-command ,grep-find-command)
540 (grep-find-template ,grep-find-template) 569 (grep-find-template ,grep-find-template)
570 (grep-use-null-filename-separator
571 ,grep-use-null-filename-separator)
541 (grep-find-use-xargs ,grep-find-use-xargs) 572 (grep-find-use-xargs ,grep-find-use-xargs)
542 (grep-highlight-matches ,grep-highlight-matches))))) 573 (grep-highlight-matches ,grep-highlight-matches)))))
543 (let* ((host-id 574 (let* ((host-id
@@ -550,7 +581,8 @@ This function is called from `compilation-filter-hook'."
550 ;; computed for every host once. 581 ;; computed for every host once.
551 (dolist (setting '(grep-command grep-template 582 (dolist (setting '(grep-command grep-template
552 grep-use-null-device grep-find-command 583 grep-use-null-device grep-find-command
553 grep-find-template grep-find-use-xargs 584 grep-use-null-filename-separator
585 grep-find-template grep-find-use-xargs
554 grep-highlight-matches)) 586 grep-highlight-matches))
555 (set setting 587 (set setting
556 (cadr (or (assq setting host-defaults) 588 (cadr (or (assq setting host-defaults)
@@ -576,6 +608,21 @@ This function is called from `compilation-filter-hook'."
576 (concat (regexp-quote hello-file) 608 (concat (regexp-quote hello-file)
577 ":[0-9]+:English"))))))))) 609 ":[0-9]+:English")))))))))
578 610
611 (when (eq grep-use-null-filename-separator 'auto-detect)
612 (setq grep-use-null-filename-separator
613 (with-temp-buffer
614 (let* ((hello-file (expand-file-name "HELLO" data-directory))
615 (args `("--null" "-ne" "^English" ,hello-file)))
616 (if grep-use-null-device
617 (setq args (append args (list null-device)))
618 (push "-H" args))
619 (and (grep-probe grep-program `(nil t nil ,@args))
620 (progn
621 (goto-char (point-min))
622 (looking-at
623 (concat (regexp-quote hello-file)
624 "\0[0-9]+:English"))))))))
625
579 (when (eq grep-highlight-matches 'auto-detect) 626 (when (eq grep-highlight-matches 'auto-detect)
580 (setq grep-highlight-matches 627 (setq grep-highlight-matches
581 (with-temp-buffer 628 (with-temp-buffer
@@ -591,6 +638,7 @@ This function is called from `compilation-filter-hook'."
591 grep-template grep-find-template) 638 grep-template grep-find-template)
592 (let ((grep-options 639 (let ((grep-options
593 (concat (if grep-use-null-device "-n" "-nH") 640 (concat (if grep-use-null-device "-n" "-nH")
641 (if grep-use-null-filename-separator " --null")
594 (if (grep-probe grep-program 642 (if (grep-probe grep-program
595 `(nil nil nil "-e" "foo" ,null-device) 643 `(nil nil nil "-e" "foo" ,null-device)
596 nil 1) 644 nil 1)
@@ -733,7 +781,7 @@ This function is called from `compilation-filter-hook'."
733 (set (make-local-variable 'compilation-error-face) 781 (set (make-local-variable 'compilation-error-face)
734 grep-hit-face) 782 grep-hit-face)
735 (set (make-local-variable 'compilation-error-regexp-alist) 783 (set (make-local-variable 'compilation-error-regexp-alist)
736 grep-regexp-alist) 784 (grep-regexp-alist))
737 ;; compilation-directory-matcher can't be nil, so we set it to a regexp that 785 ;; compilation-directory-matcher can't be nil, so we set it to a regexp that
738 ;; can never match. 786 ;; can never match.
739 (set (make-local-variable 'compilation-directory-matcher) '("\\`a\\`")) 787 (set (make-local-variable 'compilation-directory-matcher) '("\\`a\\`"))
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index b8ec50f14ae..cc9b794c5a0 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -917,20 +917,21 @@ IGNORES is a list of glob patterns."
917 (grep-compute-defaults) 917 (grep-compute-defaults)
918 (defvar grep-find-template) 918 (defvar grep-find-template)
919 (defvar grep-highlight-matches) 919 (defvar grep-highlight-matches)
920 (let* ((grep-find-template (replace-regexp-in-string "<C>" "<C> -E" 920 (pcase-let*
921 grep-find-template t t)) 921 ((grep-find-template (replace-regexp-in-string "<C>" "<C> -E"
922 (grep-highlight-matches nil) 922 grep-find-template t t))
923 ;; TODO: Sanitize the regexp to remove Emacs-specific terms, 923 (grep-highlight-matches nil)
924 ;; so that Grep can search for the "relaxed" version. Can we 924 ;; TODO: Sanitize the regexp to remove Emacs-specific terms,
925 ;; do that reliably enough, without creating false negatives? 925 ;; so that Grep can search for the "relaxed" version. Can we
926 (command (xref--rgrep-command (xref--regexp-to-extended regexp) 926 ;; do that reliably enough, without creating false negatives?
927 files 927 (command (xref--rgrep-command (xref--regexp-to-extended regexp)
928 (expand-file-name dir) 928 files
929 ignores)) 929 (expand-file-name dir)
930 (buf (get-buffer-create " *xref-grep*")) 930 ignores))
931 (grep-re (caar grep-regexp-alist)) 931 (buf (get-buffer-create " *xref-grep*"))
932 status 932 (`(,grep-re ,file-group ,line-group . ,_) (car (grep-regexp-alist)))
933 hits) 933 (status nil)
934 (hits nil))
934 (with-current-buffer buf 935 (with-current-buffer buf
935 (erase-buffer) 936 (erase-buffer)
936 (setq status 937 (setq status
@@ -944,8 +945,8 @@ IGNORES is a list of glob patterns."
944 (not (looking-at grep-re))) 945 (not (looking-at grep-re)))
945 (user-error "Search failed with status %d: %s" status (buffer-string))) 946 (user-error "Search failed with status %d: %s" status (buffer-string)))
946 (while (re-search-forward grep-re nil t) 947 (while (re-search-forward grep-re nil t)
947 (push (list (string-to-number (match-string 2)) 948 (push (list (string-to-number (match-string line-group))
948 (match-string 1) 949 (match-string file-group)
949 (buffer-substring-no-properties (point) (line-end-position))) 950 (buffer-substring-no-properties (point) (line-end-position)))
950 hits))) 951 hits)))
951 (xref--convert-hits (nreverse hits) regexp))) 952 (xref--convert-hits (nreverse hits) regexp)))