About

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.

Installation

Requirements

Download

Releases are hosted on github or pypi. The source is also available. You also need working Roswell to install Common Lisp helper cldomain.

Step one – install CL part

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.

Step two – install Python part

Now you need to install Sphinx extenstion. Just do:

pip install sphinxcontrib-cldomain

Configuration

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

Documenting Your Common Lisp Code

Common Lisp docstrings

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.

Don’t include the docstring: :nodoc:

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:

macro example-macro

No documentation from the example-macro documentation string.

Packages

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!!!

Variables

.. 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:

variable *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:

variable *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.

Functions

.. 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:

function (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.

Macros

.. 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:

macro (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.

Types (aka CLOS Classes)

.. 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:

type example-class[:slot1 slot1][:slot2 slot2]

An example class.

Generics and Methods

.. 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:

generic (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:

method (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:
method (example-generic (arg1 example-class) (arg2 :test) &optional arg3)

This is the first specialized version of example-generic.

Specializers:

Cross-references

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).

Hyperspec References

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:

  1. THE COMMON LISP SYMBOL NAME IS IN ALL CAPS, LIKE LIST OR FORMAT. (No, the documentation isn’t shouting at you. It’s the normal Lisp convention for symbols.
  2. Prefix the symbol name with COMMON-LISP:, e.g., COMMON-LISP:CAR

The cl:function: example has an example of Hyperspec-ing in its example code.

Changelog

0.14 (unreleased)

  • Script was made a separate lisp system and ported from cl-launch to roswell.
  • Now it reports if some package wasn’t found and returns proper exit codes to command line.

0.13 06-09-2015

  • updated com.dvlsoft.clon to net.didierverna.clon.

0.12 24-02-2015

  • fixed argument generation bug.

0.11 30-12-2014

  • support loading symbol information from multiple packages.

0.10 12-06-2014

  • added back parentheses to parameter lists.
  • added type information to parameter list of methods.
  • added links to other methods from a method docstring.
  • fixed bug with macro documentation strings.
  • added better keyword detection in documentation strings.
  • fixed bug where symbols at the end of documentation strings were ignored.

0.9 10-02-2014

  • fixed problem with version number generation.

0.8 10-02-2014

  • fixed bug with lisps argument.
  • removed dependency on swank.
  • remove specializers symbols package if it’s the current package.

0.7 12-06-2013

  • started to make internals more modular.
  • print specialisation for methods.
  • add links to method specializers.
  • added methods to index.

0.6 22-04-2013

  • added more documentation.
  • added better error handling when json fails to parse.
  • methods can now pull documentation from their generic.

0.5 20-04-2013

  • inherit environment when calling subprocesses.
  • better handling of symbols in doc strings.

0.4 19-04-2013

  • fixed some packaging bugs.
  • made the data model more tolerant to missing symbols.
  • fixed symbol resolving bug.
  • added output of unused symbols.

0.3 16-04-2013

  • cleaned up specializer output.
  • fixed bug when rendering specializers that have the form :KEYWORD SYMBOL.
  • updated documentation.
  • split out package code from lisp program.

0.2 14-04-2013

  • link between generics and specializers.
  • ignore symbols in documentation if they are in the arg list.
  • better Quicklisp support.
  • handling of symbols that boarder on punctuation.

0.1 UNRELEASED

  • initial prototype