`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)
(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))
;;;###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
(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)
(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