Commit | Line | Data |
---|---|---|
aa8724ae | 1 | ;;; semantic/db-find.el --- Searching through semantic databases. |
1bd95535 | 2 | |
9bf6c65c | 3 | ;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, |
49f70d46 | 4 | ;; 2009, 2010, 2011, 2012 Free Software Foundation, Inc. |
1bd95535 CY |
5 | |
6 | ;; Author: Eric M. Ludlam <zappo@gnu.org> | |
7 | ;; Keywords: tags | |
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 | ;; Databases of various forms can all be searched. | |
27 | ;; There are a few types of searches that can be done: | |
28 | ;; | |
29 | ;; Basic Name Search: | |
30 | ;; These searches scan a database table collection for tags based | |
31 | ;; on name. | |
32 | ;; | |
33 | ;; Basic Attribute Search: | |
34 | ;; These searches allow searching on specific attributes of tags, | |
35 | ;; such as name, type, or other attribute. | |
36 | ;; | |
37 | ;; Advanced Search: | |
38 | ;; These are searches that were needed to accomplish some | |
39 | ;; specialized tasks as discovered in utilities. Advanced searches | |
40 | ;; include matching methods defined outside some parent class. | |
41 | ;; | |
42 | ;; The reason for advanced searches are so that external | |
43 | ;; repositories such as the Emacs obarray, or java .class files can | |
44 | ;; quickly answer these needed questions without dumping the entire | |
45 | ;; symbol list into Emacs for additional refinement searches via | |
46 | ;; regular semanticdb search. | |
47 | ;; | |
48 | ;; How databases are decided upon is another important aspect of a | |
49 | ;; database search. When it comes to searching for a name, there are | |
50 | ;; these types of searches: | |
51 | ;; | |
52 | ;; Basic Search: | |
53 | ;; Basic search means that tags looking for a given name start | |
54 | ;; with a specific search path. Names are sought on that path | |
55 | ;; until it is empty or items on the path can no longer be found. | |
56 | ;; Use `semanticdb-dump-all-table-summary' to test this list. | |
57 | ;; Use `semanticdb-find-throttle-custom-list' to refine this list. | |
58 | ;; | |
59 | ;; Deep Search: | |
60 | ;; A deep search will search more than just the global namespace. | |
61 | ;; It will recurse into tags that contain more tags, and search | |
62 | ;; those too. | |
63 | ;; | |
64 | ;; Brute Search: | |
65 | ;; Brute search means that all tables in all databases in a given | |
66 | ;; project are searched. Brute searches are the search style as | |
67 | ;; written for semantic version 1.x. | |
68 | ;; | |
69 | ;; How does the search path work? | |
70 | ;; | |
71 | ;; A basic search starts with three parameters: | |
72 | ;; | |
73 | ;; (FINDME &optional PATH FIND-FILE-MATCH) | |
74 | ;; | |
75 | ;; FINDME is key to be searched for dependent on the type of search. | |
76 | ;; PATH is an indicator of which tables are to be searched. | |
77 | ;; FIND-FILE-MATCH indicates that any time a match is found, the | |
78 | ;; file associated with the tag should be read into a file. | |
79 | ;; | |
80 | ;; The PATH argument is then the most interesting argument. It can | |
81 | ;; have these values: | |
82 | ;; | |
83 | ;; nil - Take the current buffer, and use it's include list | |
84 | ;; buffer - Use that buffer's include list. | |
85 | ;; filename - Use that file's include list. If the file is not | |
86 | ;; in a buffer, see of there is a semanticdb table for it. If | |
87 | ;; not, read that file into a buffer. | |
88 | ;; tag - Get that tag's buffer of file file. See above. | |
89 | ;; table - Search that table, and it's include list. | |
90 | ;; | |
91 | ;; Search Results: | |
92 | ;; | |
93 | ;; Semanticdb returns the results in a specific format. There are a | |
94 | ;; series of routines for using those results, and results can be | |
95 | ;; passed in as a search-path for refinement searches with | |
96 | ;; semanticdb. Apropos for semanticdb.*find-result for more. | |
97 | ;; | |
98 | ;; Application: | |
99 | ;; | |
100 | ;; Here are applications where different searches are needed which | |
101 | ;; exist as of semantic 1.4.x | |
102 | ;; | |
103 | ;; eldoc - popup help | |
104 | ;; => Requires basic search using default path. (Header files ok) | |
105 | ;; tag jump - jump to a named tag | |
9bf6c65c | 106 | ;; => Requires a brute search using whole project. (Source files only) |
1bd95535 CY |
107 | ;; completion - Completing symbol names in a smart way |
108 | ;; => Basic search (headers ok) | |
109 | ;; type analysis - finding type definitions for variables & fcns | |
110 | ;; => Basic search (headers ok) | |
111 | ;; Class browser - organize types into some structure | |
112 | ;; => Brute search, or custom navigation. | |
113 | ||
114 | ;; TODO: | |
115 | ;; During a search, load any unloaded DB files based on paths in the | |
116 | ;; current project. | |
117 | ||
118 | (require 'semantic/db) | |
119 | (require 'semantic/db-ref) | |
120 | (eval-when-compile | |
978c25c6 | 121 | (require 'semantic/find)) |
691a065e | 122 | |
1bd95535 | 123 | ;;; Code: |
691a065e CY |
124 | |
125 | (defvar data-debug-thing-alist) | |
126 | (declare-function data-debug-insert-stuff-list "data-debug") | |
619392fc | 127 | ;;;(declare-function data-debug-insert-tag-list "adebug") |
691a065e CY |
128 | (declare-function semantic-scope-reset-cache "semantic/scope") |
129 | (declare-function semanticdb-typecache-notify-reset "semantic/db-typecache") | |
130 | (declare-function ede-current-project "ede") | |
131 | ||
1bd95535 CY |
132 | (defvar semanticdb-find-throttle-custom-list |
133 | '(repeat (radio (const 'local) | |
134 | (const 'project) | |
135 | (const 'unloaded) | |
136 | (const 'system) | |
137 | (const 'recursive) | |
138 | (const 'omniscience))) | |
139 | "Customization values for semanticdb find throttle. | |
140 | See `semanticdb-find-throttle' for details.") | |
141 | ||
691a065e | 142 | ;;;###autoload |
1bd95535 CY |
143 | (defcustom semanticdb-find-default-throttle |
144 | '(local project unloaded system recursive) | |
145 | "The default throttle for `semanticdb-find' routines. | |
146 | The throttle controls how detailed the list of database | |
147 | tables is for a symbol lookup. The value is a list with | |
148 | the following keys: | |
149 | `file' - The file the search is being performed from. | |
150 | This option is here for completeness only, and | |
151 | is assumed to always be on. | |
152 | `local' - Tables from the same local directory are included. | |
153 | This includes files directly referenced by a file name | |
154 | which might be in a different directory. | |
155 | `project' - Tables from the same local project are included | |
156 | If `project' is specified, then `local' is assumed. | |
157 | `unloaded' - If a table is not in memory, load it. If it is not cached | |
158 | on disk either, get the source, parse it, and create | |
159 | the table. | |
160 | `system' - Tables from system databases. These are specifically | |
161 | tables from system header files, or language equivalent. | |
162 | `recursive' - For include based searches, includes tables referenced | |
163 | by included files. | |
164 | `omniscience' - Included system databases which are omniscience, or | |
165 | somehow know everything. Omniscience databases are found | |
166 | in `semanticdb-project-system-databases'. | |
167 | The Emacs Lisp system DB is an omniscience database." | |
168 | :group 'semanticdb | |
169 | :type semanticdb-find-throttle-custom-list) | |
170 | ||
171 | (defun semanticdb-find-throttle-active-p (access-type) | |
172 | "Non-nil if ACCESS-TYPE is an active throttle type." | |
173 | (or (memq access-type semanticdb-find-default-throttle) | |
174 | (eq access-type 'file) | |
175 | (and (eq access-type 'local) | |
176 | (memq 'project semanticdb-find-default-throttle)) | |
177 | )) | |
178 | ||
179 | ;;; Index Class | |
180 | ;; | |
181 | ;; The find routines spend a lot of time looking stuff up. | |
182 | ;; Use this handy search index to cache data between searches. | |
183 | ;; This should allow searches to start running faster. | |
184 | (defclass semanticdb-find-search-index (semanticdb-abstract-search-index) | |
185 | ((include-path :initform nil | |
186 | :documentation | |
187 | "List of semanticdb tables from the include path.") | |
188 | (type-cache :initform nil | |
189 | :documentation | |
190 | "Cache of all the data types accessible from this file. | |
191 | Includes all types from all included files, merged namespaces, and | |
192 | expunge duplicates.") | |
193 | ) | |
194 | "Concrete search index for `semanticdb-find'. | |
195 | This class will cache data derived during various searches.") | |
196 | ||
197 | (defmethod semantic-reset ((idx semanticdb-find-search-index)) | |
198 | "Reset the object IDX." | |
691a065e | 199 | (require 'semantic/scope) |
1bd95535 CY |
200 | ;; Clear the include path. |
201 | (oset idx include-path nil) | |
202 | (when (oref idx type-cache) | |
203 | (semantic-reset (oref idx type-cache))) | |
204 | ;; Clear the scope. Scope doesn't have the data it needs to track | |
dd9af436 | 205 | ;; its own reset. |
1bd95535 CY |
206 | (semantic-scope-reset-cache) |
207 | ) | |
208 | ||
209 | (defmethod semanticdb-synchronize ((idx semanticdb-find-search-index) | |
210 | new-tags) | |
211 | "Synchronize the search index IDX with some NEW-TAGS." | |
212 | ;; Reset our parts. | |
213 | (semantic-reset idx) | |
214 | ;; Notify dependants by clearning their indicies. | |
215 | (semanticdb-notify-references | |
216 | (oref idx table) | |
217 | (lambda (tab me) | |
218 | (semantic-reset (semanticdb-get-table-index tab)))) | |
219 | ) | |
220 | ||
221 | (defmethod semanticdb-partial-synchronize ((idx semanticdb-find-search-index) | |
222 | new-tags) | |
223 | "Synchronize the search index IDX with some changed NEW-TAGS." | |
224 | ;; Only reset if include statements changed. | |
225 | (if (semantic-find-tags-by-class 'include new-tags) | |
226 | (progn | |
227 | (semantic-reset idx) | |
228 | ;; Notify dependants by clearning their indicies. | |
229 | (semanticdb-notify-references | |
230 | (oref idx table) | |
231 | (lambda (tab me) | |
232 | (semantic-reset (semanticdb-get-table-index tab)))) | |
233 | ) | |
234 | ;; Else, not an include, by just a type. | |
235 | (when (oref idx type-cache) | |
236 | (when (semanticdb-partial-synchronize (oref idx type-cache) new-tags) | |
237 | ;; If the synchronize returns true, we need to notify. | |
238 | ;; Notify dependants by clearning their indicies. | |
239 | (semanticdb-notify-references | |
240 | (oref idx table) | |
241 | (lambda (tab me) | |
242 | (let ((tab-idx (semanticdb-get-table-index tab))) | |
243 | ;; Not a full reset? | |
244 | (when (oref tab-idx type-cache) | |
691a065e | 245 | (require 'db-typecache) |
1bd95535 CY |
246 | (semanticdb-typecache-notify-reset |
247 | (oref tab-idx type-cache))) | |
248 | ))) | |
249 | )) | |
250 | )) | |
251 | ||
252 | ||
253 | ;;; Path Translations | |
254 | ;; | |
255 | ;;; OVERLOAD Functions | |
256 | ;; | |
257 | ;; These routines needed to be overloaded by specific language modes. | |
258 | ;; They are needed for translating an INCLUDE tag into a semanticdb | |
259 | ;; TABLE object. | |
3d9d8486 | 260 | ;;;###autoload |
1bd95535 CY |
261 | (define-overloadable-function semanticdb-find-translate-path (path brutish) |
262 | "Translate PATH into a list of semantic tables. | |
263 | Path translation involves identifying the PATH input argument | |
264 | in one of the following ways: | |
dd9af436 | 265 | nil - Take the current buffer, and use its include list |
1bd95535 CY |
266 | buffer - Use that buffer's include list. |
267 | filename - Use that file's include list. If the file is not | |
268 | in a buffer, see of there is a semanticdb table for it. If | |
269 | not, read that file into a buffer. | |
270 | tag - Get that tag's buffer of file file. See above. | |
dd9af436 | 271 | table - Search that table, and its include list. |
1bd95535 CY |
272 | find result - Search the results of a previous find. |
273 | ||
274 | In addition, once the base path is found, there is the possibility of | |
275 | each added table adding yet more tables to the path, so this routine | |
276 | can return a lengthy list. | |
277 | ||
278 | If argument BRUTISH is non-nil, then instead of using the include | |
279 | list, use all tables found in the parent project of the table | |
280 | identified by translating PATH. Such searches use brute force to | |
281 | scan every available table. | |
282 | ||
283 | The return value is a list of objects of type `semanticdb-table' or | |
db9e401b | 284 | their children. In the case of passing in a find result, the result |
1bd95535 CY |
285 | is returned unchanged. |
286 | ||
287 | This routine uses `semanticdb-find-table-for-include' to translate | |
288 | specific include tags into a semanticdb table. | |
289 | ||
290 | Note: When searching using a non-brutish method, the list of | |
291 | included files will be cached between runs. Database-references | |
292 | are used to track which files need to have their include lists | |
293 | refreshed when things change. See `semanticdb-ref-test'. | |
294 | ||
295 | Note for overloading: If you opt to overload this function for your | |
296 | major mode, and your routine takes a long time, be sure to call | |
297 | ||
298 | (semantic-throw-on-input 'your-symbol-here) | |
299 | ||
300 | so that it can be called from the idle work handler." | |
301 | ) | |
302 | ||
303 | (defun semanticdb-find-translate-path-default (path brutish) | |
304 | "Translate PATH into a list of semantic tables. | |
305 | If BRUTISH is non nil, return all tables associated with PATH. | |
306 | Default action as described in `semanticdb-find-translate-path'." | |
307 | (if (semanticdb-find-results-p path) | |
308 | ;; nil means perform the search over these results. | |
309 | nil | |
310 | (if brutish | |
311 | (semanticdb-find-translate-path-brutish-default path) | |
312 | (semanticdb-find-translate-path-includes-default path)))) | |
313 | ||
3d9d8486 | 314 | ;;;###autoload |
691a065e CY |
315 | (define-overloadable-function semanticdb-find-table-for-include (includetag &optional table) |
316 | "For a single INCLUDETAG found in TABLE, find a `semanticdb-table' object | |
317 | INCLUDETAG is a semantic TAG of class 'include. | |
318 | TABLE is a semanticdb table that identifies where INCLUDETAG came from. | |
319 | TABLE is optional if INCLUDETAG has an overlay of :filename attribute." | |
320 | ) | |
321 | ||
1bd95535 CY |
322 | (defun semanticdb-find-translate-path-brutish-default (path) |
323 | "Translate PATH into a list of semantic tables. | |
324 | Default action as described in `semanticdb-find-translate-path'." | |
325 | (let ((basedb | |
326 | (cond ((null path) semanticdb-current-database) | |
327 | ((semanticdb-table-p path) (oref path parent-db)) | |
328 | (t (let ((tt (semantic-something-to-tag-table path))) | |
de3a1fe9 CY |
329 | ;; @todo - What does this DO ??!?! |
330 | (with-current-buffer (semantic-tag-buffer (car tt)) | |
1bd95535 CY |
331 | semanticdb-current-database)))))) |
332 | (apply | |
333 | #'nconc | |
334 | (mapcar | |
335 | (lambda (db) | |
336 | (let ((tabs (semanticdb-get-database-tables db)) | |
337 | (ret nil)) | |
338 | ;; Only return tables of the same language (major-mode) | |
339 | ;; as the current search environment. | |
340 | (while tabs | |
341 | ||
342 | (semantic-throw-on-input 'translate-path-brutish) | |
343 | ||
344 | (if (semanticdb-equivalent-mode-for-search (car tabs) | |
345 | (current-buffer)) | |
346 | (setq ret (cons (car tabs) ret))) | |
347 | (setq tabs (cdr tabs))) | |
348 | ret)) | |
349 | ;; FIXME: | |
350 | ;; This should scan the current project directory list for all | |
351 | ;; semanticdb files, perhaps handling proxies for them. | |
352 | (semanticdb-current-database-list | |
353 | (if basedb (oref basedb reference-directory) | |
354 | default-directory)))) | |
355 | )) | |
356 | ||
357 | (defun semanticdb-find-incomplete-cache-entries-p (cache) | |
358 | "Are there any incomplete entries in CACHE?" | |
359 | (let ((ans nil)) | |
360 | (dolist (tab cache) | |
361 | (when (and (semanticdb-table-child-p tab) | |
362 | (not (number-or-marker-p (oref tab pointmax)))) | |
363 | (setq ans t)) | |
364 | ) | |
365 | ans)) | |
366 | ||
367 | (defun semanticdb-find-need-cache-update-p (table) | |
db9e401b | 368 | "Non-nil if the semanticdb TABLE cache needs to be updated." |
1bd95535 CY |
369 | ;; If we were passed in something related to a TABLE, |
370 | ;; do a caching lookup. | |
371 | (let* ((index (semanticdb-get-table-index table)) | |
372 | (cache (when index (oref index include-path))) | |
373 | (incom (semanticdb-find-incomplete-cache-entries-p cache)) | |
374 | (unl (semanticdb-find-throttle-active-p 'unloaded)) | |
375 | ) | |
376 | (if (and | |
377 | cache ;; Must have a cache | |
378 | (or | |
379 | ;; If all entries are "full", or if 'unloaded | |
380 | ;; OR | |
381 | ;; is not in the throttle, it is ok to use the cache. | |
382 | (not incom) (not unl) | |
383 | )) | |
384 | nil | |
385 | ;;cache | |
386 | ;; ELSE | |
387 | ;; | |
388 | ;; We need an update. | |
389 | t)) | |
390 | ) | |
391 | ||
392 | (defun semanticdb-find-translate-path-includes-default (path) | |
393 | "Translate PATH into a list of semantic tables. | |
394 | Default action as described in `semanticdb-find-translate-path'." | |
395 | (let ((table (cond ((null path) | |
396 | semanticdb-current-table) | |
397 | ((bufferp path) | |
398 | (semantic-buffer-local-value 'semanticdb-current-table path)) | |
399 | ((and (stringp path) (file-exists-p path)) | |
400 | (semanticdb-file-table-object path t)) | |
401 | ((semanticdb-abstract-table-child-p path) | |
402 | path) | |
403 | (t nil)))) | |
404 | (if table | |
405 | ;; If we were passed in something related to a TABLE, | |
406 | ;; do a caching lookup. | |
407 | (let ((index (semanticdb-get-table-index table))) | |
408 | (if (semanticdb-find-need-cache-update-p table) | |
409 | ;; Lets go look up our indicies | |
410 | (let ((ans (semanticdb-find-translate-path-includes--internal path))) | |
411 | (oset index include-path ans) | |
412 | ;; Once we have our new indicies set up, notify those | |
413 | ;; who depend on us if we found something for them to | |
414 | ;; depend on. | |
415 | (when ans (semanticdb-refresh-references table)) | |
416 | ans) | |
417 | ;; ELSE | |
418 | ;; | |
419 | ;; Just return the cache. | |
420 | (oref index include-path))) | |
421 | ;; If we were passed in something like a tag list, or other boring | |
422 | ;; searchable item, then instead do the regular thing without caching. | |
423 | (semanticdb-find-translate-path-includes--internal path)))) | |
424 | ||
425 | (defvar semanticdb-find-lost-includes nil | |
426 | "Include files that we cannot find associated with this buffer.") | |
427 | (make-variable-buffer-local 'semanticdb-find-lost-includes) | |
428 | ||
429 | (defvar semanticdb-find-scanned-include-tags nil | |
430 | "All include tags scanned, plus action taken on the tag. | |
431 | Each entry is an alist: | |
432 | (ACTION . TAG) | |
db9e401b | 433 | where ACTION is one of 'scanned, 'duplicate, 'lost |
1bd95535 CY |
434 | and TAG is a clone of the include tag that was found.") |
435 | (make-variable-buffer-local 'semanticdb-find-scanned-include-tags) | |
436 | ||
437 | (defvar semanticdb-implied-include-tags nil | |
438 | "Include tags implied for all files of a given mode. | |
439 | Set this variable with `defvar-mode-local' for a particular mode so | |
440 | that any symbols that exist for all files for that mode are included. | |
441 | ||
9bf6c65c | 442 | Note: This could be used as a way to write a file in a language |
1bd95535 CY |
443 | to declare all the built-ins for that language.") |
444 | ||
445 | (defun semanticdb-find-translate-path-includes--internal (path) | |
446 | "Internal implementation of `semanticdb-find-translate-path-includes-default'. | |
447 | This routine does not depend on the cache, but will always derive | |
448 | a new path from the provided PATH." | |
449 | (let ((includetags nil) | |
450 | (curtable nil) | |
451 | (matchedtables (list semanticdb-current-table)) | |
452 | (matchedincludes nil) | |
453 | (lostincludes nil) | |
454 | (scannedincludes nil) | |
455 | (incfname nil) | |
456 | nexttable) | |
457 | (cond ((null path) | |
458 | (semantic-refresh-tags-safe) | |
459 | (setq includetags (append | |
460 | (semantic-find-tags-included (current-buffer)) | |
461 | semanticdb-implied-include-tags) | |
462 | curtable semanticdb-current-table | |
463 | incfname (buffer-file-name)) | |
464 | ) | |
465 | ((semanticdb-table-p path) | |
466 | (setq includetags (semantic-find-tags-included path) | |
467 | curtable path | |
468 | incfname (semanticdb-full-filename path)) | |
469 | ) | |
470 | ((bufferp path) | |
0816d744 | 471 | (with-current-buffer path |
1bd95535 CY |
472 | (semantic-refresh-tags-safe)) |
473 | (setq includetags (semantic-find-tags-included path) | |
0816d744 SM |
474 | curtable (with-current-buffer path |
475 | semanticdb-current-table) | |
1bd95535 CY |
476 | incfname (buffer-file-name path))) |
477 | (t | |
478 | (setq includetags (semantic-find-tags-included path)) | |
479 | (when includetags | |
480 | ;; If we have some tags, derive a table from them. | |
481 | ;; else we will do nothing, so the table is useless. | |
482 | ||
483 | ;; @todo - derive some tables | |
484 | (message "Need to derive tables for %S in translate-path-includes--default." | |
485 | path) | |
486 | ))) | |
487 | ||
488 | ;; Make sure each found include tag has an originating file name associated | |
489 | ;; with it. | |
490 | (when incfname | |
491 | (dolist (it includetags) | |
492 | (semantic--tag-put-property it :filename incfname))) | |
493 | ||
494 | ;; Loop over all include tags adding to matchedtables | |
495 | (while includetags | |
496 | (semantic-throw-on-input 'semantic-find-translate-path-includes-default) | |
497 | ||
498 | ;; If we've seen this include string before, lets skip it. | |
499 | (if (member (semantic-tag-name (car includetags)) matchedincludes) | |
500 | (progn | |
501 | (setq nexttable nil) | |
502 | (push (cons 'duplicate (semantic-tag-clone (car includetags))) | |
503 | scannedincludes) | |
504 | ) | |
505 | (setq nexttable (semanticdb-find-table-for-include (car includetags) curtable)) | |
506 | (when (not nexttable) | |
507 | ;; Save the lost include. | |
508 | (push (car includetags) lostincludes) | |
509 | (push (cons 'lost (semantic-tag-clone (car includetags))) | |
510 | scannedincludes) | |
511 | ) | |
512 | ) | |
513 | ||
514 | ;; Push the include file, so if we can't find it, we only | |
515 | ;; can't find it once. | |
516 | (push (semantic-tag-name (car includetags)) matchedincludes) | |
517 | ||
518 | ;; (message "Scanning %s" (semantic-tag-name (car includetags))) | |
519 | (when (and nexttable | |
520 | (not (memq nexttable matchedtables)) | |
521 | (semanticdb-equivalent-mode-for-search nexttable | |
522 | (current-buffer)) | |
523 | ) | |
524 | ;; Add to list of tables | |
525 | (push nexttable matchedtables) | |
526 | ||
527 | ;; Queue new includes to list | |
528 | (if (semanticdb-find-throttle-active-p 'recursive) | |
529 | ;; @todo - recursive includes need to have the originating | |
530 | ;; buffer's location added to the path. | |
531 | (let ((newtags | |
532 | (cond | |
533 | ((semanticdb-table-p nexttable) | |
534 | (semanticdb-refresh-table nexttable) | |
535 | ;; Use the method directly, or we will recurse | |
536 | ;; into ourselves here. | |
537 | (semanticdb-find-tags-by-class-method | |
538 | nexttable 'include)) | |
539 | (t ;; @todo - is this ever possible??? | |
540 | (message "semanticdb-ftp - how did you do that?") | |
541 | (semantic-find-tags-included | |
542 | (semanticdb-get-tags nexttable))) | |
543 | )) | |
544 | (newincfname (semanticdb-full-filename nexttable)) | |
545 | ) | |
546 | ||
547 | (push (cons 'scanned (semantic-tag-clone (car includetags))) | |
548 | scannedincludes) | |
549 | ||
550 | ;; Setup new tags so we know where they are. | |
551 | (dolist (it newtags) | |
552 | (semantic--tag-put-property it :filename | |
553 | newincfname)) | |
554 | ||
555 | (setq includetags (nconc includetags newtags))) | |
556 | ;; ELSE - not recursive throttle | |
557 | (push (cons 'scanned-no-recurse | |
558 | (semantic-tag-clone (car includetags))) | |
559 | scannedincludes) | |
560 | ) | |
561 | ) | |
562 | (setq includetags (cdr includetags))) | |
563 | ||
564 | (setq semanticdb-find-lost-includes lostincludes) | |
565 | (setq semanticdb-find-scanned-include-tags (reverse scannedincludes)) | |
566 | ||
567 | ;; Find all the omniscient databases for this major mode, and | |
568 | ;; add them if needed | |
569 | (when (and (semanticdb-find-throttle-active-p 'omniscience) | |
570 | semanticdb-search-system-databases) | |
571 | ;; We can append any mode-specific omniscience databases into | |
572 | ;; our search list here. | |
573 | (let ((systemdb semanticdb-project-system-databases) | |
574 | (ans nil)) | |
575 | (while systemdb | |
576 | (setq ans (semanticdb-file-table | |
577 | (car systemdb) | |
578 | ;; I would expect most omniscient to return the same | |
579 | ;; thing reguardless of filename, but we may have | |
580 | ;; one that can return a table of all things the | |
581 | ;; current file needs. | |
582 | (buffer-file-name (current-buffer)))) | |
583 | (when (not (memq ans matchedtables)) | |
584 | (setq matchedtables (cons ans matchedtables))) | |
585 | (setq systemdb (cdr systemdb)))) | |
586 | ) | |
587 | (nreverse matchedtables))) | |
588 | ||
589 | (define-overloadable-function semanticdb-find-load-unloaded (filename) | |
590 | "Create a database table for FILENAME if it hasn't been parsed yet. | |
591 | Assumes that FILENAME exists as a source file. | |
592 | Assumes that a preexisting table does not exist, even if it | |
593 | isn't in memory yet." | |
594 | (if (semanticdb-find-throttle-active-p 'unloaded) | |
595 | (:override) | |
596 | (semanticdb-file-table-object filename t))) | |
597 | ||
598 | (defun semanticdb-find-load-unloaded-default (filename) | |
599 | "Load an unloaded file in FILENAME using the default semanticdb loader." | |
600 | (semanticdb-file-table-object filename)) | |
601 | ||
a964f5e5 | 602 | ;; The creation of the overload occurs above. |
1bd95535 CY |
603 | (defun semanticdb-find-table-for-include-default (includetag &optional table) |
604 | "Default implementation of `semanticdb-find-table-for-include'. | |
605 | Uses `semanticdb-current-database-list' as the search path. | |
606 | INCLUDETAG and TABLE are documented in `semanticdb-find-table-for-include'. | |
607 | Included databases are filtered based on `semanticdb-find-default-throttle'." | |
608 | (if (not (eq (semantic-tag-class includetag) 'include)) | |
609 | (signal 'wrong-type-argument (list includetag 'include))) | |
610 | ||
611 | (let ((name | |
612 | ;; Note, some languages (like Emacs or Java) use include tag names | |
613 | ;; that don't represent files! We want to have file names. | |
614 | (semantic-tag-include-filename includetag)) | |
615 | (originfiledir nil) | |
616 | (roots nil) | |
617 | (tmp nil) | |
618 | (ans nil)) | |
619 | ||
620 | ;; INCLUDETAG should have some way to reference where it came | |
621 | ;; from! If not, TABLE should provide the way. Each time we | |
622 | ;; look up a tag, we may need to find it in some relative way | |
623 | ;; and must set our current buffer eto the origin of includetag | |
624 | ;; or nothing may work. | |
625 | (setq originfiledir | |
626 | (cond ((semantic-tag-file-name includetag) | |
627 | ;; A tag may have a buffer, or a :filename property. | |
628 | (file-name-directory (semantic-tag-file-name includetag))) | |
629 | (table | |
630 | (file-name-directory (semanticdb-full-filename table))) | |
631 | (t | |
632 | ;; @todo - what to do here? Throw an error maybe | |
633 | ;; and fix usage bugs? | |
634 | default-directory))) | |
635 | ||
636 | (cond | |
637 | ;; Step 1: Relative path name | |
638 | ;; | |
639 | ;; If the name is relative, then it should be findable as relative | |
640 | ;; to the source file that this tag originated in, and be fast. | |
641 | ;; | |
642 | ((and (semanticdb-find-throttle-active-p 'local) | |
643 | (file-exists-p (expand-file-name name originfiledir))) | |
644 | ||
645 | (setq ans (semanticdb-find-load-unloaded | |
646 | (expand-file-name name originfiledir))) | |
647 | ) | |
648 | ;; Step 2: System or Project level includes | |
649 | ;; | |
650 | ((or | |
651 | ;; First, if it a system include, we can investigate that tags | |
652 | ;; dependency file | |
653 | (and (semanticdb-find-throttle-active-p 'system) | |
654 | ||
655 | ;; Sadly, not all languages make this distinction. | |
656 | ;;(semantic-tag-include-system-p includetag) | |
657 | ||
658 | ;; Here, we get local and system files. | |
659 | (setq tmp (semantic-dependency-tag-file includetag)) | |
660 | ) | |
661 | ;; Second, project files are active, we and we have EDE, | |
662 | ;; we can find it using the same tool. | |
663 | (and (semanticdb-find-throttle-active-p 'project) | |
664 | ;; Make sure EDE is available, and we have a project | |
665 | (featurep 'ede) (ede-current-project originfiledir) | |
666 | ;; The EDE query is hidden in this call. | |
667 | (setq tmp (semantic-dependency-tag-file includetag)) | |
668 | ) | |
669 | ) | |
670 | (setq ans (semanticdb-find-load-unloaded tmp)) | |
671 | ) | |
672 | ;; Somewhere in our project hierarchy | |
673 | ;; | |
674 | ;; Remember: Roots includes system databases which can create | |
675 | ;; specialized tables we can search. | |
676 | ;; | |
677 | ;; NOTE: Not used if EDE is active! | |
678 | ((and (semanticdb-find-throttle-active-p 'project) | |
679 | ;; And dont do this if it is a system include. Not supported by all languages, | |
680 | ;; but when it is, this is a nice fast way to skip this step. | |
681 | (not (semantic-tag-include-system-p includetag)) | |
682 | ;; Don't do this if we have an EDE project. | |
683 | (not (and (featurep 'ede) | |
684 | ;; Note: We don't use originfiledir here because | |
685 | ;; we want to know about the source file we are | |
686 | ;; starting from. | |
687 | (ede-current-project))) | |
688 | ) | |
689 | ||
690 | (setq roots (semanticdb-current-database-list)) | |
691 | ||
692 | (while (and (not ans) roots) | |
693 | (let* ((ref (if (slot-boundp (car roots) 'reference-directory) | |
694 | (oref (car roots) reference-directory))) | |
695 | (fname (cond ((null ref) nil) | |
696 | ((file-exists-p (expand-file-name name ref)) | |
697 | (expand-file-name name ref)) | |
698 | ((file-exists-p (expand-file-name (file-name-nondirectory name) ref)) | |
699 | (expand-file-name (file-name-nondirectory name) ref))))) | |
700 | (when (and ref fname) | |
701 | ;; There is an actual file. Grab it. | |
702 | (setq ans (semanticdb-find-load-unloaded fname))) | |
703 | ||
704 | ;; ELSE | |
705 | ;; | |
706 | ;; NOTE: We used to look up omniscient databases here, but that | |
707 | ;; is now handled one layer up. | |
708 | ;; | |
709 | ;; Missing: a database that knows where missing files are. Hmm. | |
710 | ;; perhaps I need an override function for that? | |
711 | ||
712 | ) | |
713 | ||
714 | (setq roots (cdr roots)))) | |
715 | ) | |
716 | ans)) | |
717 | ||
718 | \f | |
719 | ;;; Perform interactive tests on the path/search mechanisms. | |
720 | ;; | |
cdaea6f1 | 721 | ;;;###autoload |
1bd95535 CY |
722 | (defun semanticdb-find-test-translate-path (&optional arg) |
723 | "Call and output results of `semanticdb-find-translate-path'. | |
724 | With ARG non-nil, specify a BRUTISH translation. | |
725 | See `semanticdb-find-default-throttle' and `semanticdb-project-roots' | |
726 | for details on how this list is derived." | |
727 | (interactive "P") | |
728 | (semantic-fetch-tags) | |
729 | (require 'data-debug) | |
730 | (let ((start (current-time)) | |
731 | (p (semanticdb-find-translate-path nil arg)) | |
732 | (end (current-time)) | |
733 | ) | |
734 | (data-debug-new-buffer "*SEMANTICDB FTP ADEBUG*") | |
735 | (message "Search of tags took %.2f seconds." | |
736 | (semantic-elapsed-time start end)) | |
737 | ||
738 | (data-debug-insert-stuff-list p "*"))) | |
739 | ||
740 | (defun semanticdb-find-test-translate-path-no-loading (&optional arg) | |
741 | "Call and output results of `semanticdb-find-translate-path'. | |
742 | With ARG non-nil, specify a BRUTISH translation. | |
743 | See `semanticdb-find-default-throttle' and `semanticdb-project-roots' | |
744 | for details on how this list is derived." | |
745 | (interactive "P") | |
746 | (semantic-fetch-tags) | |
747 | (require 'data-debug) | |
748 | (let* ((semanticdb-find-default-throttle | |
a60f2e7b | 749 | (if (featurep 'semantic/db-find) |
1bd95535 CY |
750 | (remq 'unloaded semanticdb-find-default-throttle) |
751 | nil)) | |
752 | (start (current-time)) | |
753 | (p (semanticdb-find-translate-path nil arg)) | |
754 | (end (current-time)) | |
755 | ) | |
756 | (data-debug-new-buffer "*SEMANTICDB FTP ADEBUG*") | |
757 | (message "Search of tags took %.2f seconds." | |
758 | (semantic-elapsed-time start end)) | |
759 | ||
760 | (data-debug-insert-stuff-list p "*"))) | |
761 | ||
cdaea6f1 | 762 | ;;;###autoload |
1bd95535 CY |
763 | (defun semanticdb-find-adebug-lost-includes () |
764 | "Translate the current path, then display the lost includes. | |
765 | Examines the variable `semanticdb-find-lost-includes'." | |
766 | (interactive) | |
767 | (require 'data-debug) | |
768 | (semanticdb-find-translate-path nil nil) | |
769 | (let ((lost semanticdb-find-lost-includes) | |
770 | ) | |
771 | ||
772 | (if (not lost) | |
773 | (message "There are no unknown includes for %s" | |
774 | (buffer-name)) | |
775 | ||
776 | (data-debug-new-buffer "*SEMANTICDB lost-includes ADEBUG*") | |
d86d8ea8 | 777 | ;; (data-debug-insert-tag-list lost "*") |
1bd95535 CY |
778 | ))) |
779 | ||
780 | (defun semanticdb-find-adebug-insert-scanned-tag-cons (consdata prefix prebuttontext) | |
781 | "Insert a button representing scanned include CONSDATA. | |
9bf6c65c | 782 | PREFIX is the text that precedes the button. |
1bd95535 CY |
783 | PREBUTTONTEXT is some text between prefix and the overlay button." |
784 | (let* ((start (point)) | |
785 | (end nil) | |
786 | (mode (car consdata)) | |
787 | (tag (cdr consdata)) | |
788 | (name (semantic-tag-name tag)) | |
789 | (file (semantic-tag-file-name tag)) | |
790 | (str1 (format "%S %s" mode name)) | |
791 | (str2 (format " : %s" file)) | |
792 | (tip nil)) | |
793 | (insert prefix prebuttontext str1) | |
794 | (setq end (point)) | |
795 | (insert str2) | |
796 | (put-text-property start end 'face | |
797 | (cond ((eq mode 'scanned) | |
798 | 'font-lock-function-name-face) | |
799 | ((eq mode 'duplicate) | |
800 | 'font-lock-comment-face) | |
801 | ((eq mode 'lost) | |
802 | 'font-lock-variable-name-face) | |
803 | ((eq mode 'scanned-no-recurse) | |
804 | 'font-lock-type-face))) | |
805 | (put-text-property start end 'ddebug (cdr consdata)) | |
806 | (put-text-property start end 'ddebug-indent(length prefix)) | |
807 | (put-text-property start end 'ddebug-prefix prefix) | |
808 | (put-text-property start end 'help-echo tip) | |
809 | (put-text-property start end 'ddebug-function | |
810 | 'data-debug-insert-tag-parts-from-point) | |
811 | (insert "\n") | |
812 | ) | |
813 | ) | |
814 | ||
815 | (defun semanticdb-find-adebug-scanned-includes () | |
816 | "Translate the current path, then display the lost includes. | |
817 | Examines the variable `semanticdb-find-lost-includes'." | |
818 | (interactive) | |
819 | (require 'data-debug) | |
820 | (semanticdb-find-translate-path nil nil) | |
821 | (let ((scanned semanticdb-find-scanned-include-tags) | |
822 | (data-debug-thing-alist | |
823 | (cons | |
824 | '((lambda (thing) (and (consp thing) | |
825 | (symbolp (car thing)) | |
826 | (memq (car thing) | |
827 | '(scanned scanned-no-recurse | |
828 | lost duplicate)))) | |
829 | . semanticdb-find-adebug-insert-scanned-tag-cons) | |
830 | data-debug-thing-alist)) | |
831 | ) | |
832 | ||
833 | (if (not scanned) | |
834 | (message "There are no includes scanned %s" | |
835 | (buffer-name)) | |
836 | ||
837 | (data-debug-new-buffer "*SEMANTICDB scanned-includes ADEBUG*") | |
838 | (data-debug-insert-stuff-list scanned "*") | |
839 | ))) | |
840 | \f | |
1bd95535 CY |
841 | ;;; API Functions |
842 | ;; | |
843 | ;; Once you have a search result, use these routines to operate | |
844 | ;; on the search results at a higher level | |
845 | ||
3d9d8486 | 846 | ;;;###autoload |
1bd95535 CY |
847 | (defun semanticdb-strip-find-results (results &optional find-file-match) |
848 | "Strip a semanticdb search RESULTS to exclude objects. | |
849 | This makes it appear more like the results of a `semantic-find-' call. | |
850 | Optional FIND-FILE-MATCH loads all files associated with RESULTS | |
851 | into buffers. This has the side effect of enabling `semantic-tag-buffer' to | |
852 | return a value. | |
853 | If FIND-FILE-MATCH is 'name, then only the filename is stored | |
854 | in each tag instead of loading each file into a buffer. | |
855 | If the input RESULTS are not going to be used again, and if | |
856 | FIND-FILE-MATCH is nil, you can use `semanticdb-fast-strip-find-results' | |
857 | instead." | |
858 | (if find-file-match | |
859 | ;; Load all files associated with RESULTS. | |
860 | (let ((tmp results) | |
861 | (output nil)) | |
862 | (while tmp | |
863 | (let ((tab (car (car tmp))) | |
864 | (tags (cdr (car tmp)))) | |
865 | (dolist (T tags) | |
866 | ;; Normilzation gives specialty database tables a chance | |
867 | ;; to convert into a more stable tag format. | |
868 | (let* ((norm (semanticdb-normalize-one-tag tab T)) | |
869 | (ntab (car norm)) | |
870 | (ntag (cdr norm)) | |
871 | (nametable ntab)) | |
872 | ||
873 | ;; If it didn't normalize, use what we had. | |
874 | (if (not norm) | |
875 | (setq nametable tab) | |
876 | (setq output (append output (list ntag)))) | |
877 | ||
878 | ;; Find-file-match allows a tool to make sure the tag is | |
879 | ;; 'live', somewhere in a buffer. | |
880 | (cond ((eq find-file-match 'name) | |
881 | (let ((f (semanticdb-full-filename nametable))) | |
882 | (semantic--tag-put-property ntag :filename f))) | |
883 | ((and find-file-match ntab) | |
884 | (semanticdb-get-buffer ntab)) | |
885 | ) | |
886 | )) | |
887 | ) | |
888 | (setq tmp (cdr tmp))) | |
889 | output) | |
890 | ;; @todo - I could use nconc, but I don't know what the caller may do with | |
891 | ;; RESULTS after this is called. Right now semantic-complete will | |
892 | ;; recycling the input after calling this routine. | |
893 | (apply #'append (mapcar #'cdr results)))) | |
894 | ||
895 | (defun semanticdb-fast-strip-find-results (results) | |
896 | "Destructively strip a semanticdb search RESULTS to exclude objects. | |
897 | This makes it appear more like the results of a `semantic-find-' call. | |
898 | This is like `semanticdb-strip-find-results', except the input list RESULTS | |
899 | will be changed." | |
900 | (apply #'nconc (mapcar #'cdr results))) | |
901 | ||
902 | (defun semanticdb-find-results-p (resultp) | |
903 | "Non-nil if RESULTP is in the form of a semanticdb search result. | |
904 | This query only really tests the first entry in the list that is RESULTP, | |
905 | but should be good enough for debugging assertions." | |
906 | (and (listp resultp) | |
907 | (listp (car resultp)) | |
908 | (semanticdb-abstract-table-child-p (car (car resultp))) | |
909 | (or (semantic-tag-p (car (cdr (car resultp)))) | |
910 | (null (car (cdr (car resultp))))))) | |
911 | ||
912 | (defun semanticdb-find-result-prin1-to-string (result) | |
913 | "Presuming RESULT satisfies `semanticdb-find-results-p', provide a short PRIN1 output." | |
914 | (if (< (length result) 2) | |
915 | (concat "#<FIND RESULT " | |
916 | (mapconcat (lambda (a) | |
917 | (concat "(" (object-name (car a) ) " . " | |
918 | "#<TAG LIST " (number-to-string (length (cdr a))) ">)")) | |
919 | result | |
920 | " ") | |
921 | ">") | |
922 | ;; Longer results should have an abreviated form. | |
923 | (format "#<FIND RESULT %d TAGS in %d FILES>" | |
924 | (semanticdb-find-result-length result) | |
925 | (length result)))) | |
926 | ||
927 | (defun semanticdb-find-result-with-nil-p (resultp) | |
928 | "Non-nil of RESULTP is in the form of a semanticdb search result. | |
db9e401b | 929 | The value nil is valid where a TABLE usually is, but only if the TAG |
1bd95535 CY |
930 | results include overlays. |
931 | This query only really tests the first entry in the list that is RESULTP, | |
932 | but should be good enough for debugging assertions." | |
933 | (and (listp resultp) | |
934 | (listp (car resultp)) | |
935 | (let ((tag-to-test (car-safe (cdr (car resultp))))) | |
936 | (or (and (semanticdb-abstract-table-child-p (car (car resultp))) | |
937 | (or (semantic-tag-p tag-to-test) | |
938 | (null tag-to-test))) | |
939 | (and (null (car (car resultp))) | |
940 | (or (semantic-tag-with-position-p tag-to-test) | |
941 | (null tag-to-test)))) | |
942 | ))) | |
943 | ||
3d9d8486 | 944 | ;;;###autoload |
1bd95535 CY |
945 | (defun semanticdb-find-result-length (result) |
946 | "Number of tags found in RESULT." | |
947 | (let ((count 0)) | |
948 | (mapc (lambda (onetable) | |
949 | (setq count (+ count (1- (length onetable))))) | |
950 | result) | |
951 | count)) | |
952 | ||
3d9d8486 | 953 | ;;;###autoload |
1bd95535 CY |
954 | (defun semanticdb-find-result-nth (result n) |
955 | "In RESULT, return the Nth search result. | |
956 | This is a 0 based search result, with the first match being element 0. | |
957 | ||
958 | The returned value is a cons cell: (TAG . TABLE) where TAG | |
959 | is the tag at the Nth position. TABLE is the semanticdb table where | |
960 | the TAG was found. Sometimes TABLE can be nil." | |
961 | (let ((ans nil) | |
962 | (anstable nil)) | |
963 | ;; Loop over each single table hit. | |
964 | (while (and (not ans) result) | |
965 | ;; For each table result, get local length, and modify | |
966 | ;; N to be that much less. | |
967 | (let ((ll (length (cdr (car result))))) ;; local length | |
968 | (if (> ll n) | |
969 | ;; We have a local match. | |
970 | (setq ans (nth n (cdr (car result))) | |
971 | anstable (car (car result))) | |
972 | ;; More to go. Decrement N. | |
973 | (setq n (- n ll)))) | |
974 | ;; Keep moving. | |
975 | (setq result (cdr result))) | |
976 | (cons ans anstable))) | |
977 | ||
978 | (defun semanticdb-find-result-test (result) | |
979 | "Test RESULT by accessing all the tags in the list." | |
980 | (if (not (semanticdb-find-results-p result)) | |
981 | (error "Does not pass `semanticdb-find-results-p.\n")) | |
982 | (let ((len (semanticdb-find-result-length result)) | |
983 | (i 0)) | |
984 | (while (< i len) | |
985 | (let ((tag (semanticdb-find-result-nth result i))) | |
986 | (if (not (semantic-tag-p (car tag))) | |
987 | (error "%d entry is not a tag" i))) | |
988 | (setq i (1+ i))))) | |
989 | ||
3d9d8486 | 990 | ;;;###autoload |
1bd95535 CY |
991 | (defun semanticdb-find-result-nth-in-buffer (result n) |
992 | "In RESULT, return the Nth search result. | |
993 | Like `semanticdb-find-result-nth', except that only the TAG | |
994 | is returned, and the buffer it is found it will be made current. | |
995 | If the result tag has no position information, the originating buffer | |
996 | is still made current." | |
997 | (let* ((ret (semanticdb-find-result-nth result n)) | |
998 | (ans (car ret)) | |
999 | (anstable (cdr ret))) | |
1000 | ;; If we have a hit, double-check the find-file | |
1001 | ;; entry. If the file must be loaded, then gat that table's | |
1002 | ;; source file into a buffer. | |
1003 | ||
1004 | (if anstable | |
1005 | (let ((norm (semanticdb-normalize-one-tag anstable ans))) | |
1006 | (when norm | |
1007 | ;; The normalized tags can now be found based on that | |
1008 | ;; tags table. | |
dd9af436 CY |
1009 | (condition-case foo |
1010 | (progn | |
1011 | (semanticdb-set-buffer (car norm)) | |
1012 | ;; Now reset ans | |
1013 | (setq ans (cdr norm))) | |
1014 | ;; Don't error for this case, but don't store | |
1015 | ;; the thing either. | |
1016 | (no-method-definition nil)) | |
1bd95535 CY |
1017 | )) |
1018 | ) | |
1019 | ;; Return the tag. | |
1020 | ans)) | |
1021 | ||
1022 | (defun semanticdb-find-result-mapc (fcn result) | |
1023 | "Apply FCN to each element of find RESULT for side-effects only. | |
1024 | FCN takes two arguments. The first is a TAG, and the | |
9bf6c65c | 1025 | second is a DB from whence TAG originated. |
1bd95535 | 1026 | Returns result." |
dd9af436 CY |
1027 | (mapc (lambda (sublst-icky) |
1028 | (mapc (lambda (tag-icky) | |
1029 | (funcall fcn tag-icky (car sublst-icky))) | |
1030 | (cdr sublst-icky))) | |
1bd95535 CY |
1031 | result) |
1032 | result) | |
1033 | ||
1034 | ;;; Search Logging | |
1035 | ;; | |
1036 | ;; Basic logging to see what the search routines are doing. | |
1037 | (defvar semanticdb-find-log-flag nil | |
1038 | "Non-nil means log the process of searches.") | |
1039 | ||
1040 | (defvar semanticdb-find-log-buffer-name "*SemanticDB Find Log*" | |
1041 | "The name of the logging buffer.") | |
1042 | ||
1043 | (defun semanticdb-find-toggle-logging () | |
9bf6c65c | 1044 | "Toggle semanticdb logging." |
1bd95535 CY |
1045 | (interactive) |
1046 | (setq semanticdb-find-log-flag (null semanticdb-find-log-flag)) | |
1047 | (message "Semanticdb find logging is %sabled" | |
1048 | (if semanticdb-find-log-flag "en" "dis"))) | |
1049 | ||
1050 | (defun semanticdb-reset-log () | |
1051 | "Reset the log buffer." | |
1052 | (interactive) | |
1053 | (when semanticdb-find-log-flag | |
0816d744 | 1054 | (with-current-buffer (get-buffer-create semanticdb-find-log-buffer-name) |
1bd95535 CY |
1055 | (erase-buffer) |
1056 | ))) | |
1057 | ||
1058 | (defun semanticdb-find-log-move-to-end () | |
1059 | "Move to the end of the semantic log." | |
1060 | (let ((cb (current-buffer)) | |
1061 | (cw (selected-window))) | |
1062 | (unwind-protect | |
1063 | (progn | |
1064 | (set-buffer semanticdb-find-log-buffer-name) | |
1065 | (if (get-buffer-window (current-buffer) 'visible) | |
1066 | (select-window (get-buffer-window (current-buffer) 'visible))) | |
1067 | (goto-char (point-max))) | |
1068 | (if cw (select-window cw)) | |
1069 | (set-buffer cb)))) | |
1070 | ||
1071 | (defun semanticdb-find-log-new-search (forwhat) | |
1072 | "Start a new search FORWHAT." | |
1073 | (when semanticdb-find-log-flag | |
0816d744 | 1074 | (with-current-buffer (get-buffer-create semanticdb-find-log-buffer-name) |
1bd95535 CY |
1075 | (insert (format "New Search: %S\n" forwhat)) |
1076 | ) | |
1077 | (semanticdb-find-log-move-to-end))) | |
1078 | ||
1079 | (defun semanticdb-find-log-activity (table result) | |
1080 | "Log that TABLE has been searched and RESULT was found." | |
1081 | (when semanticdb-find-log-flag | |
0816d744 | 1082 | (with-current-buffer semanticdb-find-log-buffer-name |
1bd95535 CY |
1083 | (insert "Table: " (object-print table) |
1084 | " Result: " (int-to-string (length result)) " tags" | |
1085 | "\n") | |
1086 | ) | |
1087 | (semanticdb-find-log-move-to-end))) | |
1088 | ||
1089 | ;;; Semanticdb find API functions | |
1bd95535 CY |
1090 | ;; These are the routines actually used to perform searches. |
1091 | ;; | |
1092 | (defun semanticdb-find-tags-collector (function &optional path find-file-match | |
1093 | brutish) | |
1094 | "Collect all tags returned by FUNCTION over PATH. | |
1095 | The FUNCTION must take two arguments. The first is TABLE, | |
1096 | which is a semanticdb table containing tags. The second argument | |
db9e401b JB |
1097 | to FUNCTION is TAGS. TAGS may be a list of tags. If TAGS is non-nil, |
1098 | then FUNCTION should search the TAG list, not through TABLE. | |
1bd95535 CY |
1099 | |
1100 | See `semanticdb-find-translate-path' for details on PATH. | |
1101 | FIND-FILE-MATCH indicates that any time a match is found, the file | |
1102 | associated with that tag should be loaded into a buffer. | |
1103 | ||
1104 | Note: You should leave FIND-FILE-MATCH as nil. It is far more | |
1105 | efficient to take the results from any search and use | |
1106 | `semanticdb-strip-find-results' instead. This argument is here | |
1107 | for backward compatibility. | |
1108 | ||
1109 | If optional argument BRUTISH is non-nil, then ignore include statements, | |
1110 | and search all tables in this project tree." | |
1111 | (let (found match) | |
1112 | (save-excursion | |
1113 | ;; If path is a buffer, set ourselves up in that buffer | |
1114 | ;; so that the override methods work correctly. | |
1115 | (when (bufferp path) (set-buffer path)) | |
1116 | (if (semanticdb-find-results-p path) | |
1117 | ;; When we get find results, loop over that. | |
1118 | (dolist (tableandtags path) | |
1119 | (semantic-throw-on-input 'semantic-find-translate-path) | |
1120 | ;; If FIND-FILE-MATCH is non-nil, skip tables of class | |
1121 | ;; `semanticdb-search-results-table', since those are system | |
1122 | ;; databases and not associated with a file. | |
1123 | (unless (and find-file-match | |
1124 | (obj-of-class-p | |
1125 | (car tableandtags) semanticdb-search-results-table)) | |
1126 | (when (setq match (funcall function | |
1127 | (car tableandtags) (cdr tableandtags))) | |
1128 | (when find-file-match | |
1129 | (save-excursion (semanticdb-set-buffer (car tableandtags)))) | |
1130 | (push (cons (car tableandtags) match) found))) | |
1131 | ) | |
1132 | ;; Only log searches across data bases. | |
1133 | (semanticdb-find-log-new-search nil) | |
1134 | ;; If we get something else, scan the list of tables resulting | |
1135 | ;; from translating it into a list of objects. | |
1136 | (dolist (table (semanticdb-find-translate-path path brutish)) | |
1137 | (semantic-throw-on-input 'semantic-find-translate-path) | |
1138 | ;; If FIND-FILE-MATCH is non-nil, skip tables of class | |
1139 | ;; `semanticdb-search-results-table', since those are system | |
1140 | ;; databases and not associated with a file. | |
1141 | (unless (and find-file-match | |
1142 | (obj-of-class-p table semanticdb-search-results-table)) | |
1143 | (when (and table (setq match (funcall function table nil))) | |
1144 | (semanticdb-find-log-activity table match) | |
1145 | (when find-file-match | |
1146 | (save-excursion (semanticdb-set-buffer table))) | |
1147 | (push (cons table match) found)))))) | |
1148 | ;; At this point, FOUND has had items pushed onto it. | |
1149 | ;; This means items are being returned in REVERSE order | |
1150 | ;; of the tables searched, so if you just get th CAR, then | |
1151 | ;; too-bad, you may have some system-tag that has no | |
1152 | ;; buffer associated with it. | |
1153 | ||
1154 | ;; It must be reversed. | |
1155 | (nreverse found))) | |
1156 | ||
3d9d8486 | 1157 | ;;;###autoload |
1bd95535 CY |
1158 | (defun semanticdb-find-tags-by-name (name &optional path find-file-match) |
1159 | "Search for all tags matching NAME on PATH. | |
1160 | See `semanticdb-find-translate-path' for details on PATH. | |
1161 | FIND-FILE-MATCH indicates that any time a match is found, the file | |
1162 | associated with that tag should be loaded into a buffer." | |
1163 | (semanticdb-find-tags-collector | |
1164 | (lambda (table tags) | |
1165 | (semanticdb-find-tags-by-name-method table name tags)) | |
1166 | path find-file-match)) | |
1167 | ||
3d9d8486 | 1168 | ;;;###autoload |
1bd95535 CY |
1169 | (defun semanticdb-find-tags-by-name-regexp (regexp &optional path find-file-match) |
1170 | "Search for all tags matching REGEXP on PATH. | |
1171 | See `semanticdb-find-translate-path' for details on PATH. | |
1172 | FIND-FILE-MATCH indicates that any time a match is found, the file | |
1173 | associated with that tag should be loaded into a buffer." | |
1174 | (semanticdb-find-tags-collector | |
1175 | (lambda (table tags) | |
1176 | (semanticdb-find-tags-by-name-regexp-method table regexp tags)) | |
1177 | path find-file-match)) | |
1178 | ||
3d9d8486 | 1179 | ;;;###autoload |
1bd95535 CY |
1180 | (defun semanticdb-find-tags-for-completion (prefix &optional path find-file-match) |
1181 | "Search for all tags matching PREFIX on PATH. | |
1182 | See `semanticdb-find-translate-path' for details on PATH. | |
1183 | FIND-FILE-MATCH indicates that any time a match is found, the file | |
1184 | associated with that tag should be loaded into a buffer." | |
1185 | (semanticdb-find-tags-collector | |
1186 | (lambda (table tags) | |
1187 | (semanticdb-find-tags-for-completion-method table prefix tags)) | |
1188 | path find-file-match)) | |
1189 | ||
3d9d8486 | 1190 | ;;;###autoload |
1bd95535 CY |
1191 | (defun semanticdb-find-tags-by-class (class &optional path find-file-match) |
1192 | "Search for all tags of CLASS on PATH. | |
1193 | See `semanticdb-find-translate-path' for details on PATH. | |
1194 | FIND-FILE-MATCH indicates that any time a match is found, the file | |
1195 | associated with that tag should be loaded into a buffer." | |
1196 | (semanticdb-find-tags-collector | |
1197 | (lambda (table tags) | |
1198 | (semanticdb-find-tags-by-class-method table class tags)) | |
1199 | path find-file-match)) | |
1200 | ||
1201 | ;;; Deep Searches | |
1202 | (defun semanticdb-deep-find-tags-by-name (name &optional path find-file-match) | |
1203 | "Search for all tags matching NAME on PATH. | |
1204 | Search also in all components of top level tags founds. | |
1205 | See `semanticdb-find-translate-path' for details on PATH. | |
1206 | FIND-FILE-MATCH indicates that any time a match is found, the file | |
1207 | associated with that tag should be loaded into a buffer." | |
1208 | (semanticdb-find-tags-collector | |
1209 | (lambda (table tags) | |
1210 | (semanticdb-deep-find-tags-by-name-method table name tags)) | |
1211 | path find-file-match)) | |
1212 | ||
1213 | (defun semanticdb-deep-find-tags-by-name-regexp (regexp &optional path find-file-match) | |
1214 | "Search for all tags matching REGEXP on PATH. | |
1215 | Search also in all components of top level tags founds. | |
1216 | See `semanticdb-find-translate-path' for details on PATH. | |
1217 | FIND-FILE-MATCH indicates that any time a match is found, the file | |
1218 | associated with that tag should be loaded into a buffer." | |
1219 | (semanticdb-find-tags-collector | |
1220 | (lambda (table tags) | |
1221 | (semanticdb-deep-find-tags-by-name-regexp-method table regexp tags)) | |
1222 | path find-file-match)) | |
1223 | ||
1224 | (defun semanticdb-deep-find-tags-for-completion (prefix &optional path find-file-match) | |
1225 | "Search for all tags matching PREFIX on PATH. | |
1226 | Search also in all components of top level tags founds. | |
1227 | See `semanticdb-find-translate-path' for details on PATH. | |
1228 | FIND-FILE-MATCH indicates that any time a match is found, the file | |
1229 | associated with that tag should be loaded into a buffer." | |
1230 | (semanticdb-find-tags-collector | |
1231 | (lambda (table tags) | |
1232 | (semanticdb-deep-find-tags-for-completion-method table prefix tags)) | |
1233 | path find-file-match)) | |
1234 | ||
1235 | ;;; Brutish Search Routines | |
3d9d8486 | 1236 | ;; |
1bd95535 CY |
1237 | (defun semanticdb-brute-deep-find-tags-by-name (name &optional path find-file-match) |
1238 | "Search for all tags matching NAME on PATH. | |
1239 | See `semanticdb-find-translate-path' for details on PATH. | |
1240 | The argument BRUTISH will be set so that searching includes all tables | |
1241 | in the current project. | |
9bf6c65c | 1242 | FIND-FILE-MATCH indicates that any time a match is found, the file |
1bd95535 CY |
1243 | associated wit that tag should be loaded into a buffer." |
1244 | (semanticdb-find-tags-collector | |
1245 | (lambda (table tags) | |
1246 | (semanticdb-deep-find-tags-by-name-method table name tags)) | |
1247 | path find-file-match t)) | |
1248 | ||
1249 | (defun semanticdb-brute-deep-find-tags-for-completion (prefix &optional path find-file-match) | |
1250 | "Search for all tags matching PREFIX on PATH. | |
1251 | See `semanticdb-find-translate-path' for details on PATH. | |
1252 | The argument BRUTISH will be set so that searching includes all tables | |
1253 | in the current project. | |
9bf6c65c | 1254 | FIND-FILE-MATCH indicates that any time a match is found, the file |
1bd95535 CY |
1255 | associated wit that tag should be loaded into a buffer." |
1256 | (semanticdb-find-tags-collector | |
1257 | (lambda (table tags) | |
1258 | (semanticdb-deep-find-tags-for-completion-method table prefix tags)) | |
1259 | path find-file-match t)) | |
1260 | ||
1261 | (defun semanticdb-brute-find-tags-by-class (class &optional path find-file-match) | |
1262 | "Search for all tags of CLASS on PATH. | |
1263 | See `semanticdb-find-translate-path' for details on PATH. | |
1264 | The argument BRUTISH will be set so that searching includes all tables | |
1265 | in the current project. | |
1266 | FIND-FILE-MATCH indicates that any time a match is found, the file | |
1267 | associated with that tag should be loaded into a buffer." | |
1268 | (semanticdb-find-tags-collector | |
1269 | (lambda (table tags) | |
1270 | (semanticdb-find-tags-by-class-method table class tags)) | |
1271 | path find-file-match t)) | |
1272 | ||
1273 | ;;; Specialty Search Routines | |
1274 | (defun semanticdb-find-tags-external-children-of-type | |
1275 | (type &optional path find-file-match) | |
1276 | "Search for all tags defined outside of TYPE w/ TYPE as a parent. | |
1277 | See `semanticdb-find-translate-path' for details on PATH. | |
1278 | FIND-FILE-MATCH indicates that any time a match is found, the file | |
1279 | associated with that tag should be loaded into a buffer." | |
1280 | (semanticdb-find-tags-collector | |
1281 | (lambda (table tags) | |
1282 | (semanticdb-find-tags-external-children-of-type-method table type tags)) | |
1283 | path find-file-match)) | |
1284 | ||
1285 | (defun semanticdb-find-tags-subclasses-of-type | |
1286 | (type &optional path find-file-match) | |
1287 | "Search for all tags of class type defined that subclass TYPE. | |
1288 | See `semanticdb-find-translate-path' for details on PATH. | |
1289 | FIND-FILE-MATCH indicates that any time a match is found, the file | |
1290 | associated with that tag should be loaded into a buffer." | |
1291 | (semanticdb-find-tags-collector | |
1292 | (lambda (table tags) | |
1293 | (semanticdb-find-tags-subclasses-of-type-method table type tags)) | |
1294 | path find-file-match t)) | |
1295 | \f | |
1296 | ;;; METHODS | |
1297 | ;; | |
1298 | ;; Default methods for semanticdb database and table objects. | |
1299 | ;; Override these with system databases to as new types of back ends. | |
1300 | ||
1301 | ;;; Top level Searches | |
1302 | (defmethod semanticdb-find-tags-by-name-method ((table semanticdb-abstract-table) name &optional tags) | |
db9e401b | 1303 | "In TABLE, find all occurrences of tags with NAME. |
1bd95535 CY |
1304 | Optional argument TAGS is a list of tags to search. |
1305 | Returns a table of all matching tags." | |
1306 | (semantic-find-tags-by-name name (or tags (semanticdb-get-tags table)))) | |
1307 | ||
1308 | (defmethod semanticdb-find-tags-by-name-regexp-method ((table semanticdb-abstract-table) regexp &optional tags) | |
db9e401b | 1309 | "In TABLE, find all occurrences of tags matching REGEXP. |
1bd95535 CY |
1310 | Optional argument TAGS is a list of tags to search. |
1311 | Returns a table of all matching tags." | |
1312 | (semantic-find-tags-by-name-regexp regexp (or tags (semanticdb-get-tags table)))) | |
1313 | ||
1314 | (defmethod semanticdb-find-tags-for-completion-method ((table semanticdb-abstract-table) prefix &optional tags) | |
db9e401b | 1315 | "In TABLE, find all occurrences of tags matching PREFIX. |
1bd95535 CY |
1316 | Optional argument TAGS is a list of tags to search. |
1317 | Returns a table of all matching tags." | |
1318 | (semantic-find-tags-for-completion prefix (or tags (semanticdb-get-tags table)))) | |
1319 | ||
1320 | (defmethod semanticdb-find-tags-by-class-method ((table semanticdb-abstract-table) class &optional tags) | |
db9e401b | 1321 | "In TABLE, find all occurrences of tags of CLASS. |
1bd95535 CY |
1322 | Optional argument TAGS is a list of tags to search. |
1323 | Returns a table of all matching tags." | |
1324 | (semantic-find-tags-by-class class (or tags (semanticdb-get-tags table)))) | |
1325 | ||
1326 | (defmethod semanticdb-find-tags-external-children-of-type-method ((table semanticdb-abstract-table) parent &optional tags) | |
db9e401b | 1327 | "In TABLE, find all occurrences of tags whose parent is the PARENT type. |
1bd95535 CY |
1328 | Optional argument TAGS is a list of tags to search. |
1329 | Returns a table of all matching tags." | |
b90caf50 | 1330 | (require 'semantic/find) |
1bd95535 CY |
1331 | (semantic-find-tags-external-children-of-type parent (or tags (semanticdb-get-tags table)))) |
1332 | ||
1333 | (defmethod semanticdb-find-tags-subclasses-of-type-method ((table semanticdb-abstract-table) parent &optional tags) | |
db9e401b | 1334 | "In TABLE, find all occurrences of tags whose parent is the PARENT type. |
1bd95535 CY |
1335 | Optional argument TAGS is a list of tags to search. |
1336 | Returns a table of all matching tags." | |
b90caf50 | 1337 | (require 'semantic/find) |
1bd95535 CY |
1338 | (semantic-find-tags-subclasses-of-type parent (or tags (semanticdb-get-tags table)))) |
1339 | ||
1340 | ;;; Deep Searches | |
1341 | (defmethod semanticdb-deep-find-tags-by-name-method ((table semanticdb-abstract-table) name &optional tags) | |
db9e401b | 1342 | "In TABLE, find all occurrences of tags with NAME. |
1bd95535 CY |
1343 | Search in all tags in TABLE, and all components of top level tags in |
1344 | TABLE. | |
1345 | Optional argument TAGS is a list of tags to search. | |
1346 | Return a table of all matching tags." | |
1347 | (semantic-find-tags-by-name name (semantic-flatten-tags-table (or tags (semanticdb-get-tags table))))) | |
1348 | ||
1349 | (defmethod semanticdb-deep-find-tags-by-name-regexp-method ((table semanticdb-abstract-table) regexp &optional tags) | |
db9e401b | 1350 | "In TABLE, find all occurrences of tags matching REGEXP. |
1bd95535 CY |
1351 | Search in all tags in TABLE, and all components of top level tags in |
1352 | TABLE. | |
1353 | Optional argument TAGS is a list of tags to search. | |
1354 | Return a table of all matching tags." | |
1355 | (semantic-find-tags-by-name-regexp regexp (semantic-flatten-tags-table (or tags (semanticdb-get-tags table))))) | |
1356 | ||
1357 | (defmethod semanticdb-deep-find-tags-for-completion-method ((table semanticdb-abstract-table) prefix &optional tags) | |
db9e401b | 1358 | "In TABLE, find all occurrences of tags matching PREFIX. |
1bd95535 CY |
1359 | Search in all tags in TABLE, and all components of top level tags in |
1360 | TABLE. | |
1361 | Optional argument TAGS is a list of tags to search. | |
1362 | Return a table of all matching tags." | |
1363 | (semantic-find-tags-for-completion prefix (semantic-flatten-tags-table (or tags (semanticdb-get-tags table))))) | |
1364 | ||
1365 | (provide 'semantic/db-find) | |
1366 | ||
3d9d8486 CY |
1367 | ;; Local variables: |
1368 | ;; generated-autoload-file: "loaddefs.el" | |
996bc9bf | 1369 | ;; generated-autoload-load-name: "semantic/db-find" |
3d9d8486 CY |
1370 | ;; End: |
1371 | ||
3999968a | 1372 | ;; arch-tag: 5d4162f5-5092-46d7-beed-55c78aab4116 |
aa8724ae | 1373 | ;;; semantic/db-find.el ends here |