Subject: bug#55016: 28.1; xref-find-references finds no matches if project dir contains a space

From: Dmitry Gutov <[email-masked]>
Date: Sun, 24 Apr 2022 05:00:09 +0300

Hi Eli,

Sorry for the slow reply.

On 19.04.2022 21:24, Eli Zaretskii wrote:
> Dmitry, there's something here I don't understand.  In
> semantic-symref-perform-search method that uses find/grep, we do this:
> 
>      (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)))
> 
> Since we bind default-directory to ROOTDIR, why do we also need to
> pass ROOTDIR to semantic-symref-grep-use-template?  Why not use ".",
> or even nil (which gets expanded to "." AFAIU)?  Then this entire
> issue with embedded blanks in ROOTDIR would not have happened, because
> the problematic directory name would not be exposed to the shell.
> 
> What am I missing here?

This approach dates back to before CEDET was added.

But I imagine the logic was similar to what I used in: 
xref-matches-in-directory that it's easier to handle absolute file names 
which Grep outputs this way, rather that concatenate them later.

Nowadays, though, that function has come full circle with in 
71f8b55f46a, for various reasons, including macOS having a very old 
version of 'find'. Note that we fixed this particular bug in ab3ba912fc7.

symref/grep.el doesn't use ignore instructions, though, so it can easily 
use either approach.

Due to how semantic-symref-* defmethods are currently structured, 
though, the current xref-matches-in-directory's approach seems like more 
of a pain: semantic-symref-parse-tool-output-one-line cannot use lexical 
context from semantic-symref-perform-search (where we would bind a 
local-dir variable once to subsequently use when parsing every line). A 
dynamic var seems to work, though.

With we could avoid having to use 'substring'. That should lead to a 
little less consing. No idea how, though.

(Should this also use 'file-name-unquote'?)

diff --git a/lisp/cedet/semantic/symref/grep.el 
b/lisp/cedet/semantic/symref/grep.el
index 27ea80fc32..025faf1042 100644
--- a/lisp/cedet/semantic/symref/grep.el
+++ b/lisp/cedet/semantic/symref/grep.el
@@ -139,6 +139,8 @@ semantic-symref-grep--quote-grep
                              (lambda (s) (concat "\\" s))
                              string nil t))

+(defvar semantic-symref-grep-local-dir nil)
+
  (cl-defmethod semantic-symref-perform-search ((tool 
semantic-symref-tool-grep))
    "Perform a search with Grep."
    ;; Grep doesn't support some types of searches.
@@ -170,11 +172,12 @@ semantic-symref-perform-search
        (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))
+    (let ((semantic-symref-grep-local-dir (directory-file-name 
(file-local-name rootdir))))
+      (setq ans (semantic-symref-parse-tool-output tool b)))
      ;; Return the answer
      ans))

@@ -190,12 +193,12 @@ semantic-symref-parse-tool-output-one-line
            ((eq (oref tool resulttype) 'line-and-text)
             (when (re-search-forward grep-re nil t)
               (list (string-to-number (match-string line-group))
-                   (match-string file-group)
+                   (concat semantic-symref-grep-local-dir (substring 
(match-string file-group) 1))
                     (buffer-substring-no-properties (point) 
(line-end-position)))))
  	  (t
  	   (when (re-search-forward grep-re nil t)
  	     (cons (string-to-number (match-string line-group))
-		   (match-string file-group))
+		   (concat semantic-symref-grep-local-dir (substring (match-string 
file-group) 1)))
  	     )))))

  (provide 'semantic/symref/grep)