1 ;;; semantic-format.el --- Routines for formatting tags
3 ;;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 Eric M. Ludlam
5 ;; Author: Eric M. Ludlam <zappo@gnu.org>
7 ;; X-RCS: $Id: semantic-format.el,v 1.1 2007-11-26 15:10:36 michaels Exp $
9 ;; This file is not part of GNU Emacs.
11 ;; Semantic 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 2, or (at your option)
16 ;; This software 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.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
28 ;; Once a language file has been parsed into a TAG, it is often useful
29 ;; then display that tag information in browsers, completion engines, or
30 ;; help routines. The functions and setup in this file provide ways
31 ;; to reformat a tag into different standard output types.
33 ;; In addition, macros for setting up customizable variables that let
34 ;; the user choose their default format type are also provided.
38 (eval-when-compile (require 'font-lock))
39 (require 'semantic-tag)
42 ;;; Tag to text overload functions
44 ;; abbreviations, prototypes, and coloring support.
46 (defvar semantic-format-tag-functions
47 '(semantic-format-tag-name
48 semantic-format-tag-canonical-name
49 semantic-format-tag-abbreviate
50 semantic-format-tag-summarize
51 semantic-format-tag-prototype
52 semantic-format-tag-concise-prototype
53 semantic-format-tag-uml-abbreviate
54 semantic-format-tag-uml-prototype
55 semantic-format-tag-uml-concise-prototype
56 semantic-format-tag-prin1
58 "List of functions which convert a tag to text.
59 Each function must take the parameters TAG &optional PARENT COLOR.
60 TAG is the tag to convert.
61 PARENT is a parent tag or name which refers to the structure
62 or class which contains TAG. PARENT is NOT a class which a TAG
63 would claim as a parent.
64 COLOR indicates that the generated text should be colored using
68 (semantic-varalias-obsolete 'semantic-token->text-functions
69 'semantic-format-tag-functions)
71 (defvar semantic-format-tag-custom-list
73 (mapcar (lambda (f) (list 'const f))
74 semantic-format-tag-functions)
76 "A List used by customizeable variables to choose a tag to text function.
77 Use this variable in the :type field of a customizable variable.")
79 (semantic-varalias-obsolete 'semantic-token->text-custom-list
80 'semantic-format-tag-custom-list)
82 (defcustom semantic-format-use-images-flag ezimage-use-images
83 "Non-nil means semantic format functions use images.
84 Images can be used as icons instead of some types of text strings."
88 (defvar semantic-function-argument-separator ","
89 "Text used to separate arguments when creating text from tags.")
90 (make-variable-buffer-local 'semantic-function-argument-separator)
92 (defvar semantic-format-parent-separator "::"
93 "Text used to separate names when between namespaces/classes and functions.")
94 (make-variable-buffer-local 'semantic-format-parent-separator)
96 (defun semantic-test-all-format-tag-functions (&optional arg)
97 "Test all outputs from `semantic-format-tag-functions'.
98 Output is generated from the function under `point'.
99 Optional argument ARG specifies not to use color."
101 (semantic-fetch-tags)
102 (let* ((tag (semantic-current-tag))
103 (par (or (semantic-current-tag-parent)
104 (if (semantic-tag-function-parent tag)
105 (semantic-find-first-tag-by-name
106 (semantic-tag-function-parent tag)
109 (fns semantic-format-tag-functions))
110 (with-output-to-temp-buffer "*format-tag*"
111 (princ "Tag->format function tests:")
116 (let ((s (funcall (car fns) tag par (not arg))))
118 (set-buffer "*format-tag*")
119 (goto-char (point-max))
121 (setq fns (cdr fns))))
124 (defvar semantic-format-face-alist
125 `( (function . font-lock-function-name-face)
126 (variable . font-lock-variable-name-face)
127 (type . font-lock-type-face)
128 ;; These are different between Emacsen.
129 (include . ,(if (featurep 'xemacs)
130 'font-lock-preprocessor-face
131 'font-lock-constant-face))
132 (package . ,(if (featurep 'xemacs)
133 'font-lock-preprocessor-face
134 'font-lock-constant-face))
135 ;; Not a tag, but instead a feature of output
136 (label . font-lock-string-face)
137 (comment . font-lock-comment-face)
138 (keyword . font-lock-keyword-face)
142 "Face used to colorize tags of different types.
143 Override the value locally if a language supports other tag types.
144 When adding new elements, try to use symbols also returned by the parser.
145 The form of an entry in this list is of the form:
147 where SYMBOL is a tag type symbol used with semantic. FACE
148 is a symbol representing a face.
149 Faces used are generated in `font-lock' for consistency, and will not
150 be used unless font lock is a feature.")
152 (semantic-varalias-obsolete 'semantic-face-alist
153 'semantic-format-face-alist)
157 ;;; Coloring Functions
159 (defun semantic--format-colorize-text (text face-class)
160 "Apply onto TEXT a color associated with FACE-CLASS.
161 FACE-CLASS is a tag type found in `semantic-face-alist'. See this variable
162 for details on adding new types."
163 (when (featurep 'font-lock)
164 (let ((face (cdr-safe (assoc face-class semantic-format-face-alist)))
165 (newtext (concat text)))
166 (put-text-property 0 (length text) 'face face newtext)
170 (make-obsolete 'semantic-colorize-text
171 'semantic--format-colorize-text)
173 (defun semantic--format-colorize-merge-text (precoloredtext face-class)
174 "Apply onto PRECOLOREDTEXT a color associated with FACE-CLASS.
175 FACE-CLASS is a tag type found in 'semantic-face-alist'. See this
176 variable for details on adding new types."
177 (let ((face (cdr-safe (assoc face-class semantic-format-face-alist)))
178 (newtext (concat precoloredtext))
180 (if (featurep 'xemacs)
181 (add-text-properties 0 (length newtext) (list 'face face) newtext)
182 (alter-text-property 0 (length newtext) 'face
183 (lambda (current-face)
185 (cond ((facep current-face)
187 ((listp current-face)
200 ;;; Function Arguments
202 (defun semantic--format-tag-arguments (args formatter color)
203 "Format the argument list ARGS with FORMATTER.
204 FORMATTER is a function used to format a tag.
205 COLOR specifies if color should be used."
208 (push (semantic-format-tag-name-from-anything
209 (car args) nil color 'variable) out)
210 (setq args (cdr args)))
211 (mapconcat 'identity (nreverse out) semantic-function-argument-separator)
217 (define-overload semantic-format-tag-type (tag color)
218 "Convert the data type of TAG to a string usable in tag formatting.
219 It is presumed that TYPE is a string or semantic tag.")
221 (defun semantic-format-tag-type-default (tag color)
222 "Convert the data type of TAG to a string usable in tag formatting.
223 Argument COLOR specifies to colorize the text."
224 (let* ((type (semantic-tag-type tag))
225 (out (cond ((semantic-tag-p type)
226 (let* ((typetype (semantic-tag-type type))
227 (name (semantic-tag-name type))
229 (concat typetype " " name)
232 (semantic--format-colorize-text
237 (stringp (car type)))
243 (setq out (semantic--format-colorize-text out 'type))
248 ;;; Abstract formatting functions
252 (defun semantic-format-tag-prin1 (tag &optional parent color)
253 "Convert TAG to a string that is the print name for TAG.
254 PARENT and COLOR are ignored."
257 (defun semantic-format-tag-name-from-anything (anything &optional
260 "Convert just about anything into a name like string.
261 Argument ANYTHING is the thing to be converted.
262 Optional argument PARENT is the parent type if TAG is a detail.
263 Optional argument COLOR means highlight the prototype with font-lock colors.
264 Optional COLORHINT is the type of color to use if ANYTHING is not a tag
265 with a tag class. See `semantic--format-colorize-text' for a definition
266 of FACE-CLASS for which this is used."
267 (cond ((stringp anything)
268 (semantic--format-colorize-text anything colorhint))
269 ((semantic-tag-p anything)
270 (let ((ans (semantic-format-tag-name anything parent color)))
271 ;; If ANS is empty string or nil, then the name wasn't
272 ;; supplied. The implication is as in C where there is a data
273 ;; type but no name for a prototype from an include file, or
274 ;; an argument just wasn't used in the body of the fcn.
275 (if (or (null ans) (string= ans ""))
276 (setq ans (semantic-format-tag-type anything color)))
278 ((and (listp anything)
279 (stringp (car anything)))
280 (semantic--format-colorize-text (car anything) colorhint))))
283 (define-overload semantic-format-tag-name (tag &optional parent color)
284 "Return the name string describing TAG.
285 The name is the shortest possible representation.
286 Optional argument PARENT is the parent type if TAG is a detail.
287 Optional argument COLOR means highlight the prototype with font-lock colors.")
289 (defun semantic-format-tag-name-default (tag &optional parent color)
290 "Return an abbreviated string describing TAG.
291 Optional argument PARENT is the parent type if TAG is a detail.
292 Optional argument COLOR means highlight the prototype with font-lock colors."
293 (let ((name (semantic-tag-name tag))
295 (if (eq (semantic-tag-class tag) 'function)
296 (semantic-tag-function-destructor-p tag))))
298 (setq name (concat "~" name)))
300 (setq name (semantic--format-colorize-text name (semantic-tag-class tag))))
303 (defun semantic--format-tag-parent-tree (tag parent)
304 "Under Consideration.
306 Return a list of parents for TAG.
307 PARENT is the first parent, or nil. If nil, then an attempt to
308 determine PARENT is made.
309 Once PARENT is identified, additional parents are looked for.
310 The return list first element is the nearest parent, and the last
311 item is the first parent which may be a string. The root parent may
312 not be the actual first parent as there may just be a failure to find
314 ;; First, validate the PARENT argument.
316 ;; All mechanisms here must be fast as often parent
317 ;; is nil because there isn't one.
318 (setq parent (or (semantic-tag-function-parent tag)
320 (semantic-go-to-tag tag)
321 (semantic-current-tag-parent)))))
322 (when (stringp parent)
323 (setq parent (semantic-find-first-tag-by-name
324 parent (current-buffer))))
325 ;; Try and find a trail of parents from PARENT
326 (let ((rlist (list parent))
328 ;; IMPLELEMENT ME!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
331 (define-overload semantic-format-tag-canonical-name (tag &optional parent color)
332 "Return a canonical name for TAG.
333 A canonical name includes the names of any parents or namespaces preceeding
335 Optional argument PARENT is the parent type if TAG is a detail.
336 Optional argument COLOR means highlight the prototype with font-lock colors.")
338 (defun semantic-format-tag-canonical-name-default (tag &optional parent color)
339 "Return a canonical name for TAG.
340 A canonical name includes the names of any parents or namespaces preceeding
341 the tag with colons separating them.
342 Optional argument PARENT is the parent type if TAG is a detail.
343 Optional argument COLOR means highlight the prototype with font-lock colors."
346 ;; Choose a class of 'type as the default parent for something.
347 ;; Just a guess though.
348 (semantic-format-tag-name-from-anything parent nil color 'type)
349 ;; Default separator between class/namespace and others.
350 semantic-format-parent-separator
351 ;; The tag being formatted
352 (semantic-format-tag-name tag parent color))
353 ;; If not parent, then just use the tag.
354 (semantic-format-tag-name tag parent color))
358 (define-overload semantic-format-tag-abbreviate (tag &optional parent color)
359 "Return an abbreviated string describing TAG.
360 The abbreviation is to be short, with possible symbols indicating
361 the type of tag, or other information.
362 Optional argument PARENT is the parent type if TAG is a detail.
363 Optional argument COLOR means highlight the prototype with font-lock colors.")
365 (defun semantic-format-tag-abbreviate-default (tag &optional parent color)
366 "Return an abbreviated string describing TAG.
367 Optional argument PARENT is a parent tag in the tag hierarchy.
368 In this case PARENT refers to containment, not inheritance.
369 Optional argument COLOR means highlight the prototype with font-lock colors.
370 This is a simple C like default."
371 ;; Do lots of complex stuff here.
372 (let ((class (semantic-tag-class tag))
373 (name (semantic-format-tag-canonical-name tag parent color))
377 (cond ((eq class 'function)
381 ((eq class 'variable)
382 (setq suffix (if (semantic-tag-variable-default tag)
392 (setq str (concat prefix name suffix))
395 ;; Semantic 1.2.x had this misspelling. Keep it for backwards compatibiity.
396 (semantic-alias-obsolete
397 'semantic-summerize-nonterminal 'semantic-format-tag-summarize)
400 (define-overload semantic-format-tag-summarize (tag &optional parent color)
401 "Summarize TAG in a reasonable way.
402 Optional argument PARENT is the parent type if TAG is a detail.
403 Optional argument COLOR means highlight the prototype with font-lock colors.")
405 (defun semantic-format-tag-summarize-default (tag &optional parent color)
406 "Summarize TAG in a reasonable way.
407 Optional argument PARENT is the parent type if TAG is a detail.
408 Optional argument COLOR means highlight the prototype with font-lock colors."
409 (let* ((proto (semantic-format-tag-prototype tag nil color))
411 semantic-symbol->name-assoc-list-for-type-parts
412 semantic-symbol->name-assoc-list))
413 (tsymb (semantic-tag-class tag))
414 (label (capitalize (or (cdr-safe (assoc tsymb names))
415 (symbol-name tsymb)))))
417 (setq label (semantic--format-colorize-text label 'label)))
418 (concat label ": " proto)))
420 ;;; Prototype generation
423 (define-overload semantic-format-tag-prototype (tag &optional parent color)
424 "Return a prototype for TAG.
425 This function should be overloaded, though it need not be used.
426 This is because it can be used to create code by language independent
428 Optional argument PARENT is the parent type if TAG is a detail.
429 Optional argument COLOR means highlight the prototype with font-lock colors.")
431 (defun semantic-format-tag-prototype-default (tag &optional parent color)
432 "Default method for returning a prototype for TAG.
433 This will work for C like languages.
434 Optional argument PARENT is the parent type if TAG is a detail.
435 Optional argument COLOR means highlight the prototype with font-lock colors."
436 (let* ((class (semantic-tag-class tag))
437 (name (semantic-format-tag-name tag parent color))
438 (type (if (member class '(function variable type))
439 (semantic-format-tag-type tag color)))
440 (args (if (member class '(function type))
441 (semantic--format-tag-arguments
442 (if (eq class 'function)
443 (semantic-tag-function-arguments tag)
445 ;;(semantic-tag-type-members tag)
447 #'semantic-format-tag-prototype
449 (const (semantic-tag-get-attribute tag :constant-flag))
451 (if const '("const") nil)
452 (semantic-tag-get-attribute tag :typemodifiers)))
453 (array (if (eq class 'variable)
455 (semantic-tag-get-attribute
458 (while (and deref (/= deref 0))
459 (setq r (concat r "[]")
466 (if (eq class 'type) "{" "(")
468 (if (eq class 'type) "}" ")"))))
470 (setq mods (concat (mapconcat 'identity mods " ") " ")))
472 (if type (concat type " "))
478 (define-overload semantic-format-tag-concise-prototype (tag &optional parent color)
479 "Return a concise prototype for TAG.
480 Optional argument PARENT is the parent type if TAG is a detail.
481 Optional argument COLOR means highlight the prototype with font-lock colors.")
483 (defun semantic-format-tag-concise-prototype-default (tag &optional parent color)
484 "Return a concise prototype for TAG.
485 This default function will make a cheap concise prototype using C like syntax.
486 Optional argument PARENT is the parent type if TAG is a detail.
487 Optional argument COLOR means highlight the prototype with font-lock colors."
488 (let ((class (semantic-tag-class tag)))
491 (concat (semantic-format-tag-name tag parent color) "{}"))
492 ((eq class 'function)
493 (concat (semantic-format-tag-name tag parent color)
495 (semantic--format-tag-arguments
496 (semantic-tag-function-arguments tag)
497 'semantic-format-tag-concise-prototype
500 ((eq class 'variable)
501 (let* ((deref (semantic-tag-get-attribute
505 (while (and deref (/= deref 0))
506 (setq array (concat array "[]")
508 (concat (semantic-format-tag-name tag parent color)
511 (semantic-format-tag-abbreviate tag parent color)))))
513 ;;; UML display styles
515 (defcustom semantic-uml-colon-string " : "
516 "*String used as a color separator between parts of a UML string.
517 In UML, a variable may appear as `varname : type'.
518 Change this variable to change the output separator."
522 (defcustom semantic-uml-no-protection-string ""
523 "*String used to describe when no protection is specified.
524 Used by `semantic-format-tag-uml-protection-to-string'."
528 (defun semantic--format-uml-post-colorize (text tag parent)
529 "Add color to TEXT created from TAG and PARENT.
530 Adds augmentation for `abstract' and `static' entries."
531 (if (semantic-tag-abstract-p tag parent)
532 (setq text (semantic--format-colorize-merge-text text 'abstract)))
533 (if (semantic-tag-static-p tag parent)
534 (setq text (semantic--format-colorize-merge-text text 'static)))
538 (defun semantic-uml-attribute-string (tag &optional parent)
539 "Return a string for TAG, a child of PARENT representing a UML attribute.
540 UML attribute strings are things like {abstract} or {leaf}."
541 (cond ((semantic-tag-abstract-p tag parent)
543 ((semantic-tag-leaf-p tag parent)
547 (defvar semantic-format-tag-protection-image-alist
548 '(("+" . ezimage-unlock)
552 "Association of protection strings, and images to use.")
554 (defvar semantic-format-tag-protection-symbol-to-string-assoc-list
559 "Association list of the form (SYMBOL . \"STRING\") for protection symbols.
560 This associates a symbol, such as 'public with the st ring \"+\".")
562 (define-overload semantic-format-tag-uml-protection-to-string (protection-symbol color)
563 "Convert PROTECTION-SYMBOL to a string for UML.
564 By default, uses `semantic-format-tag-protection-symbol-to-string-assoc-list'
566 By defaul character returns are:
570 If PROTECTION-SYMBOL is unknown, then the return value is
571 `semantic-uml-no-protection-string'.
572 COLOR indicates if we should use an image on the text.")
574 (defun semantic-format-tag-uml-protection-to-string-default (protection-symbol color)
575 "Convert PROTECTION-SYMBOL to a string for UML.
576 Uses `semantic-format-tag-protection-symbol-to-string-assoc-list' to convert.
577 If PROTECTION-SYMBOL is unknown, then the return value is
578 `semantic-uml-no-protection-string'.
579 COLOR indicates if we should use an image on the text."
580 (let* ((ezimage-use-images (and semantic-format-use-images-flag color))
581 (key (assoc protection-symbol
582 semantic-format-tag-protection-symbol-to-string-assoc-list))
583 (str (or (cdr-safe key) semantic-uml-no-protection-string)))
584 (ezimage-image-over-string
585 (copy-sequence str) ; make a copy to keep the original pristine.
586 semantic-format-tag-protection-image-alist)))
588 (defsubst semantic-format-tag-uml-protection (tag parent color)
589 "Retrieve the protection string for TAG with PARENT.
590 Argument COLOR specifies that color should be added to the string as
592 (semantic-format-tag-uml-protection-to-string
593 (semantic-tag-protection tag parent)
596 (defun semantic--format-tag-uml-type (tag color)
597 "Format the data type of TAG to a string usable for formatting.
598 COLOR indicates if it should be colorized."
599 (let ((str (semantic-format-tag-type tag color)))
601 (concat semantic-uml-colon-string str))))
604 (define-overload semantic-format-tag-uml-abbreviate (tag &optional parent color)
605 "Return a UML style abbreviation for TAG.
606 Optional argument PARENT is the parent type if TAG is a detail.
607 Optional argument COLOR means highlight the prototype with font-lock colors.")
609 (defun semantic-format-tag-uml-abbreviate-default (tag &optional parent color)
610 "Return a UML style abbreviation for TAG.
611 Optional argument PARENT is the parent type if TAG is a detail.
612 Optional argument COLOR means highlight the prototype with font-lock colors."
613 (let* ((name (semantic-format-tag-name tag parent color))
614 (type (semantic--format-tag-uml-type tag color))
615 (protstr (semantic-format-tag-uml-protection tag parent color))
620 (if type (concat name type)
623 (setq text (semantic--format-uml-post-colorize text tag parent)))
627 (define-overload semantic-format-tag-uml-prototype (tag &optional parent color)
628 "Return a UML style prototype for TAG.
629 Optional argument PARENT is the parent type if TAG is a detail.
630 Optional argument COLOR means highlight the prototype with font-lock colors.")
632 (defun semantic-format-tag-uml-prototype-default (tag &optional parent color)
633 "Return a UML style prototype for TAG.
634 Optional argument PARENT is the parent type if TAG is a detail.
635 Optional argument COLOR means highlight the prototype with font-lock colors."
636 (let* ((class (semantic-tag-class tag))
637 (cp (semantic-format-tag-name tag parent color))
638 (type (semantic--format-tag-uml-type tag color))
639 (prot (semantic-format-tag-uml-protection tag parent color))
641 (cond ((eq class 'function)
644 (semantic--format-tag-arguments
645 (semantic-tag-function-arguments tag)
646 #'semantic-format-tag-uml-prototype
652 (setq text (concat prot cp argtext type))
654 (setq text (semantic--format-uml-post-colorize text tag parent)))
659 (define-overload semantic-format-tag-uml-concise-prototype (tag &optional parent color)
660 "Return a UML style concise prototype for TAG.
661 Optional argument PARENT is the parent type if TAG is a detail.
662 Optional argument COLOR means highlight the prototype with font-lock colors.")
664 (defun semantic-format-tag-uml-concise-prototype-default (tag &optional parent color)
665 "Return a UML style concise prototype for TAG.
666 Optional argument PARENT is the parent type if TAG is a detail.
667 Optional argument COLOR means highlight the prototype with font-lock colors."
668 (let* ((cp (semantic-format-tag-concise-prototype tag parent color))
669 (type (semantic--format-tag-uml-type tag color))
670 (prot (semantic-format-tag-uml-protection tag parent color))
673 (setq text (concat prot cp type))
675 (setq text (semantic--format-uml-post-colorize text tag parent)))
680 ;;; Compatibility and aliases
682 (semantic-alias-obsolete 'semantic-test-all-token->text-functions
683 'semantic-test-all-format-tag-functions)
685 (semantic-alias-obsolete 'semantic-prin1-nonterminal
686 'semantic-format-tag-prin1)
688 (semantic-alias-obsolete 'semantic-name-nonterminal
689 'semantic-format-tag-name)
691 (semantic-alias-obsolete 'semantic-abbreviate-nonterminal
692 'semantic-format-tag-abbreviate)
694 (semantic-alias-obsolete 'semantic-summarize-nonterminal
695 'semantic-format-tag-summarize)
697 (semantic-alias-obsolete 'semantic-prototype-nonterminal
698 'semantic-format-tag-prototype)
700 (semantic-alias-obsolete 'semantic-concise-prototype-nonterminal
701 'semantic-format-tag-concise-prototype)
703 (semantic-alias-obsolete 'semantic-uml-abbreviate-nonterminal
704 'semantic-format-tag-uml-abbreviate)
706 (semantic-alias-obsolete 'semantic-uml-prototype-nonterminal
707 'semantic-format-tag-uml-prototype)
709 (semantic-alias-obsolete 'semantic-uml-concise-prototype-nonterminal
710 'semantic-format-tag-uml-concise-prototype)
713 (provide 'semantic-format)
715 ;;; semantic-format.el ends here