CLDomain is an extension for the Sphinx documentation generation tool that allow sphinx to generate documentation for Common Lisp libraries. Documentation is extracted from the various entity’s documentation strings, loaded from ASDF systems and associated internal packages.
Hyperspec is a cross referencing extension that supports linking to the hyperspec.
Releases are hosted on github or pypi. The source is also
available. You also need working Roswell to install Common Lisp helper
cldomain
.
Install cldomain
utility using roswell:
ros install 40ants/cldomain
If everything is ok, you’ll get a script cldomain
in the
~/.roswell/bin/
directory. Add it to your PATH
.
Now you need to install Sphinx extenstion. Just do:
pip install sphinxcontrib-cldomain
Configuring CLDomain involves two actions: (a) adding the extensions to the extension list, (b) telling CLDomain the systems and packages to load.
from os.path import join, dirname, realpath, expandvars
# Extensions: add 'sphinxcontrib.cldomain' and 'sphinxcontrib.hyperspec',
# just like this example:
extensions = [
'sphinx.ext.intersphinx',
'sphinxcontrib.cldomain',
'sphinxcontrib.hyperspec'
]
# --- CL domain customizations:
#
# cl_systems: The systems and packages from which to extract documentation:
#
# name - The name of the system to load.
# path - The path to the system.
# packages - A list of the packages to extract symbol information from.
#
# Note: This conf.py sits in a subdirectory below ("../"), relative to where
# the "my-system.asd" system description file lives:
cl_systems = [{"name": "my-system",
"path": join(dirname(realpath(__file__)), "../"),
"packages": ["my-package-1", "my-package-2"]}]
# cl_quicklisp: The default is $HOME/quicklisp. Shown here for completeness,
# and you can comment it out:
cl_quicklisp = expandvars('$HOME/quicklisp')
# Ensure that the default highlighting language is CL:
highlight_language = 'common-lisp'
# For developer debugging only (and the curious, although, it did kill the cat!)
# Currently ``True`` or ``False`` to output the JSON collected from cldomain.
cl_debug = False
CLDomain collects the documentation strings for the package-exported symbols in
each system enumerated in the cl_systems
configuration variable, which
CLDomain appends to the symbol’s signature. You can include additional
documentation after the directive and it will also get included in the
Spinx-generated output. The output template looks like:
type: signature
symbol-docstring
Any additional text described in the RST files.
For an example, follow this link or read on.
Sometimes, you’d prefer to provide separate (non-docstring) documentation
instead of having CLDomain insert the Lisp docstrings. That’s what the
:nodoc
option does.
Note: Argument lists and specializers will still be printed, as in this example:
.. cl:macro:: example-macro
:nodoc:
No documentation from the ``example-macro`` documentation string.
Code:
(defmacro example-macro ((arg1 arg2) &body arg3)
"The CL Domain will try and convert any uppercase symbols into
reference for example EXAMPLE-FUNCTION or a hyperspec link LIST. Any
unmatched symbols are converted to literals as is ARG1, ARG2 and ARG3.
Explicit package references will also help resolve symbol sources
COMMON-LISP:CDR. Keywords are also detected for example :TEST."
arg3)
Output:
example-macro
No documentation from the example-macro
documentation string.
CLDomain, like Common Lisp, needs to know the current package when resolving symbols. The
:cl:package:
directive is the CLDomain equivalent of (in-package ...)
. You can switch
between packages at any time in the documentation file using this directive.
.. cl:package::
package
¶Use package
as the package name when resolving symbols to documentation:
.. cl:package:: sphinxcontrib.cldomain.doc
For multi-package documentation in the same Sphinx documentation file:
.. cl:package:: sphinxcontrib.cldomain.doc
documentation... documentation... documentation...
.. cl:package:: org.coolness.my.code
foo... bar... baz... lemon odor quux!!!
.. cl:variable::
symbol-name
¶The cl:variable directive will resolve the arguments and documentation from the common lisp definition:
.. cl:variable:: *example-variable*
Code:
(defvar *example-variable* "value"
"This is an example variable.")
Output:
*example-variable*
¶This is an example variable.
You can include additional text, which appears after the docstring (unless you
use the :nodoc:
option):
.. cl:variable:: *example-variable-2*
This variable requires more explanitory text after its docstring. Because,
more text means more clarity and further explains the intent of the original
software developer.
Code:
(defvar *example-variable-2* "another value"
"This example has additional text.")
Output:
*example-variable-2*
¶This example has additional text.
This variable requires more explanitory text after its docstring. Because, more text means more clarity and further explains the intent of the original software developer.
.. cl:function::
symbol-name
¶Outputs the function’s signature (arguments):
.. cl:function:: example-function
Code:
(defun example-function (arg1 arg2 &optional (arg3 #'sort) &key (kw *example-variable*))
"The CL Domain will try and convert any uppercase symbols into
reference for example EXAMPLE-FUNCTION, EXAMPLE-GENERIC or a hyperspec
link LIST. Any unmatched symbols are converted to literals as is
ARG1, ARG2 and ARG3. Explicit package references will also help
resolve symbol sources COMMON-LISP:CAR. Keywords are also detected
for example :KEYWORD."
(list arg1 arg2 arg3))
Output:
example-function
arg1 arg2 &optional (arg3 #'sort) &key (kw *example-variable*))¶The CL Domain will try and convert any uppercase symbols into
reference for example EXAMPLE-FUNCTION
, EXAMPLE-GENERIC
or a hyperspec
link LIST
. Any unmatched symbols are converted to literals as is
ARG1
, ARG2
and ARG3
. Explicit package references will also help
resolve symbol sources CAR
. Keywords are also detected
for example :KEYWORD
.
.. cl:macro::
symbol-name
¶Emit the macro’s signature and documentation:
.. cl:macro:: example-macro
Code:
(defmacro example-macro ((arg1 arg2) &body arg3)
"The CL Domain will try and convert any uppercase symbols into
reference for example EXAMPLE-FUNCTION or a hyperspec link LIST. Any
unmatched symbols are converted to literals as is ARG1, ARG2 and ARG3.
Explicit package references will also help resolve symbol sources
COMMON-LISP:CDR. Keywords are also detected for example :TEST."
arg3)
Output:
example-macro
(arg1 arg2) &body arg3)¶The CL Domain will try and convert any uppercase symbols into
reference for example EXAMPLE-FUNCTION
or a hyperspec link LIST
. Any
unmatched symbols are converted to literals as is ARG1
, ARG2
and ARG3
.Explicit package references will also help resolve symbol sources
CDR
. Keywords are also detected for example :TEST
.
.. cl:type::
symbol-name
¶The :cl:type:
directive emits Common Lisp Object System (CLOS) class documentation:
.. cl:type:: example-class
The :noinitargs:
option can be specified to exclude the class’ list of :initarg
initialzers that are ordinarily included in the class’ signature:
.. cl:type:: example-class
:noinitargs:
Note: There is no mechanism or directive to document individual slots at the moment.
Code:
(defclass example-class ()
((slot1 :initarg :slot1 :accessor slot1
:initform "default"
:documentation "the first slot.")
(slot2 :initarg :slot2 :accessor slot2
:documentation "the second slot."))
(:documentation "An example class."))
Output:
example-class
[:slot1 slot1][:slot2 slot2]¶An example class.
.. cl:generic::
symbol-name
¶The :cl:generic:
directive emits the documentation for a generic function and
its specializers:
.. cl:generic:: example-generic
Code:
(defgeneric example-generic (arg1 arg2 &optional arg3)
(:documentation "A test generic function."))
Output:
example-generic
arg1 arg2 &optional arg3)¶A test generic function.
Specializers: |
|
---|
.. cl:method::
symbol-name (specializer)
¶The :cl:method
emits the documentation for generic method specializers:
.. cl:method:: example-generic example-class :test
For the time being, all specializing arguments that aren’t in the current
package must be qualified with a package, e.g., common-lisp:t
Code:
(defmethod example-generic ((arg1 example-class) (arg2 (eql :test)) &optional arg3)
"This is the first specialized version of example-generic."
(list arg1 arg2 arg3))
Output:
example-generic
(arg1 example-class) (arg2 :test) &optional arg3)¶This is the first specialized version of example-generic.
Specializers: |
|
---|
Note: The output for a specializing method will include its parent generic
function’s documentation string, i.e., specializing methods inherit their
parent generic’s docstring. The :noinherit:
option suppresses this
behavior:
.. cl:method:: example-generic example-class :test
:noinherit:
example-generic
(arg1 example-class) (arg2 :test) &optional arg3)¶This is the first specialized version of example-generic.
Specializers: |
|
---|
You can cross reference Lisp entities using the following CLDomain Sphinx roles, which results in a hyperlinked reference to the matching identifier, if found:
:cl:function:
¶References a function, as in :cl:function:`example-function`
(link:
example-function
).
:cl:generic:
¶References a generic function, as in :cl:generic:`example-generic`
(link: example-generic
).
:cl:macro:
¶References a macro, as in :cl:macro:`example-macro`
(link:
example-macro
).
:cl:variable:
¶References a variable, as in :cl:variable:`*example-variable*`
(link:
*example-variable*
).
:cl:type:
¶References a type/CLOS class, as in :cl:type:`example-class`
(link:
example-class
).
:cl:symbol:
¶References a symbol, such as :cl:symbol:example-function
(link: example-function
).
Generating a reference is very easy (and you’ve probably noticed already if you’ve read the Common Lisp code snippets used to generate the examples). To generate a Hyperspec reference:
COMMON-LISP:
, e.g., COMMON-LISP:CAR
The cl:function: example has an example of Hyperspec-ing in its example code.