[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>&#9755; </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