[Checkins] SVN: grok/branches/jasper-grokdoctool/ Jasper's and
Guido's reference doc toolchain from Neanderthalsprint
Uli Fouquet
uli at gnufix.de
Fri Oct 5 11:30:12 EDT 2007
Log message for revision 80658:
Jasper's and Guido's reference doc toolchain from Neanderthalsprint
Changed:
A grok/branches/jasper-grokdoctool/
A grok/branches/jasper-grokdoctool/README.txt
A grok/branches/jasper-grokdoctool/bootstrap/
A grok/branches/jasper-grokdoctool/bootstrap/bootstrap.py
A grok/branches/jasper-grokdoctool/buildout.cfg
A grok/branches/jasper-grokdoctool/setup.py
A grok/branches/jasper-grokdoctool/src/
A grok/branches/jasper-grokdoctool/src/grokdoctool/
A grok/branches/jasper-grokdoctool/src/grokdoctool/__init__.py
A grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/
A grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/__init__.py
A grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/addnodes.py
A grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/directives.py
A grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/roles.py
A grok/branches/jasper-grokdoctool/src/grokdoctool/grok.xslt
A grok/branches/jasper-grokdoctool/src/grokdoctool/rst2html.py
A grok/branches/jasper-grokdoctool/src/grokdoctool/rst2html.xslt
-=-
Added: grok/branches/jasper-grokdoctool/README.txt
===================================================================
--- grok/branches/jasper-grokdoctool/README.txt (rev 0)
+++ grok/branches/jasper-grokdoctool/README.txt 2007-10-05 15:30:12 UTC (rev 80658)
@@ -0,0 +1,49 @@
+grokdoctool - Grok's ReST 2 HTML convertor
+=========================================
+
+version: 0.1 (SVN/Unreleased)
+
+This package contains a tool (and some test data) to convert Grok's ReST
+documentation (reference documentation) to HTML for the Grok website
+(http://grok.zope.org). The code is partially copied from the Python core
+documentation generation tools, modified to generate ReST rather than Latex.
+
+The tool walks through a directory passed in as an argument (defaulting to the
+current working directory) to find .rst or .txt files, then, for each of the
+files found, uses docutils to convert ReST to XML, and after that XSLT (lxml)
+to convert the XML to HTML. Optionally it will allow you to specify what
+stylesheet to use (to allow using it for other projects besides Grok).
+
+Installation
+============
+
+The package provides a setuptools script, called 'setup.py', which can install
+the application. To perform an installation, first run 'python setup.py build'
+as a normal user, then 'python setup.py install' as root (sudo). Note that the
+Python interpreter used to run setup.py will be the one used for running the
+tool (tested with Python 2.5 and docutils 4.x).
+
+After installation, a script called 'grokdoctool' will be in one of your 'bin'
+directories (using the --prefix location with which the Python executable was
+built, so if Python was installed in /usr/local, the script will be placed in
+/usr/local/bin).
+
+Using the script
+================
+
+Using the script is straight-forward, just call::
+
+ $ grokdoctool <mydir>
+
+to convert all the files with a .rst or .txt extension in <mydir> to HTML.
+
+For an overview of the available options, run::
+
+ $ grokdoctool --help
+
+Questions, remarks, etc.
+========================
+
+For questions, remarks, bug reports, patches, etc. send an email to either
+jasper at infrae.com or guido at pragmagik.com.
+
Added: grok/branches/jasper-grokdoctool/bootstrap/bootstrap.py
===================================================================
--- grok/branches/jasper-grokdoctool/bootstrap/bootstrap.py (rev 0)
+++ grok/branches/jasper-grokdoctool/bootstrap/bootstrap.py 2007-10-05 15:30:12 UTC (rev 80658)
@@ -0,0 +1,55 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 75593 2007-05-06 21:11:27Z jim $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+try:
+ import pkg_resources
+except ImportError:
+ ez = {}
+ exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+ ).read() in ez
+ ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+ import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+ cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+ os.P_WAIT, sys.executable, sys.executable,
+ '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+ dict(os.environ,
+ PYTHONPATH=
+ ws.find(pkg_resources.Requirement.parse('setuptools')).location
+ ),
+ ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)
Added: grok/branches/jasper-grokdoctool/buildout.cfg
===================================================================
--- grok/branches/jasper-grokdoctool/buildout.cfg (rev 0)
+++ grok/branches/jasper-grokdoctool/buildout.cfg 2007-10-05 15:30:12 UTC (rev 80658)
@@ -0,0 +1,10 @@
+[buildout]
+develop=.
+parts=grokdoctool
+
+[grokdoctool]
+recipe=zc.recipe.egg
+eggs=grokdoctool
+ docutils
+ lxml
+
Added: grok/branches/jasper-grokdoctool/setup.py
===================================================================
--- grok/branches/jasper-grokdoctool/setup.py (rev 0)
+++ grok/branches/jasper-grokdoctool/setup.py 2007-10-05 15:30:12 UTC (rev 80658)
@@ -0,0 +1,23 @@
+from setuptools import setup, find_packages
+import sys, os
+
+version = '0.1'
+
+setup(name='grokdoctool',
+ version=version,
+ description="Generate html pages out of rst python documentation files",
+ long_description="""\
+""",
+ classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+ keywords='rst html python doc grok',
+ author='Grok Team',
+ author_email='',
+ url='grok.zope.org',
+ license='',
+ packages=find_packages('src', exclude=['ez_setup', 'examples', 'tests']),
+ package_dir={'': 'src'},
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=['docutils', 'lxml'],
+ entry_points={'console_scripts':['grokdoctool=grokdoctool.rst2html:main']}
+ )
Added: grok/branches/jasper-grokdoctool/src/grokdoctool/__init__.py
===================================================================
--- grok/branches/jasper-grokdoctool/src/grokdoctool/__init__.py (rev 0)
+++ grok/branches/jasper-grokdoctool/src/grokdoctool/__init__.py 2007-10-05 15:30:12 UTC (rev 80658)
@@ -0,0 +1 @@
+#
Added: grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/__init__.py
===================================================================
--- grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/__init__.py (rev 0)
+++ grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/__init__.py 2007-10-05 15:30:12 UTC (rev 80658)
@@ -0,0 +1,2 @@
+# make this a package
+
Added: grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/addnodes.py
===================================================================
--- grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/addnodes.py (rev 0)
+++ grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/addnodes.py 2007-10-05 15:30:12 UTC (rev 80658)
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.addnodes
+ ~~~~~~~~~~~~~~~
+
+ :copyright: 2007 by Georg Brandl.
+ :license: Python license.
+"""
+
+from docutils import nodes
+
+# index markup
+class index(nodes.Invisible, nodes.Inline, nodes.TextElement): pass
+
+# description units (classdesc, funcdesc etc.)
+class desc(nodes.Admonition, nodes.Element): pass
+class desc_content(nodes.General, nodes.Element): pass
+class desc_signature(nodes.Part, nodes.Inline, nodes.TextElement): pass
+class desc_classname(nodes.Part, nodes.Inline, nodes.TextElement): pass
+class desc_name(nodes.Part, nodes.Inline, nodes.TextElement): pass
+class desc_parameterlist(nodes.Part, nodes.Inline, nodes.TextElement): pass
+class desc_parameter(nodes.Part, nodes.Inline, nodes.TextElement): pass
+class desc_optional(nodes.Part, nodes.Inline, nodes.TextElement): pass
+
+# refcount annotation
+class refcount(nodes.emphasis): pass
+
+# \versionadded, \versionchanged, \deprecated
+class versionmodified(nodes.Admonition, nodes.TextElement): pass
+
+# seealso
+class seealso(nodes.Admonition, nodes.Element): pass
+
+# productionlist
+class productionlist(nodes.Admonition, nodes.Element): pass
+class production(nodes.Part, nodes.Inline, nodes.TextElement): pass
+
+# toc tree
+class toctree(nodes.General, nodes.Element): pass
+
+# centered
+class centered(nodes.Part, nodes.Element): pass
+
+# pending xref
+class pending_xref(nodes.Element): pass
+
+# compact paragraph -- never makes a <p>
+class compact_paragraph(nodes.paragraph): pass
+
+# sets the highlighting language for literal blocks
+class highlightlang(nodes.Element): pass
+
+# like emphasis, but doesn't apply further text processors, e.g. smartypants
+class literal_emphasis(nodes.emphasis): pass
+
+# glossary
+class glossary(nodes.Element): pass
+
+# make them known to docutils. this is needed, because the HTMl writer
+# will choke at some point if these are not added
+nodes._add_node_class_names("""index desc desc_content desc_signature
+ desc_classname desc_name desc_parameterlist desc_parameter desc_optional
+ centered versionmodified seealso productionlist production toctree
+ pending_xref compact_paragraph highlightlang literal_emphasis
+ glossary""".split())
Added: grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/directives.py
===================================================================
--- grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/directives.py (rev 0)
+++ grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/directives.py 2007-10-05 15:30:12 UTC (rev 80658)
@@ -0,0 +1,477 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.directives
+ ~~~~~~~~~~~~~~~~~
+
+ Handlers for additional ReST directives.
+ Modified by Uli Fouquet
+
+ :copyright: 2007 by Georg Brandl.
+ :license: Python license.
+"""
+import re
+import string
+from os import path
+
+from docutils import nodes
+from docutils.parsers.rst import directives, roles
+from docutils.parsers.rst.directives import admonitions
+
+import addnodes
+
+# ------ index markup ---------------------------------------------------------
+
+entrytypes = [
+ 'single', 'pair', 'triple', 'quadruple',
+ 'module', 'keyword', 'operator', 'object', 'exception', 'statement', 'builtin',
+]
+
+
+# ------ functions to parse a Python or C signature and create desc_* nodes.
+# ------ also used for parameters like '*args', '**kw'.
+
+py_sig_re = re.compile(r'''^([\w.]*\.)? # class names
+ (\w+) \s* # thing name
+ (?: \((.*)\) )? $ # optionally arguments
+ ''', re.VERBOSE)
+
+py_paramlist_re = re.compile(r'([\[\],])') # split at '[', ']' and ','
+
+def parse_py_signature(signode, sig, desctype):
+ """
+ Transform a python signature into RST nodes.
+ Return (fully qualified name of the thing, classname if any).
+
+ If inside a class, the current class name is handled intelligently:
+ * it is stripped from the displayed name if present
+ * it is added to the full name (return value) if not present
+ """
+ m = py_sig_re.match(sig)
+ if m is None: raise ValueError
+ classname, name, arglist = m.groups()
+ fullname = classname and classname + name or name
+
+ signode += addnodes.desc_classname(classname, classname)
+
+ signode += addnodes.desc_name(name, name)
+ if not arglist:
+ if desctype in ('function', 'method'):
+ # for callables, add an empty parameter list
+ signode += addnodes.desc_parameterlist()
+ return fullname, classname
+ signode += addnodes.desc_parameterlist()
+
+ stack = [signode[-1]]
+ for token in py_paramlist_re.split(arglist):
+ if token == '[':
+ opt = addnodes.desc_optional()
+ stack[-1] += opt
+ stack.append(opt)
+ elif token == ']':
+ try: stack.pop()
+ except IndexError: raise ValueError
+ elif not token or token == ',' or token.isspace():
+ pass
+ else:
+ token = token.strip()
+ stack[-1] += addnodes.desc_parameter(token, token)
+ if len(stack) != 1: raise ValueError
+ return fullname, classname
+
+
+c_sig_re = re.compile(
+ r'''^([^(]*?) # return type
+ (\w+) \s* # thing name
+ (?: \((.*)\) )? $ # optionally arguments
+ ''', re.VERBOSE)
+c_funcptr_sig_re = re.compile(
+ r'''^([^(]+?) # return type
+ (\( [^()]+ \)) \s* # name in parentheses
+ \( (.*) \) $ # arguments
+ ''', re.VERBOSE)
+
+# RE to split at word boundaries
+wsplit_re = re.compile(r'(\W+)')
+
+# These C types aren't described in the reference, so don't try to create
+# a cross-reference to them
+stopwords = set(('const', 'void', 'char', 'int', 'long', 'FILE', 'struct'))
+
+def parse_c_type(node, ctype):
+ # add cross-ref nodes for all words
+ for part in filter(None, wsplit_re.split(ctype)):
+ tnode = nodes.Text(part, part)
+ if part[0] in string.letters+'_' and part not in stopwords:
+ pnode = addnodes.pending_xref(
+ '', reftype='ctype', reftarget=part, modname=None, classname=None)
+ pnode += tnode
+ node += pnode
+ else:
+ node += tnode
+
+def parse_c_signature(signode, sig, desctype):
+ """Transform a C-language signature into RST nodes."""
+ # first try the function pointer signature regex, it's more specific
+ m = c_funcptr_sig_re.match(sig)
+ if m is None:
+ m = c_sig_re.match(sig)
+ if m is None:
+ raise ValueError('no match')
+ rettype, name, arglist = m.groups()
+
+ parse_c_type(signode, rettype)
+ signode += addnodes.desc_name(name, name)
+ if not arglist:
+ if desctype == 'cfunction':
+ # for functions, add an empty parameter list
+ signode += addnodes.desc_parameterlist()
+ return name
+
+ paramlist = addnodes.desc_parameterlist()
+ arglist = arglist.replace('`', '').replace('\\ ', '') # remove markup
+ # this messes up function pointer types, but not too badly ;)
+ args = arglist.split(',')
+ for arg in args:
+ arg = arg.strip()
+ param = addnodes.desc_parameter('', '', noemph=True)
+ try:
+ ctype, argname = arg.rsplit(' ', 1)
+ except ValueError:
+ # no argument name given, only the type
+ parse_c_type(param, arg)
+ else:
+ parse_c_type(param, ctype)
+ param += nodes.emphasis(' '+argname, ' '+argname)
+ paramlist += param
+ signode += paramlist
+ return name
+
+
+opcode_sig_re = re.compile(r'(\w+(?:\+\d)?)\s*\((.*)\)')
+
+def parse_opcode_signature(signode, sig, desctype):
+ """Transform an opcode signature into RST nodes."""
+ m = opcode_sig_re.match(sig)
+ if m is None: raise ValueError
+ opname, arglist = m.groups()
+ signode += addnodes.desc_name(opname, opname)
+ paramlist = addnodes.desc_parameterlist()
+ signode += paramlist
+ paramlist += addnodes.desc_parameter(arglist, arglist)
+ return opname.strip()
+
+
+## def add_refcount_annotation(node, name):
+## """Add a reference count annotation. Return None."""
+## return
+
+def desc_directive(desctype, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ node = addnodes.desc()
+ node['desctype'] = desctype
+
+ noindex = ('noindex' in options)
+ signatures = map(lambda s: s.strip(), arguments[0].split('\n'))
+ names = []
+ clsname = None
+ for i, sig in enumerate(signatures):
+ # add a signature node for each signature in the current unit
+ # and add a reference target for it
+ sig = sig.strip()
+ signode = addnodes.desc_signature(sig, '')
+ signode['first'] = False
+ node.append(signode)
+ try:
+ if desctype in ('function', 'data', 'class', 'exception',
+ 'method', 'attribute'):
+ name, clsname = parse_py_signature(signode, sig, desctype)
+ elif desctype in ('cfunction', 'cmember', 'cmacro', 'ctype',
+ 'cvar'):
+ name = parse_c_signature(signode, sig, desctype)
+ elif desctype == 'opcode':
+ name = parse_opcode_signature(signode, sig, desctype)
+ else:
+ # describe: use generic fallback
+ raise ValueError
+ except ValueError, err:
+ signode.clear()
+ signode += addnodes.desc_name(sig, sig)
+ continue # we don't want an index entry here
+ # only add target and index entry if this is the first
+ # description of the function name in this desc block
+ if not noindex and name not in names:
+ fullname = name
+ # note target
+ if fullname not in state.document.ids:
+ signode['names'].append(fullname)
+ signode['ids'].append(fullname)
+ signode['first'] = (not names)
+ state.document.note_explicit_target(signode)
+ names.append(name)
+
+ subnode = addnodes.desc_content()
+ # needed for automatic qualification of members
+ clsname_set = False
+ if desctype == 'class' and names:
+ clsname_set = True
+ state.nested_parse(content, content_offset, subnode)
+ node.append(subnode)
+ return [node]
+
+desc_directive.content = 1
+desc_directive.arguments = (1, 0, 1)
+desc_directive.options = {'noindex': directives.flag}
+
+desctypes = [
+ # the Python ones
+ 'function',
+ 'data',
+ 'class',
+ 'method',
+ 'attribute',
+ 'exception',
+ # the C ones
+ 'cfunction',
+ 'cmember',
+ 'cmacro',
+ 'ctype',
+ 'cvar',
+ # the odd one
+ 'opcode',
+ # the generic one
+ 'describe',
+]
+
+for name in desctypes:
+ directives.register_directive(name, desc_directive)
+
+
+# ------ versionadded/versionchanged ------------------------------------------
+
+def version_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ node = addnodes.versionmodified()
+ node['type'] = name
+ node['version'] = arguments[0]
+ if len(arguments) == 2:
+ inodes, messages = state.inline_text(arguments[1], lineno+1)
+ node.extend(inodes)
+ if content:
+ state.nested_parse(content, content_offset, node)
+ ret = [node] + messages
+ else:
+ ret = [node]
+ return ret
+
+version_directive.arguments = (1, 1, 1)
+version_directive.content = 1
+
+directives.register_directive('deprecated', version_directive)
+directives.register_directive('versionadded', version_directive)
+directives.register_directive('versionchanged', version_directive)
+
+
+# ------ see also -------------------------------------------------------------
+
+def seealso_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ rv = admonitions.make_admonition(
+ addnodes.seealso, name, ['See also'], options, content,
+ lineno, content_offset, block_text, state, state_machine)
+ return rv
+
+seealso_directive.content = 1
+seealso_directive.arguments = (0, 0, 0)
+directives.register_directive('seealso', seealso_directive)
+
+
+# ------ production list (for the reference) ----------------------------------
+
+token_re = re.compile('`([a-z_]+)`')
+
+def token_xrefs(text):
+ retnodes = []
+ pos = 0
+ for m in token_re.finditer(text):
+ if m.start() > pos:
+ txt = text[pos:m.start()]
+ retnodes.append(nodes.Text(txt, txt))
+ refnode = addnodes.pending_xref(m.group(1))
+ refnode['reftype'] = 'token'
+ refnode['reftarget'] = m.group(1)
+ refnode += nodes.literal(m.group(1), m.group(1), classes=['xref'])
+ retnodes.append(refnode)
+ pos = m.end()
+ if pos < len(text):
+ retnodes.append(nodes.Text(text[pos:], text[pos:]))
+ return retnodes
+
+def productionlist_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ node = addnodes.productionlist()
+ messages = []
+ i = 0
+
+ for rule in arguments[0].split('\n'):
+ if i == 0 and ':' not in rule:
+ # production group
+ continue
+ i += 1
+ try:
+ name, tokens = rule.split(':', 1)
+ except ValueError:
+ break
+ subnode = addnodes.production()
+ subnode['tokenname'] = name.strip()
+ if subnode['tokenname']:
+ idname = 'grammar-token-%s' % subnode['tokenname']
+ if idname not in state.document.ids:
+ subnode['ids'].append(idname)
+ state.document.note_implicit_target(subnode, subnode)
+ subnode.extend(token_xrefs(tokens))
+ node.append(subnode)
+ return [node] + messages
+
+productionlist_directive.content = 0
+productionlist_directive.arguments = (1, 0, 1)
+directives.register_directive('productionlist', productionlist_directive)
+
+# ------ section metadata -----------------------------------------------------
+
+def module_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ env = state.document.settings.env
+ modname = arguments[0].strip()
+ env.currmodule = modname
+ env.note_module(modname, options.get('synopsis', ''),
+ options.get('platform', ''),
+ 'deprecated' in options)
+ ret = []
+ targetnode = nodes.target('', '', ids=['module-' + modname])
+ state.document.note_explicit_target(targetnode)
+ ret.append(targetnode)
+ if 'platform' in options:
+ node = nodes.paragraph()
+ node += nodes.emphasis('Platforms: ', 'Platforms: ')
+ node += nodes.Text(options['platform'], options['platform'])
+ ret.append(node)
+ return ret
+
+module_directive.arguments = (1, 0, 0)
+module_directive.options = {'platform': lambda x: x,
+ 'synopsis': lambda x: x,
+ 'deprecated': directives.flag}
+directives.register_directive('module', module_directive)
+
+
+def author_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ # The author directives aren't included in the built document
+ return []
+
+author_directive.arguments = (1, 0, 1)
+directives.register_directive('sectionauthor', author_directive)
+directives.register_directive('moduleauthor', author_directive)
+
+
+# ------ toctree directive ----------------------------------------------------
+
+def toctree_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ dirname = path.dirname(__file__)
+
+ subnode = addnodes.toctree()
+ includefiles = filter(None, content)
+ # absolutize filenames
+ includefiles = map(lambda x: path.normpath(path.join(dirname, x)),
+ includefiles)
+ subnode['includefiles'] = includefiles
+ subnode['maxdepth'] = options.get('maxdepth', -1)
+ return [subnode]
+
+toctree_directive.content = 1
+toctree_directive.options = {'maxdepth': int}
+directives.register_directive('toctree', toctree_directive)
+
+
+# ------ centered directive ---------------------------------------------------
+
+def centered_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ if not arguments:
+ return []
+ subnode = addnodes.centered()
+ inodes, messages = state.inline_text(arguments[0], lineno)
+ subnode.extend(inodes)
+ return [subnode] + messages
+
+centered_directive.arguments = (1, 0, 1)
+directives.register_directive('centered', centered_directive)
+
+
+# ------ highlightlanguage directive ------------------------------------------
+
+def highlightlang_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ return [addnodes.highlightlang(lang=arguments[0].strip())]
+
+highlightlang_directive.content = 0
+highlightlang_directive.arguments = (1, 0, 0)
+directives.register_directive('highlightlang', highlightlang_directive)
+
+
+# ------ literalinclude directive ---------------------------------------------
+
+def literalinclude_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ """Like .. include:: :literal:, but only warns if the include file is not found."""
+ if not state.document.settings.file_insertion_enabled:
+ return [state.document.reporter.warning('File insertion disabled',
+ line=lineno)]
+ fn = arguments[0]
+ source_dir = path.dirname(path.abspath(state_machine.input_lines.source(
+ lineno - state_machine.input_offset - 1)))
+ fn = path.normpath(path.join(source_dir, fn))
+
+ try:
+ f = open(fn)
+ text = f.read()
+ f.close()
+ except (IOError, OSError):
+ retnode = state.document.reporter.warning('Include file %r not found' %
+ arguments[0], line=lineno)
+ else:
+ retnode = nodes.literal_block(text, text, source=fn)
+ retnode.line = 1
+ return [retnode]
+
+literalinclude_directive.content = 0
+literalinclude_directive.arguments = (1, 0, 0)
+directives.register_directive('literalinclude', literalinclude_directive)
+
+
+# ------ glossary directive ---------------------------------------------------
+
+def glossary_directive(name, arguments, options, content, lineno,
+ content_offset, block_text, state, state_machine):
+ """Glossary with cross-reference targets for :dfn: roles."""
+ node = addnodes.glossary()
+ state.nested_parse(content, content_offset, node)
+
+ # the content should be definition lists
+ dls = [child for child in node if isinstance(child, nodes.definition_list)]
+ # now, extract definition terms to enable cross-reference creation
+ for dl in dls:
+ dl['classes'].append('glossary')
+ for li in dl.children:
+ if not li.children or not isinstance(li[0], nodes.term):
+ continue
+ termtext = li.children[0].astext()
+ new_id = 'term-' + nodes.make_id(termtext)
+ li[0]['names'].append(new_id)
+ li[0]['ids'].append(new_id)
+ return [node]
+
+glossary_directive.content = 1
+glossary_directive.arguments = (0, 0, 0)
+directives.register_directive('glossary', glossary_directive)
Added: grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/roles.py
===================================================================
--- grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/roles.py (rev 0)
+++ grok/branches/jasper-grokdoctool/src/grokdoctool/extensions/roles.py 2007-10-05 15:30:12 UTC (rev 80658)
@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+"""
+ sphinx.roles
+ ~~~~~~~~~~~~
+
+ Handlers for additional ReST roles.
+
+ :copyright: 2007 by Georg Brandl.
+ :license: Python license.
+"""
+
+import re
+
+from docutils import nodes, utils
+from docutils.parsers.rst import roles
+
+import addnodes
+
+ws_re = re.compile(r'\s+')
+
+generic_docroles = {
+ 'command' : nodes.strong,
+ 'dfn' : nodes.emphasis,
+ 'guilabel' : nodes.strong,
+ 'kbd' : nodes.literal,
+ 'keyword' : nodes.literal,
+ 'mailheader' : addnodes.literal_emphasis,
+ 'makevar' : nodes.Text,
+ 'manpage' : addnodes.literal_emphasis,
+ 'mimetype' : addnodes.literal_emphasis,
+ 'newsgroup' : addnodes.literal_emphasis,
+ 'option' : addnodes.literal_emphasis,
+ 'program' : nodes.strong,
+ 'regexp' : nodes.literal,
+}
+
+for rolename, nodeclass in generic_docroles.iteritems():
+ roles.register_generic_role(rolename, nodeclass)
+
+# default is `literal`
+innernodetypes = {
+ 'ref': nodes.emphasis,
+ 'term': nodes.emphasis,
+ 'token': nodes.strong,
+}
+
+def xfileref_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
+ text = utils.unescape(text)
+ if text[0:1] == '!':
+ text = text[1:]
+ return [innernodetypes.get(typ, nodes.literal)(
+ rawtext, text, classes=['xref'])], []
+ pnode = addnodes.pending_xref(rawtext)
+ pnode['reftype'] = typ
+ # if the first character is a dot, search more specific namespaces first
+ # else search builtins first
+ if text[0:1] == '.' and \
+ typ in ('data', 'exc', 'func', 'class', 'const', 'attr', 'meth'):
+ text = text[1:]
+ pnode['refspecific'] = True
+ pnode['reftarget'] = ws_re.sub((typ == 'term' and ' ' or ''), text)
+ pnode += innernodetypes.get(typ, nodes.literal)(rawtext, text,
+ classes=['xref'])
+ return [pnode], []
+
+
+_litvar_re = re.compile('{([^}]+)}')
+
+def emph_literal_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
+ text = utils.unescape(text)
+ retnodes = []
+ pos = 0
+ for m in _litvar_re.finditer(text):
+ if m.start() > pos:
+ txt = text[pos:m.start()]
+ retnodes.append(nodes.literal(txt, txt))
+ retnodes.append(nodes.emphasis('', '', nodes.literal(m.group(1), m.group(1))))
+ pos = m.end()
+ if pos < len(text):
+ retnodes.append(nodes.literal(text[pos:], text[pos:]))
+ return retnodes, []
+
+
+specific_docroles = {
+ 'data': xfileref_role,
+ 'exc': xfileref_role,
+ 'func': xfileref_role,
+ 'class': xfileref_role,
+ 'const': xfileref_role,
+ 'attr': xfileref_role,
+ 'meth': xfileref_role,
+
+ 'cfunc' : xfileref_role,
+ 'cdata' : xfileref_role,
+ 'ctype' : xfileref_role,
+ 'cmacro' : xfileref_role,
+
+ 'mod' : xfileref_role,
+
+ 'ref': xfileref_role,
+ 'token' : xfileref_role,
+ 'term': xfileref_role,
+
+ 'file' : emph_literal_role,
+ 'samp' : emph_literal_role,
+}
+
+for rolename, func in specific_docroles.iteritems():
+ roles.register_canonical_role(rolename, func)
Added: grok/branches/jasper-grokdoctool/src/grokdoctool/grok.xslt
===================================================================
--- grok/branches/jasper-grokdoctool/src/grokdoctool/grok.xslt (rev 0)
+++ grok/branches/jasper-grokdoctool/src/grokdoctool/grok.xslt 2007-10-05 15:30:12 UTC (rev 80658)
@@ -0,0 +1,162 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+ xmlns:date="http://exslt.org/dates-and-times"
+ extension-element-prefixes="date" >
+ <xsl:include href="rst2html.xslt"/>
+ <xsl:output indent="yes" method="html"/>
+ <xsl:template match="/document" priority="10">
+ <html>
+ <head>
+ <xsl:comment>
+ <xsl:text>Generated from</xsl:text>
+ <xsl:value-of select="@source"/>
+ </xsl:comment>
+ <style type="text/css">
+
+/* some default styles from grok layout */
+body {
+ font-family: verdana;
+}
+
+h1 {
+ font-family: verdana;
+ font-size: 15px;
+ line-height: 20px;
+ color: #CC9900;
+ width: 100%;
+ margin: 23px auto 8px auto;
+ border-bottom: 1px solid #CC9900;
+}
+h2 {
+ font-family: verdana;
+ font-size: 13px;
+ line-height: 20px;
+ color: #CC9900;
+ width: 100%;
+ margin: 16px auto 8px auto;
+ border-bottom: 1px dotted #cccccc;
+}
+h3 {
+ font-family: verdana;
+ font-size: 12px;
+ line-height: 12px;
+ color: #555555;
+ width: 100%;
+ margin: 16px auto -4px auto;
+}
+p {
+ font-size: 13px;
+ line-height: 20px;
+ color: #555555;
+ width: 540px;
+ margin: 8px auto;
+}
+
+pre {
+ font-size: 11px;
+ line-height: 18px;
+ color: #A90101;
+ width: 540px;
+ margin: 8px auto;
+ padding: 16px 8px;
+ border-top: 1px solid #cccccc;
+ border-bottom: 1px solid #dddddd;
+ background: #eeeeee;
+}
+ul {
+ font-size: 11px;
+ line-height: 20px;
+ color: #555555;
+ width: 540px;
+ margin: 16px auto;
+ list-style-type: none;
+}
+li {
+ margin: 0 50px 0 0;
+ left: 0;
+ padding: 0;
+}
+
+a:link {
+ color: #555555;
+ text-decoration: none;
+ border-bottom-style: dotted;
+ border-bottom-width: 1px;
+}
+
+a:hover {
+ color: #CC9900;
+ border-bottom-style: dotted;
+ background-color: #ffffff;
+ border-width: 1px;
+}
+
+a:visited {
+ color: #555555;
+ text-decoration: none;
+ border-bottom-style: dotted;
+ border-bottom-width: 1px;
+}
+
+/* custom documentation styles */
+
+span.pointing-finger {
+ color:#55555;
+}
+
+span.pointing-finger span {
+ font-size:10px;
+}
+
+.header h1 {
+ font-size:20px;
+ border:none;
+}
+.footer {
+ border-top:1px dotted #ccccc;
+}
+.footer span {
+ font-size:10px;
+ font-style:italic;
+ color:55555;
+}
+div.function-description{
+ font-size:14px;
+ margin-left:2em;
+}
+
+div.function-classname {
+ float:left;
+ font-weight:bold;
+}
+div.function-name {
+ float:left;
+ font-weight:bold;
+}
+div.function-argument {
+ font-style:italic
+}
+div.function-arguments {
+ float:left;
+ width:30em;
+}
+
+ </style>
+ <title><xsl:value-of select="title"/></title>
+ </head>
+ <body>
+ <div class="header">
+ <h1>Grok reference documentation</h1>
+ </div>
+ <xsl:apply-templates/>
+ <div class="footer">
+ <span>
+ <xsl:text>Grok reference documentation, generated on </xsl:text>
+ <xsl:value-of select="concat(date:day-name(), ' ', date:month-name(), ' ', date:day-in-month(), ' ', date:year(), ', ', date:time())"/>
+ </span>
+ </div>
+ </body>
+ </html>
+ </xsl:template>
+
+
+</xsl:stylesheet>
Added: grok/branches/jasper-grokdoctool/src/grokdoctool/rst2html.py
===================================================================
--- grok/branches/jasper-grokdoctool/src/grokdoctool/rst2html.py (rev 0)
+++ grok/branches/jasper-grokdoctool/src/grokdoctool/rst2html.py 2007-10-05 15:30:12 UTC (rev 80658)
@@ -0,0 +1,84 @@
+import sys
+import os
+from optparse import OptionParser
+from docutils.core import publish_string
+
+# import modules from python core doc generation code
+# these modules will register extensions in docutils
+from extensions import addnodes, directives, roles
+
+try:
+ from lxml import etree
+except:
+ etree = None
+
+XSLT_FILE = os.path.join(os.path.split(__file__)[0], 'grok.xslt')
+
+class ReST2HTML(object):
+ def __init__(self, inputdir, xslt_file=None):
+ self.inputdir = inputdir
+ self.xslt_file = xslt_file
+
+ def _walk(self):
+ for rootpath, directories, files in os.walk(self.inputdir):
+ if '.svn' in directories:
+ directories.remove('.svn')
+ for file in files:
+ if file.startswith('.'):
+ continue
+ if not os.path.splitext(file)[1] in ['.rst', '.txt']:
+ continue
+ yield os.path.join(rootpath, file)
+
+ def run(self):
+ for path in self._walk():
+ directory, rst_file = os.path.split(path)
+ html_file = os.path.splitext(rst_file)[0] + '.html'
+ sys.stderr.write('%s\n' % rst_file)
+ self.convert_file(path, os.path.join(directory, html_file))
+
+ def convert_file(self, rst_file, html_file):
+ fp = open(rst_file)
+ input = fp.read()
+ fp.close()
+ output = publish_string(input,
+ rst_file,
+ writer_name='xml')
+ if self.xslt_file:
+ input_doc = etree.fromstring(output)
+ transform = etree.XSLT(etree.parse(self.xslt_file))
+ output_doc = transform(input_doc)
+ output = etree.tostring(output_doc, pretty_print=True)
+ if output:
+ fp = open(html_file, 'w')
+ fp.write(output)
+ fp.close()
+
+def main():
+ usage = "usage: %prog INPUTDIR"
+ parser = OptionParser(usage)
+
+ parser.add_option('-x', '--xslt', dest="xslt_file",
+ help="use a specific xslt stylesheet",
+ metavar='XSTLFILE')
+
+ options, args = parser.parse_args()
+
+ if not len(args) == 1:
+ sys.stderr.write('%s\n' % usage)
+ sys.exit(1)
+
+ inputdir = args[0]
+
+ if not os.path.isdir(inputdir):
+ sys.stderr.write('input directory %s does not exist\n' % inputdir)
+ sys.exit(1)
+
+ xslt_file = None
+ if etree:
+ xslt_file = options.xslt_file or XSLT_FILE
+
+ ReST2HTML(inputdir, xslt_file=xslt_file).run()
+
+if __name__ == '__main__':
+ main()
Added: grok/branches/jasper-grokdoctool/src/grokdoctool/rst2html.xslt
===================================================================
--- grok/branches/jasper-grokdoctool/src/grokdoctool/rst2html.xslt (rev 0)
+++ grok/branches/jasper-grokdoctool/src/grokdoctool/rst2html.xslt 2007-10-05 15:30:12 UTC (rev 80658)
@@ -0,0 +1,171 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:output indent="yes" mode="html"/>
+
+ <xsl:template match="/document">
+ <html>
+ <head>
+ <xsl:comment>
+ <xsl:text>Generated from</xsl:text>
+ <xsl:value-of select="@source"/>
+ </xsl:comment>
+ <title><xsl:value-of select="title"/></title>
+ </head>
+ <body>
+ <xsl:apply-templates/>
+ </body>
+ </html>
+ </xsl:template>
+
+ <xsl:template match="document/title">
+ <h1><xsl:apply-templates/></h1>
+ </xsl:template>
+
+ <xsl:template match="section/title">
+ <h2>
+ <a name="{../@ids}">
+ <xsl:value-of select="."/>
+ </a>
+ </h2>
+ </xsl:template>
+
+ <xsl:template match="title_reference">
+ <strong><xsl:apply-templates/></strong>
+ </xsl:template>
+
+ <xsl:template match="paragraph">
+ <p><xsl:apply-templates/></p>
+ </xsl:template>
+
+ <xsl:template match="section">
+ <div class="section"><xsl:apply-templates/></div>
+ </xsl:template>
+
+ <xsl:template match="pending_xref">
+ <a href="#{@reftarget}" class="{@reftype}-link">
+ <xsl:apply-templates/>
+ </a>
+ </xsl:template>
+
+ <xsl:template match="literal">
+ <code>
+ <xsl:apply-templates/>
+ </code>
+ </xsl:template>
+
+ <xsl:template match="block_quote">
+ <quote>
+ <xsl:apply-templates/>
+ </quote>
+ </xsl:template>
+
+ <xsl:template match="seealso">
+ <div class="seealso">
+ <p>
+ <span class="pointingfinger">
+ <span>see also: </span>
+ <xsl:text>☛ </xsl:text>
+ </span>
+ <xsl:apply-templates/>
+ </p>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="seealso/paragraph">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="literal_block">
+ <pre>
+ <xsl:apply-templates/>
+ </pre>
+ </xsl:template>
+
+ <xsl:template match="desc">
+ <div class="{@desctype}-description">
+ <dl>
+ <xsl:apply-templates/>
+ </dl>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="desc_signature">
+ <a name="{@ids}">
+ <dt>
+ <div class="function-classname">
+ <xsl:value-of select="desc_classname"/>
+ </div>
+ <div class="function-name">
+ <xsl:value-of select="desc_name"/>
+ </div>
+ <div class="function-arguments">
+ <xsl:text>(</xsl:text>
+ <xsl:for-each select="desc_parameterlist//desc_parameter">
+ <xsl:if test="name(..) = 'desc_optional'">
+ <xsl:text>[</xsl:text>
+ </xsl:if>
+ <span class="function-argument">
+ <xsl:value-of select="."/>
+ </span>
+ <xsl:if test="name(..) = 'desc_optional'">
+ <xsl:text>]</xsl:text>
+ </xsl:if>
+
+ <xsl:if test="position()!=last()">
+ <xsl:text>, </xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text>)</xsl:text>
+ </div>
+ <br clear="both"/>
+ </dt>
+ </a>
+ </xsl:template>
+
+ <xsl:template match="desc_content">
+ <dd>
+ <xsl:apply-templates/>
+ </dd>
+ </xsl:template>
+
+ <xsl:template match="definition_list">
+ <div class="definition-list">
+ <xsl:apply-templates/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="definition_list_item">
+ <dl>
+ <xsl:apply-templates/>
+ </dl>
+ </xsl:template>
+
+ <xsl:template match="term">
+ <dt>
+ <xsl:apply-templates/>
+ </dt>
+ </xsl:template>
+
+ <xsl:template match="definition">
+ <dd>
+ <xsl:apply-templates/>
+ </dd>
+ </xsl:template>
+ <!-- attributes -->
+
+ <xsl:template match="@classes">
+ <xsl:attribute name="class">
+ <xsl:value-of select="."/>
+ </xsl:attribute>
+ </xsl:template>
+
+ <xsl:template match="text()">
+ <xsl:value-of select="."/>
+ </xsl:template>
+
+ <xsl:template match="*">
+ <xsl:message>
+ <xsl:text>Unknown element: </xsl:text>
+ <xsl:value-of select="."/>
+ </xsl:message>
+ </xsl:template>
+</xsl:stylesheet>
More information about the Checkins
mailing list