aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChong Yidong2009-08-28 15:19:20 +0000
committerChong Yidong2009-08-28 15:19:20 +0000
commit7a0e7d3387b5b675042878e5e2e5878b94b2487a (patch)
tree48f1d7c4af09bbc4abfb968332cfc74c5cc1087f
parent57e622d92b9538b2302c51ef993766276dfc7569 (diff)
downloademacs-7a0e7d3387b5b675042878e5e2e5878b94b2487a.tar.gz
emacs-7a0e7d3387b5b675042878e5e2e5878b94b2487a.zip
cedet/semantic/db.el, cedet/semantic/decorate.el,
cedet/semantic/lex-spp.el, cedet/semantic/util-modes.el: New files.
-rw-r--r--lisp/cedet/semantic/db.el989
-rw-r--r--lisp/cedet/semantic/decorate.el320
-rw-r--r--lisp/cedet/semantic/lex-spp.el1187
-rw-r--r--lisp/cedet/semantic/util-modes.el1228
4 files changed, 3724 insertions, 0 deletions
diff --git a/lisp/cedet/semantic/db.el b/lisp/cedet/semantic/db.el
new file mode 100644
index 00000000000..3b32a9a8123
--- /dev/null
+++ b/lisp/cedet/semantic/db.el
@@ -0,0 +1,989 @@
1;;; semanticdb.el --- Semantic tag database manager
2
3;;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
4;;; 2008, 2009 Free Software Foundation, Inc.
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;; Maintain a database of tags for a group of files and enable
27;; queries into the database.
28;;
29;; By default, assume one database per directory.
30;;
31
32(require 'eieio)
33;; (require 'inversion)
34;; (eval-and-compile
35;; (inversion-require 'eieio "1.0"))
36(require 'eieio-base)
37(require 'semantic)
38(eval-when-compile
39 (require 'semantic/lex-spp))
40
41;;; Variables:
42(defgroup semanticdb nil
43 "Parser Generator Persistent Database interface."
44 :group 'semantic
45 )
46;;; Code:
47(defvar semanticdb-database-list nil
48 "List of all active databases.")
49
50(defvar semanticdb-new-database-class 'semanticdb-project-database-file
51 "The default type of database created for new files.
52This can be changed on a per file basis, so that some directories
53are saved using one mechanism, and some directories via a different
54mechanism.")
55(make-variable-buffer-local 'semanticdb-new-database-class)
56
57(defvar semanticdb-default-find-index-class 'semanticdb-find-search-index
58 "The default type of search index to use for a `semanticdb-table's.
59This can be changed to try out new types of search indicies.")
60(make-variable-buffer-local 'semanticdb-default-find=index-class)
61
62
63;;; ABSTRACT CLASSES
64;;
65(defclass semanticdb-abstract-table ()
66 ((parent-db ;; :initarg :parent-db
67 ;; Do not set an initarg, or you get circular writes to disk.
68 :documentation "Database Object containing this table.")
69 (major-mode :initarg :major-mode
70 :initform nil
71 :documentation "Major mode this table belongs to.
72Sometimes it is important for a program to know if a given table has the
73same major mode as the current buffer.")
74 (tags :initarg :tags
75 :accessor semanticdb-get-tags
76 :printer semantic-tag-write-list-slot-value
77 :documentation "The tags belonging to this table.")
78 (index :type semanticdb-abstract-search-index
79 :documentation "The search index.
80Used by semanticdb-find to store additional information about
81this table for searching purposes.
82
83Note: This index will not be saved in a persistent file.")
84 (cache :type list
85 :initform nil
86 :documentation "List of cache information for tools.
87Any particular tool can cache data to a database at runtime
88with `semanticdb-cache-get'.
89
90Using a semanticdb cache does not save any information to a file,
91so your cache will need to be recalculated at runtime. Caches can be
92referenced even when the file is not in a buffer.
93
94Note: This index will not be saved in a persistent file.")
95 )
96 "A simple table for semantic tags.
97This table is the root of tables, and contains the minimum needed
98for a new table not associated with a buffer."
99 :abstract t)
100
101(defmethod semanticdb-in-buffer-p ((obj semanticdb-abstract-table))
102 "Return a nil, meaning abstract table OBJ is not in a buffer."
103 nil)
104
105(defmethod semanticdb-get-buffer ((obj semanticdb-abstract-table))
106 "Return a buffer associated with OBJ.
107If the buffer is not in memory, load it with `find-file-noselect'."
108 nil)
109
110(defmethod semanticdb-full-filename ((obj semanticdb-abstract-table))
111 "Fetch the full filename that OBJ refers to.
112Abstract tables do not have file names associated with them."
113 nil)
114
115(defmethod semanticdb-dirty-p ((obj semanticdb-abstract-table))
116 "Return non-nil if OBJ is 'dirty'."
117 nil)
118
119(defmethod semanticdb-set-dirty ((obj semanticdb-abstract-table))
120 "Mark the abstract table OBJ dirty.
121Abstract tables can not be marked dirty, as there is nothing
122for them to synchronize against."
123 ;; The abstract table can not be dirty.
124 nil)
125
126(defmethod semanticdb-normalize-tags ((obj semanticdb-abstract-table) tags)
127 "For the table OBJ, convert a list of TAGS, into standardized form.
128The default is to return TAGS.
129Some databases may default to searching and providing simplified tags
130based on whichever technique used. This method provides a hook for
131them to convert TAG into a more complete form."
132 tags)
133
134(defmethod semanticdb-normalize-one-tag ((obj semanticdb-abstract-table) tag)
135 "For the table OBJ, convert a TAG, into standardized form.
136This method returns a list of the form (DATABASE . NEWTAG).
137
138The default is to just return (OBJ TAG).
139
140Some databases may default to searching and providing simplified tags
141based on whichever technique used. This method provides a hook for
142them to convert TAG into a more complete form."
143 (cons obj tag))
144
145(defmethod object-print ((obj semanticdb-abstract-table) &rest strings)
146 "Pretty printer extension for `semanticdb-table'.
147Adds the number of tags in this file to the object print name."
148 (apply 'call-next-method obj
149 (cons (format " (%d tags)"
150 (length (semanticdb-get-tags obj))
151 )
152 strings)))
153
154;;; Index Cache
155;;
156(defclass semanticdb-abstract-search-index ()
157 ((table :initarg :table
158 :type semanticdb-abstract-table
159 :documentation "XRef to the table this belongs to.")
160 )
161 "A place where semanticdb-find can store search index information.
162The search index will store data about which other tables might be
163needed, or perhaps create hash or index tables for the current buffer."
164 :abstract t)
165
166(defmethod semanticdb-get-table-index ((obj semanticdb-abstract-table))
167 "Return the search index for the table OBJ.
168If one doesn't exist, create it."
169 (if (slot-boundp obj 'index)
170 (oref obj index)
171 (let ((idx nil))
172 (setq idx (funcall semanticdb-default-find-index-class
173 (concat (object-name obj) " index")
174 ;; Fill in the defaults
175 :table obj
176 ))
177 (oset obj index idx)
178 idx)))
179
180(defmethod semanticdb-synchronize ((idx semanticdb-abstract-search-index)
181 new-tags)
182 "Synchronize the search index IDX with some NEW-TAGS."
183 ;; The abstract class will do... NOTHING!
184 )
185
186(defmethod semanticdb-partial-synchronize ((idx semanticdb-abstract-search-index)
187 new-tags)
188 "Synchronize the search index IDX with some changed NEW-TAGS."
189 ;; The abstract class will do... NOTHING!
190 )
191
192
193;;; CONCRETE TABLE CLASSES
194;;
195(defclass semanticdb-table (semanticdb-abstract-table)
196 ((file :initarg :file
197 :documentation "File name relative to the parent database.
198This is for the file whose tags are stored in this TABLE object.")
199 (buffer :initform nil
200 :documentation "The buffer associated with this table.
201If nil, the table's buffer is no in Emacs. If it has a value, then
202it is in Emacs.")
203 (dirty :initform nil
204 :documentation
205 "Non nil if this table needs to be `Saved'.")
206 (db-refs :initform nil
207 :documentation
208 "List of `semanticdb-table' objects refering to this one.
209These aren't saved, but are instead recalculated after load.
210See the file semanticdb-ref.el for how this slot is used.")
211 (pointmax :initarg :pointmax
212 :initform nil
213 :documentation "Size of buffer when written to disk.
214Checked on retrieval to make sure the file is the same.")
215 (fsize :initarg :fsize
216 :initform nil
217 :documentation "Size of the file when it was last referenced.
218Checked when deciding if a loaded table needs updating from changes
219outside of Semantic's control.")
220 (lastmodtime :initarg :lastmodtime
221 :initform nil
222 :documentation "Last modification time of the file referenced.
223Checked when deciding if a loaded table needs updating from changes outside of
224Semantic's control.")
225 ;; @todo - need to add `last parsed time', so we can also have
226 ;; refresh checks if spp tables or the parser gets rebuilt.
227 (unmatched-syntax :initarg :unmatched-syntax
228 :documentation
229 "List of vectors specifying unmatched syntax.")
230
231 (lexical-table :initarg :lexical-table
232 :initform nil
233 :printer semantic-lex-spp-table-write-slot-value
234 :documentation
235 "Table that might be needed by the lexical analyzer.
236For C/C++, the C preprocessor macros can be saved here.")
237 )
238 "A single table of tags derived from file.")
239
240(defmethod semanticdb-in-buffer-p ((obj semanticdb-table))
241 "Return a buffer associated with OBJ.
242If the buffer is in memory, return that buffer."
243 (let ((buff (oref obj buffer)))
244 (if (buffer-live-p buff)
245 buff
246 (oset obj buffer nil))))
247
248(defmethod semanticdb-get-buffer ((obj semanticdb-table))
249 "Return a buffer associated with OBJ.
250If the buffer is in memory, return that buffer.
251If the buffer is not in memory, load it with `find-file-noselect'."
252 (or (semanticdb-in-buffer-p obj)
253 (find-file-noselect (semanticdb-full-filename obj) t)))
254
255(defmethod semanticdb-set-buffer ((obj semanticdb-table))
256 "Set the current buffer to be a buffer owned by OBJ.
257If OBJ's file is not loaded, read it in first."
258 (set-buffer (semanticdb-get-buffer obj)))
259
260(defmethod semanticdb-full-filename ((obj semanticdb-table))
261 "Fetch the full filename that OBJ refers to."
262 (expand-file-name (oref obj file)
263 (oref (oref obj parent-db) reference-directory)))
264
265(defmethod semanticdb-dirty-p ((obj semanticdb-table))
266 "Return non-nil if OBJ is 'dirty'."
267 (oref obj dirty))
268
269(defmethod semanticdb-set-dirty ((obj semanticdb-table))
270 "Mark the abstract table OBJ dirty."
271 (oset obj dirty t)
272 )
273
274(defmethod object-print ((obj semanticdb-table) &rest strings)
275 "Pretty printer extension for `semanticdb-table'.
276Adds the number of tags in this file to the object print name."
277 (apply 'call-next-method obj
278 (cons (if (oref obj dirty) ", DIRTY" "") strings)))
279
280;;; DATABASE BASE CLASS
281;;
282(defclass semanticdb-project-database (eieio-instance-tracker)
283 ((tracking-symbol :initform semanticdb-database-list)
284 (reference-directory :type string
285 :documentation "Directory this database refers to.
286When a cache directory is specified, then this refers to the directory
287this database contains symbols for.")
288 (new-table-class :initform semanticdb-table
289 :type class
290 :documentation
291 "New tables created for this database are of this class.")
292 (cache :type list
293 :initform nil
294 :documentation "List of cache information for tools.
295Any particular tool can cache data to a database at runtime
296with `semanticdb-cache-get'.
297
298Using a semanticdb cache does not save any information to a file,
299so your cache will need to be recalculated at runtime.
300
301Note: This index will not be saved in a persistent file.")
302 (tables :initarg :tables
303 :type list
304 ;; Need this protection so apps don't try to access
305 ;; the tables without using the accessor.
306 :accessor semanticdb-get-database-tables
307 :protection :protected
308 :documentation "List of `semantic-db-table' objects."))
309 "Database of file tables.")
310
311(defmethod semanticdb-full-filename ((obj semanticdb-project-database))
312 "Fetch the full filename that OBJ refers to.
313Abstract tables do not have file names associated with them."
314 nil)
315
316(defmethod semanticdb-dirty-p ((DB semanticdb-project-database))
317 "Return non-nil if DB is 'dirty'.
318A database is dirty if the state of the database changed in a way
319where it may need to resynchronize with some persistent storage."
320 (let ((dirty nil)
321 (tabs (oref DB tables)))
322 (while (and (not dirty) tabs)
323 (setq dirty (semanticdb-dirty-p (car tabs)))
324 (setq tabs (cdr tabs)))
325 dirty))
326
327(defmethod object-print ((obj semanticdb-project-database) &rest strings)
328 "Pretty printer extension for `semanticdb-project-database'.
329Adds the number of tables in this file to the object print name."
330 (apply 'call-next-method obj
331 (cons (format " (%d tables%s)"
332 (length (semanticdb-get-database-tables obj))
333 (if (semanticdb-dirty-p obj)
334 " DIRTY" "")
335 )
336 strings)))
337
338(defmethod semanticdb-create-database :STATIC ((dbc semanticdb-project-database) directory)
339 "Create a new semantic database of class DBC for DIRECTORY and return it.
340If a database for DIRECTORY has already been created, return it.
341If DIRECTORY doesn't exist, create a new one."
342 (let ((db (semanticdb-directory-loaded-p directory)))
343 (unless db
344 (setq db (semanticdb-project-database
345 (file-name-nondirectory directory)
346 :tables nil))
347 ;; Set this up here. We can't put it in the constructor because it
348 ;; would be saved, and we want DB files to be portable.
349 (oset db reference-directory (file-truename directory)))
350 db))
351
352(defmethod semanticdb-flush-database-tables ((db semanticdb-project-database))
353 "Reset the tables in DB to be empty."
354 (oset db tables nil))
355
356(defmethod semanticdb-create-table ((db semanticdb-project-database) file)
357 "Create a new table in DB for FILE and return it.
358The class of DB contains the class name for the type of table to create.
359If the table for FILE exists, return it.
360If the table for FILE does not exist, create one."
361 (let ((newtab (semanticdb-file-table db file)))
362 (unless newtab
363 ;; This implementation will satisfy autoloaded classes
364 ;; for tables.
365 (setq newtab (funcall (oref db new-table-class)
366 (file-name-nondirectory file)
367 :file (file-name-nondirectory file)
368 ))
369 (oset newtab parent-db db)
370 (object-add-to-list db 'tables newtab t))
371 newtab))
372
373(defmethod semanticdb-file-table ((obj semanticdb-project-database) filename)
374 "From OBJ, return FILENAME's associated table object."
375 (object-assoc (file-relative-name (file-truename filename)
376 (oref obj reference-directory))
377 'file (oref obj tables)))
378
379;; DATABASE FUNCTIONS
380(defun semanticdb-get-database (filename)
381 "Get a database for FILENAME.
382If one isn't found, create one."
383 (semanticdb-create-database semanticdb-new-database-class (file-truename filename)))
384
385(defun semanticdb-directory-loaded-p (path)
386 "Return the project belonging to PATH if it was already loaded."
387 (eieio-instance-tracker-find path 'reference-directory 'semanticdb-database-list))
388
389(defun semanticdb-create-table-for-file (filename)
390 "Initialize a database table for FILENAME, and return it.
391If FILENAME exists in the database already, return that.
392If there is no database for the table to live in, create one."
393 (let ((cdb nil)
394 (tbl nil)
395 (dd (file-name-directory filename))
396 )
397 ;; Allow a database override function
398 (setq cdb (semanticdb-create-database semanticdb-new-database-class
399 dd))
400 ;; Get a table for this file.
401 (setq tbl (semanticdb-create-table cdb filename))
402
403 ;; Return the pair.
404 (cons cdb tbl)
405 ))
406
407;;; Cache Cache.
408;;
409(defclass semanticdb-abstract-cache ()
410 ((table :initarg :table
411 :type semanticdb-abstract-table
412 :documentation
413 "Cross reference to the table this belongs to.")
414 )
415 "Abstract baseclass for tools to use to cache information in semanticdb.
416Tools needing a per-file cache must subclass this, and then get one as
417needed. Cache objects are identified in semanticdb by subclass.
418In order to keep your cache up to date, be sure to implement
419`semanticdb-synchronize', and `semanticdb-partial-synchronize'.
420See the file semantic-scope.el for an example."
421 :abstract t)
422
423(defmethod semanticdb-cache-get ((table semanticdb-abstract-table)
424 desired-class)
425 "Get a cache object on TABLE of class DESIRED-CLASS.
426This method will create one if none exists with no init arguments
427other than :table."
428 (assert (child-of-class-p desired-class 'semanticdb-abstract-cache))
429 (let ((cache (oref table cache))
430 (obj nil))
431 (while (and (not obj) cache)
432 (if (eq (object-class-fast (car cache)) desired-class)
433 (setq obj (car cache)))
434 (setq cache (cdr cache)))
435 (if obj
436 obj ;; Just return it.
437 ;; No object, lets create a new one and return that.
438 (setq obj (funcall desired-class "Cache" :table table))
439 (object-add-to-list table 'cache obj)
440 obj)))
441
442(defmethod semanticdb-cache-remove ((table semanticdb-abstract-table)
443 cache)
444 "Remove from TABLE the cache object CACHE."
445 (object-remove-from-list table 'cache cache))
446
447(defmethod semanticdb-synchronize ((cache semanticdb-abstract-cache)
448 new-tags)
449 "Synchronize a CACHE with some NEW-TAGS."
450 ;; The abstract class will do... NOTHING!
451 )
452
453(defmethod semanticdb-partial-synchronize ((cache semanticdb-abstract-cache)
454 new-tags)
455 "Synchronize a CACHE with some changed NEW-TAGS."
456 ;; The abstract class will do... NOTHING!
457 )
458
459(defclass semanticdb-abstract-db-cache ()
460 ((db :initarg :db
461 :type semanticdb-project-database
462 :documentation
463 "Cross reference to the database this belongs to.")
464 )
465 "Abstract baseclass for tools to use to cache information in semanticdb.
466Tools needing a database cache must subclass this, and then get one as
467needed. Cache objects are identified in semanticdb by subclass.
468In order to keep your cache up to date, be sure to implement
469`semanticdb-synchronize', and `semanticdb-partial-synchronize'.
470See the file semantic-scope.el for an example."
471 :abstract t)
472
473(defmethod semanticdb-cache-get ((db semanticdb-project-database)
474 desired-class)
475 "Get a cache object on DB of class DESIRED-CLASS.
476This method will create one if none exists with no init arguments
477other than :table."
478 (assert (child-of-class-p desired-class 'semanticdb-abstract-db-cache))
479 (let ((cache (oref db cache))
480 (obj nil))
481 (while (and (not obj) cache)
482 (if (eq (object-class-fast (car cache)) desired-class)
483 (setq obj (car cache)))
484 (setq cache (cdr cache)))
485 (if obj
486 obj ;; Just return it.
487 ;; No object, lets create a new one and return that.
488 (setq obj (funcall desired-class "Cache" :db db))
489 (object-add-to-list db 'cache obj)
490 obj)))
491
492(defmethod semanticdb-cache-remove ((db semanticdb-project-database)
493 cache)
494 "Remove from TABLE the cache object CACHE."
495 (object-remove-from-list db 'cache cache))
496
497
498(defmethod semanticdb-synchronize ((cache semanticdb-abstract-db-cache)
499 new-tags)
500 "Synchronize a CACHE with some NEW-TAGS."
501 ;; The abstract class will do... NOTHING!
502 )
503
504(defmethod semanticdb-partial-synchronize ((cache semanticdb-abstract-db-cache)
505 new-tags)
506 "Synchronize a CACHE with some changed NEW-TAGS."
507 ;; The abstract class will do... NOTHING!
508 )
509
510;;; REFRESH
511
512(defmethod semanticdb-refresh-table ((obj semanticdb-table) &optional force)
513 "If the tag list associated with OBJ is loaded, refresh it.
514Optional argument FORCE will force a refresh even if the file in question
515is not in a buffer. Avoid using FORCE for most uses, as an old cache
516may be sufficient for the general case. Forced updates can be slow.
517This will call `semantic-fetch-tags' if that file is in memory."
518 (when (or (semanticdb-in-buffer-p obj) force)
519 (save-excursion
520 (semanticdb-set-buffer obj)
521 (semantic-fetch-tags))))
522
523(defmethod semanticdb-needs-refresh-p ((obj semanticdb-table))
524 "Return non-nil of OBJ's tag list is out of date.
525The file associated with OBJ does not need to be in a buffer."
526 (let* ((ff (semanticdb-full-filename obj))
527 (buff (semanticdb-in-buffer-p obj))
528 )
529 (if buff
530 (save-excursion
531 (set-buffer buff)
532 ;; Use semantic's magic tracker to determine of the buffer is up
533 ;; to date or not.
534 (not (semantic-parse-tree-up-to-date-p))
535 ;; We assume that semanticdb is keeping itself up to date.
536 ;; via all the clever hooks
537 )
538 ;; Buffer isn't loaded. The only clue we have is if the file
539 ;; is somehow different from our mark in the semanticdb table.
540 (let* ((stats (file-attributes ff))
541 (actualsize (nth 7 stats))
542 (actualmod (nth 5 stats))
543 )
544
545 (or (not (slot-boundp obj 'tags))
546 ;; (not (oref obj tags)) --> not needed anymore?
547 (/= (or (oref obj fsize) 0) actualsize)
548 (not (equal (oref obj lastmodtime) actualmod))
549 )
550 ))))
551
552
553;;; Synchronization
554;;
555(defmethod semanticdb-synchronize ((table semanticdb-abstract-table)
556 new-tags)
557 "Synchronize the table TABLE with some NEW-TAGS."
558 (oset table tags new-tags)
559 (oset table pointmax (point-max))
560 (let ((fattr (file-attributes (semanticdb-full-filename table))))
561 (oset table fsize (nth 7 fattr))
562 (oset table lastmodtime (nth 5 fattr))
563 )
564 ;; Assume it is now up to date.
565 (oset table unmatched-syntax semantic-unmatched-syntax-cache)
566 ;; The lexical table should be good too.
567 (when (featurep 'semantic-lex-spp)
568 (oset table lexical-table (semantic-lex-spp-save-table)))
569 ;; this implies dirtyness
570 (semanticdb-set-dirty table)
571
572 ;; Synchronize the index
573 (when (slot-boundp table 'index)
574 (let ((idx (oref table index)))
575 (when idx (semanticdb-synchronize idx new-tags))))
576
577 ;; Synchronize application caches.
578 (dolist (C (oref table cache))
579 (semanticdb-synchronize C new-tags)
580 )
581
582 ;; Update cross references
583 ;; (semanticdb-refresh-references table)
584 )
585
586(defmethod semanticdb-partial-synchronize ((table semanticdb-abstract-table)
587 new-tags)
588 "Synchronize the table TABLE where some NEW-TAGS changed."
589 ;; You might think we need to reset the tags, but since the partial
590 ;; parser splices the lists, we don't need to do anything
591 ;;(oset table tags new-tags)
592 ;; We do need to mark ourselves dirty.
593 (semanticdb-set-dirty table)
594
595 ;; The lexical table may be modified.
596 (when (featurep 'semantic-lex-spp)
597 (oset table lexical-table (semantic-lex-spp-save-table)))
598
599 ;; Incremental parser doesn't mokey around with this.
600 (oset table unmatched-syntax semantic-unmatched-syntax-cache)
601
602 ;; Synchronize the index
603 (when (slot-boundp table 'index)
604 (let ((idx (oref table index)))
605 (when idx (semanticdb-partial-synchronize idx new-tags))))
606
607 ;; Synchronize application caches.
608 (dolist (C (oref table cache))
609 (semanticdb-synchronize C new-tags)
610 )
611
612 ;; Update cross references
613 ;;(when (semantic-find-tags-by-class 'include new-tags)
614 ;; (semanticdb-refresh-references table))
615 )
616
617;;; SAVE/LOAD
618;;
619(defmethod semanticdb-save-db ((DB semanticdb-project-database)
620 &optional supress-questions)
621 "Cause a database to save itself.
622The database base class does not save itself persistently.
623Subclasses could save themselves to a file, or to a database, or other
624form."
625 nil)
626
627(defun semanticdb-save-current-db ()
628 "Save the current tag database."
629 (interactive)
630 (message "Saving current tag summaries...")
631 (semanticdb-save-db semanticdb-current-database)
632 (message "Saving current tag summaries...done"))
633
634(defun semanticdb-save-all-db ()
635 "Save all semantic tag databases."
636 (interactive)
637 (message "Saving tag summaries...")
638 (mapc 'semanticdb-save-db semanticdb-database-list)
639 (message "Saving tag summaries...done"))
640
641(defun semanticdb-save-all-db-idle ()
642 "Save all semantic tag databases from idle time.
643Exit the save between databases if there is user input."
644 (semantic-safe "Auto-DB Save: %S"
645 (semantic-exit-on-input 'semanticdb-idle-save
646 (mapc (lambda (db)
647 (semantic-throw-on-input 'semanticdb-idle-save)
648 (semanticdb-save-db db t))
649 semanticdb-database-list))
650 ))
651
652;;; Directory Project support
653;;
654(defvar semanticdb-project-predicate-functions nil
655 "List of predicates to try that indicate a directory belongs to a project.
656This list is used when `semanticdb-persistent-path' contains the value
657'project. If the predicate list is nil, then presume all paths are valid.
658
659Project Management software (such as EDE and JDE) should add their own
660predicates with `add-hook' to this variable, and semanticdb will save tag
661caches in directories controlled by them.")
662
663(defmethod semanticdb-write-directory-p ((obj semanticdb-project-database))
664 "Return non-nil if OBJ should be written to disk.
665Uses `semanticdb-persistent-path' to determine the return value."
666 nil)
667
668;;; Utilities
669;;
670;; What is the current database, are two tables of an equivalent mode,
671;; and what databases are a part of the same project.
672(defun semanticdb-current-database ()
673 "Return the currently active database."
674 (or semanticdb-current-database
675 (and default-directory
676 (semanticdb-create-database semanticdb-new-database-class
677 default-directory)
678 )
679 nil))
680
681(defvar semanticdb-match-any-mode nil
682 "Non-nil to temporarilly search any major mode for a tag.
683If a particular major mode wants to search any mode, put the
684`semantic-match-any-mode' symbol onto the symbol of that major mode.
685Do not set the value of this variable permanently.")
686
687(defmacro semanticdb-with-match-any-mode (&rest body)
688 "A Semanticdb search occuring withing BODY will search tags in all modes.
689This temporarilly sets `semanticdb-match-any-mode' while executing BODY."
690 `(let ((semanticdb-match-any-mode t))
691 ,@body))
692(put 'semanticdb-with-match-any-mode 'lisp-indent-function 0)
693
694(defmethod semanticdb-equivalent-mode-for-search (table &optional buffer)
695 "Return non-nil if TABLE's mode is equivalent to BUFFER.
696See `semanticdb-equivalent-mode' for details.
697This version is used during searches. Major-modes that opt
698to set the `semantic-match-any-mode' property will be able to search
699all files of any type."
700 (or (get major-mode 'semantic-match-any-mode)
701 semanticdb-match-any-mode
702 (semanticdb-equivalent-mode table buffer))
703 )
704
705(defmethod semanticdb-equivalent-mode ((table semanticdb-abstract-table) &optional buffer)
706 "Return non-nil if TABLE's mode is equivalent to BUFFER.
707Equivalent modes are specified by by `semantic-equivalent-major-modes'
708local variable."
709 nil)
710
711(defmethod semanticdb-equivalent-mode ((table semanticdb-table) &optional buffer)
712 "Return non-nil if TABLE's mode is equivalent to BUFFER.
713Equivalent modes are specified by by `semantic-equivalent-major-modes'
714local variable."
715 (save-excursion
716 (if buffer (set-buffer buffer))
717 (or
718 ;; nil major mode in table means we don't know yet. Assume yes for now?
719 (null (oref table major-mode))
720 ;; nil means the same as major-mode
721 (and (not semantic-equivalent-major-modes)
722 (mode-local-use-bindings-p major-mode (oref table major-mode)))
723 (and semantic-equivalent-major-modes
724 (member (oref table major-mode) semantic-equivalent-major-modes))
725 )
726 ))
727
728
729;;; Associations
730;;
731;; These routines determine associations between a file, and multiple
732;; associated databases.
733
734(defcustom semanticdb-project-roots nil
735 "*List of directories, where each directory is the root of some project.
736All subdirectories of a root project are considered a part of one project.
737Values in this string can be overriden by project management programs
738via the `semanticdb-project-root-functions' variable."
739 :group 'semanticdb
740 :type '(repeat string))
741
742(defvar semanticdb-project-root-functions nil
743 "List of functions used to determine a given directories project root.
744Functions in this variable can override `semanticdb-project-roots'.
745Functions set in the variable are given one argument (a directory) and
746must return a string, (the root directory) or a list of strings (multiple
747root directories in a more complex system). This variable should be used
748by project management programs like EDE or JDE.")
749
750(defvar semanticdb-project-system-databases nil
751 "List of databases containing system library information.
752Mode authors can create their own system databases which know
753detailed information about the system libraries for querying purposes.
754Put those into this variable as a buffer-local, or mode-local
755value.")
756(make-variable-buffer-local 'semanticdb-project-system-databases)
757
758(defvar semanticdb-search-system-databases t
759 "Non nil if search routines are to include a system database.")
760
761(defun semanticdb-current-database-list (&optional dir)
762 "Return a list of databases associated with the current buffer.
763If optional argument DIR is non-nil, then use DIR as the starting directory.
764If this buffer has a database, but doesn't have a project associated
765with it, return nil.
766First, it checks `semanticdb-project-root-functions', and if that
767has no results, it checks `semanticdb-project-roots'. If that fails,
768it returns the results of function `semanticdb-current-database'.
769Always append `semanticdb-project-system-databases' if
770`semanticdb-search-system' is non-nil."
771 (let ((root nil) ; found root directory
772 (dbs nil) ; collected databases
773 (roots semanticdb-project-roots) ;all user roots
774 (dir (file-truename (or dir default-directory)))
775 )
776 ;; Find the root based on project functions.
777 (setq root (run-hook-with-args-until-success
778 'semanticdb-project-root-functions
779 dir))
780 ;; Find roots based on strings
781 (while (and roots (not root))
782 (let ((r (file-truename (car roots))))
783 (if (string-match (concat "^" (regexp-quote r)) dir)
784 (setq root r)))
785 (setq roots (cdr roots)))
786
787 ;; If no roots are found, use this directory.
788 (unless root (setq root dir))
789
790 ;; Find databases based on the root directory.
791 (when root
792 ;; The rootlist allows the root functions to possibly
793 ;; return several roots which are in different areas but
794 ;; all apart of the same system.
795 (let ((regexp (concat "^" (regexp-quote root)))
796 (adb semanticdb-database-list) ; all databases
797 )
798 (while adb
799 ;; I don't like this part, but close enough.
800 (if (and (slot-boundp (car adb) 'reference-directory)
801 (string-match regexp (oref (car adb) reference-directory)))
802 (setq dbs (cons (car adb) dbs)))
803 (setq adb (cdr adb))))
804 )
805 ;; Add in system databases
806 (when semanticdb-search-system-databases
807 (setq dbs (nconc dbs semanticdb-project-system-databases)))
808 ;; Return
809 dbs))
810
811
812;;; Generic Accessor Routines
813;;
814;; These routines can be used to get at tags in files w/out
815;; having to know a lot about semanticDB.
816(defvar semanticdb-file-table-hash (make-hash-table :test 'equal)
817 "Hash table mapping file names to database tables.")
818
819(defun semanticdb-file-table-object-from-hash (file)
820 "Retrieve a DB table from the hash for FILE.
821Does not use `file-truename'."
822 (gethash file semanticdb-file-table-hash 'no-hit))
823
824(defun semanticdb-file-table-object-put-hash (file dbtable)
825 "For FILE, associate DBTABLE in the hash table."
826 (puthash file dbtable semanticdb-file-table-hash))
827
828(defun semanticdb-file-table-object (file &optional dontload)
829 "Return a semanticdb table belonging to FILE, make it up to date.
830If file has database tags available in the database, return it.
831If file does not have tags available, and DONTLOAD is nil,
832then load the tags for FILE, and create a new table object for it.
833DONTLOAD does not affect the creation of new database objects."
834 ;; (message "Object Translate: %s" file)
835 (when (file-exists-p file)
836 (let* ((default-directory (file-name-directory file))
837 (tab (semanticdb-file-table-object-from-hash file))
838 (fullfile nil))
839
840 ;; If it is not in the cache, then extract the more traditional
841 ;; way by getting the database, and finding a table in that database.
842 ;; Once we have a table, add it to the hash.
843 (when (eq tab 'no-hit)
844 (setq fullfile (file-truename file))
845 (let ((db (or ;; This line will pick up system databases.
846 (semanticdb-directory-loaded-p default-directory)
847 ;; this line will make a new one if needed.
848 (semanticdb-get-database default-directory))))
849 (setq tab (semanticdb-file-table db fullfile))
850 (when tab
851 (semanticdb-file-table-object-put-hash file tab)
852 (when (not (string= fullfile file))
853 (semanticdb-file-table-object-put-hash fullfile tab)
854 ))
855 ))
856
857 (cond
858 ((and tab
859 ;; Is this in a buffer?
860 ;;(find-buffer-visiting (semanticdb-full-filename tab))
861 (semanticdb-in-buffer-p tab)
862 )
863 (save-excursion
864 ;;(set-buffer (find-buffer-visiting (semanticdb-full-filename tab)))
865 (semanticdb-set-buffer tab)
866 (semantic-fetch-tags)
867 ;; Return the table.
868 tab))
869 ((and tab dontload)
870 ;; If we have table, and we don't want to load it, just return it.
871 tab)
872 ((and tab
873 ;; Is table fully loaded, or just a proxy?
874 (number-or-marker-p (oref tab pointmax))
875 ;; Is this table up to date with the file?
876 (not (semanticdb-needs-refresh-p tab)))
877 ;; A-ok!
878 tab)
879 ((or (and fullfile (get-file-buffer fullfile))
880 (get-file-buffer file))
881 ;; are these two calls this faster than `find-buffer-visiting'?
882
883 ;; If FILE is being visited, but none of the above state is
884 ;; true (meaning, there is no table object associated with it)
885 ;; then it is a file not supported by Semantic, and can be safely
886 ;; ignored.
887 nil)
888 ((not dontload) ;; We must load the file.
889 ;; Full file should have been set by now. Debug why not?
890 (when (and (not tab) (not fullfile))
891 ;; This case is if a 'nil is erroneously put into the hash table. This
892 ;; would need fixing
893 (setq fullfile (file-truename file))
894 )
895
896 ;; If we have a table, but no fullfile, that's ok. Lets get the filename
897 ;; from the table which is pre-truenamed.
898 (when (and (not fullfile) tab)
899 (setq fullfile (semanticdb-full-filename tab)))
900
901 (setq tab (semanticdb-create-table-for-file-not-in-buffer fullfile))
902
903 ;; Save the new table.
904 (semanticdb-file-table-object-put-hash file tab)
905 (when (not (string= fullfile file))
906 (semanticdb-file-table-object-put-hash fullfile tab)
907 )
908 ;; Done!
909 tab)
910 (t
911 ;; Full file should have been set by now. Debug why not?
912 ;; One person found this. Is it a file that failed to parse
913 ;; in the past?
914 (when (not fullfile)
915 (setq fullfile (file-truename file)))
916
917 ;; We were asked not to load the file in and parse it.
918 ;; Instead just create a database table with no tags
919 ;; and a claim of being empty.
920 ;;
921 ;; This will give us a starting point for storing
922 ;; database cross-references so when it is loaded,
923 ;; the cross-references will fire and caches will
924 ;; be cleaned.
925 (let ((ans (semanticdb-create-table-for-file file)))
926 (setq tab (cdr ans))
927
928 ;; Save the new table.
929 (semanticdb-file-table-object-put-hash file tab)
930 (when (not (string= fullfile file))
931 (semanticdb-file-table-object-put-hash fullfile tab)
932 )
933 ;; Done!
934 tab))
935 )
936 )))
937
938(defvar semanticdb-out-of-buffer-create-table-fcn nil
939 "When non-nil, a function for creating a semanticdb table.
940This should take a filename to be parsed.")
941(make-variable-buffer-local 'semanticdb-out-of-buffer-create-table-fcn)
942
943(defun semanticdb-create-table-for-file-not-in-buffer (filename)
944 "Create a table for the file FILENAME.
945If there are no language specific configurations, this
946function will read in the buffer, parse it, and kill the buffer."
947 (if (and semanticdb-out-of-buffer-create-table-fcn
948 (not (file-remote-p filename)))
949 ;; Use external parser only of the file is accessible to the
950 ;; local file system.
951 (funcall semanticdb-out-of-buffer-create-table-fcn filename)
952 (save-excursion
953 (let* ( ;; Remember the buffer to kill
954 (kill-buffer-flag (find-buffer-visiting filename))
955 (buffer-to-kill (or kill-buffer-flag
956 (semantic-find-file-noselect filename t))))
957
958 ;; This shouldn't ever be set. Debug some issue here?
959 ;; (when kill-buffer-flag (debug))
960
961 (set-buffer buffer-to-kill)
962 ;; Find file should automatically do this for us.
963 ;; Sometimes the DB table doesn't contains tags and needs
964 ;; a refresh. For example, when the file is loaded for
965 ;; the first time, and the idle scheduler didn't get a
966 ;; chance to trigger a parse before the file buffer is
967 ;; killed.
968 (when semanticdb-current-table
969 (semantic-fetch-tags))
970 (prog1
971 semanticdb-current-table
972 (when (not kill-buffer-flag)
973 ;; If we had to find the file, then we should kill it
974 ;; to keep the master buffer list clean.
975 (kill-buffer buffer-to-kill)
976 )))))
977 )
978
979(defun semanticdb-file-stream (file)
980 "Return a list of tags belonging to FILE.
981If file has database tags available in the database, return them.
982If file does not have tags available, then load the file, and create them."
983 (let ((table (semanticdb-file-table-object file)))
984 (when table
985 (semanticdb-get-tags table))))
986
987(provide 'semantic/db)
988
989;;; semanticdb.el ends here
diff --git a/lisp/cedet/semantic/decorate.el b/lisp/cedet/semantic/decorate.el
new file mode 100644
index 00000000000..cde0b25d03b
--- /dev/null
+++ b/lisp/cedet/semantic/decorate.el
@@ -0,0 +1,320 @@
1;;; semantic-decorate.el --- Utilities for decorating/highlighting tokens.
2
3;;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2009
4;;; Free Software Foundation, Inc.
5
6;; Author: Eric M. Ludlam <zappo@gnu.org>
7;; Keywords: syntax
8
9;; This file is part of GNU Emacs.
10
11;; GNU Emacs is free software: you can redistribute it and/or modify
12;; it under the terms of the GNU General Public License as published by
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
23
24;;; Commentary:
25;;
26;; Text representing a semantic tag is wrapped in an overlay.
27;; This overlay can be used for highlighting, or setting other
28;; editing properties on a tag, such as "read only."
29;;
30
31(require 'semantic)
32(require 'pulse)
33
34;;; Code:
35
36;;; Highlighting Basics
37(defun semantic-highlight-tag (tag &optional face)
38 "Specify that TAG should be highlighted.
39Optional FACE specifies the face to use."
40 (let ((o (semantic-tag-overlay tag)))
41 (semantic-overlay-put o 'old-face
42 (cons (semantic-overlay-get o 'face)
43 (semantic-overlay-get o 'old-face)))
44 (semantic-overlay-put o 'face (or face 'semantic-tag-highlight-face))
45 ))
46
47(defun semantic-unhighlight-tag (tag)
48 "Unhighlight TAG, restoring it's previous face."
49 (let ((o (semantic-tag-overlay tag)))
50 (semantic-overlay-put o 'face (car (semantic-overlay-get o 'old-face)))
51 (semantic-overlay-put o 'old-face (cdr (semantic-overlay-get o 'old-face)))
52 ))
53
54;;; Momentary Highlighting - One line
55(defun semantic-momentary-highlight-one-tag-line (tag &optional face)
56 "Highlight the first line of TAG, unhighlighting before next command.
57Optional argument FACE specifies the face to do the highlighting."
58 (save-excursion
59 ;; Go to first line in tag
60 (semantic-go-to-tag tag)
61 (pulse-momentary-highlight-one-line (point))))
62
63;;; Momentary Highlighting - Whole Tag
64(defun semantic-momentary-highlight-tag (tag &optional face)
65 "Highlight TAG, removing highlighting when the user hits a key.
66Optional argument FACE is the face to use for highlighting.
67If FACE is not specified, then `highlight' will be used."
68 (when (semantic-tag-with-position-p tag)
69 (if (not (semantic-overlay-p (semantic-tag-overlay tag)))
70 ;; No overlay, but a position. Highlight the first line only.
71 (semantic-momentary-highlight-one-tag-line tag face)
72 ;; The tag has an overlay, highlight the whole thing
73 (pulse-momentary-highlight-overlay (semantic-tag-overlay tag)
74 face)
75 )))
76
77(defun semantic-set-tag-face (tag face)
78 "Specify that TAG should use FACE for display."
79 (semantic-overlay-put (semantic-tag-overlay tag) 'face face))
80
81(defun semantic-set-tag-invisible (tag &optional visible)
82 "Enable the text in TAG to be made invisible.
83If VISIBLE is non-nil, make the text visible."
84 (semantic-overlay-put (semantic-tag-overlay tag) 'invisible
85 (not visible)))
86
87(defun semantic-tag-invisible-p (tag)
88 "Return non-nil if TAG is invisible."
89 (semantic-overlay-get (semantic-tag-overlay tag) 'invisible))
90
91(defun semantic-set-tag-intangible (tag &optional tangible)
92 "Enable the text in TAG to be made intangible.
93If TANGIBLE is non-nil, make the text visible.
94This function does not have meaning in XEmacs because it seems that
95the extent 'intangible' property does not exist."
96 (semantic-overlay-put (semantic-tag-overlay tag) 'intangible
97 (not tangible)))
98
99(defun semantic-tag-intangible-p (tag)
100 "Return non-nil if TAG is intangible.
101This function does not have meaning in XEmacs because it seems that
102the extent 'intangible' property does not exist."
103 (semantic-overlay-get (semantic-tag-overlay tag) 'intangible))
104
105(defun semantic-overlay-signal-read-only
106 (overlay after start end &optional len)
107 "Hook used in modification hooks to prevent modification.
108Allows deletion of the entire text.
109Argument OVERLAY, AFTER, START, END, and LEN are passed in by the system."
110 ;; Stolen blithly from cpp.el in Emacs 21.1
111 (if (and (not after)
112 (or (< (semantic-overlay-start overlay) start)
113 (> (semantic-overlay-end overlay) end)))
114 (error "This text is read only")))
115
116(defun semantic-set-tag-read-only (tag &optional writable)
117 "Enable the text in TAG to be made read-only.
118Optional argument WRITABLE should be non-nil to make the text writable
119instead of read-only."
120 (let ((o (semantic-tag-overlay tag))
121 (hook (if writable nil '(semantic-overlay-signal-read-only))))
122 (if (featurep 'xemacs)
123 ;; XEmacs extents have a 'read-only' property.
124 (semantic-overlay-put o 'read-only (not writable))
125 (semantic-overlay-put o 'modification-hooks hook)
126 (semantic-overlay-put o 'insert-in-front-hooks hook)
127 (semantic-overlay-put o 'insert-behind-hooks hook))))
128
129(defun semantic-tag-read-only-p (tag)
130 "Return non-nil if the current TAG is marked read only."
131 (let ((o (semantic-tag-overlay tag)))
132 (if (featurep 'xemacs)
133 ;; XEmacs extents have a 'read-only' property.
134 (semantic-overlay-get o 'read-only)
135 (member 'semantic-overlay-signal-read-only
136 (semantic-overlay-get o 'modification-hooks)))))
137
138;;; backwards compatability
139
140(semantic-alias-obsolete 'semantic-highlight-token
141 'semantic-highlight-tag)
142(semantic-alias-obsolete 'semantic-unhighlight-token
143 'semantic-unhighlight-tag)
144(semantic-alias-obsolete 'semantic-momentary-highlight-token
145 'semantic-momentary-highlight-tag)
146(semantic-alias-obsolete 'semantic-set-token-face
147 'semantic-set-tag-face)
148(semantic-alias-obsolete 'semantic-set-token-invisible
149 'semantic-set-tag-invisible)
150(semantic-alias-obsolete 'semantic-token-invisible-p
151 'semantic-tag-invisible-p)
152(semantic-alias-obsolete 'semantic-set-token-intangible
153 'semantic-set-tag-intangible)
154(semantic-alias-obsolete 'semantic-token-intangible-p
155 'semantic-tag-intangible-p)
156(semantic-alias-obsolete 'semantic-set-token-read-only
157 'semantic-set-tag-read-only)
158(semantic-alias-obsolete 'semantic-token-read-only-p
159 'semantic-tag-read-only-p)
160
161;;; Secondary overlays
162;;
163;; Some types of decoration require a second overlay to be made.
164;; It could be for images, arrows, or whatever.
165;; We need a way to create such an overlay, and make sure it
166;; gets whacked, but doesn't show up in the master list
167;; of overlays used for searching.
168(defun semantic-tag-secondary-overlays (tag)
169 "Return a list of secondary overlays active on TAG."
170 (semantic--tag-get-property tag 'secondary-overlays))
171
172(defun semantic-tag-create-secondary-overlay (tag &optional link-hook)
173 "Create a secondary overlay for TAG.
174Returns an overlay. The overlay is also saved in TAG.
175LINK-HOOK is a function called whenever TAG is to be linked into
176a buffer. It should take TAG and OVERLAY as arguments.
177The LINK-HOOK should be used to position and set properties on the
178generated secondary overlay."
179 (if (not (semantic-tag-overlay tag))
180 ;; do nothing if there is no overlay
181 nil
182 (let* ((os (semantic-tag-start tag))
183 (oe (semantic-tag-end tag))
184 (o (semantic-make-overlay os oe (semantic-tag-buffer tag) t))
185 (attr (semantic-tag-secondary-overlays tag))
186 )
187 (semantic--tag-put-property tag 'secondary-overlays (cons o attr))
188 (semantic-overlay-put o 'semantic-secondary t)
189 (semantic-overlay-put o 'semantic-link-hook link-hook)
190 (semantic-tag-add-hook tag 'link-hook 'semantic--tag-link-secondary-overlays)
191 (semantic-tag-add-hook tag 'unlink-hook 'semantic--tag-unlink-secondary-overlays)
192 (semantic-tag-add-hook tag 'unlink-copy-hook 'semantic--tag-unlink-copy-secondary-overlays)
193 (run-hook-with-args link-hook tag o)
194 o)))
195
196(defun semantic-tag-get-secondary-overlay (tag property)
197 "Return secondary overlays from TAG with PROPERTY.
198PROPERTY is a symbol and all overlays with that symbol are returned.."
199 (let* ((olsearch (semantic-tag-secondary-overlays tag))
200 (o nil))
201 (while olsearch
202 (when (semantic-overlay-get (car olsearch) property)
203 (setq o (cons (car olsearch) o)))
204 (setq olsearch (cdr olsearch)))
205 o))
206
207(defun semantic-tag-delete-secondary-overlay (tag overlay-or-property)
208 "Delete from TAG the secondary overlay OVERLAY-OR-PROPERTY.
209If OVERLAY-OR-PROPERTY is an overlay, delete that overlay.
210If OVERLAY-OR-PROPERTY is a symbol, find the overlay with that property."
211 (let* ((o overlay-or-property))
212 (if (semantic-overlay-p o)
213 (setq o (list o))
214 (setq o (semantic-tag-get-secondary-overlay tag overlay-or-property)))
215 (while (semantic-overlay-p (car o))
216 ;; We don't really need to worry about the hooks.
217 ;; They will clean themselves up eventually ??
218 (semantic--tag-put-property
219 tag 'secondary-overlays
220 (delete (car o) (semantic-tag-secondary-overlays tag)))
221 (semantic-overlay-delete (car o))
222 (setq o (cdr o)))))
223
224(defun semantic--tag-unlink-copy-secondary-overlays (tag)
225 "Unlink secondary overlays from TAG which is a copy.
226This means we don't destroy the overlays, only remove reference
227from them in TAG."
228 (let ((ol (semantic-tag-secondary-overlays tag)))
229 (while ol
230 ;; Else, remove all traces of ourself from the tag
231 ;; Note to self: Does this prevent multiple types of secondary
232 ;; overlays per tag?
233 (semantic-tag-remove-hook tag 'link-hook 'semantic--tag-link-secondary-overlays)
234 (semantic-tag-remove-hook tag 'unlink-hook 'semantic--tag-unlink-secondary-overlays)
235 (semantic-tag-remove-hook tag 'unlink-copy-hook 'semantic--tag-unlink-copy-secondary-overlays)
236 ;; Next!
237 (setq ol (cdr ol)))
238 (semantic--tag-put-property tag 'secondary-overlays nil)
239 ))
240
241(defun semantic--tag-unlink-secondary-overlays (tag)
242 "Unlink secondary overlays from TAG."
243 (let ((ol (semantic-tag-secondary-overlays tag))
244 (nl nil))
245 (while ol
246 (if (semantic-overlay-get (car ol) 'semantic-link-hook)
247 ;; Only put in a proxy if there is a link-hook. If there is no link-hook
248 ;; the decorating mode must know when tags are unlinked on its own.
249 (setq nl (cons (semantic-overlay-get (car ol) 'semantic-link-hook)
250 nl))
251 ;; Else, remove all traces of ourself from the tag
252 ;; Note to self: Does this prevent multiple types of secondary
253 ;; overlays per tag?
254 (semantic-tag-remove-hook tag 'link-hook 'semantic--tag-link-secondary-overlays)
255 (semantic-tag-remove-hook tag 'unlink-hook 'semantic--tag-unlink-secondary-overlays)
256 (semantic-tag-remove-hook tag 'unlink-copy-hook 'semantic--tag-unlink-copy-secondary-overlays)
257 )
258 (semantic-overlay-delete (car ol))
259 (setq ol (cdr ol)))
260 (semantic--tag-put-property tag 'secondary-overlays (nreverse nl))
261 ))
262
263(defun semantic--tag-link-secondary-overlays (tag)
264 "Unlink secondary overlays from TAG."
265 (let ((ol (semantic-tag-secondary-overlays tag)))
266 ;; Wipe out old values.
267 (semantic--tag-put-property tag 'secondary-overlays nil)
268 ;; Run all the link hooks.
269 (while ol
270 (semantic-tag-create-secondary-overlay tag (car ol))
271 (setq ol (cdr ol)))
272 ))
273
274;;; Secondary Overlay Uses
275;;
276;; States to put on tags that depend on a secondary overlay.
277(defun semantic-set-tag-folded (tag &optional folded)
278 "Fold TAG, such that only the first line of text is shown.
279Optional argument FOLDED should be non-nil to fold the tag.
280nil implies the tag should be fully shown."
281 ;; If they are different, do the deed.
282 (let ((o (semantic-tag-folded-p tag)))
283 (if (not folded)
284 ;; We unfold.
285 (when o
286 (semantic-tag-delete-secondary-overlay tag 'semantic-folded))
287 (unless o
288 ;; Add the foldn
289 (setq o (semantic-tag-create-secondary-overlay tag))
290 ;; mark as folded
291 (semantic-overlay-put o 'semantic-folded t)
292 ;; Move to cover end of tag
293 (save-excursion
294 (goto-char (semantic-tag-start tag))
295 (end-of-line)
296 (semantic-overlay-move o (point) (semantic-tag-end tag)))
297 ;; We need to modify the invisibility spec for this to
298 ;; work.
299 (if (or (eq buffer-invisibility-spec t)
300 (not (assoc 'semantic-fold buffer-invisibility-spec)))
301 (add-to-invisibility-spec '(semantic-fold . t)))
302 (semantic-overlay-put o 'invisible 'semantic-fold)
303 (overlay-put o 'isearch-open-invisible
304 'semantic-set-tag-folded-isearch)))
305 ))
306
307(defun semantic-set-tag-folded-isearch (overlay)
308 "Called by isearch if it discovers text in the folded region.
309OVERLAY is passed in by isearch."
310 (semantic-set-tag-folded (semantic-current-tag) nil)
311 )
312
313(defun semantic-tag-folded-p (tag)
314 "Non-nil if TAG is currently folded."
315 (semantic-tag-get-secondary-overlay tag 'semantic-folded)
316 )
317
318(provide 'semantic/decorate)
319
320;;; semantic-decorate.el ends here
diff --git a/lisp/cedet/semantic/lex-spp.el b/lisp/cedet/semantic/lex-spp.el
new file mode 100644
index 00000000000..7be7a3a816b
--- /dev/null
+++ b/lisp/cedet/semantic/lex-spp.el
@@ -0,0 +1,1187 @@
1;;; semantic-lex-spp.el --- Semantic Lexical Pre-processor
2
3;;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4
5;; Author: Eric M. Ludlam <zappo@gnu.org>
6
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software: you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
11;; the Free Software Foundation, either version 3 of the License, or
12;; (at your option) any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
21
22;;; Commentary:
23;;
24;; The Semantic Preprocessor works with semantic-lex to provide a phase
25;; during lexical analysis to do the work of a pre-processor.
26;;
27;; A pre-processor identifies lexical syntax mixed in with another language
28;; and replaces some keyword tokens with streams of alternate tokens.
29;;
30;; If you use SPP in your language, be sure to specify this in your
31;; semantic language setup function:
32;;
33;; (add-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook nil t)
34;;
35;;
36;; Special Lexical Tokens:
37;;
38;; There are several special lexical tokens that are used by the
39;; Semantic PreProcessor lexer. They are:
40;;
41;; Declarations:
42;; spp-macro-def - A definition of a lexical macro.
43;; spp-macro-undef - A removal of a definition of a lexical macro.
44;; spp-system-include - A system level include file
45;; spp-include - An include file
46;; spp-concat - A lexical token representing textual concatenation
47;; of symbol parts.
48;;
49;; Operational tokens:
50;; spp-arg-list - Represents an argument list to a macro.
51;; spp-symbol-merge - A request for multiple symbols to be textually merged.
52;;
53;;; TODO:
54;;
55;; Use `semantic-push-parser-warning' for situations where there are likely
56;; macros that are undefined unexpectedly, or other problem.
57;;
58;; TODO:
59;;
60;; Try to handle the case of:
61;;
62;; #define NN namespace nn {
63;; #define NN_END }
64;;
65;; NN
66;; int mydecl() {}
67;; NN_END
68;;
69
70(require 'semantic/lex)
71
72;;; Code:
73(defvar semantic-lex-spp-macro-symbol-obarray nil
74 "Table of macro keywords used by the Semantic Preprocessor.
75These symbols will be used in addition to those in
76`semantic-lex-spp-dynamic-macro-symbol-obarray'.")
77(make-variable-buffer-local 'semantic-lex-spp-macro-symbol-obarray)
78
79(defvar semantic-lex-spp-project-macro-symbol-obarray nil
80 "Table of macro keywords for this project.
81These symbols will be used in addition to those in
82`semantic-lex-spp-dynamic-macro-symbol-obarray'.")
83(make-variable-buffer-local 'semantic-lex-spp-project-macro-symbol-obarray)
84
85(defvar semantic-lex-spp-dynamic-macro-symbol-obarray nil
86 "Table of macro keywords used during lexical analysis.
87Macros are lexical symbols which are replaced by other lexical
88tokens during lexical analysis. During analysis symbols can be
89added and removed from this symbol table.")
90(make-variable-buffer-local 'semantic-lex-spp-dynamic-macro-symbol-obarray)
91
92(defvar semantic-lex-spp-dynamic-macro-symbol-obarray-stack nil
93 "A stack of obarrays for temporarilly scoped macro values.")
94(make-variable-buffer-local 'semantic-lex-spp-dynamic-macro-symbol-obarray-stack)
95
96(defvar semantic-lex-spp-expanded-macro-stack nil
97 "The stack of lexical SPP macros we have expanded.")
98;; The above is not buffer local. Some macro expansions need to be
99;; dumped into a secondary buffer for re-lexing.
100
101;;; NON-RECURSIVE MACRO STACK
102;; C Pre-processor does not allow recursive macros. Here are some utils
103;; for managing the symbol stack of where we've been.
104
105(defmacro semantic-lex-with-macro-used (name &rest body)
106 "With the macro NAME currently being expanded, execute BODY.
107Pushes NAME into the macro stack. The above stack is checked
108by `semantic-lex-spp-symbol' to not return true for any symbol
109currently being expanded."
110 `(unwind-protect
111 (progn
112 (push ,name semantic-lex-spp-expanded-macro-stack)
113 ,@body)
114 (pop semantic-lex-spp-expanded-macro-stack)))
115(put 'semantic-lex-with-macro-used 'lisp-indent-function 1)
116
117(add-hook
118 'edebug-setup-hook
119 #'(lambda ()
120
121 (def-edebug-spec semantic-lex-with-macro-used
122 (symbolp def-body)
123 )
124
125 ))
126
127;;; MACRO TABLE UTILS
128;;
129;; The dynamic macro table is a buffer local variable that is modified
130;; during the analysis. OBARRAYs are used, so the language must
131;; have symbols that are compatible with Emacs Lisp symbols.
132;;
133(defsubst semantic-lex-spp-symbol (name)
134 "Return spp symbol with NAME or nil if not found.
135The searcy priority is:
136 1. DYNAMIC symbols
137 2. PROJECT specified symbols.
138 3. SYSTEM specified symbols."
139 (and
140 ;; Only strings...
141 (stringp name)
142 ;; Make sure we don't recurse.
143 (not (member name semantic-lex-spp-expanded-macro-stack))
144 ;; Do the check of the various tables.
145 (or
146 ;; DYNAMIC
147 (and (arrayp semantic-lex-spp-dynamic-macro-symbol-obarray)
148 (intern-soft name semantic-lex-spp-dynamic-macro-symbol-obarray))
149 ;; PROJECT
150 (and (arrayp semantic-lex-spp-project-macro-symbol-obarray)
151 (intern-soft name semantic-lex-spp-project-macro-symbol-obarray))
152 ;; SYSTEM
153 (and (arrayp semantic-lex-spp-macro-symbol-obarray)
154 (intern-soft name semantic-lex-spp-macro-symbol-obarray))
155 ;; ...
156 )))
157
158(defsubst semantic-lex-spp-symbol-p (name)
159 "Return non-nil if a keyword with NAME exists in any keyword table."
160 (if (semantic-lex-spp-symbol name)
161 t))
162
163(defsubst semantic-lex-spp-dynamic-map ()
164 "Return the dynamic macro map for the current buffer."
165 (or semantic-lex-spp-dynamic-macro-symbol-obarray
166 (setq semantic-lex-spp-dynamic-macro-symbol-obarray
167 (make-vector 13 0))))
168
169(defsubst semantic-lex-spp-dynamic-map-stack ()
170 "Return the dynamic macro map for the current buffer."
171 (or semantic-lex-spp-dynamic-macro-symbol-obarray-stack
172 (setq semantic-lex-spp-dynamic-macro-symbol-obarray-stack
173 (make-vector 13 0))))
174
175(defun semantic-lex-spp-symbol-set (name value &optional obarray-in)
176 "Set value of spp symbol with NAME to VALUE and return VALUE.
177If optional OBARRAY-IN is non-nil, then use that obarray instead of
178the dynamic map."
179 (if (and (stringp value) (string= value "")) (setq value nil))
180 (set (intern name (or obarray-in
181 (semantic-lex-spp-dynamic-map)))
182 value))
183
184(defsubst semantic-lex-spp-symbol-remove (name &optional obarray)
185 "Remove the spp symbol with NAME.
186If optional OBARRAY is non-nil, then use that obarray instead of
187the dynamic map."
188 (unintern name (or obarray
189 (semantic-lex-spp-dynamic-map))))
190
191(defun semantic-lex-spp-symbol-push (name value)
192 "Push macro NAME with VALUE into the map.
193Reverse with `semantic-lex-spp-symbol-pop'."
194 (let* ((map (semantic-lex-spp-dynamic-map))
195 (stack (semantic-lex-spp-dynamic-map-stack))
196 (mapsym (intern name map))
197 (stacksym (intern name stack))
198 (mapvalue (when (boundp mapsym) (symbol-value mapsym)))
199 )
200 (when (boundp mapsym)
201 ;; Make sure there is a stack
202 (if (not (boundp stacksym)) (set stacksym nil))
203 ;; If there is a value to push, then push it.
204 (set stacksym (cons mapvalue (symbol-value stacksym)))
205 )
206 ;; Set our new value here.
207 (set mapsym value)
208 ))
209
210(defun semantic-lex-spp-symbol-pop (name)
211 "Pop macro NAME from the stackmap into the orig map.
212Reverse with `semantic-lex-spp-symbol-pop'."
213 (let* ((map (semantic-lex-spp-dynamic-map))
214 (stack (semantic-lex-spp-dynamic-map-stack))
215 (mapsym (intern name map))
216 (stacksym (intern name stack))
217 (oldvalue nil)
218 )
219 (if (or (not (boundp stacksym) )
220 (= (length (symbol-value stacksym)) 0))
221 ;; Nothing to pop, remove it.
222 (unintern name map)
223 ;; If there is a value to pop, then add it to the map.
224 (set mapsym (car (symbol-value stacksym)))
225 (set stacksym (cdr (symbol-value stacksym)))
226 )))
227
228(defsubst semantic-lex-spp-symbol-stream (name)
229 "Return replacement stream of macro with NAME."
230 (let ((spp (semantic-lex-spp-symbol name)))
231 (if spp
232 (symbol-value spp))))
233
234(defun semantic-lex-make-spp-table (specs)
235 "Convert spp macro list SPECS into an obarray and return it.
236SPECS must be a list of (NAME . REPLACEMENT) elements, where:
237
238NAME is the name of the spp macro symbol to define.
239REPLACEMENT a string that would be substituted in for NAME."
240
241 ;; Create the symbol hash table
242 (let ((semantic-lex-spp-macro-symbol-obarray (make-vector 13 0))
243 spec)
244 ;; fill it with stuff
245 (while specs
246 (setq spec (car specs)
247 specs (cdr specs))
248 (semantic-lex-spp-symbol-set
249 (car spec)
250 (cdr spec)
251 semantic-lex-spp-macro-symbol-obarray))
252 semantic-lex-spp-macro-symbol-obarray))
253
254(defun semantic-lex-spp-save-table ()
255 "Return a list of spp macros and values.
256The return list is meant to be saved in a semanticdb table."
257 (let (macros)
258 (when (arrayp semantic-lex-spp-dynamic-macro-symbol-obarray)
259 (mapatoms
260 #'(lambda (symbol)
261 (setq macros (cons (cons (symbol-name symbol)
262 (symbol-value symbol))
263 macros)))
264 semantic-lex-spp-dynamic-macro-symbol-obarray))
265 macros))
266
267(defun semantic-lex-spp-macros ()
268 "Return a list of spp macros as Lisp symbols.
269The value of each symbol is the replacement stream."
270 (let (macros)
271 (when (arrayp semantic-lex-spp-macro-symbol-obarray)
272 (mapatoms
273 #'(lambda (symbol)
274 (setq macros (cons symbol macros)))
275 semantic-lex-spp-macro-symbol-obarray))
276 (when (arrayp semantic-lex-spp-project-macro-symbol-obarray)
277 (mapatoms
278 #'(lambda (symbol)
279 (setq macros (cons symbol macros)))
280 semantic-lex-spp-project-macro-symbol-obarray))
281 (when (arrayp semantic-lex-spp-dynamic-macro-symbol-obarray)
282 (mapatoms
283 #'(lambda (symbol)
284 (setq macros (cons symbol macros)))
285 semantic-lex-spp-dynamic-macro-symbol-obarray))
286 macros))
287
288(defun semantic-lex-spp-set-dynamic-table (new-entries)
289 "Set the dynamic symbol table to NEW-ENTRIES.
290For use with semanticdb restoration of state."
291 (dolist (e new-entries)
292 ;; Default obarray for below is the dynamic map.
293 (semantic-lex-spp-symbol-set (car e) (cdr e))))
294
295(defun semantic-lex-spp-reset-hook (start end)
296 "Reset anything needed by SPP for parsing.
297In this case, reset the dynamic macro symbol table if
298START is (point-min).
299END is not used."
300 (when (= start (point-min))
301 (setq semantic-lex-spp-dynamic-macro-symbol-obarray nil
302 semantic-lex-spp-dynamic-macro-symbol-obarray-stack nil
303 ;; This shouldn't not be nil, but reset just in case.
304 semantic-lex-spp-expanded-macro-stack nil)
305 ))
306
307;;; MACRO EXPANSION: Simple cases
308;;
309;; If a user fills in the table with simple strings, we can
310;; support that by converting them into tokens with the
311;; various analyzers that are available.
312
313(defun semantic-lex-spp-extract-regex-and-compare (analyzer value)
314 "Extract a regexp from an ANALYZER and use to match VALUE.
315Return non-nil if it matches"
316 (let* ((condition (car analyzer))
317 (regex (cond ((eq (car condition) 'looking-at)
318 (nth 1 condition))
319 (t
320 nil))))
321 (when regex
322 (string-match regex value))
323 ))
324
325(defun semantic-lex-spp-simple-macro-to-macro-stream (val beg end argvalues)
326 "Convert lexical macro contents VAL into a macro expansion stream.
327These are for simple macro expansions that a user may have typed in directly.
328As such, we need to analyze the input text, to figure out what kind of real
329lexical token we should be inserting in its place.
330
331Argument VAL is the value of some macro to be converted into a stream.
332BEG and END are the token bounds of the macro to be expanded
333that will somehow gain a much longer token stream.
334ARGVALUES are values for any arg list, or nil."
335 (cond
336 ;; We perform a replacement. Technically, this should
337 ;; be a full lexical step over the "val" string, but take
338 ;; a guess that its just a keyword or existing symbol.
339 ;;
340 ;; Probably a really bad idea. See how it goes.
341 ((semantic-lex-spp-extract-regex-and-compare
342 semantic-lex-symbol-or-keyword val)
343 (semantic-lex-push-token
344 (semantic-lex-token (or (semantic-lex-keyword-p val) 'symbol)
345 beg end
346 val)))
347
348 ;; Ok, the rest of these are various types of syntax.
349 ;; Conveniences for users that type in their symbol table.
350 ((semantic-lex-spp-extract-regex-and-compare
351 semantic-lex-punctuation val)
352 (semantic-lex-token 'punctuation beg end val))
353 ((semantic-lex-spp-extract-regex-and-compare
354 semantic-lex-number val)
355 (semantic-lex-token 'number beg end val))
356 ((semantic-lex-spp-extract-regex-and-compare
357 semantic-lex-paren-or-list val)
358 (semantic-lex-token 'semantic-list beg end val))
359 ((semantic-lex-spp-extract-regex-and-compare
360 semantic-lex-string val)
361 (semantic-lex-token 'string beg end val))
362 (t nil)
363 ))
364
365;;; MACRO EXPANSION : Lexical token replacement
366;;
367;; When substituting in a macro from a token stream of formatted
368;; semantic lex tokens, things can be much more complicated.
369;;
370;; Some macros have arguments that get set into the dynamic macro
371;; table during replacement.
372;;
373;; In general, the macro tokens are substituted into the regular
374;; token stream, but placed under the characters of the original
375;; macro symbol.
376;;
377;; Argument lists are saved as a lexical token at the beginning
378;; of a replacement value.
379
380(defun semantic-lex-spp-one-token-to-txt (tok)
381 "Convert the token TOK into a string.
382If TOK is made of multiple tokens, convert those to text. This
383conversion is needed if a macro has a merge symbol in it that
384combines the text of two previously distinct symbols. For
385exampe, in c:
386
387#define (a,b) a ## b;"
388 (let ((txt (semantic-lex-token-text tok))
389 (sym nil)
390 )
391 (cond ((and (eq (car tok) 'symbol)
392 (setq sym (semantic-lex-spp-symbol txt))
393 (not (semantic-lex-spp-macro-with-args (symbol-value sym)))
394 )
395 ;; Now that we have a symbol,
396 (let ((val (symbol-value sym)))
397 (cond ((and (consp val)
398 (symbolp (car val)))
399 (semantic-lex-spp-one-token-to-txt val))
400 ((and (consp val)
401 (consp (car val))
402 (symbolp (car (car val))))
403 (mapconcat (lambda (subtok)
404 (semantic-lex-spp-one-token-to-txt subtok))
405 val
406 ""))
407 ;; If val is nil, that's probably wrong.
408 ;; Found a system header case where this was true.
409 ((null val) "")
410 ;; Debug wierd stuff.
411 (t (debug)))
412 ))
413 ((stringp txt)
414 txt)
415 (t nil))
416 ))
417
418(defun semantic-lex-spp-macro-with-args (val)
419 "If the macro value VAL has an argument list, return the arglist."
420 (when (and val (consp val) (consp (car val))
421 (eq 'spp-arg-list (car (car val))))
422 (car (cdr (car val)))))
423
424(defun semantic-lex-spp-token-macro-to-macro-stream (val beg end argvalues)
425 "Convert lexical macro contents VAL into a macro expansion stream.
426Argument VAL is the value of some macro to be converted into a stream.
427BEG and END are the token bounds of the macro to be expanded
428that will somehow gain a much longer token stream.
429ARGVALUES are values for any arg list, or nil.
430See comments in code for information about how token streams are processed
431and what valid VAL values are."
432
433 ;; A typical VAL value might be either a stream of tokens.
434 ;; Tokens saved into a macro stream always includes the text from the
435 ;; buffer, since the locations specified probably don't represent
436 ;; that text anymore, or even the same buffer.
437 ;;
438 ;; CASE 1: Simple token stream
439 ;;
440 ;; #define SUPER mysuper::
441 ;; ==>
442 ;;((symbol "mysuper" 480 . 487)
443 ;; (punctuation ":" 487 . 488)
444 ;; (punctuation ":" 488 . 489))
445 ;;
446 ;; CASE 2: Token stream with argument list
447 ;;
448 ;; #define INT_FCN(name) int name (int in)
449 ;; ==>
450 ;; ((spp-arg-list ("name") 558 . 564)
451 ;; (INT "int" 565 . 568)
452 ;; (symbol "name" 569 . 573)
453 ;; (semantic-list "(int in)" 574 . 582))
454 ;;
455 ;; In the second case, a macro with an argument list as the a rgs as the
456 ;; first entry.
457 ;;
458 ;; CASE 3: Symbol text merge
459 ;;
460 ;; #define TMP(a) foo_ ## a
461 ;; ==>
462 ;; ((spp-arg-list ("a") 20 . 23)
463 ;; (spp-symbol-merge ((symbol "foo_" 24 . 28) (symbol "a" 32 . 33))
464 ;; 24 . 33))
465 ;;
466 ;; Usually in conjunction with a macro with an argument, merging symbol
467 ;; parts is a way of fabricating new symbols from pieces inside the macro.
468 ;; These macros use `spp-symbol-merge' tokens whose TEXT part is another
469 ;; token stream. This sub-stream ought to consist of only 2 SYMBOL pieces,
470 ;; though I suppose keywords might be ok. The end result of this example
471 ;; merge symbol would be (symbol "foo_A" 24 . 33) where A is the symbol
472 ;; passed in from the arg list "a".
473 ;;
474 ;; CASE 4: Nested token streams
475 ;;
476 ;; #define FOO(f) f
477 ;; #define BLA bla FOO(foo)
478 ;; ==>
479 ;; ((INT "int" 82 . 85)
480 ;; (symbol "FOO" 86 . 89)
481 ;; (semantic-list "(foo)" 89 . 94))
482 ;;
483 ;; Nested token FOO shows up in the table of macros, and gets replace
484 ;; inline. This is the same as case 2.
485
486 (let ((arglist (semantic-lex-spp-macro-with-args val))
487 (argalist nil)
488 (val-tmp nil)
489 (v nil)
490 )
491 ;; CASE 2: Dealing with the arg list.
492 (when arglist
493 ;; Skip the arg list.
494 (setq val (cdr val))
495
496 ;; Push args into the replacement list.
497 (let ((AV argvalues))
498 (dolist (A arglist)
499 (let* ((argval (car AV)))
500
501 (semantic-lex-spp-symbol-push A argval)
502 (setq argalist (cons (cons A argval) argalist))
503 (setq AV (cdr AV)))))
504 )
505
506 ;; Set val-tmp after stripping arguments.
507 (setq val-tmp val)
508
509 ;; CASE 1: Push everything else onto the list.
510 ;; Once the arg list is stripped off, CASE 2 is the same
511 ;; as CASE 1.
512 (while val-tmp
513 (setq v (car val-tmp))
514 (setq val-tmp (cdr val-tmp))
515
516 (let* (;; The text of the current lexical token.
517 (txt (car (cdr v)))
518 ;; Try to convert txt into a macro declaration. If it is
519 ;; not a macro, use nil.
520 (txt-macro-or-nil (semantic-lex-spp-symbol txt))
521 ;; If our current token is a macro, then pull off the argument
522 ;; list.
523 (macro-and-args
524 (when txt-macro-or-nil
525 (semantic-lex-spp-macro-with-args (symbol-value txt-macro-or-nil)))
526 )
527 ;; We need to peek at the next token when testing for
528 ;; used macros with arg lists.
529 (next-tok-class (semantic-lex-token-class (car val-tmp)))
530 )
531
532 (cond
533 ;; CASE 3: Merge symbols together.
534 ((eq (semantic-lex-token-class v) 'spp-symbol-merge)
535 ;; We need to merge the tokens in the 'text segement together,
536 ;; and produce a single symbol from it.
537 (let ((newsym
538 (mapconcat (lambda (tok)
539 (semantic-lex-spp-one-token-to-txt tok))
540 txt
541 "")))
542 (semantic-lex-push-token
543 (semantic-lex-token 'symbol beg end newsym))
544 ))
545
546 ;; CASE 2: Argument replacement. If a discovered symbol is in
547 ;; the active list of arguments, then we need to substitute
548 ;; in the new value.
549 ((and (eq (semantic-lex-token-class v) 'symbol) txt-macro-or-nil
550 (or (and macro-and-args (eq next-tok-class 'semantic-list))
551 (not macro-and-args))
552 )
553 (let ((AV nil))
554 (when macro-and-args
555 (setq AV
556 (semantic-lex-spp-stream-for-arglist (car val-tmp)))
557 ;; We used up these args. Pull from the stream.
558 (setq val-tmp (cdr val-tmp))
559 )
560
561 (semantic-lex-with-macro-used txt
562 ;; Don't recurse directly into this same fcn, because it is
563 ;; convenient to have plain string replacements too.
564 (semantic-lex-spp-macro-to-macro-stream
565 (symbol-value txt-macro-or-nil)
566 beg end AV))
567 ))
568
569 ;; This is a HACK for the C parser. The 'macros text
570 ;; property is some storage so that the parser can do
571 ;; some C specific text manipulations.
572 ((eq (semantic-lex-token-class v) 'semantic-list)
573 ;; Push our arg list onto the semantic list.
574 (when argalist
575 (setq txt (concat txt)) ; Copy the text.
576 (put-text-property 0 1 'macros argalist txt))
577 (semantic-lex-push-token
578 (semantic-lex-token (semantic-lex-token-class v) beg end txt))
579 )
580
581 ;; CASE 1: Just another token in the stream.
582 (t
583 ;; Nothing new.
584 (semantic-lex-push-token
585 (semantic-lex-token (semantic-lex-token-class v) beg end txt))
586 )
587 )))
588
589 ;; CASE 2: The arg list we pushed onto the symbol table
590 ;; must now be removed.
591 (dolist (A arglist)
592 (semantic-lex-spp-symbol-pop A))
593 ))
594
595;;; Macro Merging
596;;
597;; Used when token streams from different macros include eachother.
598;; Merged macro streams perform in place replacements.
599
600(defun semantic-lex-spp-merge-streams (raw-stream)
601 "Merge elements from the RAW-STREAM together.
602Handle spp-concat symbol concatenation.
603Handle Nested macro replacements.
604Return the cooked stream."
605 (let ((cooked-stream nil))
606 ;; Merge the stream
607 (while raw-stream
608 (cond ((eq (semantic-lex-token-class (car raw-stream)) 'spp-concat)
609 ;; handle hashhash, by skipping it.
610 (setq raw-stream (cdr raw-stream))
611 ;; Now merge the symbols.
612 (let ((prev-tok (car cooked-stream))
613 (next-tok (car raw-stream)))
614 (setq cooked-stream (cdr cooked-stream))
615 (push (semantic-lex-token
616 'spp-symbol-merge
617 (semantic-lex-token-start prev-tok)
618 (semantic-lex-token-end next-tok)
619 (list prev-tok next-tok))
620 cooked-stream)
621 ))
622 (t
623 (push (car raw-stream) cooked-stream))
624 )
625 (setq raw-stream (cdr raw-stream))
626 )
627
628 (nreverse cooked-stream))
629 )
630
631;;; MACRO EXPANSION
632;;
633;; There are two types of expansion.
634;;
635;; 1. Expansion using a value made up of lexical tokens.
636;; 2. User input replacement from a plain string.
637
638(defun semantic-lex-spp-macro-to-macro-stream (val beg end argvalues)
639 "Convert lexical macro contents VAL into a macro expansion stream.
640Argument VAL is the value of some macro to be converted into a stream.
641BEG and END are the token bounds of the macro to be expanded
642that will somehow gain a much longer token stream.
643ARGVALUES are values for any arg list, or nil."
644 (cond
645 ;; If val is nil, then just skip it.
646 ((null val) t)
647 ;; If it is a token, then return that token rebuilt.
648 ((and (consp val) (car val) (symbolp (car val)))
649 (semantic-lex-push-token
650 (semantic-lex-token (car val) beg end (semantic-lex-token-text val))))
651 ;; Test for a token list.
652 ((and (consp val) (consp (car val)) (car (car val))
653 (symbolp (car (car val))))
654 (semantic-lex-spp-token-macro-to-macro-stream val beg end argvalues))
655 ;; Test for miscellaneous strings.
656 ((stringp val)
657 (semantic-lex-spp-simple-macro-to-macro-stream val beg end argvalues))
658 ))
659
660;;; --------------------------------------------------------
661;;;
662;;; ANALYZERS:
663;;;
664
665;;; Symbol Is Macro
666;;
667;; An analyser that will push tokens from a macro in place
668;; of the macro symbol.
669;;
670(defun semantic-lex-spp-anlyzer-do-replace (sym val beg end)
671 "Do the lexical replacement for SYM with VAL.
672Argument BEG and END specify the bounds of SYM in the buffer."
673 (if (not val)
674 (setq semantic-lex-end-point end)
675 (let ((arg-in nil)
676 (arg-parsed nil)
677 (arg-split nil)
678 )
679
680 ;; Check for arguments.
681 (setq arg-in (semantic-lex-spp-macro-with-args val))
682
683 (when arg-in
684 (save-excursion
685 (goto-char end)
686 (setq arg-parsed
687 (semantic-lex-spp-one-token-and-move-for-macro
688 (point-at-eol)))
689 (setq end (semantic-lex-token-end arg-parsed))
690
691 (when (and (listp arg-parsed) (eq (car arg-parsed) 'semantic-list))
692 (setq arg-split
693 ;; Use lex to split up the contents of the argument list.
694 (semantic-lex-spp-stream-for-arglist arg-parsed)
695 ))
696 ))
697
698 ;; if we have something to sub in, then do it.
699 (semantic-lex-spp-macro-to-macro-stream val beg end arg-split)
700 (setq semantic-lex-end-point end)
701 )
702 ))
703
704(defvar semantic-lex-spp-replacements-enabled t
705 "Non-nil means do replacements when finding keywords.
706Disable this only to prevent recursive expansion issues.")
707
708(defun semantic-lex-spp-analyzer-push-tokens-for-symbol (str beg end)
709 "Push lexical tokens for the symbol or keyword STR.
710STR occurs in the current buffer between BEG and END."
711 (let (sym val)
712 (cond
713 ;;
714 ;; It is a macro. Prepare for a replacement.
715 ((and semantic-lex-spp-replacements-enabled
716 (semantic-lex-spp-symbol-p str))
717 (setq sym (semantic-lex-spp-symbol str)
718 val (symbol-value sym)
719 count 0)
720
721 (let ((semantic-lex-spp-expanded-macro-stack
722 semantic-lex-spp-expanded-macro-stack))
723
724 (semantic-lex-with-macro-used str
725 ;; Do direct replacements of single value macros of macros.
726 ;; This solves issues with a macro containing one symbol that
727 ;; is another macro, and get arg lists passed around.
728 (while (and val (consp val)
729 (semantic-lex-token-p (car val))
730 (eq (length val) 1)
731 (eq (semantic-lex-token-class (car val)) 'symbol)
732 (semantic-lex-spp-symbol-p (semantic-lex-token-text (car val)))
733 (< count 10)
734 )
735 (setq str (semantic-lex-token-text (car val)))
736 (setq sym (semantic-lex-spp-symbol str)
737 val (symbol-value sym))
738 ;; Prevent recursion
739 (setq count (1+ count))
740 ;; This prevents a different kind of recursion.
741 (push str semantic-lex-spp-expanded-macro-stack)
742 )
743
744 (semantic-lex-spp-anlyzer-do-replace sym val beg end))
745
746 ))
747 ;; Anything else.
748 (t
749 ;; A regular keyword.
750 (semantic-lex-push-token
751 (semantic-lex-token (or (semantic-lex-keyword-p str) 'symbol)
752 beg end))))
753 ))
754
755(define-lex-regex-analyzer semantic-lex-spp-replace-or-symbol-or-keyword
756 "Like 'semantic-lex-symbol-or-keyword' plus preprocessor macro replacement."
757 "\\(\\sw\\|\\s_\\)+"
758 (let ((str (match-string 0))
759 (beg (match-beginning 0))
760 (end (match-end 0)))
761 (semantic-lex-spp-analyzer-push-tokens-for-symbol str beg end)))
762
763;;; ANALYZERS FOR NEW MACROS
764;;
765;; These utilities and analyzer declaration function are for
766;; creating an analyzer which produces new macros in the macro table.
767;;
768;; There are two analyzers. One for new macros, and one for removing
769;; a macro.
770
771(defun semantic-lex-spp-first-token-arg-list (token)
772 "If TOKEN is a semantic-list, turn it into a an SPP ARG LIST."
773 (when (and (consp token)
774 (symbolp (car token))
775 (eq 'semantic-list (car token)))
776 ;; Convert TOKEN in place.
777 (let ((argsplit (cedet-split-string (semantic-lex-token-text token)
778 "[(), ]" t)))
779 (setcar token 'spp-arg-list)
780 (setcar (nthcdr 1 token) argsplit))
781 ))
782
783(defun semantic-lex-spp-one-token-and-move-for-macro (max)
784 "Lex up one token, and move to end of that token.
785Don't go past MAX."
786 (let ((ans (semantic-lex (point) max 0 0)))
787 (if (not ans)
788 (progn (goto-char max)
789 nil)
790 (when (> (semantic-lex-token-end (car ans)) max)
791 (let ((bounds (semantic-lex-token-bounds (car ans))))
792 (setcdr bounds max)))
793 (goto-char (semantic-lex-token-end (car ans)))
794 (car ans))
795 ))
796
797(defun semantic-lex-spp-stream-for-arglist (token)
798 "Lex up the contents of the arglist TOKEN.
799Parsing starts inside the parens, and ends at the end of TOKEN."
800 (let ((end (semantic-lex-token-end token))
801 (fresh-toks nil)
802 (toks nil))
803 (save-excursion
804
805 (if (stringp (nth 1 token))
806 ;; If the 2nd part of the token is a string, then we have
807 ;; a token specifically extracted from a buffer. Possibly
808 ;; a different buffer. This means we need to do something
809 ;; nice to parse its contents.
810 (let ((txt (semantic-lex-token-text token)))
811 (semantic-lex-spp-lex-text-string
812 (substring txt 1 (1- (length txt)))))
813
814 ;; This part is like the original
815 (goto-char (semantic-lex-token-start token))
816 ;; A cheat for going into the semantic list.
817 (forward-char 1)
818 (setq fresh-toks (semantic-lex-spp-stream-for-macro (1- end)))
819 (dolist (tok fresh-toks)
820 (when (memq (semantic-lex-token-class tok) '(symbol semantic-list))
821 (setq toks (cons tok toks))))
822
823 (nreverse toks)))))
824
825(defun semantic-lex-spp-lex-text-string (text)
826 "Lex the text string TEXT using the current buffer's state.
827Use this to parse text extracted from a macro as if it came from
828the current buffer. Since the lexer is designed to only work in
829a buffer, we need to create a new buffer, and populate it with rules
830and variable state from the current buffer."
831 (let* ((buf (get-buffer-create " *SPP parse hack*"))
832 (mode major-mode)
833 (fresh-toks nil)
834 (toks nil)
835 (origbuff (current-buffer))
836 (important-vars '(semantic-lex-spp-macro-symbol-obarray
837 semantic-lex-spp-project-macro-symbol-obarray
838 semantic-lex-spp-dynamic-macro-symbol-obarray
839 semantic-lex-spp-dynamic-macro-symbol-obarray-stack
840 semantic-lex-spp-expanded-macro-stack
841 ))
842 )
843 (set-buffer buf)
844 (erase-buffer)
845 ;; Below is a painful hack to make sure everything is setup correctly.
846 (when (not (eq major-mode mode))
847 (funcall mode)
848 ;; Hack in mode-local
849 (activate-mode-local-bindings)
850 ;; CHEATER! The following 3 lines are from
851 ;; `semantic-new-buffer-fcn', but we don't want to turn
852 ;; on all the other annoying modes for this little task.
853 (setq semantic-new-buffer-fcn-was-run t)
854 (semantic-lex-init)
855 (semantic-clear-toplevel-cache)
856 (remove-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook
857 t)
858 ;; Second Cheat: copy key variables reguarding macro state from the
859 ;; the originating buffer we are parsing.
860 (dolist (V important-vars)
861 (set V (semantic-buffer-local-value V origbuff)))
862 )
863 (insert text)
864 (goto-char (point-min))
865
866 (setq fresh-toks (semantic-lex-spp-stream-for-macro (point-max)))
867 (dolist (tok fresh-toks)
868 (when (memq (semantic-lex-token-class tok) '(symbol semantic-list))
869 (setq toks (cons tok toks))))
870
871 (nreverse toks)))
872
873;;;; FIRST DRAFT
874;; This is the fist version of semantic-lex-spp-stream-for-arglist
875;; that worked pretty well. It doesn't work if the TOKEN was derived
876;; from some other buffer, in which case it can get the wrong answer
877;; or throw an error if the token location in the originating buffer is
878;; larger than the current buffer.
879;;(defun semantic-lex-spp-stream-for-arglist-orig (token)
880;; "Lex up the contents of the arglist TOKEN.
881;; Parsing starts inside the parens, and ends at the end of TOKEN."
882;; (save-excursion
883;; (let ((end (semantic-lex-token-end token))
884;; (fresh-toks nil)
885;; (toks nil))
886;; (goto-char (semantic-lex-token-start token))
887;; ;; A cheat for going into the semantic list.
888;; (forward-char 1)
889;; (setq fresh-toks (semantic-lex-spp-stream-for-macro (1- end)))
890;; (dolist (tok fresh-toks)
891;; (when (memq (semantic-lex-token-class tok) '(symbol semantic-list))
892;; (setq toks (cons tok toks))))
893;; (nreverse toks))
894;; ))
895
896;;;; USING SPLIT
897;; This doesn't work, because some arguments passed into a macro
898;; might contain non-simple symbol words, which this doesn't handle.
899;;
900;; Thus, you need a full lex to occur.
901;; (defun semantic-lex-spp-stream-for-arglist-split (token)
902;; "Lex up the contents of the arglist TOKEN.
903;; Parsing starts inside the parens, and ends at the end of TOKEN."
904;; (let* ((txt (semantic-lex-token-text token))
905;; (split (split-string (substring txt 1 (1- (length txt)))
906;; "(), " t))
907;; ;; Hack for lexing.
908;; (semantic-lex-spp-analyzer-push-tokens-for-symbol nil))
909;; (dolist (S split)
910;; (semantic-lex-spp-analyzer-push-tokens-for-symbol S 0 1))
911;; (reverse semantic-lex-spp-analyzer-push-tokens-for-symbol)))
912
913
914(defun semantic-lex-spp-stream-for-macro (eos)
915 "Lex up a stream of tokens for a #define statement.
916Parsing starts at the current point location.
917EOS is the end of the stream to lex for this macro."
918 (let ((stream nil))
919 (while (< (point) eos)
920 (let* ((tok (semantic-lex-spp-one-token-and-move-for-macro eos))
921 (str (when tok
922 (semantic-lex-token-text tok)))
923 )
924 (if str
925 (push (semantic-lex-token (semantic-lex-token-class tok)
926 (semantic-lex-token-start tok)
927 (semantic-lex-token-end tok)
928 str)
929 stream)
930 ;; Nothing to push.
931 nil)))
932 (goto-char eos)
933 ;; Fix the order
934 (nreverse stream)
935 ))
936
937(defmacro define-lex-spp-macro-declaration-analyzer (name doc regexp tokidx
938 &rest valform)
939 "Define a lexical analyzer for defining new MACROS.
940NAME is the name of the analyzer.
941DOC is the documentation for the analyzer.
942REGEXP is a regular expression for the analyzer to match.
943See `define-lex-regex-analyzer' for more on regexp.
944TOKIDX is an index into REGEXP for which a new lexical token
945of type `spp-macro-def' is to be created.
946VALFORM are forms that return the value to be saved for this macro, or nil.
947When implementing a macro, you can use `semantic-lex-spp-stream-for-macro'
948to convert text into a lexical stream for storage in the macro."
949 (let ((start (make-symbol "start"))
950 (end (make-symbol "end"))
951 (val (make-symbol "val"))
952 (startpnt (make-symbol "startpnt"))
953 (endpnt (make-symbol "endpnt")))
954 `(define-lex-regex-analyzer ,name
955 ,doc
956 ,regexp
957 (let ((,start (match-beginning ,tokidx))
958 (,end (match-end ,tokidx))
959 (,startpnt semantic-lex-end-point)
960 (,val (save-match-data ,@valform))
961 (,endpnt semantic-lex-end-point))
962 (semantic-lex-spp-symbol-set
963 (buffer-substring-no-properties ,start ,end)
964 ,val)
965 (semantic-lex-push-token
966 (semantic-lex-token 'spp-macro-def
967 ,start ,end))
968 ;; Preserve setting of the end point from the calling macro.
969 (when (and (/= ,startpnt ,endpnt)
970 (/= ,endpnt semantic-lex-end-point))
971 (setq semantic-lex-end-point ,endpnt))
972 ))))
973
974(defmacro define-lex-spp-macro-undeclaration-analyzer (name doc regexp tokidx)
975 "Undefine a lexical analyzer for defining new MACROS.
976NAME is the name of the analyzer.
977DOC is the documentation for the analyzer.
978REGEXP is a regular expression for the analyzer to match.
979See `define-lex-regex-analyzer' for more on regexp.
980TOKIDX is an index into REGEXP for which a new lexical token
981of type `spp-macro-undef' is to be created."
982 (let ((start (make-symbol "start"))
983 (end (make-symbol "end")))
984 `(define-lex-regex-analyzer ,name
985 ,doc
986 ,regexp
987 (let ((,start (match-beginning ,tokidx))
988 (,end (match-end ,tokidx))
989 )
990 (semantic-lex-spp-symbol-remove
991 (buffer-substring-no-properties ,start ,end))
992 (semantic-lex-push-token
993 (semantic-lex-token 'spp-macro-undef
994 ,start ,end))
995 ))))
996
997;;; INCLUDES
998;;
999;; These analyzers help a language define how include files
1000;; are identified. These are ONLY for languages that perform
1001;; an actual textual includesion, and not for imports.
1002;;
1003;; This section is supposed to allow the macros from the headers to be
1004;; added to the local dynamic macro table, but that hasn't been
1005;; written yet.
1006;;
1007(defcustom semantic-lex-spp-use-headers-flag nil
1008 "*Non-nil means to pre-parse headers as we go.
1009For languages that use the Semantic pre-processor, this can
1010improve the accuracy of parsed files where include files
1011can change the state of what's parsed in the current file.
1012
1013Note: Note implemented yet"
1014 :group 'semantic
1015 :type 'boolean)
1016
1017(defun semantic-lex-spp-merge-header (name)
1018 "Extract and merge any macros from the header with NAME.
1019Finds the header file belonging to NAME, gets the macros
1020from that file, and then merge the macros with our current
1021symbol table."
1022 (when semantic-lex-spp-use-headers-flag
1023 ;; @todo - do this someday, ok?
1024 ))
1025
1026(defmacro define-lex-spp-include-analyzer (name doc regexp tokidx
1027 &rest valform)
1028 "Define a lexical analyzer for defining a new INCLUDE lexical token.
1029Macros defined in the found include will be added to our running table
1030at the time the include statement is found.
1031NAME is the name of the analyzer.
1032DOC is the documentation for the analyzer.
1033REGEXP is a regular expression for the analyzer to match.
1034See `define-lex-regex-analyzer' for more on regexp.
1035TOKIDX is an index into REGEXP for which a new lexical token
1036of type `spp-macro-include' is to be created.
1037VALFORM are forms that return the name of the thing being included, and the
1038type of include. The return value should be of the form:
1039 (NAME . TYPE)
1040where NAME is the name of the include, and TYPE is the type of the include,
1041where a valid symbol is 'system, or nil."
1042 (let ((start (make-symbol "start"))
1043 (end (make-symbol "end"))
1044 (val (make-symbol "val"))
1045 (startpnt (make-symbol "startpnt"))
1046 (endpnt (make-symbol "endpnt")))
1047 `(define-lex-regex-analyzer ,name
1048 ,doc
1049 ,regexp
1050 (let ((,start (match-beginning ,tokidx))
1051 (,end (match-end ,tokidx))
1052 (,startpnt semantic-lex-end-point)
1053 (,val (save-match-data ,@valform))
1054 (,endpnt semantic-lex-end-point))
1055 ;;(message "(car ,val) -> %S" (car ,val))
1056 (semantic-lex-spp-merge-header (car ,val))
1057 (semantic-lex-push-token
1058 (semantic-lex-token (if (eq (cdr ,val) 'system)
1059 'spp-system-include
1060 'spp-include)
1061 ,start ,end
1062 (car ,val)))
1063 ;; Preserve setting of the end point from the calling macro.
1064 (when (and (/= ,startpnt ,endpnt)
1065 (/= ,endpnt semantic-lex-end-point))
1066 (setq semantic-lex-end-point ,endpnt))
1067 ))))
1068
1069;;; EIEIO USAGE
1070;;
1071;; Semanticdb can save off macro tables for quick lookup later.
1072;;
1073;; These routines are for saving macro lists into an EIEIO persistent
1074;; file.
1075(defvar semantic-lex-spp-macro-max-length-to-save 200
1076 "*Maximum length of an SPP macro before we opt to not save it.")
1077
1078(defun semantic-lex-spp-table-write-slot-value (value)
1079 "Write out the VALUE of a slot for EIEIO.
1080The VALUE is a spp lexical table."
1081 (if (not value)
1082 (princ "nil")
1083 (princ "\n '(")
1084 ;(princ value)
1085 (dolist (sym value)
1086 (princ "(")
1087 (prin1 (car sym))
1088 (let* ((first (car (cdr sym)))
1089 (rest (cdr sym)))
1090 (when (not (listp first))
1091 (error "Error in macro \"%s\"" (car sym)))
1092 (when (eq (car first) 'spp-arg-list)
1093 (princ " ")
1094 (prin1 first)
1095 (setq rest (cdr rest))
1096 )
1097
1098 (when rest
1099 (princ " . ")
1100 (let ((len (length (cdr rest))))
1101 (cond ((< len 2)
1102 (condition-case nil
1103 (prin1 rest)
1104 (error
1105 (princ "nil ;; Error writing macro\n"))))
1106 ((< len semantic-lex-spp-macro-max-length-to-save)
1107 (princ "\n ")
1108 (condition-case nil
1109 (prin1 rest)
1110 (error
1111 (princ "nil ;; Error writing macro\n ")))
1112 )
1113 (t ;; Too Long!
1114 (princ "nil ;; Too Long!\n ")
1115 ))))
1116 )
1117 (princ ")\n ")
1118 )
1119 (princ ")\n"))
1120)
1121
1122;;; TESTS
1123;;
1124(defun semantic-lex-spp-write-test ()
1125 "Test the semantic tag writer against the current buffer."
1126 (interactive)
1127 (with-output-to-temp-buffer "*SPP Write Test*"
1128 (semantic-lex-spp-table-write-slot-value
1129 (semantic-lex-spp-save-table))))
1130
1131(defun semantic-lex-spp-write-utest ()
1132 "Unit test using the test spp file to test the slot write fcn."
1133 (interactive)
1134 (let* ((sem (locate-library "semantic-lex-spp.el"))
1135 (dir (file-name-directory sem)))
1136 (save-excursion
1137 (set-buffer (find-file-noselect
1138 (expand-file-name "tests/testsppreplace.c"
1139 dir)))
1140 (semantic-lex-spp-write-test))))
1141
1142;;; MACRO TABLE DEBUG
1143;;
1144(defun semantic-lex-spp-describe (&optional buffer)
1145 "Describe the current list of spp macros for BUFFER.
1146If BUFFER is not provided, use the current buffer."
1147 (interactive)
1148 (let ((syms (save-excursion
1149 (if buffer (set-buffer buffer))
1150 (semantic-lex-spp-macros)))
1151 (sym nil))
1152 (with-output-to-temp-buffer "*SPP MACROS*"
1153 (princ "Macro\t\tValue\n")
1154 (while syms
1155 (setq sym (car syms)
1156 syms (cdr syms))
1157 (princ (symbol-name sym))
1158 (princ "\t")
1159 (if (< (length (symbol-name sym)) 8)
1160 (princ "\t"))
1161 (prin1 (symbol-value sym))
1162 (princ "\n")
1163 ))))
1164
1165;;; EDEBUG Handlers
1166;;
1167(add-hook
1168 'edebug-setup-hook
1169 #'(lambda ()
1170
1171 (def-edebug-spec define-lex-spp-macro-declaration-analyzer
1172 (&define name stringp stringp form def-body)
1173 )
1174
1175 (def-edebug-spec define-lex-spp-macro-undeclaration-analyzer
1176 (&define name stringp stringp form)
1177 )
1178
1179 (def-edebug-spec define-lex-spp-include-analyzer
1180 (&define name stringp stringp form def-body)
1181 )
1182 ))
1183
1184
1185(provide 'semantic/lex-spp)
1186
1187;;; semantic-lex-spp.el ends here
diff --git a/lisp/cedet/semantic/util-modes.el b/lisp/cedet/semantic/util-modes.el
new file mode 100644
index 00000000000..e38e1b94637
--- /dev/null
+++ b/lisp/cedet/semantic/util-modes.el
@@ -0,0 +1,1228 @@
1;;; semantic-util-modes.el --- Semantic minor modes
2
3;;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
4;;; Free Software Foundation, Inc.
5
6;; Authors: Eric M. Ludlam <zappo@gnu.org>
7;; David Ponce <david@dponce.com>
8;; Keywords: syntax
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;; Semantic utility minor modes.
28;;
29
30;;; Code:
31(require 'semantic)
32
33(eval-when-compile
34 (require 'semantic/decorate)
35 )
36
37;;; Compatibility
38(if (fboundp 'propertize)
39 (defalias 'semantic-propertize 'propertize)
40 (defsubst semantic-propertize (string &rest properties)
41 "Return a copy of STRING with text properties added.
42Dummy implementation for compatibility which just return STRING and
43ignore PROPERTIES."
44 string)
45 )
46
47;;; Group for all semantic enhancing modes
48(defgroup semantic-modes nil
49 "Minor modes associated with the Semantic architecture."
50 :group 'semantic)
51
52;;;;
53;;;; Semantic minor modes stuff
54;;;;
55(defcustom semantic-update-mode-line t
56 "*If non-nil, show enabled minor modes in the mode line.
57Only minor modes that are not turned on globally are shown in the mode
58line."
59 :group 'semantic
60 :type 'boolean
61 :require 'semantic/util-modes
62 :initialize 'custom-initialize-default
63 :set (lambda (sym val)
64 (set-default sym val)
65 ;; Update status of all Semantic enabled buffers
66 (semantic-map-buffers
67 #'semantic-mode-line-update)))
68
69(defcustom semantic-mode-line-prefix
70 (semantic-propertize "S" 'face 'bold)
71 "*Prefix added to minor mode indicators in the mode line."
72 :group 'semantic
73 :type 'string
74 :require 'semantic/util-modes
75 :initialize 'custom-initialize-default)
76
77(defvar semantic-minor-modes-status nil
78 "String showing Semantic minor modes which are locally enabled.
79It is displayed in the mode line.")
80(make-variable-buffer-local 'semantic-minor-modes-status)
81
82(defvar semantic-minor-mode-alist nil
83 "Alist saying how to show Semantic minor modes in the mode line.
84Like variable `minor-mode-alist'.")
85
86(defun semantic-mode-line-update ()
87 "Update display of Semantic minor modes in the mode line.
88Only minor modes that are locally enabled are shown in the mode line."
89 (setq semantic-minor-modes-status nil)
90 (if semantic-update-mode-line
91 (let ((ml semantic-minor-mode-alist)
92 mm ms see)
93 (while ml
94 (setq mm (car ml)
95 ms (cadr mm)
96 mm (car mm)
97 ml (cdr ml))
98 (when (and (symbol-value mm)
99 ;; Only show local minor mode status
100 (not (memq mm semantic-init-hooks)))
101 (and ms
102 (symbolp ms)
103 (setq ms (symbol-value ms)))
104 (and (stringp ms)
105 (not (member ms see)) ;; Don't duplicate same status
106 (setq see (cons ms see)
107 ms (if (string-match "^[ ]*\\(.+\\)" ms)
108 (match-string 1 ms)))
109 (setq semantic-minor-modes-status
110 (if semantic-minor-modes-status
111 (concat semantic-minor-modes-status "/" ms)
112 ms)))))
113 (if semantic-minor-modes-status
114 (setq semantic-minor-modes-status
115 (concat
116 " "
117 (if (string-match "^[ ]*\\(.+\\)"
118 semantic-mode-line-prefix)
119 (match-string 1 semantic-mode-line-prefix)
120 "S")
121 "/"
122 semantic-minor-modes-status))))))
123
124(defun semantic-desktop-ignore-this-minor-mode (buffer)
125 "Installed as a minor-mode initializer for Desktop mode.
126BUFFER is the buffer to not initialize a Semantic minor mode in."
127 nil)
128
129(defun semantic-add-minor-mode (toggle name &optional keymap)
130 "Register a new Semantic minor mode.
131TOGGLE is a symbol which is the name of a buffer-local variable that
132is toggled on or off to say whether the minor mode is active or not.
133It is also an interactive function to toggle the mode.
134
135NAME specifies what will appear in the mode line when the minor mode
136is active. NAME should be either a string starting with a space, or a
137symbol whose value is such a string.
138
139Optional KEYMAP is the keymap for the minor mode that will be added to
140`minor-mode-map-alist'."
141 ;; Add a dymmy semantic minor mode to display the status
142 (or (assq 'semantic-minor-modes-status minor-mode-alist)
143 (setq minor-mode-alist (cons (list 'semantic-minor-modes-status
144 'semantic-minor-modes-status)
145 minor-mode-alist)))
146 (if (fboundp 'add-minor-mode)
147 ;; Emacs 21 & XEmacs
148 (add-minor-mode toggle "" keymap)
149 ;; Emacs 20
150 (or (assq toggle minor-mode-alist)
151 (setq minor-mode-alist (cons (list toggle "") minor-mode-alist)))
152 (or (not keymap)
153 (assq toggle minor-mode-map-alist)
154 (setq minor-mode-map-alist (cons (cons toggle keymap)
155 minor-mode-map-alist))))
156 ;; Record how to display this minor mode in the mode line
157 (let ((mm (assq toggle semantic-minor-mode-alist)))
158 (if mm
159 (setcdr mm (list name))
160 (setq semantic-minor-mode-alist (cons (list toggle name)
161 semantic-minor-mode-alist))))
162
163 ;; Semantic minor modes don't work w/ Desktop restore.
164 ;; This line will disable this minor mode from being restored
165 ;; by Desktop.
166 (when (boundp 'desktop-minor-mode-handlers)
167 (add-to-list 'desktop-minor-mode-handlers
168 (cons toggle 'semantic-desktop-ignore-this-minor-mode)))
169 )
170
171(defun semantic-toggle-minor-mode-globally (mode &optional arg)
172 "Toggle minor mode MODE in every Semantic enabled buffer.
173Return non-nil if MODE is turned on in every Semantic enabled buffer.
174If ARG is positive, enable, if it is negative, disable. If ARG is
175nil, then toggle. Otherwise do nothing. MODE must be a valid minor
176mode defined in `minor-mode-alist' and must be too an interactive
177function used to toggle the mode."
178 (or (and (fboundp mode) (assq mode minor-mode-alist))
179 (error "Semantic minor mode %s not found" mode))
180 (if (not arg)
181 (if (memq mode semantic-init-hooks)
182 (setq arg -1)
183 (setq arg 1)))
184 ;; Add or remove the MODE toggle function from
185 ;; `semantic-init-hooks'. Then turn MODE on or off in every
186 ;; Semantic enabled buffer.
187 (cond
188 ;; Turn off if ARG < 0
189 ((< arg 0)
190 (remove-hook 'semantic-init-hooks mode)
191 (semantic-map-buffers #'(lambda () (funcall mode -1)))
192 nil)
193 ;; Turn on if ARG > 0
194 ((> arg 0)
195 (add-hook 'semantic-init-hooks mode)
196 (semantic-map-buffers #'(lambda () (funcall mode 1)))
197 t)
198 ;; Otherwise just check MODE state
199 (t
200 (memq mode semantic-init-hooks))
201 ))
202
203;;;;
204;;;; Minor mode to highlight areas that a user edits.
205;;;;
206
207(defun global-semantic-highlight-edits-mode (&optional arg)
208 "Toggle global use of option `semantic-highlight-edits-mode'.
209If ARG is positive, enable, if it is negative, disable.
210If ARG is nil, then toggle."
211 (interactive "P")
212 (setq global-semantic-highlight-edits-mode
213 (semantic-toggle-minor-mode-globally
214 'semantic-highlight-edits-mode arg)))
215
216(defcustom global-semantic-highlight-edits-mode nil
217 "*If non-nil enable global use of variable `semantic-highlight-edits-mode'.
218When this mode is enabled, changes made to a buffer are highlighted
219until the buffer is reparsed."
220 :group 'semantic
221 :group 'semantic-modes
222 :type 'boolean
223 :require 'semantic/util-modes
224 :initialize 'custom-initialize-default
225 :set (lambda (sym val)
226 (global-semantic-highlight-edits-mode (if val 1 -1))))
227
228(defcustom semantic-highlight-edits-mode-hook nil
229 "*Hook run at the end of function `semantic-highlight-edits-mode'."
230 :group 'semantic
231 :type 'hook)
232
233(defface semantic-highlight-edits-face
234 '((((class color) (background dark))
235 ;; Put this back to something closer to black later.
236 (:background "gray20"))
237 (((class color) (background light))
238 (:background "gray90")))
239 "*Face used to show dirty tokens in `semantic-highlight-edits-mode'."
240 :group 'semantic-faces)
241
242(defun semantic-highlight-edits-new-change-hook-fcn (overlay)
243 "Function set into `semantic-edits-new-change-hook'.
244Argument OVERLAY is the overlay created to mark the change.
245This function will set the face property on this overlay."
246 (semantic-overlay-put overlay 'face 'semantic-highlight-edits-face))
247
248(defvar semantic-highlight-edits-mode-map
249 (let ((km (make-sparse-keymap)))
250 km)
251 "Keymap for highlight-edits minor mode.")
252
253(defvar semantic-highlight-edits-mode nil
254 "Non-nil if highlight-edits minor mode is enabled.
255Use the command `semantic-highlight-edits-mode' to change this variable.")
256(make-variable-buffer-local 'semantic-highlight-edits-mode)
257
258(defun semantic-highlight-edits-mode-setup ()
259 "Setup option `semantic-highlight-edits-mode'.
260The minor mode can be turned on only if semantic feature is available
261and the current buffer was set up for parsing. When minor mode is
262enabled parse the current buffer if needed. Return non-nil if the
263minor mode is enabled."
264 (if semantic-highlight-edits-mode
265 (if (not (and (featurep 'semantic) (semantic-active-p)))
266 (progn
267 ;; Disable minor mode if semantic stuff not available
268 (setq semantic-highlight-edits-mode nil)
269 (error "Buffer %s was not set up for parsing"
270 (buffer-name)))
271 (semantic-make-local-hook 'semantic-edits-new-change-hooks)
272 (add-hook 'semantic-edits-new-change-hooks
273 'semantic-highlight-edits-new-change-hook-fcn nil t)
274 )
275 ;; Remove hooks
276 (remove-hook 'semantic-edits-new-change-hooks
277 'semantic-highlight-edits-new-change-hook-fcn t)
278 )
279 semantic-highlight-edits-mode)
280
281(defun semantic-highlight-edits-mode (&optional arg)
282 "Minor mode for highlighting changes made in a buffer.
283Changes are tracked by semantic so that the incremental parser can work
284properly.
285This mode will highlight those changes as they are made, and clear them
286when the incremental parser accounts for those edits.
287With prefix argument ARG, turn on if positive, otherwise off. The
288minor mode can be turned on only if semantic feature is available and
289the current buffer was set up for parsing. Return non-nil if the
290minor mode is enabled."
291 (interactive
292 (list (or current-prefix-arg
293 (if semantic-highlight-edits-mode 0 1))))
294 (setq semantic-highlight-edits-mode
295 (if arg
296 (>
297 (prefix-numeric-value arg)
298 0)
299 (not semantic-highlight-edits-mode)))
300 (semantic-highlight-edits-mode-setup)
301 (run-hooks 'semantic-highlight-edits-mode-hook)
302 (if (interactive-p)
303 (message "highlight-edits minor mode %sabled"
304 (if semantic-highlight-edits-mode "en" "dis")))
305 (semantic-mode-line-update)
306 semantic-highlight-edits-mode)
307
308(semantic-add-minor-mode 'semantic-highlight-edits-mode
309 "e"
310 semantic-highlight-edits-mode-map)
311
312
313;;;;
314;;;; Minor mode to show unmatched-syntax elements
315;;;;
316(defun global-semantic-show-unmatched-syntax-mode (&optional arg)
317 "Toggle global use of option `semantic-show-unmatched-syntax-mode'.
318If ARG is positive, enable, if it is negative, disable.
319If ARG is nil, then toggle."
320 (interactive "P")
321 (setq global-semantic-show-unmatched-syntax-mode
322 (semantic-toggle-minor-mode-globally
323 'semantic-show-unmatched-syntax-mode arg)))
324
325(defcustom global-semantic-show-unmatched-syntax-mode nil
326 "*If non-nil, enable global use of `semantic-show-unmatched-syntax-mode'.
327When this mode is enabled, syntax in the current buffer which the
328semantic parser cannot match is highlighted with a red underline."
329 :group 'semantic
330 :group 'semantic-modes
331 :type 'boolean
332 :require 'semantic/util-modes
333 :initialize 'custom-initialize-default
334 :set (lambda (sym val)
335 (global-semantic-show-unmatched-syntax-mode (if val 1 -1))))
336
337(defcustom semantic-show-unmatched-syntax-mode-hook nil
338 "*Hook run at the end of function `semantic-show-unmatched-syntax-mode'."
339 :group 'semantic
340 :type 'hook)
341
342(defface semantic-unmatched-syntax-face
343 '((((class color) (background dark))
344 (:underline "red"))
345 (((class color) (background light))
346 (:underline "red")))
347 "*Face used to show unmatched syntax in.
348The face is used in `semantic-show-unmatched-syntax-mode'."
349 :group 'semantic-faces)
350
351(defsubst semantic-unmatched-syntax-overlay-p (overlay)
352 "Return non-nil if OVERLAY is an unmatched syntax one."
353 (eq (semantic-overlay-get overlay 'semantic) 'unmatched))
354
355(defun semantic-showing-unmatched-syntax-p ()
356 "Return non-nil if an unmatched syntax overlay was found in buffer."
357 (let ((ol (semantic-overlays-in (point-min) (point-max)))
358 found)
359 (while (and ol (not found))
360 (setq found (semantic-unmatched-syntax-overlay-p (car ol))
361 ol (cdr ol)))
362 found))
363
364(defun semantic-show-unmatched-lex-tokens-fetch ()
365 "Fetch a list of unmatched lexical tokens from the current buffer.
366Uses the overlays which have accurate bounds, and rebuilds what was
367originally passed in."
368 (let ((ol (semantic-overlays-in (point-min) (point-max)))
369 (ustc nil))
370 (while ol
371 (if (semantic-unmatched-syntax-overlay-p (car ol))
372 (setq ustc (cons (cons 'thing
373 (cons (semantic-overlay-start (car ol))
374 (semantic-overlay-end (car ol))))
375 ustc)))
376 (setq ol (cdr ol)))
377 (nreverse ustc))
378 )
379
380(defun semantic-clean-unmatched-syntax-in-region (beg end)
381 "Remove all unmatched syntax overlays between BEG and END."
382 (let ((ol (semantic-overlays-in beg end)))
383 (while ol
384 (if (semantic-unmatched-syntax-overlay-p (car ol))
385 (semantic-overlay-delete (car ol)))
386 (setq ol (cdr ol)))))
387
388(defsubst semantic-clean-unmatched-syntax-in-buffer ()
389 "Remove all unmatched syntax overlays found in current buffer."
390 (semantic-clean-unmatched-syntax-in-region
391 (point-min) (point-max)))
392
393(defsubst semantic-clean-token-of-unmatched-syntax (token)
394 "Clean the area covered by TOKEN of unmatched syntax markers."
395 (semantic-clean-unmatched-syntax-in-region
396 (semantic-tag-start token) (semantic-tag-end token)))
397
398(defun semantic-show-unmatched-syntax (syntax)
399 "Function set into `semantic-unmatched-syntax-hook'.
400This will highlight elements in SYNTAX as unmatched syntax."
401 ;; This is called when `semantic-show-unmatched-syntax-mode' is
402 ;; enabled. Highlight the unmatched syntax, and then add a semantic
403 ;; property to that overlay so we can add it to the official list of
404 ;; semantic supported overlays. This gets it cleaned up for errors,
405 ;; buffer cleaning, and the like.
406 (semantic-clean-unmatched-syntax-in-buffer) ;Clear previous highlighting
407 (if syntax
408 (let (o)
409 (while syntax
410 (setq o (semantic-make-overlay (semantic-lex-token-start (car syntax))
411 (semantic-lex-token-end (car syntax))))
412 (semantic-overlay-put o 'semantic 'unmatched)
413 (semantic-overlay-put o 'face 'semantic-unmatched-syntax-face)
414 (setq syntax (cdr syntax))))
415 ))
416
417(defun semantic-next-unmatched-syntax (point &optional bound)
418 "Find the next overlay for unmatched syntax after POINT.
419Do not search past BOUND if non-nil."
420 (save-excursion
421 (goto-char point)
422 (let ((os point) (ol nil))
423 (while (and os (< os (or bound (point-max))) (not ol))
424 (setq os (semantic-overlay-next-change os))
425 (when os
426 ;; Get overlays at position
427 (setq ol (semantic-overlays-at os))
428 ;; find the overlay that belongs to semantic
429 ;; and starts at the found position.
430 (while (and ol (listp ol))
431 (and (semantic-unmatched-syntax-overlay-p (car ol))
432 (setq ol (car ol)))
433 (if (listp ol)
434 (setq ol (cdr ol))))))
435 ol)))
436
437(defvar semantic-show-unmatched-syntax-mode-map
438 (let ((km (make-sparse-keymap)))
439 (define-key km "\C-c,`" 'semantic-show-unmatched-syntax-next)
440 km)
441 "Keymap for command `semantic-show-unmatched-syntax-mode'.")
442
443(defvar semantic-show-unmatched-syntax-mode nil
444 "Non-nil if show-unmatched-syntax minor mode is enabled.
445Use the command `semantic-show-unmatched-syntax-mode' to change this
446variable.")
447(make-variable-buffer-local 'semantic-show-unmatched-syntax-mode)
448
449(defun semantic-show-unmatched-syntax-mode-setup ()
450 "Setup the `semantic-show-unmatched-syntax' minor mode.
451The minor mode can be turned on only if semantic feature is available
452and the current buffer was set up for parsing. When minor mode is
453enabled parse the current buffer if needed. Return non-nil if the
454minor mode is enabled."
455 (if semantic-show-unmatched-syntax-mode
456 (if (not (and (featurep 'semantic) (semantic-active-p)))
457 (progn
458 ;; Disable minor mode if semantic stuff not available
459 (setq semantic-show-unmatched-syntax-mode nil)
460 (error "Buffer %s was not set up for parsing"
461 (buffer-name)))
462 ;; Add hooks
463 (semantic-make-local-hook 'semantic-unmatched-syntax-hook)
464 (add-hook 'semantic-unmatched-syntax-hook
465 'semantic-show-unmatched-syntax nil t)
466 (semantic-make-local-hook 'semantic-pre-clean-token-hooks)
467 (add-hook 'semantic-pre-clean-token-hooks
468 'semantic-clean-token-of-unmatched-syntax nil t)
469 ;; Show unmatched syntax elements
470 (if (not (semantic--umatched-syntax-needs-refresh-p))
471 (semantic-show-unmatched-syntax
472 (semantic-unmatched-syntax-tokens))))
473 ;; Remove hooks
474 (remove-hook 'semantic-unmatched-syntax-hook
475 'semantic-show-unmatched-syntax t)
476 (remove-hook 'semantic-pre-clean-token-hooks
477 'semantic-clean-token-of-unmatched-syntax t)
478 ;; Cleanup unmatched-syntax highlighting
479 (semantic-clean-unmatched-syntax-in-buffer))
480 semantic-show-unmatched-syntax-mode)
481
482(defun semantic-show-unmatched-syntax-mode (&optional arg)
483 "Minor mode to highlight unmatched lexical syntax tokens.
484When a parser executes, some elements in the buffer may not match any
485parser rules. These text characters are considered unmatched syntax.
486Often time, the display of unmatched syntax can expose coding
487problems before the compiler is run.
488
489With prefix argument ARG, turn on if positive, otherwise off. The
490minor mode can be turned on only if semantic feature is available and
491the current buffer was set up for parsing. Return non-nil if the
492minor mode is enabled.
493
494\\{semantic-show-unmatched-syntax-mode-map}"
495 (interactive
496 (list (or current-prefix-arg
497 (if semantic-show-unmatched-syntax-mode 0 1))))
498 (setq semantic-show-unmatched-syntax-mode
499 (if arg
500 (>
501 (prefix-numeric-value arg)
502 0)
503 (not semantic-show-unmatched-syntax-mode)))
504 (semantic-show-unmatched-syntax-mode-setup)
505 (run-hooks 'semantic-show-unmatched-syntax-mode-hook)
506 (if (interactive-p)
507 (message "show-unmatched-syntax minor mode %sabled"
508 (if semantic-show-unmatched-syntax-mode "en" "dis")))
509 (semantic-mode-line-update)
510 semantic-show-unmatched-syntax-mode)
511
512(semantic-add-minor-mode 'semantic-show-unmatched-syntax-mode
513 "u"
514 semantic-show-unmatched-syntax-mode-map)
515
516(defun semantic-show-unmatched-syntax-next ()
517 "Move forward to the next occurrence of unmatched syntax."
518 (interactive)
519 (let ((o (semantic-next-unmatched-syntax (point))))
520 (if o
521 (goto-char (semantic-overlay-start o)))))
522
523
524;;;;
525;;;; Minor mode to display the parser state in the modeline.
526;;;;
527
528(defcustom global-semantic-show-parser-state-mode nil
529 "*If non-nil enable global use of `semantic-show-parser-state-mode'.
530When enabled, the current parse state of the current buffer is displayed
531in the mode line. See `semantic-show-parser-state-marker' for details
532on what is displayed."
533 :group 'semantic
534 :type 'boolean
535 :require 'semantic/util-modes
536 :initialize 'custom-initialize-default
537 :set (lambda (sym val)
538 (global-semantic-show-parser-state-mode (if val 1 -1))))
539
540(defun global-semantic-show-parser-state-mode (&optional arg)
541 "Toggle global use of option `semantic-show-parser-state-mode'.
542If ARG is positive, enable, if it is negative, disable.
543If ARG is nil, then toggle."
544 (interactive "P")
545 (setq global-semantic-show-parser-state-mode
546 (semantic-toggle-minor-mode-globally
547 'semantic-show-parser-state-mode arg)))
548
549(defcustom semantic-show-parser-state-mode-hook nil
550 "*Hook run at the end of function `semantic-show-parser-state-mode'."
551 :group 'semantic
552 :type 'hook)
553
554(defvar semantic-show-parser-state-mode-map
555 (let ((km (make-sparse-keymap)))
556 km)
557 "Keymap for show-parser-state minor mode.")
558
559(defvar semantic-show-parser-state-mode nil
560 "Non-nil if show-parser-state minor mode is enabled.
561Use the command `semantic-show-parser-state-mode' to change this variable.")
562(make-variable-buffer-local 'semantic-show-parser-state-mode)
563
564(defun semantic-show-parser-state-mode-setup ()
565 "Setup option `semantic-show-parser-state-mode'.
566The minor mode can be turned on only if semantic feature is available
567and the current buffer was set up for parsing. When minor mode is
568enabled parse the current buffer if needed. Return non-nil if the
569minor mode is enabled."
570 (if semantic-show-parser-state-mode
571 (if (not (and (featurep 'semantic) (semantic-active-p)))
572 (progn
573 ;; Disable minor mode if semantic stuff not available
574 (setq semantic-show-parser-state-mode nil)
575 (error "Buffer %s was not set up for parsing"
576 (buffer-name)))
577 ;; Set up mode line
578
579 (when (not
580 (memq 'semantic-show-parser-state-string mode-line-modified))
581 (setq mode-line-modified
582 (append mode-line-modified
583 '(semantic-show-parser-state-string))))
584 ;; Add hooks
585 (semantic-make-local-hook 'semantic-edits-new-change-hooks)
586 (add-hook 'semantic-edits-new-change-hooks
587 'semantic-show-parser-state-marker nil t)
588 (semantic-make-local-hook 'semantic-edits-incremental-reparse-failed-hooks)
589 (add-hook 'semantic-edits-incremental-reparse-failed-hooks
590 'semantic-show-parser-state-marker nil t)
591 (semantic-make-local-hook 'semantic-after-partial-cache-change-hook)
592 (add-hook 'semantic-after-partial-cache-change-hook
593 'semantic-show-parser-state-marker nil t)
594 (semantic-make-local-hook 'semantic-after-toplevel-cache-change-hook)
595 (add-hook 'semantic-after-toplevel-cache-change-hook
596 'semantic-show-parser-state-marker nil t)
597 (semantic-show-parser-state-marker)
598
599 (semantic-make-local-hook 'semantic-before-auto-parse-hooks)
600 (add-hook 'semantic-before-auto-parse-hooks
601 'semantic-show-parser-state-auto-marker nil t)
602 (semantic-make-local-hook 'semantic-after-auto-parse-hooks)
603 (add-hook 'semantic-after-auto-parse-hooks
604 'semantic-show-parser-state-marker nil t)
605
606 (semantic-make-local-hook 'semantic-before-idle-scheduler-reparse-hooks)
607 (add-hook 'semantic-before-idle-scheduler-reparse-hooks
608 'semantic-show-parser-state-auto-marker nil t)
609 (semantic-make-local-hook 'semantic-after-idle-scheduler-reparse-hooks)
610 (add-hook 'semantic-after-idle-scheduler-reparse-hooks
611 'semantic-show-parser-state-marker nil t)
612 )
613 ;; Remove parts of mode line
614 (setq mode-line-modified
615 (delq 'semantic-show-parser-state-string mode-line-modified))
616 ;; Remove hooks
617 (remove-hook 'semantic-edits-new-change-hooks
618 'semantic-show-parser-state-marker t)
619 (remove-hook 'semantic-edits-incremental-reparse-failed-hooks
620 'semantic-show-parser-state-marker t)
621 (remove-hook 'semantic-after-partial-cache-change-hook
622 'semantic-show-parser-state-marker t)
623 (remove-hook 'semantic-after-toplevel-cache-change-hook
624 'semantic-show-parser-state-marker t)
625
626 (remove-hook 'semantic-before-auto-parse-hooks
627 'semantic-show-parser-state-auto-marker t)
628 (remove-hook 'semantic-after-auto-parse-hooks
629 'semantic-show-parser-state-marker t)
630
631 (remove-hook 'semantic-before-idle-scheduler-reparse-hooks
632 'semantic-show-parser-state-auto-marker t)
633 (remove-hook 'semantic-after-idle-scheduler-reparse-hooks
634 'semantic-show-parser-state-marker t)
635 )
636 semantic-show-parser-state-mode)
637
638(defun semantic-show-parser-state-mode (&optional arg)
639 "Minor mode for displaying parser cache state in the modeline.
640The cache can be in one of three states. They are
641Up to date, Partial reprase needed, and Full reparse needed.
642The state is indicated in the modeline with the following characters:
643 `-' -> The cache is up to date.
644 `!' -> The cache requires a full update.
645 `~' -> The cache needs to be incrementally parsed.
646 `%' -> The cache is not currently parseable.
647 `@' -> Auto-parse in progress (not set here.)
648With prefix argument ARG, turn on if positive, otherwise off. The
649minor mode can be turned on only if semantic feature is available and
650the current buffer was set up for parsing. Return non-nil if the
651minor mode is enabled."
652 (interactive
653 (list (or current-prefix-arg
654 (if semantic-show-parser-state-mode 0 1))))
655 (setq semantic-show-parser-state-mode
656 (if arg
657 (>
658 (prefix-numeric-value arg)
659 0)
660 (not semantic-show-parser-state-mode)))
661 (semantic-show-parser-state-mode-setup)
662 (run-hooks 'semantic-show-parser-state-mode-hook)
663 (if (interactive-p)
664 (message "show-parser-state minor mode %sabled"
665 (if semantic-show-parser-state-mode "en" "dis")))
666 (semantic-mode-line-update)
667 semantic-show-parser-state-mode)
668
669(semantic-add-minor-mode 'semantic-show-parser-state-mode
670 ""
671 semantic-show-parser-state-mode-map)
672
673(defvar semantic-show-parser-state-string nil
674 "String showing the parser state for this buffer.
675See `semantic-show-parser-state-marker' for details.")
676(make-variable-buffer-local 'semantic-show-parser-state-string)
677
678(defun semantic-show-parser-state-marker (&rest ignore)
679 "Set `semantic-show-parser-state-string' to indicate parser state.
680This marker is one of the following:
681 `-' -> The cache is up to date.
682 `!' -> The cache requires a full update.
683 `~' -> The cache needs to be incrementally parsed.
684 `%' -> The cache is not currently parseable.
685 `@' -> Auto-parse in progress (not set here.)
686Arguments IGNORE are ignored, and accepted so this can be used as a hook
687in many situations."
688 (setq semantic-show-parser-state-string
689 (cond ((semantic-parse-tree-needs-rebuild-p)
690 "!")
691 ((semantic-parse-tree-needs-update-p)
692 "^")
693 ((semantic-parse-tree-unparseable-p)
694 "%")
695 (t
696 "-")))
697 ;;(message "Setup mode line indicator to [%s]" semantic-show-parser-state-string)
698 (semantic-mode-line-update))
699
700(defun semantic-show-parser-state-auto-marker ()
701 "Hook function run before an autoparse.
702Set up `semantic-show-parser-state-marker' to show `@'
703to indicate a parse in progress."
704 (unless (semantic-parse-tree-up-to-date-p)
705 (setq semantic-show-parser-state-string "@")
706 (semantic-mode-line-update)
707 ;; For testing.
708 ;;(sit-for 1)
709 ))
710
711
712;;;;
713;;;; Minor mode to make function decls sticky.
714;;;;
715
716(defun global-semantic-stickyfunc-mode (&optional arg)
717 "Toggle global use of option `semantic-stickyfunc-mode'.
718If ARG is positive, enable, if it is negative, disable.
719If ARG is nil, then toggle."
720 (interactive "P")
721 (setq global-semantic-stickyfunc-mode
722 (semantic-toggle-minor-mode-globally
723 'semantic-stickyfunc-mode arg)))
724
725(defcustom global-semantic-stickyfunc-mode nil
726 "*If non-nil, enable global use of `semantic-stickyfunc-mode'.
727This minor mode only works for Emacs 21 or later.
728When enabled, the header line is enabled, and the first line
729of the current function or method is displayed in it.
730This makes it appear that the first line of that tag is
731`sticky' to the top of the window."
732 :group 'semantic
733 :group 'semantic-modes
734 :type 'boolean
735 :require 'semantic/util-modes
736 :initialize 'custom-initialize-default
737 :set (lambda (sym val)
738 (global-semantic-stickyfunc-mode (if val 1 -1))))
739
740(defcustom semantic-stickyfunc-mode-hook nil
741 "*Hook run at the end of function `semantic-stickyfunc-mode'."
742 :group 'semantic
743 :type 'hook)
744
745(defvar semantic-stickyfunc-mode-map
746 (let ((km (make-sparse-keymap)))
747 (define-key km [ header-line down-mouse-1 ] 'semantic-stickyfunc-menu)
748 km)
749 "Keymap for stickyfunc minor mode.")
750
751(defvar semantic-stickyfunc-popup-menu nil
752 "Menu used if the user clicks on the header line used by stickyfunc mode.")
753
754(easy-menu-define
755 semantic-stickyfunc-popup-menu
756 semantic-stickyfunc-mode-map
757 "Stickyfunc Menu"
758 '("Stickyfunc Mode" :visible (progn nil)
759 [ "Copy Headerline Tag" senator-copy-tag
760 :active (semantic-current-tag)
761 :help "Copy the current tag to the tag ring"]
762 [ "Kill Headerline Tag" senator-kill-tag
763 :active (semantic-current-tag)
764 :help "Kill tag text to the kill ring, and copy the tag to the tag ring"
765 ]
766 [ "Copy Headerline Tag to Register" senator-copy-tag-to-register
767 :active (semantic-current-tag)
768 :help "Copy the current tag to a register"
769 ]
770 [ "Narrow To Headerline Tag" senator-narrow-to-defun
771 :active (semantic-current-tag)
772 :help "Narrow to the bounds of the current tag."]
773 [ "Fold Headerline Tag" senator-fold-tag-toggle
774 :active (semantic-current-tag)
775 :style toggle
776 :selected (let ((tag (semantic-current-tag)))
777 (and tag (semantic-tag-folded-p tag)))
778 :help "Fold the current tag to one line"
779 ]
780 "---"
781 [ "About This Header Line"
782 (lambda () (interactive)
783 (describe-function 'semantic-stickyfunc-mode)) t])
784 )
785
786(defvar semantic-stickyfunc-mode nil
787 "Non-nil if stickyfunc minor mode is enabled.
788Use the command `semantic-stickyfunc-mode' to change this variable.")
789(make-variable-buffer-local 'semantic-stickyfunc-mode)
790
791(defcustom semantic-stickyfunc-indent-string
792 (if (and window-system (not (featurep 'xemacs)))
793 (concat
794 (condition-case nil
795 ;; Test scroll bar location
796 (let ((charwidth (frame-char-width))
797 (scrollpos (frame-parameter (selected-frame)
798 'vertical-scroll-bars))
799 )
800 (if (or (eq scrollpos 'left)
801 ;; Now wait a minute. If you turn scroll-bar-mode
802 ;; on, then off, the new value is t, not left.
803 ;; Will this mess up older emacs where the default
804 ;; was on the right? I don't think so since they don't
805 ;; support a header line.
806 (eq scrollpos t))
807 (let ((w (when (boundp 'scroll-bar-width)
808 (symbol-value 'scroll-bar-width))))
809
810 (if (not w)
811 (setq w (frame-parameter (selected-frame)
812 'scroll-bar-width)))
813
814 ;; in 21.2, the frame parameter is sometimes empty
815 ;; so we need to get the value here.
816 (if (not w)
817 (setq w (+ (get 'scroll-bar-width 'x-frame-parameter)
818 ;; In 21.4, or perhaps 22.1 the x-frame
819 ;; parameter is different from the frame
820 ;; parameter by only 1 pixel.
821 1)))
822
823 (if (not w)
824 " "
825 (setq w (+ 2 w)) ; Some sort of border around
826 ; the scrollbar.
827 (make-string (/ w charwidth) ? )))
828 ""))
829 (error ""))
830 (condition-case nil
831 ;; Test fringe size.
832 (let* ((f (window-fringes))
833 (fw (car f))
834 (numspace (/ fw (frame-char-width)))
835 )
836 (make-string numspace ? ))
837 (error
838 ;; Well, the fancy new Emacs functions failed. Try older
839 ;; tricks.
840 (condition-case nil
841 ;; I'm not so sure what's up with the 21.1-21.3 fringe.
842 ;; It looks to be about 1 space wide.
843 (if (get 'fringe 'face)
844 " "
845 "")
846 (error ""))))
847 )
848 ;; Not Emacs or a window system means no scrollbar or fringe,
849 ;; and perhaps not even a header line to worry about.
850 "")
851 "*String used to indent the stickyfunc header.
852Customize this string to match the space used by scrollbars and
853fringe so it does not appear that the code is moving left/right
854when it lands in the sticky line."
855 :group 'semantic
856 :type 'string)
857
858(defvar semantic-stickyfunc-old-hlf nil
859 "Value of the header line when entering sticky func mode.")
860
861(defconst semantic-stickyfunc-header-line-format
862 (cond ((featurep 'xemacs)
863 nil)
864 ((>= emacs-major-version 22)
865 '(:eval (list
866 ;; Magic bit I found on emacswiki.
867 (propertize " " 'display '((space :align-to 0)))
868 (semantic-stickyfunc-fetch-stickyline))))
869 ((= emacs-major-version 21)
870 '(:eval (list semantic-stickyfunc-indent-string
871 (semantic-stickyfunc-fetch-stickyline))))
872 (t nil))
873 "The header line format used by sticky func mode.")
874
875(defun semantic-stickyfunc-mode-setup ()
876 "Setup option `semantic-stickyfunc-mode'.
877For semantic enabled buffers, make the function declaration for the top most
878function \"sticky\". This is accomplished by putting the first line of
879text for that function in Emacs 21's header line."
880 (if semantic-stickyfunc-mode
881 (progn
882 (unless (and (featurep 'semantic) (semantic-active-p))
883 ;; Disable minor mode if semantic stuff not available
884 (setq semantic-stickyfunc-mode nil)
885 (error "Buffer %s was not set up for parsing" (buffer-name)))
886 (unless (boundp 'default-header-line-format)
887 ;; Disable if there are no header lines to use.
888 (setq semantic-stickyfunc-mode nil)
889 (error "Sticky Function mode requires Emacs 21"))
890 ;; Enable the mode
891 ;; Save previous buffer local value of header line format.
892 (when (and (local-variable-p 'header-line-format (current-buffer))
893 (not (eq header-line-format
894 semantic-stickyfunc-header-line-format)))
895 (set (make-local-variable 'semantic-stickyfunc-old-hlf)
896 header-line-format))
897 (setq header-line-format semantic-stickyfunc-header-line-format)
898 )
899 ;; Disable sticky func mode
900 ;; Restore previous buffer local value of header line format if
901 ;; the current one is the sticky func one.
902 (when (eq header-line-format semantic-stickyfunc-header-line-format)
903 (kill-local-variable 'header-line-format)
904 (when (local-variable-p 'semantic-stickyfunc-old-hlf (current-buffer))
905 (setq header-line-format semantic-stickyfunc-old-hlf)
906 (kill-local-variable 'semantic-stickyfunc-old-hlf))))
907 semantic-stickyfunc-mode)
908
909(defun semantic-stickyfunc-mode (&optional arg)
910 "Minor mode to show the title of a tag in the header line.
911Enables/disables making the header line of functions sticky.
912A function (or other tag class specified by
913`semantic-stickyfunc-sticky-classes') has a header line, meaning the
914first line which describes the rest of the construct. This first
915line is what is displayed in the Emacs 21 header line.
916
917With prefix argument ARG, turn on if positive, otherwise off. The
918minor mode can be turned on only if semantic feature is available and
919the current buffer was set up for parsing. Return non-nil if the
920minor mode is enabled."
921 (interactive
922 (list (or current-prefix-arg
923 (if semantic-stickyfunc-mode 0 1))))
924 (setq semantic-stickyfunc-mode
925 (if arg
926 (>
927 (prefix-numeric-value arg)
928 0)
929 (not semantic-stickyfunc-mode)))
930 (semantic-stickyfunc-mode-setup)
931 (run-hooks 'semantic-stickyfunc-mode-hook)
932 (if (interactive-p)
933 (message "Stickyfunc minor mode %sabled"
934 (if semantic-stickyfunc-mode "en" "dis")))
935 (semantic-mode-line-update)
936 semantic-stickyfunc-mode)
937
938(defvar semantic-stickyfunc-sticky-classes
939 '(function type)
940 "List of tag classes which sticky func will display in the header line.")
941(make-variable-buffer-local 'semantic-stickyfunc-sticky-classes)
942
943(defun semantic-stickyfunc-tag-to-stick ()
944 "Return the tag to stick at the current point."
945 (let ((tags (nreverse (semantic-find-tag-by-overlay (point)))))
946 ;; Get rid of non-matching tags.
947 (while (and tags
948 (not (member
949 (semantic-tag-class (car tags))
950 semantic-stickyfunc-sticky-classes))
951 )
952 (setq tags (cdr tags)))
953 (car tags)))
954
955(defun semantic-stickyfunc-fetch-stickyline ()
956 "Make the function at the top of the current window sticky.
957Capture it's function declaration, and place it in the header line.
958If there is no function, disable the header line."
959 (let ((str
960 (save-excursion
961 (goto-char (window-start (selected-window)))
962 (forward-line -1)
963 (end-of-line)
964 ;; Capture this function
965 (let* ((tag (semantic-stickyfunc-tag-to-stick)))
966 ;; TAG is nil if there was nothing of the apropriate type there.
967 (if (not tag)
968 ;; Set it to be the text under the header line
969 (buffer-substring (point-at-bol) (point-at-eol))
970 ;; Get it
971 (goto-char (semantic-tag-start tag))
972 ;; Klaus Berndl <klaus.berndl@sdm.de>:
973 ;; goto the tag name; this is especially needed for languages
974 ;; like c++ where a often used style is like:
975 ;; void
976 ;; ClassX::methodM(arg1...)
977 ;; {
978 ;; ...
979 ;; }
980 ;; Without going to the tag-name we would get"void" in the
981 ;; header line which is IMHO not really useful
982 (search-forward (semantic-tag-name tag) nil t)
983 (buffer-substring (point-at-bol) (point-at-eol))
984 ))))
985 (start 0))
986 (while (string-match "%" str start)
987 (setq str (replace-match "%%" t t str 0)
988 start (1+ (match-end 0)))
989 )
990 ;; In 21.4 (or 22.1) the heder doesn't expand tabs. Hmmmm.
991 ;; We should replace them here.
992 ;;
993 ;; This hack assumes that tabs are kept smartly at tab boundaries
994 ;; instead of in a tab boundary where it might only represent 4 spaces.
995 (while (string-match "\t" str start)
996 (setq str (replace-match " " t t str 0)))
997 str))
998
999(defun semantic-stickyfunc-menu (event)
1000 "Popup a menu that can help a user understand stickyfunc-mode.
1001Argument EVENT describes the event that caused this function to be called."
1002 (interactive "e")
1003 (let* ((startwin (selected-window))
1004 (win (car (car (cdr event))))
1005 )
1006 (select-window win t)
1007 (save-excursion
1008 (goto-char (window-start win))
1009 (sit-for 0)
1010 (popup-menu semantic-stickyfunc-popup-menu event)
1011 )
1012 (select-window startwin)))
1013
1014
1015(semantic-add-minor-mode 'semantic-stickyfunc-mode
1016 "" ;; Don't need indicator. It's quite visible
1017 semantic-stickyfunc-mode-map)
1018
1019
1020
1021;;;;
1022;;;; Minor mode to make highlight the current function
1023;;;;
1024
1025;; Highlight the first like of the function we are in if it is different
1026;; from the the tag going off the top of the screen.
1027(defun global-semantic-highlight-func-mode (&optional arg)
1028 "Toggle global use of option `semantic-highlight-func-mode'.
1029If ARG is positive, enable, if it is negative, disable.
1030If ARG is nil, then toggle."
1031 (interactive "P")
1032 (setq global-semantic-highlight-func-mode
1033 (semantic-toggle-minor-mode-globally
1034 'semantic-highlight-func-mode arg)))
1035
1036(defcustom global-semantic-highlight-func-mode nil
1037 "*If non-nil, enable global use of `semantic-highlight-func-mode'.
1038When enabled, the first line of the current tag is highlighted."
1039 :group 'semantic
1040 :group 'semantic-modes
1041 :type 'boolean
1042 :require 'semantic/util-modes
1043 :initialize 'custom-initialize-default
1044 :set (lambda (sym val)
1045 (global-semantic-highlight-func-mode (if val 1 -1))))
1046
1047(defcustom semantic-highlight-func-mode-hook nil
1048 "*Hook run at the end of function `semantic-highlight-func-mode'."
1049 :group 'semantic
1050 :type 'hook)
1051
1052(defvar semantic-highlight-func-mode-map
1053 (let ((km (make-sparse-keymap))
1054 (m3 (if (featurep 'xemacs) [ button3 ] [ mouse-3 ]))
1055 )
1056 (define-key km m3 'semantic-highlight-func-menu)
1057 km)
1058 "Keymap for highlight-func minor mode.")
1059
1060(defvar semantic-highlight-func-popup-menu nil
1061 "Menu used if the user clicks on the header line used by `semantic-highlight-func-mode'.")
1062
1063(easy-menu-define
1064 semantic-highlight-func-popup-menu
1065 semantic-highlight-func-mode-map
1066 "Highlight-Func Menu"
1067 '("Highlight-Func Mode" :visible (progn nil)
1068 [ "Copy Tag" senator-copy-tag
1069 :active (semantic-current-tag)
1070 :help "Copy the current tag to the tag ring"]
1071 [ "Kill Tag" senator-kill-tag
1072 :active (semantic-current-tag)
1073 :help "Kill tag text to the kill ring, and copy the tag to the tag ring"
1074 ]
1075 [ "Copy Tag to Register" senator-copy-tag-to-register
1076 :active (semantic-current-tag)
1077 :help "Copy the current tag to a register"
1078 ]
1079 [ "Narrow To Tag" senator-narrow-to-defun
1080 :active (semantic-current-tag)
1081 :help "Narrow to the bounds of the current tag."]
1082 [ "Fold Tag" senator-fold-tag-toggle
1083 :active (semantic-current-tag)
1084 :style toggle
1085 :selected (let ((tag (semantic-stickyfunc-tag-to-stick)))
1086 (and tag (semantic-tag-folded-p tag)))
1087 :help "Fold the current tag to one line"
1088 ]
1089 "---"
1090 [ "About This Tag" semantic-describe-tag t])
1091 )
1092
1093(defun semantic-highlight-func-menu (event)
1094 "Popup a menu that displays things to do to the current tag.
1095Argument EVENT describes the event that caused this function to be called."
1096 (interactive "e")
1097 (let* ((startwin (selected-window))
1098 (win (semantic-event-window event))
1099 )
1100 (select-window win t)
1101 (save-excursion
1102 ;(goto-char (window-start win))
1103 (mouse-set-point event)
1104 (sit-for 0)
1105 (semantic-popup-menu semantic-highlight-func-popup-menu)
1106 )
1107 (select-window startwin)))
1108
1109(defvar semantic-highlight-func-mode nil
1110 "Non-nil if highlight-func minor mode is enabled.
1111Use the command `semantic-highlight-func-mode' to change this variable.")
1112(make-variable-buffer-local 'semantic-highlight-func-mode)
1113
1114(defvar semantic-highlight-func-ct-overlay nil
1115 "Overlay used to highlight the tag the cursor is in.")
1116(make-variable-buffer-local 'semantic-highlight-func-ct-overlay)
1117
1118(defface semantic-highlight-func-current-tag-face
1119 '((((class color) (background dark))
1120 ;; Put this back to something closer to black later.
1121 (:background "gray20"))
1122 (((class color) (background light))
1123 (:background "gray90")))
1124 "Face used to show the top of current function."
1125 :group 'semantic-faces)
1126
1127
1128(defun semantic-highlight-func-mode-setup ()
1129 "Setup option `semantic-highlight-func-mode'.
1130For semantic enabled buffers, highlight the first line of the
1131current tag declaration."
1132 (if semantic-highlight-func-mode
1133 (progn
1134 (unless (and (featurep 'semantic) (semantic-active-p))
1135 ;; Disable minor mode if semantic stuff not available
1136 (setq semantic-highlight-func-mode nil)
1137 (error "Buffer %s was not set up for parsing" (buffer-name)))
1138 ;; Setup our hook
1139 (add-hook 'post-command-hook 'semantic-highlight-func-highlight-current-tag nil t)
1140 )
1141 ;; Disable highlight func mode
1142 (remove-hook 'post-command-hook 'semantic-highlight-func-highlight-current-tag t)
1143 (semantic-highlight-func-highlight-current-tag t)
1144 )
1145 semantic-highlight-func-mode)
1146
1147(defun semantic-highlight-func-mode (&optional arg)
1148 "Minor mode to highlight the first line of the current tag.
1149Enables/disables making the header line of functions sticky.
1150A function (or other tag class specified by
1151`semantic-stickfunc-sticky-classes') is highlighted, meaning the
1152first line which describes the rest of the construct.
1153
1154See `semantic-stickfunc-mode' for putting a function in the
1155header line. This mode recycles the stickyfunc configuration
1156classes list.
1157
1158With prefix argument ARG, turn on if positive, otherwise off. The
1159minor mode can be turned on only if semantic feature is available and
1160the current buffer was set up for parsing. Return non-nil if the
1161minor mode is enabled."
1162 (interactive
1163 (list (or current-prefix-arg
1164 (if semantic-highlight-func-mode 0 1))))
1165 (setq semantic-highlight-func-mode
1166 (if arg
1167 (>
1168 (prefix-numeric-value arg)
1169 0)
1170 (not semantic-highlight-func-mode)))
1171 (semantic-highlight-func-mode-setup)
1172 (run-hooks 'semantic-highlight-func-mode-hook)
1173 (if (interactive-p)
1174 (message "Highlight-Func minor mode %sabled"
1175 (if semantic-highlight-func-mode "en" "dis")))
1176 semantic-highlight-func-mode)
1177
1178(defun semantic-highlight-func-highlight-current-tag (&optional disable)
1179 "Highlight the current tag under point.
1180Optional argument DISABLE will turn off any active highlight.
1181If the current tag for this buffer is different from the last time this
1182function was called, move the overlay."
1183 (when (and (not (minibufferp))
1184 (or (not semantic-highlight-func-ct-overlay)
1185 (eq (semantic-overlay-buffer
1186 semantic-highlight-func-ct-overlay)
1187 (current-buffer))))
1188 (let* ((tag (semantic-stickyfunc-tag-to-stick))
1189 (ol semantic-highlight-func-ct-overlay))
1190 (when (not ol)
1191 ;; No overlay in this buffer. Make one.
1192 (setq ol (semantic-make-overlay (point-min) (point-min)
1193 (current-buffer) t nil))
1194 (semantic-overlay-put ol 'highlight-func t)
1195 (semantic-overlay-put ol 'face 'semantic-highlight-func-current-tag-face)
1196 (semantic-overlay-put ol 'keymap semantic-highlight-func-mode-map)
1197 (semantic-overlay-put ol 'help-echo
1198 "Current Function : mouse-3 - Context menu")
1199 (setq semantic-highlight-func-ct-overlay ol)
1200 )
1201
1202 ;; TAG is nil if there was nothing of the apropriate type there.
1203 (if (or (not tag) disable)
1204 ;; No tag, make the overlay go away.
1205 (progn
1206 (semantic-overlay-put ol 'tag nil)
1207 (semantic-overlay-move ol (point-min) (point-min) (current-buffer))
1208 )
1209
1210 ;; We have a tag, if it is the same, do nothing.
1211 (unless (eq (semantic-overlay-get ol 'tag) tag)
1212 (save-excursion
1213 (goto-char (semantic-tag-start tag))
1214 (search-forward (semantic-tag-name tag) nil t)
1215 (semantic-overlay-put ol 'tag tag)
1216 (semantic-overlay-move ol (point-at-bol) (point-at-eol))
1217 )
1218 )
1219 )))
1220 nil)
1221
1222(semantic-add-minor-mode 'semantic-highlight-func-mode
1223 "" ;; Don't need indicator. It's quite visible
1224 nil)
1225
1226(provide 'semantic/util-modes)
1227
1228;;; semantic-util-modes.el ends here