| 1 | ;;; semantic/tag-file.el --- Routines that find files based on tags. |
| 2 | |
| 3 | ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, |
| 4 | ;; 2009, 2010 Free Software Foundation, Inc. |
| 5 | |
| 6 | ;; Author: Eric M. Ludlam <zappo@gnu.org> |
| 7 | ;; Keywords: syntax |
| 8 | |
| 9 | ;; This file is part of GNU Emacs. |
| 10 | |
| 11 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
| 12 | ;; it under the terms of the GNU General Public License as published by |
| 13 | ;; the Free Software Foundation, either version 3 of the License, or |
| 14 | ;; (at your option) any later version. |
| 15 | |
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 19 | ;; GNU General Public License for more details. |
| 20 | |
| 21 | ;; You should have received a copy of the GNU General Public License |
| 22 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
| 23 | |
| 24 | ;;; Commentary: |
| 25 | ;; |
| 26 | ;; A tag, by itself, can have representations in several files. |
| 27 | ;; These routines will find those files. |
| 28 | |
| 29 | (require 'semantic/tag) |
| 30 | |
| 31 | (defvar ede-minor-mode) |
| 32 | (declare-function semanticdb-table-child-p "semantic/db" t t) |
| 33 | (declare-function semanticdb-get-buffer "semantic/db") |
| 34 | (declare-function semantic-dependency-find-file-on-path "semantic/dep") |
| 35 | (declare-function ede-toplevel "ede/files") |
| 36 | |
| 37 | ;;; Code: |
| 38 | |
| 39 | ;;; Location a TAG came from. |
| 40 | ;; |
| 41 | ;;;###autoload |
| 42 | (define-overloadable-function semantic-go-to-tag (tag &optional parent) |
| 43 | "Go to the location of TAG. |
| 44 | TAG may be a stripped element, in which case PARENT specifies a |
| 45 | parent tag that has position information. |
| 46 | PARENT can also be a `semanticdb-table' object." |
| 47 | (:override |
| 48 | (save-match-data |
| 49 | (cond ((semantic-tag-in-buffer-p tag) |
| 50 | ;; We have a linked tag, go to that buffer. |
| 51 | (set-buffer (semantic-tag-buffer tag))) |
| 52 | ((semantic-tag-file-name tag) |
| 53 | ;; If it didn't have a buffer, but does have a file |
| 54 | ;; name, then we need to get to that file so the tag |
| 55 | ;; location is made accurate. |
| 56 | (set-buffer (find-file-noselect (semantic-tag-file-name tag)))) |
| 57 | ((and parent (semantic-tag-p parent) (semantic-tag-in-buffer-p parent)) |
| 58 | ;; The tag had nothing useful, but we have a parent with |
| 59 | ;; a buffer, then go there. |
| 60 | (set-buffer (semantic-tag-buffer parent))) |
| 61 | ((and parent (semantic-tag-p parent) (semantic-tag-file-name parent)) |
| 62 | ;; Tag had nothing, and the parent only has a file-name, then |
| 63 | ;; find that file, and switch to that buffer. |
| 64 | (set-buffer (find-file-noselect (semantic-tag-file-name parent)))) |
| 65 | ((and parent (featurep 'semantic/db) |
| 66 | (semanticdb-table-child-p parent)) |
| 67 | (set-buffer (semanticdb-get-buffer parent))) |
| 68 | (t |
| 69 | ;; Well, just assume things are in the current buffer. |
| 70 | nil |
| 71 | ))) |
| 72 | ;; We should be in the correct buffer now, try and figure out |
| 73 | ;; where the tag is. |
| 74 | (cond ((semantic-tag-with-position-p tag) |
| 75 | ;; If it's a number, go there |
| 76 | (goto-char (semantic-tag-start tag))) |
| 77 | ((semantic-tag-with-position-p parent) |
| 78 | ;; Otherwise, it's a trimmed vector, such as a parameter, |
| 79 | ;; or a structure part. If there is a parent, we can use it |
| 80 | ;; as a bounds for searching. |
| 81 | (goto-char (semantic-tag-start parent)) |
| 82 | ;; Here we make an assumption that the text returned by |
| 83 | ;; the parser and concocted by us actually exists |
| 84 | ;; in the buffer. |
| 85 | (re-search-forward (semantic-tag-name tag) |
| 86 | (semantic-tag-end parent) |
| 87 | t)) |
| 88 | ((semantic-tag-get-attribute tag :line) |
| 89 | ;; The tag has a line number in it. Go there. |
| 90 | (goto-char (point-min)) |
| 91 | (forward-line (1- (semantic-tag-get-attribute tag :line)))) |
| 92 | ((and (semantic-tag-p parent) (semantic-tag-get-attribute parent :line)) |
| 93 | ;; The tag has a line number in it. Go there. |
| 94 | (goto-char (point-min)) |
| 95 | (forward-line (1- (semantic-tag-get-attribute parent :line))) |
| 96 | (re-search-forward (semantic-tag-name tag) nil t)) |
| 97 | (t |
| 98 | ;; Take a guess that the tag has a unique name, and just |
| 99 | ;; search for it from the beginning of the buffer. |
| 100 | (goto-char (point-min)) |
| 101 | (re-search-forward (semantic-tag-name tag) nil t))) |
| 102 | ) |
| 103 | ) |
| 104 | |
| 105 | (make-obsolete-overload 'semantic-find-nonterminal |
| 106 | 'semantic-go-to-tag "23.2") |
| 107 | |
| 108 | ;;; Dependencies |
| 109 | ;; |
| 110 | ;; A tag which is of type 'include specifies a dependency. |
| 111 | ;; Dependencies usually represent a file of some sort. |
| 112 | ;; Find the file described by a dependency. |
| 113 | |
| 114 | ;;;###autoload |
| 115 | (define-overloadable-function semantic-dependency-tag-file (&optional tag) |
| 116 | "Find the filename represented from TAG. |
| 117 | Depends on `semantic-dependency-include-path' for searching. Always searches |
| 118 | `.' first, then searches additional paths." |
| 119 | (or tag (setq tag (car (semantic-find-tag-by-overlay nil)))) |
| 120 | (unless (semantic-tag-of-class-p tag 'include) |
| 121 | (signal 'wrong-type-argument (list tag 'include))) |
| 122 | (save-excursion |
| 123 | (let ((result nil) |
| 124 | (default-directory default-directory) |
| 125 | (edefind nil) |
| 126 | (tag-fname nil)) |
| 127 | (cond ((semantic-tag-in-buffer-p tag) |
| 128 | ;; If the tag has an overlay and buffer associated with it, |
| 129 | ;; switch to that buffer so that we get the right override metohds. |
| 130 | (set-buffer (semantic-tag-buffer tag))) |
| 131 | ((semantic-tag-file-name tag) |
| 132 | ;; If it didn't have a buffer, but does have a file |
| 133 | ;; name, then we need to get to that file so the tag |
| 134 | ;; location is made accurate. |
| 135 | ;;(set-buffer (find-file-noselect (semantic-tag-file-name tag))) |
| 136 | ;; |
| 137 | ;; 2/3/08 |
| 138 | ;; The above causes unnecessary buffer loads all over the place. Ick! |
| 139 | ;; All we really need is for 'default-directory' to be set correctly. |
| 140 | (setq default-directory (file-name-directory (semantic-tag-file-name tag))) |
| 141 | )) |
| 142 | ;; Setup the filename represented by this include |
| 143 | (setq tag-fname (semantic-tag-include-filename tag)) |
| 144 | |
| 145 | ;; First, see if this file exists in the current EDE project |
| 146 | (if (and (fboundp 'ede-expand-filename) ede-minor-mode |
| 147 | (setq edefind |
| 148 | (condition-case nil |
| 149 | (let ((proj (ede-toplevel))) |
| 150 | (when proj |
| 151 | (ede-expand-filename proj tag-fname))) |
| 152 | (error nil)))) |
| 153 | (setq result edefind)) |
| 154 | (if (not result) |
| 155 | (setq result |
| 156 | ;; I don't have a plan for refreshing tags with a dependency |
| 157 | ;; stuck on them somehow. I'm thinking that putting a cache |
| 158 | ;; onto the dependancy finding with a hash table might be best. |
| 159 | ;;(if (semantic--tag-get-property tag 'dependency-file) |
| 160 | ;; (semantic--tag-get-property tag 'dependency-file) |
| 161 | (:override |
| 162 | (save-excursion |
| 163 | (require 'semantic/dep) |
| 164 | (semantic-dependency-find-file-on-path |
| 165 | tag-fname (semantic-tag-include-system-p tag)))) |
| 166 | ;; ) |
| 167 | )) |
| 168 | (if (stringp result) |
| 169 | (progn |
| 170 | (semantic--tag-put-property tag 'dependency-file result) |
| 171 | result) |
| 172 | ;; @todo: Do something to make this get flushed w/ |
| 173 | ;; when the path is changed. |
| 174 | ;; @undo: Just eliminate |
| 175 | ;; (semantic--tag-put-property tag 'dependency-file 'none) |
| 176 | nil) |
| 177 | ))) |
| 178 | |
| 179 | (make-obsolete-overload 'semantic-find-dependency |
| 180 | 'semantic-dependency-tag-file "23.2") |
| 181 | |
| 182 | ;;; PROTOTYPE FILE |
| 183 | ;; |
| 184 | ;; In C, a function in the .c file often has a representation in a |
| 185 | ;; corresponding .h file. This routine attempts to find the |
| 186 | ;; prototype file a given source file would be associated with. |
| 187 | ;; This can be used by prototype manager programs. |
| 188 | (define-overloadable-function semantic-prototype-file (buffer) |
| 189 | "Return a file in which prototypes belonging to BUFFER should be placed. |
| 190 | Default behavior (if not overridden) looks for a token specifying the |
| 191 | prototype file, or the existence of an EDE variable indicating which |
| 192 | file prototypes belong in." |
| 193 | (:override |
| 194 | ;; Perform some default behaviors |
| 195 | (if (and (fboundp 'ede-header-file) ede-minor-mode) |
| 196 | (with-current-buffer buffer |
| 197 | (ede-header-file)) |
| 198 | ;; No EDE options for a quick answer. Search. |
| 199 | (with-current-buffer buffer |
| 200 | (if (re-search-forward "::Header:: \\([a-zA-Z0-9.]+\\)" nil t) |
| 201 | (match-string 1)))))) |
| 202 | |
| 203 | (semantic-alias-obsolete 'semantic-find-nonterminal |
| 204 | 'semantic-go-to-tag "23.2") |
| 205 | |
| 206 | (semantic-alias-obsolete 'semantic-find-dependency |
| 207 | 'semantic-dependency-tag-file "23.2") |
| 208 | |
| 209 | |
| 210 | (provide 'semantic/tag-file) |
| 211 | |
| 212 | ;; Local variables: |
| 213 | ;; generated-autoload-file: "loaddefs.el" |
| 214 | ;; generated-autoload-load-name: "semantic/tag-file" |
| 215 | ;; End: |
| 216 | |
| 217 | ;; arch-tag: 71d4cf18-c1ec-414c-bb0a-c2ed914c1361 |
| 218 | ;;; semantic/tag-file.el ends here |