#14: allow distinct programs for cmdoption directive.

This commit is contained in:
Georg Brandl 2008-11-09 18:28:36 +01:00
parent 7b62fc8f2d
commit fb26a2a5fc
7 changed files with 157 additions and 64 deletions

View File

@ -17,7 +17,7 @@ typical module section might start like this::
.. moduleauthor:: John Idle <john@python.invalid>
The directives you can use for module are:
The directives you can use for module declarations are:
.. directive:: .. module:: name
@ -67,8 +67,8 @@ The directives you can use for module are:
.. _desc-units:
Description units
-----------------
Object description units
------------------------
There are a number of directives used to describe specific features provided by
modules. Each directive requires one or more signatures to provide basic
@ -204,39 +204,6 @@ The directives are:
Like :dir:`method`, but indicates that the method is a static method.
.. versionadded:: 0.4
.. directive:: .. cmdoption:: name args, name args, ...
Describes a command line option or switch. Option argument names should be
enclosed in angle brackets. Example::
.. cmdoption:: -m <module>, --module <module>
Run a module as a script.
The directive will create a cross-reference target named after the *first*
option, referencable by :role:`option` (in the example case, you'd use
something like ``:option:`-m```).
.. directive:: .. envvar:: name
Describes an environment variable that the documented code uses or defines.
There is also a generic version of these directives:
.. directive:: .. describe:: text
This directive produces the same formatting as the specific ones explained
above but does not create index entries or cross-referencing targets. It is
used, for example, to describe the directives in this document. Example::
.. describe:: opcode
Describes a Python bytecode instruction.
Extensions may add more directives like that, using the
:func:`~sphinx.application.Sphinx.add_description_unit` method.
.. _signatures:
@ -308,3 +275,77 @@ This will render like this:
:param limit: maximum number of stack frames to show
:type limit: integer or None
:rtype: list of strings
Command-line program markup
~~~~~~~~~~~~~~~~~~~~~~~~~~~
There is a set of directives allowing documenting command-line programs:
.. directive:: .. cmdoption:: name args, name args, ...
Describes a command line option or switch. Option argument names should be
enclosed in angle brackets. Example::
.. cmdoption:: -m <module>, --module <module>
Run a module as a script.
The directive will create a cross-reference target named after the *first*
option, referencable by :role:`option` (in the example case, you'd use
something like ``:option:`-m```).
.. directive:: .. envvar:: name
Describes an environment variable that the documented code or program uses or
defines.
.. directive:: .. program:: name
Like :dir:`currentmodule`, this directive produces no output. Instead, it
serves to notify Sphinx that all following :dir:`cmdoption` directives
document options for the program called *name*.
If you use :dir:`program`, you have to qualify the references in your
:role:`option` roles by the program name, so if you have the following
situation ::
.. program:: rm
.. cmdoption:: -r
Work recursively.
.. program:: svn
.. cmdoption:: -r revision
Specify the revision to work upon.
then ``:option:`rm -r``` would refer to the first option, while
``:option:`svn -r``` would refer to the second one.
The program name may contain spaces (in case you want to document subcommands
like ``svn add`` and ``svn commit`` separately).
.. versionadded:: 0.5
Custom description units
~~~~~~~~~~~~~~~~~~~~~~~~
There is also a generic version of these directives:
.. directive:: .. describe:: text
This directive produces the same formatting as the specific ones explained
above but does not create index entries or cross-referencing targets. It is
used, for example, to describe the directives in this document. Example::
.. describe:: opcode
Describes a Python bytecode instruction.
Extensions may add more directives like that, using the
:func:`~sphinx.application.Sphinx.add_description_unit` method.

View File

@ -14,10 +14,9 @@ from docutils import nodes
from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.util import ws_re
ws_re = re.compile(r'\s+')
# ------ information units ---------------------------------------------------------
def desc_index_text(desctype, module, name, add_modules):
@ -352,17 +351,17 @@ def parse_c_signature(signode, sig, desctype):
option_desc_re = re.compile(
r'(/|-|--)([-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)')
r'((?:/|-|--)[-_a-zA-Z0-9]+)(\s*.*?)(?=,\s+(?:/|-|--)|$)')
def parse_option_desc(signode, sig):
"""Transform an option description into RST nodes."""
count = 0
firstname = ''
for m in option_desc_re.finditer(sig):
prefix, optname, args = m.groups()
optname, args = m.groups()
if count:
signode += addnodes.desc_addname(', ', ', ')
signode += addnodes.desc_name(prefix+optname, prefix+optname)
signode += addnodes.desc_name(optname, optname)
signode += addnodes.desc_addname(args, args)
if not count:
firstname = optname
@ -402,12 +401,17 @@ def desc_directive(desctype, arguments, options, content, lineno,
elif desctype == 'cmdoption':
optname = parse_option_desc(signode, sig)
if not noindex:
targetname = 'cmdoption-' + optname
targetname = optname.replace('/', '-')
if env.currprogram:
targetname = '-' + env.currprogram + targetname
targetname = 'cmdoption' + targetname
signode['ids'].append(targetname)
state.document.note_explicit_target(signode)
inode['entries'].append(('pair', _('command line option; %s') % sig,
targetname, targetname))
env.note_reftarget('option', optname, targetname)
inode['entries'].append(
('pair', _('%scommand line option; %s') %
((env.currprogram and env.currprogram + ' ' or ''), sig),
targetname, targetname))
env.note_progoption(optname, targetname)
continue
elif desctype == 'describe':
signode.clear()

View File

@ -14,9 +14,8 @@ from docutils import nodes
from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.util import patfilter
from sphinx.roles import caption_ref_re
from sphinx.locale import pairindextypes
from sphinx.util import patfilter, ws_re, caption_ref_re
from sphinx.util.compat import make_admonition
@ -159,6 +158,20 @@ directives.register_directive('sectionauthor', author_directive)
directives.register_directive('moduleauthor', author_directive)
def program_directive(name, arguments, options, content, lineno,
content_offset, block_text, state, state_machine):
env = state.document.settings.env
program = ws_re.sub('-', arguments[0].strip())
if program == 'None':
env.currprogram = None
else:
env.currprogram = program
return []
program_directive.arguments = (1, 0, 1)
directives.register_directive('program', program_directive)
# ------ index markup --------------------------------------------------------------
indextypes = [

View File

@ -57,7 +57,7 @@ default_settings = {
# This is increased every time an environment attribute is added
# or changed to properly invalidate pickle files.
ENV_VERSION = 25
ENV_VERSION = 26
default_substitutions = set([
@ -266,8 +266,9 @@ class BuildEnvironment:
self.modules = {} # modname -> docname, synopsis, platform, deprecated
self.labels = {} # labelname -> docname, labelid, sectionname
self.anonlabels = {} # labelname -> docname, labelid
self.progoptions = {} # (program, name) -> docname, labelid
self.reftargets = {} # (type, name) -> docname, labelid
# where type is term, token, option, envvar, citation
# where type is term, token, envvar, citation
# Other inventories
self.indexentries = {} # docname -> list of
@ -281,6 +282,7 @@ class BuildEnvironment:
self.currmodule = None # current module name
self.currclass = None # current class name
self.currdesc = None # current descref name
self.currprogram = None # current program name
self.index_num = 0 # autonumber for index targets
self.gloss_entries = set() # existing definition labels
@ -331,6 +333,9 @@ class BuildEnvironment:
for key, (fn, _) in self.reftargets.items():
if fn == docname:
del self.reftargets[key]
for key, (fn, _) in self.progoptions.items():
if fn == docname:
del self.progoptions[key]
for version, changes in self.versionchanges.items():
new = [change for change in changes if change[1] != docname]
changes[:] = new
@ -826,6 +831,9 @@ class BuildEnvironment:
self.modules[modname] = (self.docname, synopsis, platform, deprecated)
self.filemodules.setdefault(self.docname, []).append(modname)
def note_progoption(self, optname, labelid):
self.progoptions[self.currprogram, optname] = (self.docname, labelid)
def note_reftarget(self, type, name, labelid):
self.reftargets[type, name] = (self.docname, labelid)
@ -968,7 +976,7 @@ class BuildEnvironment:
'meth', 'cfunc', 'cmember', 'cdata', 'ctype', 'cmacro'))
def resolve_references(self, doctree, fromdocname, builder):
reftarget_roles = set(('token', 'term', 'option', 'citation'))
reftarget_roles = set(('token', 'term', 'citation'))
# add all custom xref types too
reftarget_roles.update(i[0] for i in additional_xref_types.values())
@ -1028,6 +1036,19 @@ class BuildEnvironment:
newnode['refuri'] = builder.get_relative_uri(
fromdocname, docname) + '#' + labelid
newnode.append(contnode)
elif typ == 'option':
progname = node['refprogram']
docname, labelid = self.progoptions.get((progname, target), ('', ''))
if not docname:
newnode = contnode
else:
newnode = nodes.reference('', '')
if docname == fromdocname:
newnode['refid'] = labelid
else:
newnode['refuri'] = builder.get_relative_uri(
fromdocname, docname) + '#' + labelid
newnode.append(contnode)
elif typ in reftarget_roles:
docname, labelid = self.reftargets.get((typ, target), ('', ''))
if not docname:

View File

@ -643,6 +643,8 @@ def setup(app):
noindex=directives.flag)
app.add_directive('autoattribute', auto_directive, 1, (1, 0, 1),
noindex=directives.flag)
app.add_directive('autoprogram', auto_directive, 1, (1, 0, 1),
noindex=directives.flag)
# deprecated: remove in some future version.
app.add_config_value('automodule_skip_lines', 0, True)
app.add_config_value('autoclass_content', 'class', True)

View File

@ -15,9 +15,8 @@ from docutils import nodes, utils
from docutils.parsers.rst import roles
from sphinx import addnodes
from sphinx.util import ws_re, caption_ref_re
ws_re = re.compile(r'\s+')
caption_ref_re = re.compile(r'^([^<]+?)\s*<(.+)>$')
generic_docroles = {
'command' : nodes.strong,
@ -143,7 +142,7 @@ def xfileref_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
# fallback: everything after '<' is the target
target = text[brace+1:]
title = text[:brace]
# special target for Python object cross-references
# special target for Python object cross-references
if typ in ('data', 'exc', 'func', 'class', 'const', 'attr', 'meth', 'mod', 'obj'):
# fix-up parentheses in link title
if titleistarget:
@ -166,9 +165,17 @@ def xfileref_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
target = target[1:]
pnode['refspecific'] = True
# some other special cases for the target
elif typ == 'option' and target[0] in '-/':
# strip option marker from target
target = target[1:]
elif typ == 'option':
program = env.currprogram
if titleistarget:
if ' ' in title and not (title.startswith('/') or title.startswith('-')):
program, target = re.split(' (?=-|--|/)', title, 1)
program = ws_re.sub('-', program)
target = target.strip()
elif ' ' in target:
program, target = re.split(' (?=-|--|/)', target, 1)
program = ws_re.sub('-', program)
pnode['refprogram'] = program
elif typ == 'term':
# normalize whitespace in definition terms (if the term reference is
# broken over a line, a newline will be in target)
@ -217,21 +224,21 @@ specific_docroles = {
'obj': xfileref_role,
'cfunc' : xfileref_role,
'cmember': xfileref_role,
'cdata' : xfileref_role,
'ctype' : xfileref_role,
'cmacro' : xfileref_role,
'cdata': xfileref_role,
'ctype': xfileref_role,
'cmacro': xfileref_role,
'mod' : xfileref_role,
'mod': xfileref_role,
'keyword': xfileref_role,
'ref': xfileref_role,
'token' : xfileref_role,
'token': xfileref_role,
'term': xfileref_role,
'option': xfileref_role,
'menuselection' : menusel_role,
'file' : emph_literal_role,
'samp' : emph_literal_role,
'menuselection': menusel_role,
'file': emph_literal_role,
'samp': emph_literal_role,
}
for rolename, func in specific_docroles.iteritems():

View File

@ -18,6 +18,11 @@ import traceback
from os import path
# Generally useful regular expressions.
ws_re = re.compile(r'\s+')
caption_ref_re = re.compile(r'^([^<]+?)\s*<(.+)>$')
# SEP separates path elements in the canonical file names
#
# Define SEP as a manifest constant, not so much because we expect it to change