unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: "Mattias Engdegård" <mattiase@acm.org>
To: Juri Linkov <juri@linkov.net>
Cc: Lars Ingebrigtsen <larsi@gnus.org>,
	49836@debbugs.gnu.org, Dmitry Gutov <dgutov@yandex.ru>
Subject: bug#49836: Support ripgrep in semantic-symref-tool-grep
Date: Sat, 18 Sep 2021 15:53:51 +0200	[thread overview]
Message-ID: <34778BC0-8D97-4266-8B1F-9D1839E858B5@acm.org> (raw)
In-Reply-To: <87sfzrbke1.fsf_-_@mail.linkov.net>

[-- Attachment #1: Type: text/plain, Size: 1246 bytes --]

Attached is a straw-man patch that is not production-quality but illustrates some of the concepts I'd like to see:

* ripgrep supported for M-?
* ripgrep auto-detected and used by default if available
* treat ripgrep as a search method of its own and not just a different grep program
* corollary: selection of search method should be made symbolically and not by supplying shell command strings

Concerns not addressed by the patch:

* unify back-ends and customisation options in xref.el and symref/grep.el
* tramp
* correct way to auto-detect ripgrep -- I have no idea, really, and would gladly settle for something dead simple, perhaps looking at the output of rg --version, instead of the voodoo code in the patch
* other search methods -- for example, it would be interesting to allow use of Spotlight or similar indexed searching tools in some cases.
* speeding up the parts that are not ripgrep. If the actual command (ripgrep or something else) takes zero seconds, what if anything prevents a crisp snappy response from Emacs?

That said, it appears to work. Right now I'm not near my Linux machine and can just compare against the fairly slow BSD grep that comes with macOS, so obviously the speed-up is tremendous.



[-- Attachment #2: 0001-xref-ripgrep-support.patch --]
[-- Type: application/octet-stream, Size: 7394 bytes --]

From 0d3fa647fd6a0c3a27bc5f9905e24103a3d6b617 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Thu, 16 Sep 2021 17:14:33 +0200
Subject: [PATCH] xref ripgrep support

Auto-detect presence of ripgrep and use it if available.
It speeds up `xref-find-references` (M-q), between a little and very much.
---
 lisp/cedet/semantic/symref/grep.el | 121 +++++++++++++++++++++--------
 1 file changed, 88 insertions(+), 33 deletions(-)

diff --git a/lisp/cedet/semantic/symref/grep.el b/lisp/cedet/semantic/symref/grep.el
index 1e282c3052..106d46dc76 100644
--- a/lisp/cedet/semantic/symref/grep.el
+++ b/lisp/cedet/semantic/symref/grep.el
@@ -79,16 +79,7 @@ semantic-symref-derive-find-filepatterns
                    ;; Only take in simple patterns, so try to convert this one.
                    (string-match "\\\\\\.\\([^\\'>]+\\)\\\\'" (car X)))
           (push (concat "*." (match-string 1 (car X))) pat))))
-    ;; Convert the list into some find-flags.
-    (if (null pat)
-        (error "Customize `semantic-symref-filepattern-alist' for %S"
-               major-mode)
-      (let ((args `("-name" ,(car pat))))
-        (if (null (cdr pat))
-            args
-          `("(" ,@args
-            ,@(mapcan (lambda (s) `("-o" "-name" ,s)) (cdr pat))
-            ")"))))))
+    pat))
 
 (defvar semantic-symref-grep-flags)
 
@@ -133,12 +124,91 @@ semantic-symref-grep-shell
   :group 'semantic
   :type 'string)
 
+(defcustom semantic-symref-grep-tool 'auto-detect
+  "The tool to use for searching in files."
+  :type '(choice (const :tag "Auto-detect" auto-detect)
+                 (const :tag "Ripgrep" ripgrep)
+                 (const :tag "find + grep" find-grep))
+  :group 'semantic)
+
+(defcustom semantic-symref-grep-ripgrep-command "rg"
+  "Name of the ripgrep command to use."
+  :type 'file
+  :group 'semantic)
+
+(defun semantic-symref-grep--auto-detect-tool ()
+  (let ((have-rg
+         (with-temp-buffer
+           (let ((hello-file (grep-hello-file)))
+             (let ((process-file-side-effects nil))
+               (unwind-protect
+                   (eql (ignore-errors
+                          (process-file
+                           semantic-symref-grep-ripgrep-command
+                           nil t nil "^Copyright"
+                           (file-local-name hello-file)))
+                        0)
+                 (when (file-remote-p hello-file)
+                   (delete-file hello-file))))))))
+    (if have-rg
+        'ripgrep
+      'find-grep)))
+
 (defun semantic-symref-grep--quote-extended (string)
   "Quote STRING as an extended-syntax regexp."
   (replace-regexp-in-string (rx (in ".^$*+?|{}[]()|\\"))
                             (lambda (s) (concat "\\" s))
                             string nil t))
 
+(defun semantic-symref-grep--command (rootdir filepatterns file-name-only
+                                      pattern-type pattern)
+  "Compute search command to run.
+ROOTDIR is the root of the tree to search.  FILEPATTERNS is a
+list of glob patterns that match the files to search.
+If FILE-NAME-ONLY is non-nil, the search only wants the names of files.
+PATTERN-TYPE indicates the type of PATTERN:
+ `regexp'     -- PATTERN is an extended (egrep) regexp.
+ `symbol'     -- PATTERN is a literal identifier.
+
+Return the command and arguments as a list of strings."
+  (when (eq semantic-symref-grep-tool 'auto-detect)
+    (setq semantic-symref-grep-tool
+          (semantic-symref-grep--auto-detect-tool)))
+  (cond
+   ((eq semantic-symref-grep-tool 'ripgrep)
+    (let ((filepat-args
+           (mapcan (lambda (s) (list "-g" s)) filepatterns))
+          (flags (cond (file-name-only "-l")
+                       ((eq pattern-type 'symbol) "-nw")
+                       (t "-n")))
+          (pat-arg (if (eq pattern-type 'symbol)
+                       (semantic-symref-grep--quote-extended pattern)
+                     pattern))
+          (dir (expand-file-name rootdir)))
+      `(,semantic-symref-grep-ripgrep-command
+        ,@filepat-args ,flags "-e" ,pat-arg ,dir)))
+   (t
+    (let* ((filepat-args
+            ;; Convert the list into some find-flags.
+            (let ((args `("-name" ,(car filepatterns))))
+              (if (cdr filepatterns)
+                  `("(" ,@args
+                    ,@(mapcan (lambda (s) (list "-o" "-name" s))
+                              (cdr filepatterns))
+                    ")")
+                args)))
+           (filepattern (mapconcat #'shell-quote-argument filepat-args " "))
+           (grepflags (cond (file-name-only "-l ")
+                            ((eq pattern-type 'regexp) "-nE ")
+                            (t "-nwE ")))
+           (pat-arg (if (eq pattern-type 'symbol)
+                        (semantic-symref-grep--quote-extended pattern)
+                      pattern))
+           (cmd (semantic-symref-grep-use-template
+                 (directory-file-name (file-local-name rootdir))
+                 filepattern grepflags pat-arg)))
+      `(,semantic-symref-grep-shell ,shell-command-switch ,cmd)))))
+
 (cl-defmethod semantic-symref-perform-search ((tool semantic-symref-tool-grep))
   "Perform a search with Grep."
   ;; Grep doesn't support some types of searches.
@@ -150,33 +220,18 @@ semantic-symref-perform-search
   (let* (;; Find the file patterns to use.
 	 (rootdir (semantic-symref-calculate-rootdir))
 	 (filepatterns (semantic-symref-derive-find-filepatterns))
-         (filepattern (mapconcat #'shell-quote-argument filepatterns " "))
-	 ;; Grep based flags.
-	 (grepflags (cond ((eq (oref tool resulttype) 'file)
-                           "-l ")
-                          ((eq (oref tool searchtype) 'regexp)
-                           "-nE ")
-                          (t "-nw ")))
-         (searchfor (oref tool searchfor))
-         (greppat (if (eq (oref tool searchtype) 'regexp)
-                      searchfor
-                    (semantic-symref-grep--quote-extended searchfor)))
-	 ;; Misc
-	 (b (get-buffer-create "*Semantic SymRef*"))
-	 (ans nil)
-	 )
+         (greppat (oref tool searchfor))
+         (file-names-only (eq (oref tool resulttype) 'file))
+         (search-type (oref tool searchtype))
+         (command (semantic-symref-grep--command
+                   rootdir filepatterns file-names-only search-type greppat))
+	 (b (get-buffer-create "*Semantic SymRef*")))
 
     (with-current-buffer b
       (erase-buffer)
       (setq default-directory rootdir)
-      (let ((cmd (semantic-symref-grep-use-template
-                  (directory-file-name (file-local-name rootdir))
-                  filepattern grepflags greppat)))
-        (process-file semantic-symref-grep-shell nil b nil
-                      shell-command-switch cmd)))
-    (setq ans (semantic-symref-parse-tool-output tool b))
-    ;; Return the answer
-    ans))
+      (apply #'process-file (car command) nil b nil (cdr command)))
+    (semantic-symref-parse-tool-output tool b)))
 
 (cl-defmethod semantic-symref-parse-tool-output-one-line ((tool semantic-symref-tool-grep))
   "Parse one line of grep output, and return it as a match list.
-- 
2.21.1 (Apple Git-122.3)


  parent reply	other threads:[~2021-09-18 13:53 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-02 21:05 bug#49836: Support ripgrep in semantic-symref-tool-grep Juri Linkov
2021-08-03  8:10 ` Juri Linkov
2021-08-04  3:14   ` Dmitry Gutov
2021-08-04 21:23     ` Juri Linkov
2021-08-05  3:03       ` Dmitry Gutov
2021-08-06  0:35         ` Juri Linkov
2021-08-07 14:12           ` Dmitry Gutov
2021-09-18 13:53 ` Mattias Engdegård [this message]
2021-09-18 14:14   ` Eli Zaretskii
2021-09-18 14:18     ` Mattias Engdegård
2021-09-18 14:25       ` Eli Zaretskii
2021-09-18 21:48       ` Dmitry Gutov
2021-09-18 23:53   ` Dmitry Gutov
2021-09-19  0:21     ` Jim Porter
2021-09-19 10:11       ` Mattias Engdegård
2021-09-20  0:14         ` Dmitry Gutov
2021-09-20  5:09           ` Jim Porter
2021-09-20 17:04             ` Dmitry Gutov
     [not found] <83h7elbzo3.fsf@gnu.org>
     [not found] ` <7b0409e3-fc88-b34e-9365-25356bb85859@yandex.ru>
     [not found]   ` <83bl4tbxyu.fsf@gnu.org>
     [not found]     ` <12215e07-af4e-2db7-1869-16ac92feb806@yandex.ru>
     [not found]       ` <8335q5bt9b.fsf@gnu.org>
     [not found]         ` <ee8b7d7f-abd1-42fc-a273-819ccef3c4e7@yandex.ru>
2021-09-17 16:07           ` Juri Linkov
2021-09-17 16:24             ` Lars Ingebrigtsen
2021-09-18 18:37               ` Juri Linkov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=34778BC0-8D97-4266-8B1F-9D1839E858B5@acm.org \
    --to=mattiase@acm.org \
    --cc=49836@debbugs.gnu.org \
    --cc=dgutov@yandex.ru \
    --cc=juri@linkov.net \
    --cc=larsi@gnus.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).