Commit | Line | Data |
---|---|---|
aa8724ae | 1 | ;;; semantic/db-ebrowse.el --- Semanticdb backend using ebrowse. |
f273dfc6 | 2 | |
73b0cd50 | 3 | ;; Copyright (C) 2005-2011 |
9bf6c65c | 4 | ;; Free Software Foundation, Inc. |
f273dfc6 | 5 | |
aef8fbf1 GM |
6 | ;; Authors: Eric M. Ludlam <zappo@gnu.org> |
7 | ;; Joakim Verona | |
f273dfc6 CY |
8 | ;; Keywords: tags |
9 | ||
10 | ;; This file is part of GNU Emacs. | |
11 | ||
12 | ;; GNU Emacs is free software: you can redistribute it and/or modify | |
13 | ;; it under the terms of the GNU General Public License as published by | |
14 | ;; the Free Software Foundation, either version 3 of the License, or | |
15 | ;; (at your option) any later version. | |
16 | ||
17 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | ;; GNU General Public License for more details. | |
21 | ||
22 | ;; You should have received a copy of the GNU General Public License | |
23 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | |
24 | ||
25 | ;;; Commentary: | |
26 | ;; | |
27 | ;; This program was started by Eric Ludlam, and Joakim Verona finished | |
28 | ;; the implementation by adding searches and fixing bugs. | |
29 | ;; | |
30 | ;; Read in custom-created ebrowse BROWSE files into a semanticdb back | |
31 | ;; end. | |
32 | ;; | |
33 | ;; Add these databases to the 'system' search. | |
34 | ;; Possibly use ebrowse for local parsing too. | |
35 | ;; | |
36 | ;; When real details are needed out of the tag system from ebrowse, | |
37 | ;; we will need to delve into the originating source and parse those | |
38 | ;; files the usual way. | |
39 | ;; | |
40 | ;; COMMANDS: | |
41 | ;; `semanticdb-create-ebrowse-database' - Call EBROWSE to create a | |
42 | ;; system database for some directory. In general, use this for | |
43 | ;; system libraries, such as /usr/include, or include directories | |
44 | ;; large software projects. | |
45 | ;; Customize `semanticdb-ebrowse-file-match' to make sure the correct | |
46 | ;; file extensions are matched. | |
47 | ;; | |
48 | ;; `semanticdb-load-ebrowse-caches' - Load all the EBROWSE caches from | |
49 | ;; your semanticdb system database directory. Once they are | |
50 | ;; loaded, they become searchable as omnipotent databases for | |
51 | ;; all C++ files. This is called automatically by semantic-load. | |
52 | ;; Call it a second time to refresh the Emacs DB with the file. | |
53 | ;; | |
54 | ||
b90caf50 CY |
55 | (require 'ebrowse) |
56 | (require 'semantic) | |
57 | (require 'semantic/db-file) | |
58 | ||
f273dfc6 CY |
59 | (eval-when-compile |
60 | ;; For generic function searching. | |
61 | (require 'eieio) | |
62 | (require 'eieio-opt) | |
b90caf50 | 63 | (require 'semantic/find)) |
aa8724ae CY |
64 | |
65 | (declare-function semantic-add-system-include "semantic/dep") | |
f273dfc6 | 66 | |
f273dfc6 CY |
67 | ;;; Code: |
68 | (defvar semanticdb-ebrowse-default-file-name "BROWSE" | |
69 | "The EBROWSE file name used for system caches.") | |
70 | ||
71 | (defcustom semanticdb-ebrowse-file-match "\\.\\(hh?\\|HH?\\|hpp\\)" | |
72 | "Regular expression matching file names for ebrowse to parse. | |
73 | This expression should exclude C++ headers that have no extension. | |
74 | By default, include only headers since the semantic use of EBrowse | |
75 | is only for searching via semanticdb, and thus only headers would | |
76 | be searched." | |
77 | :group 'semanticdb | |
78 | :type 'string) | |
79 | ||
aa8724ae CY |
80 | ;;; SEMANTIC Database related Code |
81 | ;;; Classes: | |
82 | (defclass semanticdb-table-ebrowse (semanticdb-table) | |
83 | ((major-mode :initform c++-mode) | |
84 | (ebrowse-tree :initform nil | |
85 | :initarg :ebrowse-tree | |
86 | :documentation | |
87 | "The raw ebrowse tree for this file." | |
88 | ) | |
89 | (global-extract :initform nil | |
90 | :initarg :global-extract | |
91 | :documentation | |
92 | "Table of ebrowse tags specific to this file. | |
db9e401b | 93 | This table is composited from the ebrowse *Globals* section.") |
aa8724ae CY |
94 | ) |
95 | "A table for returning search results from ebrowse.") | |
96 | ||
97 | (defclass semanticdb-project-database-ebrowse | |
98 | (semanticdb-project-database) | |
99 | ((new-table-class :initform semanticdb-table-ebrowse | |
100 | :type class | |
101 | :documentation | |
102 | "New tables created for this database are of this class.") | |
103 | (system-include-p :initform nil | |
104 | :initarg :system-include | |
105 | :documentation | |
106 | "Flag indicating this database represents a system include directory.") | |
107 | (ebrowse-struct :initform nil | |
108 | :initarg :ebrowse-struct | |
109 | ) | |
110 | ) | |
111 | "Semantic Database deriving tags using the EBROWSE tool. | |
112 | EBROWSE is a C/C++ parser for use with `ebrowse' Emacs program.") | |
113 | ||
114 | ||
f273dfc6 CY |
115 | (defun semanticdb-ebrowse-C-file-p (file) |
116 | "Is FILE a C or C++ file?" | |
117 | (or (string-match semanticdb-ebrowse-file-match file) | |
118 | (and (string-match "/\\w+$" file) | |
119 | (not (file-directory-p file)) | |
120 | (let ((tmp (get-buffer-create "*semanticdb-ebrowse-tmp*"))) | |
0816d744 | 121 | (with-current-buffer tmp |
f273dfc6 CY |
122 | (condition-case nil |
123 | (insert-file-contents file nil 0 100 t) | |
124 | (error (insert-file-contents file nil nil nil t))) | |
125 | (goto-char (point-min)) | |
126 | (looking-at "\\s-*/\\(\\*\\|/\\)") | |
127 | )) | |
128 | ))) | |
129 | ||
130 | (defun semanticdb-create-ebrowse-database (dir) | |
db9e401b | 131 | "Create an EBROWSE database for directory DIR. |
f273dfc6 CY |
132 | The database file is stored in ~/.semanticdb, or whichever directory |
133 | is specified by `semanticdb-default-save-directory'." | |
134 | (interactive "DDirectory: ") | |
135 | (setq dir (file-name-as-directory dir)) ;; for / on end | |
136 | (let* ((savein (semanticdb-ebrowse-file-for-directory dir)) | |
137 | (filebuff (get-buffer-create "*SEMANTICDB EBROWSE TMP*")) | |
138 | (files (directory-files (expand-file-name dir) t)) | |
139 | (mma auto-mode-alist) | |
140 | (regexp nil) | |
141 | ) | |
142 | ;; Create the input to the ebrowse command | |
0816d744 | 143 | (with-current-buffer filebuff |
f273dfc6 CY |
144 | (buffer-disable-undo filebuff) |
145 | (setq default-directory (expand-file-name dir)) | |
146 | ||
147 | ;;; @TODO - convert to use semanticdb-collect-matching-filenames | |
148 | ;; to get the file names. | |
149 | ||
150 | ||
a4bdf715 CY |
151 | (mapc (lambda (f) |
152 | (when (semanticdb-ebrowse-C-file-p f) | |
153 | (insert f) | |
154 | (insert "\n"))) | |
155 | files) | |
f273dfc6 | 156 | ;; Cleanup the ebrowse output buffer. |
0816d744 | 157 | (with-current-buffer (get-buffer-create "*EBROWSE OUTPUT*") |
f273dfc6 CY |
158 | (erase-buffer)) |
159 | ;; Call the EBROWSE command. | |
160 | (message "Creating ebrowse file: %s ..." savein) | |
161 | (call-process-region (point-min) (point-max) | |
162 | "ebrowse" nil "*EBROWSE OUTPUT*" nil | |
163 | (concat "--output-file=" savein) | |
164 | "--very-verbose") | |
165 | ) | |
166 | ;; Create a short LOADER program for loading in this database. | |
167 | (let* ((lfn (concat savein "-load.el")) | |
168 | (lf (find-file-noselect lfn))) | |
0816d744 | 169 | (with-current-buffer lf |
f273dfc6 CY |
170 | (erase-buffer) |
171 | (insert "(semanticdb-ebrowse-load-helper \"" | |
172 | (expand-file-name dir) | |
173 | "\")\n") | |
174 | (save-buffer) | |
175 | (kill-buffer (current-buffer))) | |
176 | (message "Creating ebrowse file: %s ... done" savein) | |
177 | ;; Reload that database | |
178 | (load lfn nil t) | |
179 | ))) | |
180 | ||
181 | (defun semanticdb-load-ebrowse-caches () | |
182 | "Load all semanticdb controlled EBROWSE caches." | |
183 | (interactive) | |
184 | (let ((f (directory-files semanticdb-default-save-directory | |
185 | t (concat semanticdb-ebrowse-default-file-name "-load.el$") t))) | |
186 | (while f | |
187 | (load (car f) nil t) | |
188 | (setq f (cdr f))) | |
189 | )) | |
190 | ||
191 | (defun semanticdb-ebrowse-load-helper (directory) | |
192 | "Create the semanticdb database via ebrowse for directory. | |
193 | If DIRECTORY is found to be defunct, it won't load the DB, and will | |
194 | warn instead." | |
195 | (if (file-directory-p directory) | |
196 | (semanticdb-create-database semanticdb-project-database-ebrowse | |
197 | directory) | |
198 | (let* ((BF (semanticdb-ebrowse-file-for-directory directory)) | |
199 | (BFL (concat BF "-load.el")) | |
200 | (BFLB (concat BF "-load.el~"))) | |
201 | (save-window-excursion | |
202 | (with-output-to-temp-buffer "*FILES TO DELETE*" | |
203 | (princ "The following BROWSE files are obsolete.\n\n") | |
204 | (princ BF) | |
205 | (princ "\n") | |
206 | (princ BFL) | |
207 | (princ "\n") | |
208 | (when (file-exists-p BFLB) | |
209 | (princ BFLB) | |
210 | (princ "\n")) | |
211 | ) | |
212 | (when (y-or-n-p (format | |
213 | "Warning: Obsolete BROWSE file for: %s\nDelete? " | |
214 | directory)) | |
215 | (delete-file BF) | |
216 | (delete-file BFL) | |
217 | (when (file-exists-p BFLB) | |
218 | (delete-file BFLB)) | |
219 | ))))) | |
220 | ||
f273dfc6 CY |
221 | ;JAVE this just instantiates a default empty ebrowse struct? |
222 | ; how would new instances wind up here? | |
223 | ; the ebrowse class isnt singleton, unlike the emacs lisp one | |
224 | (defvar-mode-local c++-mode semanticdb-project-system-databases | |
225 | () | |
226 | "Search Ebrowse for symbols.") | |
227 | ||
228 | (defmethod semanticdb-needs-refresh-p ((table semanticdb-table-ebrowse)) | |
229 | "EBROWSE database do not need to be refreshed. | |
230 | ||
231 | JAVE: stub for needs-refresh, because, how do we know if BROWSE files | |
232 | are out of date? | |
233 | ||
234 | EML: Our database should probably remember the timestamp/checksum of | |
235 | the most recently read EBROWSE file, and use that." | |
236 | nil | |
237 | ) | |
238 | ||
239 | ||
240 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
241 | ||
242 | ||
243 | ||
244 | ;;; EBROWSE code | |
245 | ;; | |
246 | ;; These routines deal with part of the ebrowse interface. | |
247 | (defun semanticdb-ebrowse-file-for-directory (dir) | |
248 | "Return the file name for DIR where the ebrowse BROWSE file is. | |
249 | This file should reside in `semanticdb-default-save-directory'." | |
250 | (let* ((semanticdb-default-save-directory | |
251 | semanticdb-default-save-directory) | |
252 | (B (semanticdb-file-name-directory | |
253 | 'semanticdb-project-database-file | |
254 | (concat (expand-file-name dir) | |
255 | semanticdb-ebrowse-default-file-name))) | |
256 | ) | |
257 | B)) | |
258 | ||
259 | (defun semanticdb-ebrowse-get-ebrowse-structure (dir) | |
260 | "Return the ebrowse structure for directory DIR. | |
261 | This assumes semantic manages the BROWSE files, so they are assumed to live | |
262 | where semantic cache files live, depending on your settings. | |
263 | ||
264 | For instance: /home/<username>/.semanticdb/!usr!include!BROWSE" | |
265 | (let* ((B (semanticdb-ebrowse-file-for-directory dir)) | |
266 | (buf (get-buffer-create "*semanticdb ebrowse*"))) | |
267 | (message "semanticdb-ebrowse %s" B) | |
268 | (when (file-exists-p B) | |
269 | (set-buffer buf) | |
270 | (buffer-disable-undo buf) | |
271 | (erase-buffer) | |
272 | (insert-file-contents B) | |
273 | (let ((ans nil) | |
274 | (efcn (symbol-function 'ebrowse-show-progress))) | |
275 | (fset 'ebrowse-show-progress #'(lambda (&rest junk) nil)) | |
276 | (unwind-protect ;; Protect against errors w/ ebrowse | |
277 | (setq ans (list B (ebrowse-read))) | |
278 | ;; These items must always happen | |
279 | (erase-buffer) | |
280 | (fset 'ebrowse-show-fcn efcn) | |
281 | ) | |
282 | ans)))) | |
283 | ||
284 | ;;; Methods for creating a database or tables | |
285 | ;; | |
286 | (defmethod semanticdb-create-database :STATIC ((dbeC semanticdb-project-database-ebrowse) | |
287 | directory) | |
288 | "Create a new semantic database for DIRECTORY based on ebrowse. | |
289 | If there is no database for DIRECTORY available, then | |
290 | {not implemented yet} create one. Return nil if that is not possible." | |
291 | ;; MAKE SURE THAT THE FILE LOADED DOESN'T ALREADY EXIST. | |
aa8724ae | 292 | (require 'semantic/dep) |
f273dfc6 CY |
293 | (let ((dbs semanticdb-database-list) |
294 | (found nil)) | |
295 | (while (and (not found) dbs) | |
296 | (when (semanticdb-project-database-ebrowse-p (car dbs)) | |
297 | (when (string= (oref (car dbs) reference-directory) directory) | |
298 | (setq found (car dbs)))) | |
299 | (setq dbs (cdr dbs))) | |
300 | ;;STATIC means DBE cant be used as object, only as a class | |
301 | (let* ((ebrowse-data (semanticdb-ebrowse-get-ebrowse-structure directory)) | |
302 | (dat (car (cdr ebrowse-data))) | |
303 | (ebd (car dat)) | |
304 | (db nil) | |
305 | (default-directory directory) | |
306 | ) | |
307 | (if found | |
308 | (setq db found) | |
309 | (setq db (make-instance | |
310 | dbeC | |
311 | directory | |
312 | :ebrowse-struct ebd | |
313 | )) | |
314 | (oset db reference-directory directory)) | |
315 | ||
316 | ;; Once we recycle or make a new DB, refresh the | |
317 | ;; contents from the BROWSE file. | |
318 | (oset db tables nil) | |
319 | ;; only possible after object creation, tables inited to nil. | |
320 | (semanticdb-ebrowse-strip-trees db dat) | |
321 | ||
322 | ;; Once our database is loaded, if we are a system DB, we | |
323 | ;; add ourselves to the include list for C++. | |
324 | (semantic-add-system-include directory 'c++-mode) | |
325 | (semantic-add-system-include directory 'c-mode) | |
326 | ||
327 | db))) | |
328 | ||
329 | (defmethod semanticdb-ebrowse-strip-trees ((dbe semanticdb-project-database-ebrowse) | |
330 | data) | |
331 | "For the ebrowse database DBE, strip all tables from DATA." | |
332 | ;JAVE what it actually seems to do is split the original tree in "tables" associated with files | |
333 | ; im not sure it actually works: | |
334 | ; the filename slot sometimes gets to be nil, | |
335 | ; apparently for classes which definition cant be found, yet needs to be included in the tree | |
336 | ; like library baseclasses | |
337 | ; a file can define several classes | |
338 | (let ((T (car (cdr data))));1st comes a header, then the tree | |
339 | (while T | |
340 | ||
341 | (let* ((tree (car T)) | |
342 | (class (ebrowse-ts-class tree)); root class of tree | |
343 | ;; Something funny going on with this file thing... | |
344 | (filename (or (ebrowse-cs-source-file class) | |
345 | (ebrowse-cs-file class))) | |
346 | ) | |
347 | (cond | |
348 | ((ebrowse-globals-tree-p tree) | |
349 | ;; We have the globals tree.. save this special. | |
350 | (semanticdb-ebrowse-add-globals-to-table dbe tree) | |
351 | ) | |
352 | (t | |
353 | ;; ebrowse will collect all the info from multiple files | |
354 | ;; into one tree. Semantic wants all the bits to be tied | |
355 | ;; into different files. We need to do a full dissociation | |
356 | ;; into semantic parsable tables. | |
357 | (semanticdb-ebrowse-add-tree-to-table dbe tree) | |
358 | )) | |
359 | (setq T (cdr T)))) | |
360 | )) | |
361 | ||
362 | ;;; Filename based methods | |
363 | ;; | |
364 | (defun semanticdb-ebrowse-add-globals-to-table (dbe tree) | |
365 | "For database DBE, add the ebrowse TREE into the table." | |
366 | (if (or (not (ebrowse-ts-p tree)) | |
367 | (not (ebrowse-globals-tree-p tree))) | |
368 | (signal 'wrong-type-argument (list 'ebrowse-ts-p tree))) | |
369 | ||
370 | (let* ((class (ebrowse-ts-class tree)) | |
371 | (fname (or (ebrowse-cs-source-file class) | |
372 | (ebrowse-cs-file class) | |
373 | ;; Not def'd here, assume our current | |
374 | ;; file | |
375 | (concat default-directory "/unknown-proxy.hh"))) | |
376 | (vars (ebrowse-ts-member-functions tree)) | |
377 | (fns (ebrowse-ts-member-variables tree)) | |
378 | (toks nil) | |
379 | ) | |
380 | (while vars | |
381 | (let ((nt (semantic-tag (ebrowse-ms-name (car vars)) | |
382 | 'variable)) | |
383 | (defpoint (ebrowse-bs-point class))) | |
384 | (when defpoint | |
385 | (semantic--tag-set-overlay nt | |
386 | (vector defpoint defpoint))) | |
387 | (setq toks (cons nt toks))) | |
388 | (setq vars (cdr vars))) | |
389 | (while fns | |
390 | (let ((nt (semantic-tag (ebrowse-ms-name (car fns)) | |
391 | 'function)) | |
392 | (defpoint (ebrowse-bs-point class))) | |
393 | (when defpoint | |
394 | (semantic--tag-set-overlay nt | |
395 | (vector defpoint defpoint))) | |
396 | (setq toks (cons nt toks))) | |
397 | (setq fns (cdr fns))) | |
398 | ||
399 | )) | |
400 | ||
401 | (defun semanticdb-ebrowse-add-tree-to-table (dbe tree &optional fname baseclasses) | |
402 | "For database DBE, add the ebrowse TREE into the table for FNAME. | |
9bf6c65c | 403 | Optional argument BASECLASSES specifies a baseclass to the tree being provided." |
f273dfc6 CY |
404 | (if (not (ebrowse-ts-p tree)) |
405 | (signal 'wrong-type-argument (list 'ebrowse-ts-p tree))) | |
406 | ||
407 | ;; Strategy overview: | |
408 | ;; 1) Calculate the filename for this tree. | |
409 | ;; 2) Find a matching namespace in TAB, or create a new one. | |
410 | ;; 3) Fabricate a tag proxy for CLASS | |
411 | ;; 4) Add it to the namespace | |
412 | ;; 5) Add subclasses | |
413 | ||
414 | ;; 1 - Find the filename | |
415 | (if (not fname) | |
416 | (setq fname (or (ebrowse-cs-source-file (ebrowse-ts-class tree)) | |
417 | (ebrowse-cs-file (ebrowse-ts-class tree)) | |
418 | ;; Not def'd here, assume our current | |
419 | ;; file | |
420 | (concat default-directory "/unknown-proxy.hh")))) | |
421 | ||
422 | (let* ((tab (or (semanticdb-file-table dbe fname) | |
423 | (semanticdb-create-table dbe fname))) | |
424 | (class (ebrowse-ts-class tree)) | |
425 | (scope (ebrowse-cs-scope class)) | |
aa8724ae | 426 | (ns (when scope (split-string scope ":" t))) |
f273dfc6 CY |
427 | (nst nil) |
428 | (cls nil) | |
429 | ) | |
430 | ||
431 | ;; 2 - Get the namespace tag | |
432 | (when ns | |
433 | (let ((taglst (if (slot-boundp tab 'tags) (oref tab tags) nil))) | |
434 | (setq nst (semantic-find-first-tag-by-name (car ns) taglst)) | |
435 | (when (not nst) | |
436 | (setq nst (semantic-tag (car ns) 'type :type "namespace")) | |
437 | (oset tab tags (cons nst taglst)) | |
438 | ))) | |
439 | ||
440 | ;; 3 - Create a proxy tg. | |
441 | (setq cls (semantic-tag (ebrowse-cs-name class) | |
442 | 'type | |
443 | :type "class" | |
444 | :superclasses baseclasses | |
445 | :faux t | |
446 | :filename fname | |
447 | )) | |
448 | (let ((defpoint (ebrowse-bs-point class))) | |
449 | (when defpoint | |
450 | (semantic--tag-set-overlay cls | |
451 | (vector defpoint defpoint)))) | |
452 | ||
453 | ;; 4 - add to namespace | |
454 | (if nst | |
455 | (semantic-tag-put-attribute | |
456 | nst :members (cons cls (semantic-tag-get-attribute nst :members))) | |
457 | (oset tab tags (cons cls (when (slot-boundp tab 'tags) | |
458 | (oref tab tags))))) | |
459 | ||
460 | ;; 5 - Subclasses | |
461 | (let* ((subclass (ebrowse-ts-subclasses tree)) | |
462 | (pname (ebrowse-cs-name class))) | |
463 | (when (ebrowse-cs-scope class) | |
464 | (setq pname (concat (mapconcat (lambda (a) a) (cdr ns) "::") "::" pname))) | |
465 | ||
466 | (while subclass | |
467 | (let* ((scc (ebrowse-ts-class (car subclass))) | |
468 | (fname (or (ebrowse-cs-source-file scc) | |
469 | (ebrowse-cs-file scc) | |
470 | ;; Not def'd here, assume our current | |
471 | ;; file | |
472 | fname | |
473 | ))) | |
474 | (when fname | |
475 | (semanticdb-ebrowse-add-tree-to-table | |
476 | dbe (car subclass) fname pname))) | |
477 | (setq subclass (cdr subclass)))) | |
478 | )) | |
479 | ||
480 | ;;; | |
481 | ;; Overload for converting the simple faux tag into something better. | |
482 | ;; | |
483 | (defmethod semanticdb-normalize-tags ((obj semanticdb-table-ebrowse) tags) | |
484 | "Convert in Ebrowse database OBJ a list of TAGS into a complete tag. | |
485 | The default tag provided by searches exclude many features of a | |
486 | semantic parsed tag. Look up the file for OBJ, and match TAGS | |
487 | against a semantic parsed tag that has all the info needed, and | |
488 | return that." | |
489 | (let ((tagret nil) | |
490 | ) | |
491 | ;; SemanticDB will automatically create a regular database | |
492 | ;; on top of the file just loaded by ebrowse during the set | |
493 | ;; buffer. Fetch that table, and use it's tag list to look | |
494 | ;; up the tag we just got, and thus turn it into a full semantic | |
495 | ;; tag. | |
496 | (while tags | |
497 | (let ((tag (car tags))) | |
498 | (save-excursion | |
499 | (semanticdb-set-buffer obj) | |
500 | (let ((ans nil)) | |
501 | ;; Gee, it would be nice to do this, but ebrowse LIES. Oi. | |
502 | (when (semantic-tag-with-position-p tag) | |
503 | (goto-char (semantic-tag-start tag)) | |
504 | (let ((foundtag (semantic-current-tag))) | |
505 | ;; Make sure the discovered tag is the same as what we started with. | |
506 | (when (string= (semantic-tag-name tag) | |
507 | (semantic-tag-name foundtag)) | |
508 | ;; We have a winner! | |
509 | (setq ans foundtag)))) | |
510 | ;; Sometimes ebrowse lies. Do a generic search | |
511 | ;; to find it within this file. | |
512 | (when (not ans) | |
513 | ;; We might find multiple hits for this tag, and we have no way | |
514 | ;; of knowing which one the user wanted. Return the first one. | |
515 | (setq ans (semantic-deep-find-tags-by-name | |
516 | (semantic-tag-name tag) | |
517 | (semantic-fetch-tags)))) | |
518 | (if (semantic-tag-p ans) | |
519 | (setq tagret (cons ans tagret)) | |
520 | (setq tagret (append ans tagret))) | |
521 | )) | |
522 | (setq tags (cdr tags)))) | |
523 | tagret)) | |
524 | ||
525 | (defmethod semanticdb-normalize-one-tag ((obj semanticdb-table-ebrowse) tag) | |
526 | "Convert in Ebrowse database OBJ one TAG into a complete tag. | |
527 | The default tag provided by searches exclude many features of a | |
528 | semantic parsed tag. Look up the file for OBJ, and match TAG | |
529 | against a semantic parsed tag that has all the info needed, and | |
530 | return that." | |
531 | (let ((tagret nil) | |
532 | (objret nil)) | |
533 | ;; SemanticDB will automatically create a regular database | |
534 | ;; on top of the file just loaded by ebrowse during the set | |
535 | ;; buffer. Fetch that table, and use it's tag list to look | |
536 | ;; up the tag we just got, and thus turn it into a full semantic | |
537 | ;; tag. | |
538 | (save-excursion | |
539 | (semanticdb-set-buffer obj) | |
540 | (setq objret semanticdb-current-table) | |
541 | (when (not objret) | |
542 | ;; What to do?? | |
543 | (debug)) | |
544 | (let ((ans nil)) | |
545 | ;; Gee, it would be nice to do this, but ebrowse LIES. Oi. | |
546 | (when (semantic-tag-with-position-p tag) | |
547 | (goto-char (semantic-tag-start tag)) | |
548 | (let ((foundtag (semantic-current-tag))) | |
549 | ;; Make sure the discovered tag is the same as what we started with. | |
550 | (when (string= (semantic-tag-name tag) | |
551 | (semantic-tag-name foundtag)) | |
552 | ;; We have a winner! | |
553 | (setq ans foundtag)))) | |
554 | ;; Sometimes ebrowse lies. Do a generic search | |
555 | ;; to find it within this file. | |
556 | (when (not ans) | |
557 | ;; We might find multiple hits for this tag, and we have no way | |
558 | ;; of knowing which one the user wanted. Return the first one. | |
559 | (setq ans (semantic-deep-find-tags-by-name | |
560 | (semantic-tag-name tag) | |
561 | (semantic-fetch-tags)))) | |
562 | (if (semantic-tag-p ans) | |
563 | (setq tagret ans) | |
564 | (setq tagret (car ans))) | |
565 | )) | |
566 | (cons objret tagret))) | |
567 | ||
568 | ;;; Search Overrides | |
569 | ;; | |
570 | ;; NOTE WHEN IMPLEMENTING: Be sure to add doc-string updates explaining | |
571 | ;; how your new search routines are implemented. | |
572 | ;; | |
573 | (defmethod semanticdb-find-tags-by-name-method | |
574 | ((table semanticdb-table-ebrowse) name &optional tags) | |
575 | "Find all tags named NAME in TABLE. | |
576 | Return a list of tags." | |
577 | ;;(message "semanticdb-find-tags-by-name-method name -- %s" name) | |
578 | (if tags | |
579 | ;; If TAGS are passed in, then we don't need to do work here. | |
580 | (call-next-method) | |
581 | ;; If we ever need to do something special, add here. | |
582 | ;; Since ebrowse tags are converted into semantic tags, we can | |
583 | ;; get away with this sort of thing. | |
584 | (call-next-method) | |
585 | ) | |
586 | ) | |
587 | ||
588 | (defmethod semanticdb-find-tags-by-name-regexp-method | |
589 | ((table semanticdb-table-ebrowse) regex &optional tags) | |
590 | "Find all tags with name matching REGEX in TABLE. | |
591 | Optional argument TAGS is a list of tags to search. | |
592 | Return a list of tags." | |
593 | (if tags (call-next-method) | |
594 | ;; YOUR IMPLEMENTATION HERE | |
595 | (call-next-method) | |
596 | )) | |
597 | ||
598 | (defmethod semanticdb-find-tags-for-completion-method | |
599 | ((table semanticdb-table-ebrowse) prefix &optional tags) | |
db9e401b | 600 | "In TABLE, find all occurrences of tags matching PREFIX. |
f273dfc6 CY |
601 | Optional argument TAGS is a list of tags to search. |
602 | Returns a table of all matching tags." | |
603 | (if tags (call-next-method) | |
604 | ;; YOUR IMPLEMENTATION HERE | |
605 | (call-next-method) | |
606 | )) | |
607 | ||
608 | (defmethod semanticdb-find-tags-by-class-method | |
609 | ((table semanticdb-table-ebrowse) class &optional tags) | |
db9e401b | 610 | "In TABLE, find all occurrences of tags of CLASS. |
f273dfc6 CY |
611 | Optional argument TAGS is a list of tags to search. |
612 | Returns a table of all matching tags." | |
613 | (if tags (call-next-method) | |
614 | (call-next-method))) | |
615 | ||
616 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
617 | ||
618 | ;;; Deep Searches | |
619 | ;; | |
620 | ;; If your language does not have a `deep' concept, these can be left | |
621 | ;; alone, otherwise replace with implementations similar to those | |
622 | ;; above. | |
623 | ;; | |
624 | ||
625 | (defmethod semanticdb-deep-find-tags-by-name-method | |
626 | ((table semanticdb-table-ebrowse) name &optional tags) | |
627 | "Find all tags name NAME in TABLE. | |
db9e401b | 628 | Optional argument TAGS is a list of tags to search. |
f273dfc6 CY |
629 | Like `semanticdb-find-tags-by-name-method' for ebrowse." |
630 | ;;(semanticdb-find-tags-by-name-method table name tags) | |
631 | (call-next-method)) | |
632 | ||
633 | (defmethod semanticdb-deep-find-tags-by-name-regexp-method | |
634 | ((table semanticdb-table-ebrowse) regex &optional tags) | |
635 | "Find all tags with name matching REGEX in TABLE. | |
636 | Optional argument TAGS is a list of tags to search. | |
637 | Like `semanticdb-find-tags-by-name-method' for ebrowse." | |
638 | ;;(semanticdb-find-tags-by-name-regexp-method table regex tags) | |
639 | (call-next-method)) | |
640 | ||
641 | (defmethod semanticdb-deep-find-tags-for-completion-method | |
642 | ((table semanticdb-table-ebrowse) prefix &optional tags) | |
db9e401b | 643 | "In TABLE, find all occurrences of tags matching PREFIX. |
f273dfc6 CY |
644 | Optional argument TAGS is a list of tags to search. |
645 | Like `semanticdb-find-tags-for-completion-method' for ebrowse." | |
646 | ;;(semanticdb-find-tags-for-completion-method table prefix tags) | |
647 | (call-next-method)) | |
648 | ||
649 | ;;; Advanced Searches | |
650 | ;; | |
651 | (defmethod semanticdb-find-tags-external-children-of-type-method | |
652 | ((table semanticdb-table-ebrowse) type &optional tags) | |
653 | "Find all nonterminals which are child elements of TYPE | |
654 | Optional argument TAGS is a list of tags to search. | |
655 | Return a list of tags." | |
656 | (if tags (call-next-method) | |
657 | ;; Ebrowse collects all this type of stuff together for us. | |
658 | ;; but we can't use it.... yet. | |
659 | nil | |
660 | )) | |
661 | ||
f273dfc6 CY |
662 | (provide 'semantic/db-ebrowse) |
663 | ||
aa8724ae | 664 | ;;; semantic/db-ebrowse.el ends here |