[version 0.4.1 ediware**20080728150316] { addfile ./CHANGELOG.txt hunk ./CHANGELOG.txt 1 +Version 0.4.1 +2008-05-29 +Require SB-INTROSPECT for SBCL + +Version 0.4.0 +2007-04-17 +Added MAYBE-SKIP-METHODS-P +Slightly enhanced CSS (thanks to Martin Enders) + +Version 0.3.0 +2007-03-19 +Ported to AllegroCL (patch by Willem Broekema) +Show method qualifiers (patch by Willem Broekema) + +Version 0.2.0 +2007-02-26 +Ported to SBCL (patch by Michael Weber) + +Version 0.1.2 +2006-08-26 +Added condition types +Changed package handling in system definition (thanks to Christophe Rhodes) + +Version 0.1.1 +2006-08-10 +Added HYPERDOC support + +Version 0.1.0 +2006-08-09 +First public release adddir ./doc addfile ./doc/index.html hunk ./doc/index.html 1 + + + + + + DOCUMENTATION-TEMPLATE - Prepare HTML documentation for Common Lisp libraries + + + + + +

DOCUMENTATION-TEMPLATE - Prepare HTML documentation for Common Lisp libraries

+ +
+
 

Abstract

This +is a quick hack which helps to build HTML pages that look +like this one or like +the one you're currently looking at. It hasn't been tested +thoroughly, it isn't properly documented, it only works +with LispWorks, +SBCL, and AllegroCL, and it most likely doesn't do +what you expect. +

+The code comes with +a BSD-style +license so you can basically do with it whatever you want. + +

+Download shortcut: http://weitz.de/files/documentation-template.tar.gz. +

+ +
 

Contents

+
    +
  1. Download +
  2. The DOCUMENTATION-TEMPLATE dictionary +
      +
    1. create-template +
    2. *target* +
    3. *maybe-skip-methods-p* +
    +
  3. Acknowledgements +
+ +
 

Download

+ +DOCUMENTATION-TEMPLATE together with this documentation can be downloaded from http://weitz.de/files/documentation-template.tar.gz. The +current version is 0.4.1. +

+If you want to send patches, please read this first. + +
 

The DOCUMENTATION-TEMPLATE dictionary

+ +The following symbols are exported: + + + +


[Function]
create-template package &key target maybe-skip-methods-p subtitle if-exists if-does-not-exist => result +


+ +Writes an HTML page with preliminary documentation entries and +an index for all exported symbols of the package package to the +file target. +If maybe-skip-methods-p is true, documentation entries for +inidividual methods are skipped if the corresponding generic function +has a documentation string + +
+ + + + + +


[Special variable]
*target* +


+ +Where to output the HTML page. If this value is not NIL, it will +be the default target for CREATE-TEMPLATE. CREATE-TEMPLATE will also +set this value. + +
+ + + +


[Special variable]
*maybe-skip-methods-p* +


+ +This is the default value for the :MAYBE-SKIP-METHODS-P keyword +argument of CREATE-TEMPLATE and its initial value is NIL. +
+ + +
 

Acknowledgements

+ +

+This documentation was prepared with, you guessed it, DOCUMENTATION-TEMPLATE. Thanks to Michael Weber for the SBCL patches and to Willem Broekema for the AllegroCL patches. +

+

+$Header: /usr/local/cvsrep/documentation-template/doc/index.html,v 1.12 2008/05/29 08:22:26 edi Exp $ +

BACK TO MY HOMEPAGE + + + addfile ./documentation-template.asd hunk ./documentation-template.asd 1 - +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/documentation-template/documentation-template.asd,v 1.11 2008/05/29 08:23:37 edi Exp $ + +;;; Copyright (c) 2006-2008, Dr. Edmund Weitz. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(in-package :cl-user) + +(defpackage :documentation-template-asd + (:use :cl :asdf)) + +(in-package :documentation-template-asd) + +#+:sbcl +(require :sb-introspect) + +(asdf:defsystem :documentation-template + :serial t + :version "0.4.1" + :components ((:file "packages") + (:file "specials") + (:file "util") + (:file "output")) + :depends-on (:cl-who)) addfile ./output.lisp hunk ./output.lisp 1 - +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: DOCUMENTATION-TEMPLATE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/documentation-template/output.lisp,v 1.14 2008/05/29 08:23:37 edi Exp $ + +;;; Copyright (c) 2006-2008, Dr. Edmund Weitz. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(in-package :documentation-template) + +(defun write-entry-header (name type &key (write-name-p t)) + "Writes the header for a documentation entry of name NAME and +type TYPE. The HTML anchor will only get a 'name' attribute if +WRITE-NAME-P is true and NAME is not a SETF name." + (format t "~%~%~%~%


[~A]
" + name type (and write-name-p (atom name) (string-downcase name)))) + +(defun write-entry-footer (name doc-string) + "Writes the footer for a documentation entry for the name NAME +including the documentation string DOC-STRING." + (format t "~%


~%~%~@[~A~]~%~%
~%~%~%" + (and doc-string (escape-string-iso-8859 doc-string)) name)) + +(defun write-constant-entry (symbol doc-string) + "Writes a full documentation entry for the constant SYMBOL." + (write-entry-header symbol "Constant") + (format t "~A" (string-downcase symbol)) + (write-entry-footer symbol doc-string)) + +(defun write-special-var-entry (symbol doc-string) + "Writes a full documentation entry for the special variable +SYMBOL." + (write-entry-header symbol "Special variable") + (format t "~A" (string-downcase symbol)) + (write-entry-footer symbol doc-string)) + +(defun write-class-entry (symbol doc-string) + "Writes a full documentation entry for the class SYMBOL." + (write-entry-header symbol (if (subtypep symbol 'condition) + "Condition type" "Standard class")) + + (format t "~A" (string-downcase symbol)) + (write-entry-footer symbol doc-string)) + +(defun write-lambda-list* (lambda-list &optional specializers) + "The function which does all the work for WRITE-LAMBDA-LIST and +calls itself recursive if needed." + (let (body-seen after-required-args-p (firstp t)) + (dolist (part lambda-list) + (cond (body-seen (setq body-seen nil)) + (t (when (and (consp part) after-required-args-p) + (setq part (first part))) + (unless firstp + (write-char #\Space)) + (setq firstp nil) + (cond ((consp part) + ;; a destructuring lambda list - recurse + (write-char #\() + (write-lambda-list* part) + (write-char #\))) + ((member part '(&key &optional &rest &allow-other-keys &aux &environment &whole)) + ;; marks these between and + (setq after-required-args-p t) + (format t "~A" (escape-string (string-downcase part)))) + ((eq part '&body) + ;; we don't really write '&BODY', we write it + ;; like in the CLHS + (setq body-seen t + after-required-args-p t) + (write-string "declaration* statement*")) + (t + (let ((specializer (pop specializers))) + (cond ((and specializer (not (eq specializer t))) + ;; add specializers if there are any left + (write-string (escape-string + (string-downcase + (format nil "(~A ~A)" part specializer))))) + (t (write-string (escape-string (string-downcase part))))))))))))) + +(defun write-lambda-list (lambda-list &key (resultp t) specializers) + "Writes the lambda list LAMBDA-LIST, optionally with the +specializers SPECIALIZERS. Adds something like `=> result' at +the end if RESULTP is true." + (write-string "") + (write-lambda-list* lambda-list specializers) + (write-string "") + (when resultp + (write-string " => result"))) + +(defun write-macro-entry (symbol lambda-list doc-string) + "Writes a full documentation entry for the macro SYMBOL." + (write-entry-header symbol "Macro") + (format t "~A " (string-downcase symbol)) + (write-lambda-list lambda-list) + (write-entry-footer symbol doc-string)) + +(defun write-function-entry (name lambda-list doc-string other-entries + &key genericp signature-only-p specializers qualifiers) + "Writes a full documentation entry for the function, generic +function, or method with name NAME. NAME is a generic function +if GENERICP is true, SPECIALIZERS is a list of specializers, +i.e. in this case NAME is a method. Likewise, QUALIFIERS is a +list of qualifiers. SIGNATURE-ONLY-P means that we don't want a +full header." + (let* ((setfp (consp name)) + (symbol (if setfp (second name) name)) + (type (cond (specializers :method) + (genericp :generic-function) + (t :function))) + ;; check if this is a reader for which there is a writer (so + ;; we have an accessor) with the same signature + (writer (and (not setfp) + (find-if (lambda (entry) + (and (equal `(setf ,name) (first entry)) + (eq type (second entry)) + (or (null specializers) + (equal specializers (rest (fifth entry)))))) + other-entries))) + (resultp (and (not setfp) + (null (intersection '(:before :after) + qualifiers))))) + (cond (signature-only-p + (write-string "")) + (t + (write-entry-header name (if writer + (ecase type + (:method "Specialized accessor") + (:generic-function "Generic accessor") + (:function "Accessor")) + (ecase type + (:method "Method") + (:generic-function "Generic function") + (:function "Function"))) + :write-name-p (null specializers)))) + (cond (setfp + (format t "(setf (~A " (string-downcase symbol)) + (write-lambda-list (rest lambda-list) :resultp resultp :specializers (rest specializers)) + (write-string ") ") + ;; we should use the specializer here as well + (format t "~A" (string-downcase (first lambda-list))) + (write-string ")") + (format t "~(~{ ~S~^~}~)" qualifiers)) + (t (format t "~A " (string-downcase symbol)) + (write-lambda-list lambda-list :specializers specializers :resultp resultp) + (format t "~(~{ ~S~^~}~)" qualifiers))) + (when writer + ;; if this is an accessor, the add the writer immediately after + ;; the reader.. + (format t "~%
") + (destructuring-bind (name doc-type lambda-list doc-string &optional specializers qualifiers) + writer + (declare (ignore doc-type doc-string)) + (write-function-entry name lambda-list nil nil + :signature-only-p t + :specializers specializers + :qualifiers qualifiers)) + ;; ...and remove it from the list of entries which haven't been + ;; written yet + (setq other-entries (remove writer other-entries)))) + (unless signature-only-p + (write-entry-footer name doc-string)) + other-entries) + +(defun write-entry (entry other-entries) + "Write one documentation entry corresponding to ENTRY. +OTHER-ENTRIES is the list of the remaining entries waiting to be +written. OTHER-ENTRIES, probably updated, will be returned." + (destructuring-bind (name doc-type lambda-list doc-string &optional specializers qualifiers) + entry + (unless (or (consp name) specializers) + ;; add NAME to index list unless it's a SETF name or the name of + ;; a method + (push name *symbols*)) + (ecase doc-type + (:constant (write-constant-entry name doc-string)) + (:special-var (write-special-var-entry name doc-string)) + (:class (write-class-entry name doc-string)) + (:macro (write-macro-entry name lambda-list doc-string)) + (:function (setq other-entries + (write-function-entry name lambda-list doc-string other-entries))) + (:generic-function (setq other-entries + (write-function-entry name lambda-list doc-string other-entries + :genericp t))) + (:method (setq other-entries + (write-function-entry name lambda-list doc-string other-entries + :specializers specializers + :qualifiers qualifiers))))) + other-entries) + +(defun write-page-header (package-name subtitle symbols) + "Writes the header of the HTML page. Assumes that the library +has the same name as the package. Adds a list of all exported +symbols with links." + (format t " + + + + + ~A - ~A + + + + + +

~2:*~A - ~A

+ +
+
 

Abstract

+ +The code comes with +a BSD-style +license so you can basically do with it whatever you want. + +

+Download shortcut: http://weitz.de/files/~:*~A.tar.gz. +

+ +
 

Contents

+
    +
  1. Download +
  2. The ~A dictionary +
      +~{
    1. ~:*~A +~}
    +
  3. Acknowledgements +
+ +
 

Download

+ +~2:*~A together with this documentation can be downloaded from http://weitz.de/files/~:*~A.tar.gz. The +current version is 0.1.0. + +
 

The ~A dictionary

+ +" + package-name subtitle (string-downcase package-name) + package-name symbols)) + +(defun write-page-footer () + "Writes the footer of the HTML page." + (write-string " + +
 

Acknowledgements

+ +

+This documentation was prepared with DOCUMENTATION-TEMPLATE. +

+

+$Header: /usr/local/cvsrep/documentation-template/output.lisp,v 1.14 2008/05/29 08:23:37 edi Exp $ +

BACK TO MY HOMEPAGE + + +")) + +(defun create-template (package &key (target (or *target* + #-:lispworks (error "*TARGET* not specified.") + #+:lispworks + (capi:prompt-for-file "Select an output target:" + :operation :save + :filters '("HTML Files" "*.HTML;*.HTM" + "All Files" "*.*") + :filter "*.HTML;*.HTM"))) + (subtitle "a cool library") + ((:maybe-skip-methods-p *maybe-skip-methods-p*) + *maybe-skip-methods-p*) + (if-exists :supersede) + (if-does-not-exist :create)) + "Writes an HTML page with preliminary documentation entries and an +index for all exported symbols of the package PACKAGE to the file +TARGET. If MAYBE-SKIP-METHODS-P is true, documentation entries for +inidividual methods are skipped if the corresponding generic function +has a documentation string." + (when target + (setq *target* target)) + (let (*symbols*) + (with-open-file (*standard-output* target + :direction :output + :if-exists if-exists + :if-does-not-exist if-does-not-exist) + (let ((body + (with-output-to-string (*standard-output*) + (let ((entries (collect-all-doc-entries package))) + (loop + (let ((entry (or (pop entries) (return)))) + (setq entries (write-entry entry entries)))))))) + (write-page-header (package-name package) subtitle + (mapcar #'string-downcase (reverse *symbols*))) + (write-string body) + (write-page-footer)))) + (values)) addfile ./packages.lisp hunk ./packages.lisp 1 +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: CL-USER; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/documentation-template/packages.lisp,v 1.9 2008/05/29 08:23:37 edi Exp $ + +;;; Copyright (c) 2006-2008, Dr. Edmund Weitz. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(in-package :cl-user) + +(defpackage :documentation-template + (:use :cl + :cl-who + #+:lispworks :clos + #+:sbcl :sb-mop + #+:allegro :mop) + #+:lispworks (:add-use-defaults t) + (:export :*maybe-skip-methods-p* + :*target* + :create-template)) addfile ./specials.lisp hunk ./specials.lisp 1 +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: DOCUMENTATION-TEMPLATE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/documentation-template/specials.lisp,v 1.7 2008/05/29 08:23:37 edi Exp $ + +;;; Copyright (c) 2006-2008, Dr. Edmund Weitz. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(in-package :documentation-template) + +(defvar *target* nil + "Where to output the HTML page. If this value is not NIL, it will +be the default target for CREATE-TEMPLATE. CREATE-TEMPLATE will also +set this value.") + +(defvar *maybe-skip-methods-p* nil + "This is the default value for the :MAYBE-SKIP-METHODS-P keyword +argument of CREATE-TEMPLATE and its initial value is NIL. It is also +used internally.") + +(defvar *symbols* nil + "The list of symbols for which we will create an index with links.") + +;; stuff for Nikodemus Siivola's HYPERDOC +;; see +;; and +;; also used by LW-ADD-ONS + +(defvar *hyperdoc-base-uri* "http://weitz.de/documentation-template/") + +(let ((exported-symbols-alist + (loop for symbol being the external-symbols of :documentation-template + collect (cons symbol + (concatenate 'string + "#" + (string-downcase symbol)))))) + (defun hyperdoc-lookup (symbol type) + (declare (ignore type)) + (cdr (assoc symbol + exported-symbols-alist + :test #'eq)))) addfile ./util.lisp hunk ./util.lisp 1 - +;;; -*- Mode: LISP; Syntax: COMMON-LISP; Package: DOCUMENTATION-TEMPLATE; Base: 10 -*- +;;; $Header: /usr/local/cvsrep/documentation-template/util.lisp,v 1.13 2008/05/29 08:23:37 edi Exp $ + +;;; Copyright (c) 2006-2008, Dr. Edmund Weitz. All rights reserved. + +;;; Redistribution and use in source and binary forms, with or without +;;; modification, are permitted provided that the following conditions +;;; are met: + +;;; * Redistributions of source code must retain the above copyright +;;; notice, this list of conditions and the following disclaimer. + +;;; * Redistributions in binary form must reproduce the above +;;; copyright notice, this list of conditions and the following +;;; disclaimer in the documentation and/or other materials +;;; provided with the distribution. + +;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED +;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +(in-package :documentation-template) + +;;; For the purpose of this file, an "entry" is a list of four or five +;;; symbols - a name, a keyword for the kind of the entry, a lambda +;;; list (for functions and macros), a documentation string, and +;;; optionally a list of specializers + +#+(or :sbcl :allegro) +(defun function-lambda-list (function) + "Returns the lambda list of the function designator FUNCTION." + #+:sbcl + (sb-introspect:function-arglist function) + #+:allegro + (excl:arglist function)) + +(defun symbol-constant-p (symbol) + "Returns true if SYMBOL is a constant." + #+:lispworks (sys:symbol-constant-p symbol) + #-:lispworks (constantp symbol)) + +(defun declared-special-p (symbol) + "Returns true if SYMBOL is declared special." + #+:lispworks (sys:declared-special-p symbol) + #+:sbcl (eql :special (sb-int:info :variable :kind symbol)) + #+:allegro (eq (sys:variable-information symbol) :special)) + +(defun constant-doc-entry (symbol) + "Returns a list with one entry for a constant if SYMBOL names a +constant." + (when (symbol-constant-p symbol) + (list (list symbol :constant nil (documentation symbol 'variable))))) + +(defun special-var-doc-entry (symbol) + "Returns a list with one entry for a special variable if SYMBOL +names a special variable." + ;; skip constants because SYS:DECLARED-SPECIAL-P is true for them as + ;; well + (when (and (not (symbol-constant-p symbol)) + (declared-special-p symbol)) + (list (list symbol :special-var nil (documentation symbol 'variable))))) + +(defun class-doc-entry (symbol) + "Returns a list with one entry for a class if SYMBOL names a +class." + (when (find-class symbol nil) + (list (list symbol :class nil (documentation symbol 'type))))) + +(defun macro-doc-entry (symbol) + "Returns a list with one entry for a macro if SYMBOL names a +macro." + (when (and (fboundp symbol) + (macro-function symbol)) + (list (list symbol :macro (function-lambda-list symbol) + (documentation symbol 'function))))) + +#+:sbcl +(defgeneric %sbcl-simple-specializer (specializer) + (:documentation "Returns a simple representation of +SPECIALIZER.") + (:method (specializer) + (class-name specializer)) + (:method ((specializer eql-specializer)) + `(eql ,(eql-specializer-object specializer)))) + +(defun simplify-specializer (specializer) + "Converts specializers which are classes to their names, leaves +the rest alone." + (or (ignore-errors #+(or :lispworks :allegro) (class-name specializer) + #+:sbcl (%sbcl-simple-specializer specializer)) + specializer)) + +(defun generic-function-doc-entry (name) + "Returns a list with one entry for a generic function and one +entry for each of its methods if NAME names a generic function." + (when (and (fboundp name) + (typep (fdefinition name) 'standard-generic-function)) + (let* ((lambda-list (function-lambda-list name)) + (generic-function-documentation (documentation name 'function)) + (generic-function-entry + (list name :generic-function lambda-list + generic-function-documentation))) + (cond ((and generic-function-documentation *maybe-skip-methods-p*) + (list generic-function-entry)) + (t (cons generic-function-entry + (loop for method in (generic-function-methods (fdefinition name)) + collect (list name :method lambda-list + (documentation method t) + (mapcar #'simplify-specializer (method-specializers method)) + (method-qualifiers method))))))))) + +(defun function-doc-entry (name) + "Returns a list with one entry for a function if NAME names a +plain old function." + (when (and (fboundp name) + ;; no macros + (or (listp name) + (not (macro-function name))) + ;; no generic functions + (not (typep (fdefinition name) 'standard-generic-function))) + (list (list name :function (function-lambda-list name) + (documentation name 'function))))) + +(defun doc-entries (symbol) + "Returns a list of all possible entries for the symbol SYMBOL +and for the corresponding SETF function name." + (let ((setf-name `(setf ,symbol))) + `(,@(constant-doc-entry symbol) + ,@(special-var-doc-entry symbol) + ,@(class-doc-entry symbol) + ,@(macro-doc-entry symbol) + ,@(generic-function-doc-entry symbol) + ,@(function-doc-entry symbol) + ,@(generic-function-doc-entry setf-name) + ,@(function-doc-entry setf-name)))) + +(defun doc-type-ordinal (type) + "Assigns ordinals to the different kinds of entries for sorting +purposes." + (ecase type + (:constant 0) + (:special-var 1) + (:class 2) + (:macro 3) + (:function 4) + (:generic-function 5) + (:method 6))) + +(defun name= (name1 name2) + "Two function names are equal if they are EQUAL - this covers +symbols as well as general function names." + (equal name1 name2)) + +(defun name< (name1 name2) + "Comparison function used for sorting - symbols are \"smaller\" +then SETF names, otherwise sort alphabetically." + (or (and (consp name2) + (atom name1)) + (and (consp name1) + (consp name2) + (string< (second name1) (second name2))) + (and (atom name1) + (atom name2) + (string< name1 name2)))) + +(defun doc-entry< (entry1 entry2) + "Comparions function used for sorting - sort by name and, if +the names are the same, by DOC-TYPE-ORDINAL." + (or (name< (first entry1) (first entry2)) + (and (name= (first entry1) (first entry2)) + (< (doc-type-ordinal (second entry1)) + (doc-type-ordinal (second entry2)))))) + +(defun collect-all-doc-entries (package) + "Returns a sorted list of entries for all exported symbols of +PACKAGE." + (let (result) + (do-external-symbols (symbol package (sort result #'doc-entry<)) + (setq result (nconc (doc-entries symbol) result))))) }