diff --git a/CHANGES b/CHANGES index 4915baf0af..5370920474 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +Changes in trunk +================ + +* sphinx.application: Support a new method, ``add_crossref_type``. + It works like ``add_description_unit`` but the directive will only + create a target and no output. + + Release 0.1.61950 (Mar 26, 2008) ================================ diff --git a/doc/changes.rst b/doc/changes.rst index 51da6e6938..3d9f758a0b 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -1,3 +1,5 @@ +.. _changes: + Changes in Sphinx ***************** diff --git a/doc/ext/appapi.rst b/doc/ext/appapi.rst index 7b57ffa738..9e5e303ab8 100644 --- a/doc/ext/appapi.rst +++ b/doc/ext/appapi.rst @@ -48,13 +48,15 @@ the following public API: source, *role* the role function (see the `Docutils documentation `_ on details). -.. method:: Sphinx.add_description_unit(directivename, rolename, indexdesc='', parse_node=None) +.. method:: Sphinx.add_description_unit(directivename, rolename, indextemplate='', parse_node=None, ref_nodeclass=None) This method is a very convenient way to add a new type of information that can be cross-referenced. It will do this: * Create a new directive (called *directivename*) for a :term:`description - unit`. It will automatically add index entries if *indexdesc* is nonempty. + unit`. It will automatically add index entries if *indextemplate* is + nonempty; if given, it must contain exactly one instance of ``%s``. See + the example below for how the template will be interpreted. * Create a new role (called *rolename*) to cross-reference to these description units. * If you provide *parse_node*, it must be a function that takes a string and @@ -65,7 +67,7 @@ the following public API: For example, if you have this call in a custom Sphinx extension:: - app.add_description_unit('directive', 'dir', 'directive') + app.add_description_unit('directive', 'dir', 'pair: %s; directive') you can use this markup in your documents:: @@ -77,9 +79,44 @@ the following public API: See also the :dir:`function` directive. + For the directive, an index entry will be generated as if you had prepended :: + + .. index:: pair: function; directive + + The reference node will be of class ``literal`` (so it will be rendered in a + proportional font, as appropriate for code) unless you give the *ref_nodeclass* + argument, which must be a docutils node class (most useful are + ``docutils.nodes.emphasis`` or ``docutils.nodes.strong`` -- you can also use + ``docutils.nodes.generated`` if you want no further text decoration). + For the role content, you have the same options as for standard Sphinx roles (see :ref:`xref-syntax`). +.. method:: Sphinx.add_crossref_type(directivename, rolename, indextemplate='', ref_nodeclass=None) + + This method is very similar to :meth:`add_description_unit` except that the + directive it generates must be empty, and will produce no output. + + That means that you can add semantic targets to your sources, and refer to + them using custom roles instead of generic ones (like :role:`ref`). Example + call:: + + app.add_crossref_type('topic', 'topic', 'single: %s', docutils.nodes.emphasis) + + Example usage:: + + .. topic:: application API + + The application API + ------------------- + + <...> + + See also :topic:`this section `. + + (Of course, the element following the ``topic`` directive needn't be a + section.) + .. method:: Sphinx.connect(event, callback) Register *callback* to be called when *event* is emitted. For details on diff --git a/doc/ext/doctest.rst b/doc/ext/doctest.rst index cfcd0bec0f..9de6ba9e9c 100644 --- a/doc/ext/doctest.rst +++ b/doc/ext/doctest.rst @@ -77,9 +77,6 @@ names. They will be respected when the test is run, but stripped from presentation output. - .. versionadded:: 0.1.61798 - Removal of ```` and inline options in presentation output. - .. directive:: .. testcode:: [group] diff --git a/doc/intro.rst b/doc/intro.rst index c5e6f71b3c..4dd080c1ce 100644 --- a/doc/intro.rst +++ b/doc/intro.rst @@ -12,6 +12,13 @@ look at `Epydoc `_, which also understands reST. .. XXX web app +.. note:: + + While Sphinx' version is still *0.1.revision*, no mention will be made in the + docs if a feature is added or changed. The :ref:`Changelog ` is the + only source of version annotations. + + Prerequisites ------------- diff --git a/sphinx/application.py b/sphinx/application.py index 98952376e5..35db38eaf4 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -18,10 +18,10 @@ from docutils import nodes from docutils.parsers.rst import directives, roles import sphinx -from sphinx.roles import xfileref_role +from sphinx.roles import xfileref_role, innernodetypes from sphinx.config import Config from sphinx.builder import builtin_builders -from sphinx.directives import desc_directive, additional_xref_types +from sphinx.directives import desc_directive, target_directive, additional_xref_types from sphinx.util.console import bold @@ -195,8 +195,18 @@ class Sphinx(object): def add_role(self, name, role): roles.register_canonical_role(name, role) - def add_description_unit(self, directivename, rolename, indexdesc='', - parse_node=None): - additional_xref_types[directivename] = (rolename, indexdesc, parse_node) + def add_description_unit(self, directivename, rolename, indextemplate='', + parse_node=None, ref_nodeclass=None): + additional_xref_types[directivename] = (rolename, indextemplate, parse_node) directives.register_directive(directivename, desc_directive) roles.register_canonical_role(rolename, xfileref_role) + if ref_nodeclass is not None: + innernodetypes[rolename] = ref_nodeclass + + def add_crossref_type(self, directivename, rolename, indextemplate='', + ref_nodeclass=None): + additional_xref_types[directivename] = (rolename, indextemplate, None) + directives.register_directive(directivename, target_directive) + roles.register_canonical_role(rolename, xfileref_role) + if ref_nodeclass is not None: + innernodetypes[rolename] = ref_nodeclass diff --git a/sphinx/directives.py b/sphinx/directives.py index cc8ae65a8a..84f2cbc403 100644 --- a/sphinx/directives.py +++ b/sphinx/directives.py @@ -21,6 +21,8 @@ from docutils.parsers.rst import directives from sphinx import addnodes from sphinx.util.compat import make_admonition +ws_re = re.compile(r'\s+') + # ------ index markup -------------------------------------------------------------- entrytypes = [ @@ -324,20 +326,26 @@ def desc_directive(desctype, arguments, options, content, lineno, continue else: # another registered generic x-ref directive - rolename, indextext, parse_node = additional_xref_types[desctype] + rolename, indextemplate, parse_node = additional_xref_types[desctype] if parse_node: fullname = parse_node(env, sig, signode) else: signode.clear() signode += addnodes.desc_name(sig, sig) - fullname = sig + # normalize whitespace like xfileref_role does + fullname = ws_re.sub('', sig) if not noindex: targetname = '%s-%s' % (rolename, fullname) signode['ids'].append(targetname) state.document.note_explicit_target(signode) - if indextext: - env.note_index_entry('pair', - '%s; %s' % (indextext, fullname), + if indextemplate: + indexentry = indextemplate % (fullname,) + indextype = 'single' + colon = indexentry.find(':') + if colon != -1: + indextype = indexentry[:colon].strip() + indexentry = indexentry[colon+1:].strip() + env.note_index_entry(indextype, indexentry, targetname, targetname) env.note_reftarget(rolename, fullname, targetname) # don't use object indexing below @@ -413,13 +421,41 @@ desctypes = [ for _name in desctypes: directives.register_directive(_name, desc_directive) -# Generic cross-reference types; they can be registered in the application +# Generic cross-reference types; they can be registered in the application; +# the directives are either desc_directive or target_directive additional_xref_types = { - # directive name: (role name, index text) + # directive name: (role name, index text, function to parse the desc node) 'envvar': ('envvar', 'environment variable', None), } +# ------ target -------------------------------------------------------------------- + +def target_directive(targettype, arguments, options, content, lineno, + content_offset, block_text, state, state_machine): + """Generic target for user-defined cross-reference types.""" + env = state.document.settings.env + rolename, indextemplate, _ = additional_xref_types[targettype] + # normalize whitespace in fullname like xfileref_role does + fullname = ws_re.sub('', arguments[0].strip()) + targetname = '%s-%s' % (rolename, fullname) + node = nodes.target('', '', ids=[targetname]) + state.document.note_explicit_target(node) + if indextemplate: + indexentry = indextemplate % (fullname,) + indextype = 'single' + colon = indexentry.find(':') + if colon != -1: + indextype = indexentry[:colon].strip() + indexentry = indexentry[colon+1:].strip() + env.note_index_entry(indextype, indexentry, targetname, targetname) + env.note_reftarget(rolename, fullname, targetname) + return [node] + +target_directive.content = 0 +target_directive.arguments = (1, 0, 1) + + # ------ versionadded/versionchanged ----------------------------------------------- def version_directive(name, arguments, options, content, lineno,