1 ;;; eieio-doc.el --- create texinfo documentation for an eieio class
3 ;;; Copyright (C) 1996, 1998, 1999, 2000, 2001, 2004, 2005 Eric M. Ludlam
5 ;; Author: <zappo@gnu.org>
6 ;; RCS: $Id: eieio-doc.el,v 1.4 2007-11-26 15:01:04 michaels Exp $
7 ;; Keywords: OO, lisp, docs
9 ;; This program 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 2, or (at your option)
14 ;; This program 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.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 ;; Boston, MA 02110-1301, USA.
24 ;; Please send bug reports, etc. to zappo@gnu.org
28 ;; Outputs into the current buffer documentation in texinfo format
32 ;; for a class, all it's children, and all it's slots.
35 (defvar eieiodoc-currently-in-node nil
36 "String representing the node we go BACK to.")
38 (defvar eieiodoc-current-section-level nil
39 "String represending what type of section header to use.")
41 (defvar eieiodoc-prev-class nil
42 "Non-nil when while `eieiodoc-recurse' is running.
43 Can be referenced from the recursed function.")
45 (defvar eieiodoc-next-class nil
46 "Non-nil when `eieiodoc-recurse' is running.
47 Can be referenced from the recursed function.")
49 (defun eieiodoc-class-nuke (root-class indexstring &optional skiplist)
50 "Call `eieiodoc-class' after nuking everything from POINT on.
51 ROOT-CLASS, INDEXSTRING, and SKIPLIST are the same as `eieiodoc-class'."
52 (delete-region (point) (point-max))
54 (eieiodoc-class root-class indexstring skiplist))
56 (defun eieiodoc-class (root-class indexstring &optional skiplist)
57 "Create documentation starting with ROOT-CLASS.
58 The first job is to create an indented menu of all the classes
59 starting with `root-class' and including all it's children. Once this
60 is done, @nodes are created for all the subclasses. Each node is then
61 documented with a description of the class, a brief inheritance tree
62 \(with xrefs) and a list of all slots in a big table. Where each slot
63 is inherited from is also documented. In addition, each class is
64 documented in the index referenced by INDEXSTRING, a two letter code
65 described in the texinfo manual.
67 The optional third argument SKIPLIST is a list of object not to put
68 into any menus, nodes or lists."
71 (completing-read "Class: " (eieio-build-class-alist) nil t))
72 (read-string "Index name (2 chars): ")))
73 (if (looking-at "[ \t\n]+@end ignore")
74 (goto-char (match-end 0)))
76 (setq eieiodoc-currently-in-node
77 (if (re-search-backward "@node \\([^,]+\\)" nil t)
78 (buffer-substring (match-beginning 1) (match-end 1))
80 eieiodoc-current-section-level
81 (if (re-search-forward "@\\(chapter\\|\\(sub\\)*section\\)"
84 (goto-char (match-beginning 0))
85 (cond ((looking-at "@chapter") "section")
86 ((looking-at "@section") "subsection")
87 ((looking-at "@\\(sub\\)+section") "subsubsection")
91 (eieiodoc-main-menu root-class skiplist)
93 (eieiodoc-recurse root-class 'eieiodoc-one-node nil skiplist)))
95 (defun eieiodoc-main-menu (class skiplist)
96 "Create a menu of all classes under CLASS indented the correct amount.
97 SKIPLIST is a list of objects to skip"
100 (eieiodoc-recurse class (lambda (class level)
101 (insert "* " (make-string level ? )
102 (symbol-name class) " ::\n"))
104 (insert "@end menu\n"))
106 (defun eieiodoc-one-node (class level)
107 "Create a node for CLASS, and for all subclasses of CLASS in order.
108 This function should only be called by `eieiodoc-class'
109 Argument LEVEL is the current level of recursion we have hit."
110 (message "Building node for %s" class)
111 (insert "\n@node " (symbol-name class) ", "
112 (if eieiodoc-next-class (symbol-name eieiodoc-next-class) " ") ", "
113 (if eieiodoc-prev-class (symbol-name eieiodoc-prev-class) " ") ", "
114 eieiodoc-currently-in-node "\n"
115 "@comment node-name, next, previous, up\n"
116 "@" eieiodoc-current-section-level " " (symbol-name class) "\n"
117 ;; indexstring is grabbed from parent calling function
118 "@" indexstring "index " (symbol-name class) "\n\n")
119 ;; Now lets create a nifty little inheritance tree
124 (setq revlist (cons cl revlist)
125 cl (class-parent cl)))
126 (insert "@table @asis\n@item Inheritance Tree:\n")
128 ;; root-class is dragged in from the top-level function
129 (insert "@table @code\n@item "
130 (if (and (child-of-class-p (car revlist) root-class)
131 (not (eq class (car revlist))))
132 (concat "@w{@xref{" (symbol-name (car revlist)) "}.}")
133 (symbol-name (car revlist)))
135 (setq revlist (cdr revlist)
137 ;; the value of rclass is brought in from caller
138 (let ((clist (reverse (aref (class-v rclass) class-children))))
140 (insert "No children")
141 (insert "@table @asis\n@item Children:\n")
143 (insert "@w{@xref{" (symbol-name (car clist)) "}")
144 (if (cdr clist) (insert ",") (insert "."))
146 (setq clist (cdr clist)))
147 (insert "\n@end table\n")
150 (insert "\n@end table\n")
151 (setq depth (1- depth)))
152 (insert "@end table\n\n "))
153 ;; Now lets build some documentation by extracting information from
154 ;; the class description vector
155 (let* ((cv (class-v class))
156 (docs (aref cv class-public-doc))
157 (names (aref cv class-public-a))
158 (deflt (aref cv class-public-d))
159 (prot (aref cv class-protection))
160 (typev (aref cv class-public-type))
165 ;; doc of the class itself
166 (insert (eieiodoc-texify-docstring (documentation class) class)
167 "\n\n@table @asis\n")
170 (setq anchor (point))
171 (insert "@item Slots:\n\n@table @code\n")
173 (if (eieiodoc-one-attribute class (car names) (car docs)
174 (car prot) (car deflt) (aref typev i))
176 (setq names (cdr names)
181 (insert "@end table\n\n")
182 (if (not set-one) (delete-region (point) anchor))
184 (insert "@end table\n")
185 ;; Finally, document all the methods associated with this class.
186 (let ((methods (eieio-all-generic-functions class))
188 (if (not methods) nil
189 (if (string= eieiodoc-current-section-level "subsubsection")
190 (insert "@" eieiodoc-current-section-level)
191 (insert "@sub" eieiodoc-current-section-level))
192 (insert " Specialized Methods\n\n")
194 (setq doc (eieio-method-documentation (car methods) class))
195 (insert "@deffn Method " (symbol-name (car methods)))
197 (insert "\n Undocumented")
201 (eieiodoc-output-deffn-args (car (car doc)))
203 (eieiodoc-insert-and-massage-docstring-with-args
204 (cdr (car doc)) (car (car doc)) class)))
208 (insert " :PRIMARY ")
209 (eieiodoc-output-deffn-args (car (car doc)))
211 (eieiodoc-insert-and-massage-docstring-with-args
212 (cdr (car doc)) (car (car doc)) class)))
217 (eieiodoc-output-deffn-args (car (car doc)))
219 (eieiodoc-insert-and-massage-docstring-with-args
220 (cdr (car doc)) (car (car doc)) class)))
221 (insert "\n@end deffn\n\n"))
222 (setq methods (cdr methods)))))
225 (defun eieiodoc-insert-and-massage-docstring-with-args (doc arglst class)
226 "Update DOC with texinfo strings using ARGLST with @var.
227 Argument CLASS is the class passed to `eieiodoc-texify-docstring'."
228 (let ((start (point))
230 (case-fold-search nil))
232 (insert (eieiodoc-texify-docstring doc class))
235 (narrow-to-region start end)
237 ;; Now find arguments
239 (goto-char (point-min))
240 (while (re-search-forward (upcase (symbol-name (car arglst))) nil t)
241 (replace-match "@var{\\&}" t))
242 (setq arglst (cdr arglst)))))))
244 (defun eieiodoc-output-deffn-args (arglst)
245 "Output ARGLST for a deffn."
247 (insert (symbol-name (car arglst)) " ")
248 (setq arglst (cdr arglst))))
250 (defun eieiodoc-one-attribute (class attribute doc priv deflt type)
251 "Create documentation of CLASS for a single ATTRIBUTE.
252 Assume this attribute is inside a table, so it is initiated with the
253 @item indicator. If this attribute is not inserted (because it is
254 contained in the parent) then return nil, else return t.
255 DOC is the documentation to use, PRIV is non-nil if it is a private slot,
256 and DEFLT is the default value. TYPE is the symbol describing what type
257 validation is done on that slot."
258 (let ((pv (eieiodoc-parent-diff class attribute))
259 (ia (eieio-attribute-to-initarg class attribute))
261 (if (or (eq pv t) (not ia))
262 nil ;; same in parent or no init arg
264 (insert "@item " (if priv "Private: " "")
266 (if (and type (not (eq type t)))
267 (insert "\nType: @code{" (format "%S" type) "}"))
268 (if (not (eq deflt eieio-unbound))
269 (insert " @*\nDefault Value: @code{"(format "%S" deflt) "}"))
272 ;; default differs only, xref the parent
273 ;; This should be upgraded to actually search for the last
274 ;; differing default (or the original.)
275 (insert "@xref{" (symbol-name (class-parent class)) "}.\n")
276 (insert (if doc (eieiodoc-texify-docstring doc class) "Not Documented")
282 (defun eieiodoc-recurse (rclass func &optional level skiplist)
283 "Recurse down all children of RCLASS, calling FUNC on each one.
284 LEVEL indicates the current depth below the first call we are. The
285 function FUNC will be called with RCLASS and LEVEL. This will then
286 recursivly call itself once for each child class of RCLASS. The
287 optional fourth argument SKIPLIST is a list of objects to ignore while
290 (if (not level) (setq level 0))
292 ;; we reverse the children so they appear in the same order as it
293 ;; does in the code that creates them.
294 (let* ((children (reverse (aref (class-v rclass) class-children)))
295 (ocnc eieiodoc-next-class)
296 (eieiodoc-next-class (or (car children) ocnc))
297 (eieiodoc-prev-class eieiodoc-prev-class))
299 (if (not (member rclass skiplist))
301 (apply func (list rclass level))
303 (setq eieiodoc-prev-class rclass)))
306 (setq eieiodoc-next-class (or (car (cdr children)) ocnc))
307 (setq eieiodoc-prev-class (eieiodoc-recurse (car children) func (1+ level)))
308 (setq children (cdr children)))
309 ;; return the previous class so that the prev/next node gets it right
310 eieiodoc-prev-class))
312 (defun eieiodoc-parent-diff (class slot)
313 "Return nil if the parent of CLASS does not have slot SLOT.
314 Return t if it does, and return 'default if the default has changed."
315 (let ((df nil) (err t)
316 (scoped-class (class-parent class))
317 (eieio-skip-typecheck))
319 (setq df (eieio-oref-default (class-parent class) slot)
321 (invalid-slot-name (setq df nil))
322 (error (setq df nil)))
325 (if (equal df (eieio-oref-default class slot))
329 (defun eieiodoc-texify-docstring (string class)
330 "Take STRING, (a normal doc string), and convert it into a texinfo string.
331 For instances where CLASS is the class being referenced, do not Xref
334 `function' => @dfn{function}
335 `variable' => @code{variable}
336 `class' => @code{class} @xref{class}
337 `unknown' => @code{unknonwn}
338 'quoteme => @code{quoteme}
339 non-nil => non-@code{nil}
342 [ stuff ] => @code{[ stuff ]}
344 (while (string-match "`\\([-a-zA-Z0-9]+\\)'" string)
345 (let* ((vs (substring string (match-beginning 1) (match-end 1)))
346 (v (intern-soft vs)))
349 (replace-match (concat
350 (if (and (not (class-p v))(fboundp v))
353 (if (and (class-p v) (not (eq v class)))
354 (concat " @xref{" vs "}.")))
356 (while (string-match "\\( \\|^\\|-\\)\\(nil\\|t\\|'[-a-zA-Z0-9]+\\|:[-a-zA-Z0-9]+\\)\\([ ,]\\|$\\)" string)
357 (setq string (replace-match "@code{\\2}" t nil string 2)))
358 (while (string-match "\\( \\|^\\)\\(\\[[^]]+\\]\\)\\( \\|$\\)" string)
359 (setq string (replace-match "@code{\\2}" t nil string 2)))
360 (while (string-match "\\( \\|^\\)\\(\\(\\(C-\\|M-\\|S-\\)+\\([^ \t\n]\\|RET\\|SPC\\|TAB\\)\\)\\|\\(RET\\|SPC\\|TAB\\)\\)\\( \\|$\\)" string)
361 (setq string (replace-match "@kbd{\\2}" t nil string 2)))
366 ;;; eieio-doc.el ends here