Source

semantic / semanticdb-search.el

Full commit
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
;;; semanticdb-search.el --- Searching through semantic databases.

;;; Copyright (C) 2000, 2001, 2002, 2003, 2004 Eric M. Ludlam

;; Author: Eric M. Ludlam <zappo@gnu.org>
;; Keywords: tags
;; X-RCS: $Id$

;; This file is not part of GNU Emacs.

;; Semanticdb is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; This software is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;; 
;;; Commentary:
;;
;; Databases of various forms can all be searched.  These routines
;; cover many common forms of searching.
;;
;; There are three types of searches that can be implemented:
;;
;; Basic Search:
;;  These searches allow searching on specific attributes of tags,
;;  such as name or type.
;;
;; Advanced Search:
;;  These are searches that were needed to accomplish some tasks
;;  during in utilities.  Advanced searches include matching methods
;;  defined outside some parent class.
;;
;;  The reason for advanced searches are so that external
;;  repositories such as the Emacs obarray, or java .class files can
;;  quickly answer these needed questions without dumping the entire
;;  symbol list into Emacs for a regular semanticdb search.
;;
;; Generic Search:
;;  The generic search, `semanticdb-find-nonterminal-by-function'
;;  accepts a Emacs Lisp predicate that tests tags in Semantic
;;  format.  Most external searches cannot perform this search.

(require 'semanticdb)
(require 'semantic-find)

;;; Code:
;;
;;; Classes:
(defclass semanticdb-search-results-table (semanticdb-abstract-table)
  (
   )
  "Table used for search results when there is no file or table association.
Examples include search results from external sources such as from
Emacs' own symbol table, or from external libraries.")

(defmethod semanticdb-refresh-table ((obj semanticdb-search-results-table))
  "If the tag list associated with OBJ is loaded, refresh it.
This will call `semantic-fetch-tags' if that file is in memory."
  nil)

(defmethod semanticdb-printable-name ((table semanticdb-search-results-table))
  "Return a string which is a short and logical printable name for TABLE.
A search result may not have a file assocated with it, so we need to
provide a reasonable identification."
  (concat "System: " (object-name-string table))
  )

;;; Utils
;;
;; Convenience routines for searches
(defun semanticdb-collect-find-results (result-in-databases
					result-finding-function
					ignore-system
					find-file-on-match)
  "Collect results across RESULT-IN-DATABASES for RESULT-FINDING-FUNCTION.
If RESULT-IN-DATABASES is nil, search a range of associated databases
calculated by `semanticdb-current-database-list'.
RESULT-IN-DATABASES is a list of variable `semanticdb-project-database'
objects.
RESULT-FINDING-FUNCTION should accept one argument, the database being searched.
Argument IGNORE-SYSTEM specifies if any available system databases should
be ignored, or searched.
Argument FIND-FILE-ON-MATCH indicates that the found databases
should be capable of doing so."
  (if (not (listp result-in-databases))
      (signal 'wrong-type-argument (list 'listp result-in-databases)))
  (let* ((semanticdb-search-system-databases
	  (if ignore-system
	      nil
	    semanticdb-search-system-databases))
	 (dbs (or result-in-databases
		  ;; Calculate what database to use.
		  ;; Something simple and dumb for now.
		  (or (semanticdb-current-database-list)
		      (list (semanticdb-current-database)))))
	 (case-fold-search semantic-case-fold)
	 (res (mapcar
	       (lambda (db)
		 (if (or (not find-file-on-match)
			 (not (child-of-class-p
			       (oref db new-table-class)
			       semanticdb-search-results-table)))
		     (funcall result-finding-function db)))
	       dbs))
	 out)
    ;; Flatten the list.  The DB is unimportant at this stage.
    (setq res (apply 'append res))
    (setq out nil)
    ;; Move across results, and throw out empties.
    (while res
      (if (car res)
	  (setq out (cons (car res) out)))
      (setq res (cdr res)))
    ;; Results
    out))

;;; Programatic interfaces
;;
;; These routines all perform different types of searches, and are
;; interfaces to the database methods used to also perform those searches.

;;;###autoload
(defun semanticdb-find-nonterminal-by-token
  (token &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
  "Find all occurances of nonterminals with token TOKEN in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES, DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-collect-find-results
   databases
   (lambda (db)
     (semanticdb-find-nonterminal-by-token-method
      db token search-parts search-includes diff-mode find-file-match))
   ignore-system
   find-file-match))
(make-obsolete 'semanticdb-find-nonterminal-by-token
	       "Please don't use this function")

;;;###autoload
(defun semanticdb-find-nonterminal-by-name
  (name &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
  "Find all occurances of nonterminals with name NAME in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES, DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
Return a list ((DB-TABLE . TOKEN) ...)."
  (semanticdb-collect-find-results
   databases
   (lambda (db)
     (semanticdb-find-nonterminal-by-name-method
      db name search-parts search-includes diff-mode find-file-match))
   ignore-system
   find-file-match))
(make-obsolete 'semanticdb-find-nonterminal-by-name
	       "Please don't use this function")

;;;###autoload
(defun semanticdb-find-nonterminal-by-name-regexp
  (regex &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
  "Find all occurances of nonterminals with name matching REGEX in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-collect-find-results
   databases
   (lambda (db)
     (semanticdb-find-nonterminal-by-name-regexp-method
      db regex search-parts search-includes diff-mode find-file-match))
   ignore-system
   find-file-match))
(make-obsolete 'semanticdb-find-nonterminal-by-name-regexp
	       "Please don't use this function")


;;;###autoload
(defun semanticdb-find-nonterminal-by-type
  (type &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
  "Find all nonterminals with a type of TYPE in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-collect-find-results
   databases
   (lambda (db)
     (semanticdb-find-nonterminal-by-type-method
      db type search-parts search-includes diff-mode find-file-match))
   ignore-system
   find-file-match))
(make-obsolete 'semanticdb-find-nonterminal-by-type
	       "Please don't use this function")


;;;###autoload
(defun semanticdb-find-nonterminal-by-property
  (property value &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
  "Find all nonterminals with a PROPERTY equal to VALUE in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-collect-find-results
   databases
   (lambda (db)
     (semanticdb-find-nonterminal-by-property-method
      db property value search-parts search-includes diff-mode find-file-match))
   ignore-system
   find-file-match))
(make-obsolete 'semanticdb-find-nonterminal-by-property
	       "Please don't use this function")

;;;###autoload
(defun semanticdb-find-nonterminal-by-extra-spec
  (spec &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
  "Find all nonterminals with a SPEC in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-collect-find-results
   databases
   (lambda (db)
     (semanticdb-find-nonterminal-by-extra-spec-method
      db spec search-parts search-includes diff-mode find-file-match))
   ignore-system
   find-file-match))
(make-obsolete 'semanticdb-find-nonterminal-by-extra-spec
	       "Please don't use this function")

;;;###autoload
(defun semanticdb-find-nonterminal-by-extra-spec-value
  (spec value &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
  "Find all nonterminals with a SPEC equal to VALUE in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-collect-find-results
   databases
   (lambda (db)
     (semanticdb-find-nonterminal-by-extra-spec-value-method
      db spec value search-parts search-includes diff-mode find-file-match))
   ignore-system
   find-file-match))
(make-obsolete 'semanticdb-find-nonterminal-by-extra-spec-value
	       "Please don't use this function")

;;; Advanced Search Routines
;;
(defun semanticdb-find-nonterminal-external-children-of-type
  (type &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
  "Find all nonterminals which are child elements of TYPE.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-collect-find-results
   databases
   (lambda (db)
     (semanticdb-find-nonterminal-external-children-of-type-method
      db type search-parts search-includes diff-mode find-file-match))
   ignore-system
   find-file-match))

;;; Generic Search routine
;;

;;;###autoload
(defun semanticdb-find-nonterminal-by-function
  (function &optional databases search-parts search-includes diff-mode find-file-match ignore-system)
  "Find all occurances of nonterminals which match FUNCTION.
Search in all DATABASES.  If DATABASES is nil, search a range of
associated databases calculated `semanticdb-current-database-list' and
DATABASES is a list of variable `semanticdb-project-database' objects.
When SEARCH-PARTS is non-nil the search will include children of tags.
When SEARCH-INCLUDES is non-nil, the search will include dependency files.
When DIFF-MODE is non-nil, search databases which are of a different mode.
A Mode is the `major-mode' that file was in when it was last parsed.
When FIND-FILE-MATCH is non-nil, the make sure any found token's file is
in an Emacs buffer.
When IGNORE-SYSTEM is non-nil, system libraries are not searched.
Return a list ((DB-TABLE . TOKEN-OR-TOKEN-LIST) ...)."
  (semanticdb-collect-find-results
   databases
   (lambda (db)
     (semanticdb-find-nonterminal-by-function-method
      db function search-parts search-includes diff-mode find-file-match))
   ignore-system
   find-file-match))

;;; Search Methods
;;
;; These are the base routines for searching semantic databases.
;; Overload these with your subclasses to participate in the searching
;; mechanism.
(defmethod semanticdb-find-nonterminal-by-token-method
  ((database semanticdb-project-database) token search-parts search-includes diff-mode find-file-match)
  "In DB, find all occurances of nonterminals with token TOKEN in databases.
See `semanticdb-find-nonterminal-by-function-method' for details on,
SEARCH-PARTS, SEARCH-INCLUDES, DIFF-MODE, and FIND-FILE-MATCH.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (let ((goofy-token-name token))
    (semanticdb-find-nonterminal-by-function-method
     database (lambda (stream sp si)
		(semantic-brute-find-tag-by-class goofy-token-name stream sp si))
     search-parts search-includes diff-mode find-file-match)))

(defmethod semanticdb-find-nonterminal-by-name-method
  ((database semanticdb-project-database) name search-parts search-includes diff-mode find-file-match)
  "Find all occurances of nonterminals with name NAME in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES, DIFF-MODE, and FIND-FILE-MATCH.
Return a list ((DB-TABLE . TOKEN) ...)."
  (semanticdb-find-nonterminal-by-function-method
   database
   (lambda (stream sp si)
     (semantic-brute-find-first-tag-by-name name stream sp si))
   search-parts search-includes diff-mode find-file-match))

(defmethod semanticdb-find-nonterminal-by-name-regexp-method
  ((database semanticdb-project-database) regex search-parts search-includes diff-mode find-file-match)
  "Find all occurances of nonterminals with name matching REGEX in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, and FIND-FILE-MATCH.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-find-nonterminal-by-function-method
   database
   (lambda (stream sp si)
     (semantic-brute-find-tag-by-name-regexp regex stream sp si))
   search-parts search-includes diff-mode find-file-match))

(defmethod semanticdb-find-nonterminal-by-type-method
  ((database semanticdb-project-database) type search-parts search-includes diff-mode find-file-match)
  "Find all nonterminals with a type of TYPE in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, and FIND-FILE-MATCH.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-find-nonterminal-by-function-method
   database
   (lambda (stream sp si)
     (semantic-brute-find-tag-by-type type stream sp si))
   search-parts search-includes diff-mode find-file-match))

(defmethod semanticdb-find-nonterminal-by-property-method
  ((database semanticdb-project-database) property value search-parts search-includes diff-mode find-file-match)
  "Find all nonterminals with a PROPERTY equal to VALUE in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, and FIND-FILE-MATCH.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-find-nonterminal-by-function-method
   database
   (lambda (stream sp si)
     (semantic-brute-find-tag-by-property property value stream sp si))
   search-parts search-includes diff-mode find-file-match))

(defmethod semanticdb-find-nonterminal-by-extra-spec-method
  ((database semanticdb-project-database) spec search-parts search-includes diff-mode find-file-match)
  "Find all nonterminals with a SPEC in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, and FIND-FILE-MATCH.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-find-nonterminal-by-function-method
   database
   (lambda (stream sp si)
     (semantic-brute-find-tag-by-attribute spec stream sp si))
   search-parts search-includes diff-mode find-file-match))

(defmethod semanticdb-find-nonterminal-by-extra-spec-value-method
  ((database semanticdb-project-database) spec value search-parts search-includes diff-mode find-file-match)
  "Find all nonterminals with a SPEC equal to VALUE in databases.
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, and FIND-FILE-MATCH.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-find-nonterminal-by-function-method
   database
   (lambda (stream sp si)
     (semantic-brute-find-tag-by-attribute-value spec value stream sp si))
   search-parts search-includes diff-mode find-file-match))

;;; Advanced Searches
;;
(defmethod semanticdb-find-nonterminal-external-children-of-type-method
  ((database semanticdb-project-database) type search-parts search-includes diff-mode find-file-match)
  "Find all nonterminals which are child elements of TYPE
See `semanticdb-find-nonterminal-by-function' for details on DATABASES,
SEARCH-PARTS, SEARCH-INCLUDES DIFF-MODE, FIND-FILE-MATCH and IGNORE-SYSTEM.
Return a list ((DB-TABLE . TOKEN-LIST) ...)."
  (semanticdb-find-nonterminal-by-function-method
   database
   `(lambda (stream sp si)
      (semantic-brute-find-tag-by-function
       (lambda (tok)
	 (let ((p (semantic-nonterminal-external-member-parent tok)))
	   (and (stringp p) (string= ,type p)))
	 )
       stream sp si))
   nil nil t))

;;; Generic Search
;;
(defmethod semanticdb-find-nonterminal-by-function-method
  ((database semanticdb-project-database)
   function &optional search-parts search-includes diff-mode find-file-match)
  "In DATABASE, find all occurances of nonterminals which match FUNCTION.
When SEARCH-PARTS is non-nil the search will include children of tags.
When SEARCH-INCLUDES is non-nil, the search will include dependency files.
When DIFF-MODE is non-nil, search databases which are of a different mode.
A mode is the `major-mode' that file was in when it was last parsed.
When FIND-FILE-MATCH is non-nil, the make sure any found token's file is
in an Emacs buffer.
Return a list of matches."
  (let* ((ret nil)
	 (files (semanticdb-get-database-tables database))
	 (found nil)
	 (orig-buffer (current-buffer)))
    (while files
      (when (or diff-mode
		(semanticdb-equivalent-mode (car files) orig-buffer))
	;; This can cause unneeded refreshes while typing with
	;; senator-eldoc mode.
	;;(semanticdb-refresh-table (car files))
	(setq found (funcall function
			     (semanticdb-get-tags (car files))
			     search-parts
			     search-includes
			     )))
      (if found
	  (progn
	    ;; When something is found, make sure we read in that buffer if it
	    ;; had not already been loaded.
	    (if find-file-match
		(save-excursion (semanticdb-set-buffer (car files))))
	    ;; In theory, the database is up-to-date with what is in the file, and
	    ;; these tags are ready to go.
	    ;; There is a bug lurking here I don't have time to fix.
	    (setq ret (cons (cons (car files) found) ret))
	    (setq found nil)))
      (setq files (cdr files)))
    (nreverse ret)))

(provide 'semanticdb-search)

;;; semanticdb-search.el ends here