diff options
| author | Noam Postavsky | 2016-09-13 20:48:09 -0400 |
|---|---|---|
| committer | Noam Postavsky | 2017-07-19 20:03:00 -0400 |
| commit | 644cdd1aa0a10dbfffa3b9b4c7a97f8cddded0b8 (patch) | |
| tree | e32e53f267c7607806d0a88d239fd4e79ba2f965 | |
| parent | eda9aa0d314ca8e8919d4c17927aa86290449f8d (diff) | |
| download | emacs-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/NEWS | 16 | ||||
| -rw-r--r-- | lisp/progmodes/grep.el | 104 | ||||
| -rw-r--r-- | lisp/progmodes/xref.el | 33 |
3 files changed, 105 insertions, 48 deletions
| @@ -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 |
| 706 | viewing HTML files and the like. | 706 | viewing HTML files and the like. |
| 707 | 707 | ||
| 708 | ** Grep | ||
| 709 | |||
| 710 | --- | ||
| 711 | *** Grep commands will now use GNU grep's '--null' option if | ||
| 712 | available, which allows distinguishing the filename from contents if | ||
| 713 | they 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 | ||
| 717 | before running. This is controlled by the 'grep-save-buffers' | ||
| 718 | variable. | ||
| 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 |
| 1054 | mode bindings: 'C-c @ C-a', 'C-c @ C-t', 'C-c @ C-d', and 'C-c @ C-e.' | 1066 | mode 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 | ||
| 1057 | before running. This is controlled by the 'grep-save-buffers' | ||
| 1058 | variable. | ||
| 1059 | |||
| 1060 | --- | 1068 | --- |
| 1061 | ** Customizable variable 'query-replace-from-to-separator' | 1069 | ** Customizable variable 'query-replace-from-to-separator' |
| 1062 | now doesn't propertize the string value of the separator. | 1070 | now 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'. |
| 49 | SYMBOL should be one of `grep-command', `grep-template', | 49 | SYMBOL 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. | ||
| 165 | This 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. | |||
| 357 | Notice that using \\[next-error] or \\[compile-goto-error] modifies | 366 | Notice 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. | ||
| 394 | See `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 | 403 | See `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)) | 412 | The regexp used depends on `grep-use-null-filename-separator'. |
| 380 | (end (save-excursion (goto-char beg) (line-end-position))) | 413 | See `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))) |