From ff86b1870ae4dc930901ff879764e1042a88003d Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Sun, 9 Jun 2024 19:20:22 +0200 Subject: [PATCH] xref.el: Cease depending on Semantic --- lisp/cedet/semantic/symref/grep.el | 31 +++-------- lisp/progmodes/grep.el | 87 +++++++++++++++++++++++++++++- lisp/progmodes/xref.el | 39 ++------------ 3 files changed, 98 insertions(+), 59 deletions(-) diff --git a/lisp/cedet/semantic/symref/grep.el b/lisp/cedet/semantic/symref/grep.el index cc4d1546c85..13cb9c7e072 100644 --- a/lisp/cedet/semantic/symref/grep.el +++ b/lisp/cedet/semantic/symref/grep.el @@ -42,35 +42,18 @@ This tool uses EDE to find the root of the project, then executes `find-grep' in the project. The output is parsed for hits and those hits returned.") -(defvar semantic-symref-filepattern-alist - '((c-mode "*.[ch]") - (c++-mode "*.[chCH]" "*.[ch]pp" "*.cc" "*.hh") - (html-mode "*.html" "*.shtml" "*.php") - (mhtml-mode "*.html" "*.shtml" "*.php") ; FIXME: remove - ; duplication of - ; HTML-related patterns. - ; Maybe they belong in the - ; major mode definition? - (ruby-mode "*.r[bu]" "*.rake" "*.gemspec" "*.erb" "*.haml" - "Rakefile" "Thorfile" "Capfile" "Guardfile" "Vagrantfile") - (python-mode "*.py" "*.pyi" "*.pyw") - (perl-mode "*.pl" "*.PL") - (lisp-interaction-mode "*.el" "*.ede" ".emacs" "_emacs") - ) - "List of major modes and file extension pattern. -See find -name man page for format.") +(defvar semantic-symref-filepattern-alist nil "Unused obsolete variable.") +(make-obsolete-variable 'semantic-symref-filepattern-alist + 'grep-filepattern-alist "30.1") (defun semantic-symref-derive-find-filepatterns (&optional mode) - ;; FIXME: This should be moved to grep.el, where it could be used - ;; for "C-u M-x grep" as well. "Derive a list of file (glob) patterns for the current buffer. -Looks first in `semantic-symref-filepattern-alist'. If it is not -there, it then looks in `auto-mode-alist', and attempts to derive something -from that. +Looks first in `grep-filepattern-alist'. If it is not there, it then +looks in `auto-mode-alist', and attempts to derive something from that. Optional argument MODE specifies the `major-mode' to test." ;; First, try the filepattern alist. (let* ((mode (or mode major-mode)) - (pat (cdr (assoc mode semantic-symref-filepattern-alist)))) + (pat (cdr (assoc mode grep-filepattern-alist)))) (when (not pat) ;; No hit, try auto-mode-alist. (dolist (X auto-mode-alist) @@ -80,7 +63,7 @@ Optional argument MODE specifies the `major-mode' to test." (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" + (error "Customize `grep-filepattern-alist' for %S" major-mode) (let ((args `("-name" ,(car pat)))) (if (null (cdr pat)) diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el index dc2d9519746..7c8a3124da4 100644 --- a/lisp/progmodes/grep.el +++ b/lisp/progmodes/grep.el @@ -1489,6 +1489,91 @@ The returned file name is relative." ;;;###autoload (defalias 'rzgrep #'zrgrep) -(provide 'grep) +(defvar grep-filepattern-alist + '((c-mode "*.[ch]") + (c++-mode "*.[chCH]" "*.[ch]pp" "*.cc" "*.hh") + (html-mode "*.html" "*.shtml" "*.php") + (mhtml-mode "*.html" "*.shtml" "*.php") + (ruby-mode "*.r[bu]" "*.rake" "*.gemspec" "*.erb" "*.haml" + "Rakefile" "Thorfile" "Capfile" "Guardfile" "Vagrantfile") + (python-mode "*.py" "*.pyi" "*.pyw") + (perl-mode "*.pl" "*.PL") + (lisp-interaction-mode "*.el" "*.ede" ".emacs" "_emacs")) + "Association list of major modes and file extension patterns.") + +(defun grep-derive-find-filepatterns (&optional mode) + "Derive a list of file (glob) patterns for major MODE. + +If MODE is nil or omitted, it defaults to the current major mode. + +If MODE has an entry in `grep-filepattern-alist', return the +corresponding pattern from there. Otherwise, try to derive a pattern +from `auto-mode-alist' entries." + ;; First, try the filepattern alist. + (let* ((mode (or mode major-mode)) + (pat (cdr (assoc mode grep-filepattern-alist)))) + (unless pat + ;; No hit, try `auto-mode-alist'. + (dolist (x auto-mode-alist) + (when (and (eq (cdr x) mode) + ;; Only take in simple patterns, so try to convert this one. + (string-match "\\\\\\.\\([^\\'>]+\\)\\\\'" (car x))) + (push (concat "*." (match-string 1 (car x))) pat)))) + (when pat + ;; Convert the list into some find-flags. + (let ((args `("-name" ,(car pat)))) + (if (cdr pat) + `("(" ,@args + ,@(mapcan (lambda (s) `("-o" "-name" ,s)) (cdr pat)) + ")") + args))))) + +(defun grep-use-template (rootdir filepattern flags pattern) + "Use the grep template expand feature to create a grep command. +ROOTDIR is the root location to run the `find' from. +FILEPATTERN is a string representing find flags for searching file patterns. +FLAGS are flags passed to Grep, such as -n or -l. +PATTERN is the pattern used by Grep." + (grep-compute-defaults) + (grep-expand-template grep-find-template pattern filepattern rootdir nil flags)) + +(defun grep--quote-grep (string) + "Quote STRING as a grep-syntax regexp." + (replace-regexp-in-string (rx (in ".^$*[\\")) + (lambda (s) (concat "\\" s)) + string nil t)) + +(defun grep--parse-output (buf dir) + "Parse buffer BUF containing Grep results in DIR, return list of matches." + (with-current-buffer buf + (goto-char (point-min)) + (let ((result nil) + (hit nil)) + (while (setq hit + (pcase-let + ((`(,grep-re ,file-group ,line-group . ,_) (car grep-regexp-alist))) + (when (re-search-forward grep-re nil t) + (list (string-to-number (match-string line-group)) + (concat dir (substring (match-string file-group) 1)) + (buffer-substring-no-properties (point) (line-end-position)))))) + (setq result (cons hit result))) + (nreverse result)))) + +;;;###autoload +(defun grep-perform-search (symbol dir) + "Perform a search for SYMBOL in DIR with Grep." + (let* (;; Find the file patterns to use. + (filepatterns (grep-derive-find-filepatterns)) + (filepattern (mapconcat #'shell-quote-argument filepatterns " ")) + (greppat (grep--quote-grep symbol)) + ;; Misc + (buf (get-buffer-create " *Grep Search*"))) + (with-current-buffer buf + (erase-buffer) + (setq default-directory dir) + (process-file shell-file-name nil buf nil shell-command-switch + (grep-use-template "." filepattern '("-nw") greppat))) + (grep--parse-output buf (directory-file-name (file-local-name dir))))) +(provide 'grep) ;;; grep.el ends here diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index d234aa1a026..720266bee69 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -268,11 +268,7 @@ To create an xref object, call `xref-make'.") (cl-defgeneric xref-backend-references (_backend identifier) "Find references of IDENTIFIER. The result must be a list of xref objects. If no references can -be found, return nil. - -The default implementation uses `semantic-symref-tool-alist' to -find a search tool; by default, this uses \"find | grep\" in the -current project's main and external roots." +be found, return nil." (mapcan (lambda (dir) (message "Searching %s..." dir) @@ -1891,41 +1887,16 @@ and just use etags." (kill-local-variable 'xref-backend-functions)) (setq-local xref-backend-functions xref-etags-mode--saved))) -(declare-function semantic-symref-instantiate "semantic/symref") -(declare-function semantic-symref-perform-search "semantic/symref") (declare-function grep-expand-template "grep") -(defvar ede-minor-mode) ;; ede.el ;;;###autoload (defun xref-references-in-directory (symbol dir) "Find all references to SYMBOL in directory DIR. -Return a list of xref values. - -This function uses the Semantic Symbol Reference API, see -`semantic-symref-tool-alist' for details on which tools are used, -and when." +Return a list of xref values." (cl-assert (directory-name-p dir)) - (require 'semantic/symref) - (defvar semantic-symref-tool) - - ;; Some symref backends use `ede-project-root-directory' as the root - ;; directory for the search, rather than `default-directory'. Since - ;; the caller has specified `dir', we bind `ede-minor-mode' to nil - ;; to force the backend to use `default-directory'. - (let* ((ede-minor-mode nil) - (default-directory dir) - ;; FIXME: Remove CScope and Global from the recognized tools? - ;; The current implementations interpret the symbol search as - ;; "find all calls to the given function", but not function - ;; definition. And they return nothing when passed a variable - ;; name, even a global one. - (semantic-symref-tool 'detect) - (case-fold-search nil) - (inst (semantic-symref-instantiate :searchfor symbol - :searchtype 'symbol - :searchscope 'subdirs - :resulttype 'line-and-text))) - (xref--convert-hits (semantic-symref-perform-search inst) + (let* ((default-directory dir) + (case-fold-search nil)) + (xref--convert-hits (grep-perform-search symbol dir) (format "\\_<%s\\_>" (regexp-quote symbol))))) (define-obsolete-function-alias -- 2.39.2