123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
- (require 'semantic)
- (defvar ede-minor-mode)
- (declare-function data-debug-new-buffer "data-debug")
- (declare-function data-debug-insert-object-slots "eieio-datadebug")
- (declare-function ede-toplevel "ede/base")
- (declare-function ede-project-root-directory "ede/files")
- (declare-function ede-up-directory "ede/files")
- (defvar semantic-symref-tool 'detect
- "*The active symbol reference tool name.
- The tool symbol can be 'detect, or a symbol that is the name of
- a tool that can be used for symbol referencing.")
- (make-variable-buffer-local 'semantic-symref-tool)
- (defvar semantic-symref-tool-alist
- '( ( (lambda (rootdir) (file-exists-p (expand-file-name "GPATH" rootdir))) .
- global)
- ( (lambda (rootdir) (file-exists-p (expand-file-name "ID" rootdir))) .
- idutils)
- ( (lambda (rootdir) (file-exists-p (expand-file-name "cscope.out" rootdir))) .
- cscope )
- )
- "Alist of tools usable by `semantic-symref'.
- Each entry is of the form:
- ( PREDICATE . KEY )
- Where PREDICATE is a function that takes a directory name for the
- root of a project, and returns non-nil if the tool represented by KEY
- is supported.
- If no tools are supported, then 'grep is assumed.")
- (defun semantic-symref-calculate-rootdir ()
- "Calculate the root directory for a symref search.
- Start with and EDE project, or use the default directory."
- (let* ((rootproj (when (and (featurep 'ede) ede-minor-mode)
- (ede-toplevel)))
- (rootdirbase (if rootproj
- (ede-project-root-directory rootproj)
- default-directory)))
- (if (and rootproj (condition-case nil
-
- (oref rootproj :metasubproject)
- (error nil)))
- (ede-up-directory rootdirbase)
- rootdirbase)))
- (defun semantic-symref-detect-symref-tool ()
- "Detect the symref tool to use for the current buffer."
- (if (not (eq semantic-symref-tool 'detect))
- semantic-symref-tool
-
- (let* ((rootdir (semantic-symref-calculate-rootdir))
- (tools semantic-symref-tool-alist))
- (while (and tools (eq semantic-symref-tool 'detect))
- (when (funcall (car (car tools)) rootdir)
- (setq semantic-symref-tool (cdr (car tools))))
- (setq tools (cdr tools)))
- (when (eq semantic-symref-tool 'detect)
- (setq semantic-symref-tool 'grep))
- semantic-symref-tool)))
- (defun semantic-symref-instantiate (&rest args)
- "Instantiate a new symref search object.
- ARGS are the initialization arguments to pass to the created class."
- (let* ((srt (symbol-name (semantic-symref-detect-symref-tool)))
- (class (intern-soft (concat "semantic-symref-tool-" srt)))
- (inst nil)
- )
- (when (not (class-p class))
- (error "Unknown symref tool %s" semantic-symref-tool))
- (setq inst (apply 'make-instance class args))
- inst))
- (defvar semantic-symref-last-result nil
- "The last calculated symref result.")
- (defun semantic-symref-data-debug-last-result ()
- "Run the last symref data result in Data Debug."
- (interactive)
- (require 'eieio-datadebug)
- (if semantic-symref-last-result
- (progn
- (data-debug-new-buffer "*Symbol Reference ADEBUG*")
- (data-debug-insert-object-slots semantic-symref-last-result "]"))
- (message "Empty results.")))
- (defun semantic-symref-find-references-by-name (name &optional scope tool-return)
- "Find a list of references to NAME in the current project.
- Optional SCOPE specifies which file set to search. Defaults to 'project.
- Refers to `semantic-symref-tool', to determine the reference tool to use
- for the current buffer.
- Returns an object of class `semantic-symref-result'.
- TOOL-RETURN is an optional symbol, which will be assigned the tool used
- to perform the search. This was added for use by a test harness."
- (interactive "sName: ")
- (let* ((inst (semantic-symref-instantiate
- :searchfor name
- :searchtype 'symbol
- :searchscope (or scope 'project)
- :resulttype 'line))
- (result (semantic-symref-get-result inst)))
- (when tool-return
- (set tool-return inst))
- (prog1
- (setq semantic-symref-last-result result)
- (when (called-interactively-p 'interactive)
- (semantic-symref-data-debug-last-result))))
- )
- (defun semantic-symref-find-tags-by-name (name &optional scope)
- "Find a list of references to NAME in the current project.
- Optional SCOPE specifies which file set to search. Defaults to 'project.
- Refers to `semantic-symref-tool', to determine the reference tool to use
- for the current buffer.
- Returns an object of class `semantic-symref-result'."
- (interactive "sName: ")
- (let* ((inst (semantic-symref-instantiate
- :searchfor name
- :searchtype 'tagname
- :searchscope (or scope 'project)
- :resulttype 'line))
- (result (semantic-symref-get-result inst)))
- (prog1
- (setq semantic-symref-last-result result)
- (when (called-interactively-p 'interactive)
- (semantic-symref-data-debug-last-result))))
- )
- (defun semantic-symref-find-tags-by-regexp (name &optional scope)
- "Find a list of references to NAME in the current project.
- Optional SCOPE specifies which file set to search. Defaults to 'project.
- Refers to `semantic-symref-tool', to determine the reference tool to use
- for the current buffer.
- Returns an object of class `semantic-symref-result'."
- (interactive "sName: ")
- (let* ((inst (semantic-symref-instantiate
- :searchfor name
- :searchtype 'tagregexp
- :searchscope (or scope 'project)
- :resulttype 'line))
- (result (semantic-symref-get-result inst)))
- (prog1
- (setq semantic-symref-last-result result)
- (when (called-interactively-p 'interactive)
- (semantic-symref-data-debug-last-result))))
- )
- (defun semantic-symref-find-tags-by-completion (name &optional scope)
- "Find a list of references to NAME in the current project.
- Optional SCOPE specifies which file set to search. Defaults to 'project.
- Refers to `semantic-symref-tool', to determine the reference tool to use
- for the current buffer.
- Returns an object of class `semantic-symref-result'."
- (interactive "sName: ")
- (let* ((inst (semantic-symref-instantiate
- :searchfor name
- :searchtype 'tagcompletions
- :searchscope (or scope 'project)
- :resulttype 'line))
- (result (semantic-symref-get-result inst)))
- (prog1
- (setq semantic-symref-last-result result)
- (when (called-interactively-p 'interactive)
- (semantic-symref-data-debug-last-result))))
- )
- (defun semantic-symref-find-file-references-by-name (name &optional scope)
- "Find a list of references to NAME in the current project.
- Optional SCOPE specifies which file set to search. Defaults to 'project.
- Refers to `semantic-symref-tool', to determine the reference tool to use
- for the current buffer.
- Returns an object of class `semantic-symref-result'."
- (interactive "sName: ")
- (let* ((inst (semantic-symref-instantiate
- :searchfor name
- :searchtype 'regexp
- :searchscope (or scope 'project)
- :resulttype 'file))
- (result (semantic-symref-get-result inst)))
- (prog1
- (setq semantic-symref-last-result result)
- (when (called-interactively-p 'interactive)
- (semantic-symref-data-debug-last-result))))
- )
- (defun semantic-symref-find-text (text &optional scope)
- "Find a list of occurrences of TEXT in the current project.
- TEXT is a regexp formatted for use with egrep.
- Optional SCOPE specifies which file set to search. Defaults to 'project.
- Refers to `semantic-symref-tool', to determine the reference tool to use
- for the current buffer.
- Returns an object of class `semantic-symref-result'."
- (interactive "sEgrep style Regexp: ")
- (let* ((inst (semantic-symref-instantiate
- :searchfor text
- :searchtype 'regexp
- :searchscope (or scope 'project)
- :resulttype 'line))
- (result (semantic-symref-get-result inst)))
- (prog1
- (setq semantic-symref-last-result result)
- (when (called-interactively-p 'interactive)
- (semantic-symref-data-debug-last-result))))
- )
- (defclass semantic-symref-result ()
- ((created-by :initarg :created-by
- :type semantic-symref-tool-baseclass
- :documentation
- "Back-pointer to the symref tool creating these results.")
- (hit-files :initarg :hit-files
- :type list
- :documentation
- "The list of files hit.")
- (hit-text :initarg :hit-text
- :type list
- :documentation
- "If the result doesn't provide full lines, then fill in hit-text.
- GNU Global does completion search this way.")
- (hit-lines :initarg :hit-lines
- :type list
- :documentation
- "The list of line hits.
- Each element is a cons cell of the form (LINE . FILENAME).")
- (hit-tags :initarg :hit-tags
- :type list
- :documentation
- "The list of tags with hits in them.
- Use the `semantic-symref-hit-tags' method to get this list.")
- )
- "The results from a symbol reference search.")
- (defmethod semantic-symref-result-get-files ((result semantic-symref-result))
- "Get the list of files from the symref result RESULT."
- (if (slot-boundp result :hit-files)
- (oref result hit-files)
- (let* ((lines (oref result :hit-lines))
- (files (mapcar (lambda (a) (cdr a)) lines))
- (ans nil))
- (setq ans (list (car files))
- files (cdr files))
- (dolist (F files)
-
-
-
- (when (not (string= F (car ans)))
- (setq ans (cons F ans))))
- (oset result hit-files (nreverse ans))
- )
- ))
- (defmethod semantic-symref-result-get-tags ((result semantic-symref-result)
- &optional open-buffers)
- "Get the list of tags from the symref result RESULT.
- Optional OPEN-BUFFERS indicates that the buffers that the hits are
- in should remain open after scanning.
- Note: This can be quite slow if most of the hits are not in buffers
- already."
- (if (and (slot-boundp result :hit-tags) (oref result hit-tags))
- (oref result hit-tags)
-
- (let ((lines (oref result :hit-lines))
- (txt (oref (oref result :created-by) :searchfor))
- (searchtype (oref (oref result :created-by) :searchtype))
- (ans nil)
- (out nil)
- (buffs-to-kill nil))
- (save-excursion
- (setq
- ans
- (mapcar
- (lambda (hit)
- (let* ((line (car hit))
- (file (cdr hit))
- (buff (get-file-buffer file))
- (tag nil)
- )
- (cond
-
- (buff
- (set-buffer buff))
-
-
- (t
- (let ((kbuff
- (if open-buffers
-
-
- (let ((ede-auto-add-method 'never))
- (find-file-noselect file t))
-
-
-
- (semantic-find-file-noselect file t))))
- (set-buffer kbuff)
- (setq buffs-to-kill (cons kbuff buffs-to-kill))
- (semantic-fetch-tags)
- ))
- )
-
-
- (goto-char (point-min))
- (forward-line (1- line))
-
- (re-search-forward (regexp-quote txt)
- (point-at-eol)
- t)
- (setq tag (semantic-current-tag))
-
-
-
-
-
- (when (and (eq searchtype 'symbol)
- (string= (semantic-tag-name tag) txt))
- (setq tag (or (semantic-current-tag-parent) tag)))
-
- (when tag
- (setq tag (semantic-tag-copy tag nil t))
-
- (semantic--tag-put-property tag :hit (list line)))
- tag))
- lines)))
-
- (when (not open-buffers)
- (mapc 'kill-buffer buffs-to-kill))
-
- (dolist (T ans)
- (if (and T (not (semantic-equivalent-tag-p (car out) T)))
- (setq out (cons T out))
- (when T
-
- (let ((lines (append (semantic--tag-get-property (car out) :hit)
- (semantic--tag-get-property T :hit))))
- (semantic--tag-put-property (car out) :hit lines)))
- ))
-
- (oset result :hit-tags (nreverse out)))))
- (defclass semantic-symref-tool-baseclass ()
- ((searchfor :initarg :searchfor
- :type string
- :documentation "The thing to search for.")
- (searchtype :initarg :searchtype
- :type symbol
- :documentation "The type of search to do.
- Values could be `symbol, `regexp, 'tagname, or 'completion.")
- (searchscope :initarg :searchscope
- :type symbol
- :documentation
- "The scope to search for.
- Can be 'project, 'target, or 'file.")
- (resulttype :initarg :resulttype
- :type symbol
- :documentation
- "The kind of search results desired.
- Can be 'line, 'file, or 'tag.
- The type of result can be converted from 'line to 'file, or 'line to 'tag,
- but not from 'file to 'line or 'tag.")
- )
- "Baseclass for all symbol references tools.
- A symbol reference tool supplies functionality to identify the locations of
- where different symbols are used.
- Subclasses should be named `semantic-symref-tool-NAME', where
- NAME is the name of the tool used in the configuration variable
- `semantic-symref-tool'"
- :abstract t)
- (defmethod semantic-symref-get-result ((tool semantic-symref-tool-baseclass))
- "Calculate the results of a search based on TOOL.
- The symref TOOL should already contain the search criteria."
- (let ((answer (semantic-symref-perform-search tool))
- )
- (when answer
- (let ((answersym (if (eq (oref tool :resulttype) 'file)
- :hit-files
- (if (stringp (car answer))
- :hit-text
- :hit-lines))))
- (semantic-symref-result (oref tool searchfor)
- answersym
- answer
- :created-by tool))
- )
- ))
- (defmethod semantic-symref-perform-search ((tool semantic-symref-tool-baseclass))
- "Base search for symref tools should throw an error."
- (error "Symref tool objects must implement `semantic-symref-perform-search'"))
- (defmethod semantic-symref-parse-tool-output ((tool semantic-symref-tool-baseclass)
- outputbuffer)
- "Parse the entire OUTPUTBUFFER of a symref tool.
- Calls the method `semantic-symref-parse-tool-output-one-line' over and
- over until it returns nil."
- (with-current-buffer outputbuffer
- (goto-char (point-min))
- (let ((result nil)
- (hit nil))
- (while (setq hit (semantic-symref-parse-tool-output-one-line tool))
- (setq result (cons hit result)))
- (nreverse result)))
- )
- (defmethod semantic-symref-parse-tool-output-one-line ((tool semantic-symref-tool-baseclass))
- "Base tool output parser is not implemented."
- (error "Symref tool objects must implement `semantic-symref-parse-tool-output-one-line'"))
- (provide 'semantic/symref)
|