From: Spencer Baugh Date: Sun, 26 May 2024 13:26:09 +0000 (-0400) Subject: In rgrep, check matching files before excluding files X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=70d904d10e64d73e99c513ff78e0e462776f5a1e;p=emacs.git In rgrep, check matching files before excluding files There are a lot of excluding globs, and checking them all is expensive. The files glob (i.e. the glob for files we actually want) is usually just one or two entries, so it's quite fast to check. If find checks the files glob first and then the excluding glob, it has to do much less checking (since the files glob will substantially narrow down the set of files on its own), and find performance is much better. In my benchmarking, this takes (rgrep "foo" "*.el" "~/src/emacs/trunk/") from ~410ms to ~130ms. Further optimizations are possible now that the ignores and matched files are in the same argument which can be rearranged more easily without compatibility issues; I'll do those optimizations in later commits. * lisp/progmodes/grep.el (rgrep-find-ignores-in-): Add. * lisp/progmodes/grep.el (rgrep-default-command): Check rgrep-find-ignores-in- and move the excluded files glob to part of the "files" argument. (Bug#71179) (cherry picked from commit b71fa27987d89774c84b0c9362ddfb4a0f679856) --- diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el index cd2f81dc24f..3e67fa37cb6 100644 --- a/lisp/progmodes/grep.el +++ b/lisp/progmodes/grep.el @@ -214,6 +214,21 @@ by `grep-compute-defaults'; to change the default value, use :set #'grep-apply-setting :version "22.1") +(defvar rgrep-find-ignores-in- t + "If nil, when `rgrep' expands `grep-find-template', file ignores go in . + +By default, the placeholder contains find options for affecting the +directory list, and the placeholder contains the find options which +affect which files are matched, both `grep-find-ignored-files' and the +FILES argument to `rgrep'. + +This separation allows the two sources of file matching in to be +optimized together into a set of options which are overall faster for +\"find\" to evaluate. + +If nil, contains ignores both for directories and files, and +contains only the FILES argument. This is the old behavior.") + (defvar grep-quoting-style nil "Whether to use POSIX-like shell argument quoting.") @@ -1365,45 +1380,49 @@ to indicate whether the grep should be case sensitive or not." (defun rgrep-default-command (regexp files dir) "Compute the command for \\[rgrep] to use by default." - (require 'find-dired) ; for `find-name-arg' - (grep-expand-template - grep-find-template - regexp - (concat (shell-quote-argument "(" grep-quoting-style) - " " find-name-arg " " - (mapconcat - (lambda (x) (shell-quote-argument x grep-quoting-style)) - (split-string files) - (concat " -o " find-name-arg " ")) - " " - (shell-quote-argument ")" grep-quoting-style)) - dir - (concat - (when-let ((ignored-dirs (rgrep-find-ignored-directories dir))) - (concat "-type d " - (shell-quote-argument "(" grep-quoting-style) - ;; we should use shell-quote-argument here - " -path " - (mapconcat - (lambda (d) - (shell-quote-argument (concat "*/" d) grep-quoting-style)) - ignored-dirs - " -o -path ") - " " - (shell-quote-argument ")" grep-quoting-style) - " -prune -o ")) - (when-let ((ignored-files (grep-find-ignored-files dir))) - (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) (shell-quote-argument ignore grep-quoting-style)) - ignored-files - " -o -name ") - " " - (shell-quote-argument ")" grep-quoting-style) - " -prune -o "))))) + (require 'find-dired) ; for `find-name-arg' + (let ((ignored-files-arg + (when-let ((ignored-files (grep-find-ignored-files dir))) + (concat (shell-quote-argument "(" grep-quoting-style) + ;; we should use shell-quote-argument here + " -name " + (mapconcat + (lambda (ignore) (shell-quote-argument ignore grep-quoting-style)) + ignored-files + " -o -name ") + " " (shell-quote-argument ")" grep-quoting-style))))) + (grep-expand-template + grep-find-template + regexp + (concat (shell-quote-argument "(" grep-quoting-style) + " " find-name-arg " " + (mapconcat + (lambda (x) (shell-quote-argument x grep-quoting-style)) + (split-string files) + (concat " -o " find-name-arg " ")) + " " + (shell-quote-argument ")" grep-quoting-style) + (when (and rgrep-find-ignores-in- ignored-files-arg) + (concat " " (shell-quote-argument "!" grep-quoting-style) " " ignored-files-arg))) + dir + (concat + (when-let ((ignored-dirs (rgrep-find-ignored-directories dir))) + (concat "-type d " + (shell-quote-argument "(" grep-quoting-style) + ;; we should use shell-quote-argument here + " -path " + (mapconcat + (lambda (d) + (shell-quote-argument (concat "*/" d) grep-quoting-style)) + ignored-dirs + " -o -path ") + " " + (shell-quote-argument ")" grep-quoting-style) + " -prune -o ")) + (when (and (not rgrep-find-ignores-in-) ignored-files-arg) + (concat (shell-quote-argument "!" grep-quoting-style) " -type d " + ignored-files-arg + " -prune -o ")))))) (defun grep-find-toggle-abbreviation () "Toggle showing the hidden part of rgrep/lgrep/zrgrep command line."