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 ------------ * `Sphinx `_ >=3.21.7 * Roswell_ >=17.4.8.76 * `asdf `_ >=3.1 * `quicklisp `_ * `pygments-cl-repl `_ 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: .. code-block:: sh 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: .. code-block:: sh pip install sphinxcontrib-cldomain .. _github: https://github.com/russell/sphinxcontrib-cldomain/releases .. _pypi: https://pypi.python.org/pypi/sphinxcontrib-cldomain .. _source: https://github.com/russell/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. .. code-block:: python 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 :ref:`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: .. code-block:: common-lisp (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: .. cl:macro:: example-macro :nodoc: 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. .. rst: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:package:: sphinxcontrib.cldomain.doc Variables --------- .. rst:directive:: .. cl:variable:: symbol-name The cl:variable directive will resolve the arguments and documentation from the common lisp definition:: .. cl:variable:: *example-variable* Code: .. code-block:: common-lisp (defvar *example-variable* "value" "This is an example variable.") Output: .. cl:variable:: *example-variable* .. _variable2: 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: .. code-block:: common-lisp (defvar *example-variable-2* "another value" "This example has additional text.") Output: .. 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. Functions --------- .. rst:directive:: .. cl:function:: symbol-name Outputs the function's signature (arguments):: .. cl:function:: example-function .. _hyperspec_example: Code: .. code-block:: common-lisp (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: .. cl:function:: example-function Macros ------ .. rst:directive:: .. cl:macro:: symbol-name Emit the macro's signature and documentation:: .. cl:macro:: example-macro Code: .. code-block:: common-lisp (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: .. cl:macro:: example-macro Types (aka CLOS Classes) ------------------------ .. rst:directive:: .. 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: .. code-block:: common-lisp (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: .. cl:type:: example-class Generics and Methods -------------------- .. rst:directive:: .. cl:generic:: symbol-name The ``:cl:generic:`` directive emits the documentation for a generic function and its specializers:: .. cl:generic:: example-generic Code: .. code-block:: common-lisp (defgeneric example-generic (arg1 arg2 &optional arg3) (:documentation "A test generic function.")) Output: .. cl:generic:: example-generic .. rst:directive:: .. 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: .. code-block:: common-lisp (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: .. cl:method:: example-generic example-class :test 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: .. cl:method:: example-generic example-class :test :noinherit: 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: .. rst:role:: cl:function References a function, as in ``:cl:function:`example-function``` (link: :cl:function:`example-function`). .. rst:role:: cl:generic References a generic function, as in ``:cl:generic:`example-generic``` (link: :cl:generic:`example-generic`). .. rst:role:: cl:macro References a macro, as in ``:cl:macro:`example-macro``` (link: :cl:macro:`example-macro`). .. rst:role:: cl:variable References a variable, as in ``:cl:variable:`*example-variable*``` (link: :cl:variable:`*example-variable*`). .. rst:role:: cl:type References a type/CLOS class, as in ``:cl:type:`example-class``` (link: :cl:type:`example-class`). .. FIXME rst:role:: cl:method .. FIXME .. FIXME References a generic-specializing method, as in .. FIXME``:cl:method:`example-generic``` (link: :cl:method:`example-generic .. FIXME example-class :test`). .. rst:role:: cl:symbol References a symbol, such as ``:cl:symbol:example-function`` (link: :cl:symbol:`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 :ref:`cl:function: example` has an example of Hyperspec-ing in its example code. Changelog ========= .. include:: ../../ChangeLog.rst .. _roswell: https://github.com/roswell/roswell