[Zope-Checkins] SVN: Zope/trunk/lib/python/docutils/ Updated docutils to 0.3.4 (merge from tiran-restfixing-branch)

Christian 'Tiran' Heimes heimes at faho.rwth-aachen.de
Thu May 13 11:25:54 EDT 2004


Log message for revision 24625:
Updated docutils to 0.3.4 (merge from tiran-restfixing-branch)


-=-
Modified: Zope/trunk/lib/python/docutils/__init__.py
===================================================================
--- Zope/trunk/lib/python/docutils/__init__.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/__init__.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:04 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:37 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -51,12 +51,14 @@
 
 __docformat__ = 'reStructuredText'
 
-__version__ = '0.3.1'
-"""``major.minor.micro`` version number.  The micro number is bumped any time
-there's a change in the API incompatible with one of the front ends or
-significant new functionality.  The minor number is bumped whenever there is a
+__version__ = '0.3.4'
+"""``major.minor.micro`` version number.  The micro number is bumped
+any time there's a change in the API incompatible with one of the
+front ends or significant new functionality, and at any alpha or beta
+release.  The minor number is bumped whenever there is a stable
 project release.  The major number will be bumped when the project is
-feature-complete, and perhaps if there is a major change in the design."""
+feature-complete, and perhaps if there is a major change in the
+design."""
 
 
 class ApplicationError(StandardError): pass
@@ -122,18 +124,35 @@
 
     default_transforms = ()
     """Transforms required by this class.  Override in subclasses."""
+    
+    unknown_reference_resolvers = ()
+    """List of functions to try to resolve unknown references.  Called when
+    FinalCheckVisitor is unable to find a correct target.  The list should
+    contain functions which will try to resolve unknown references, with the
+    following signature::
 
+        def reference_resolver(node):
+            '''Returns boolean: true if resolved, false if not.'''
 
+    Each function must have a "priority" attribute which will affect the order
+    the unknown_reference_resolvers are run::
+
+        reference_resolver.priority = 100
+
+    Override in subclasses."""
+
+
 class Component(SettingsSpec, TransformSpec):
 
     """Base class for Docutils components."""
 
     component_type = None
-    """Override in subclasses."""
+    """Name of the component type ('reader', 'parser', 'writer').  Override in
+    subclasses."""
 
     supported = ()
     """Names for this component.  Override in subclasses."""
-
+    
     def supports(self, format):
         """
         Is `format` supported by this component?

Modified: Zope/trunk/lib/python/docutils/core.py
===================================================================
--- Zope/trunk/lib/python/docutils/core.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/core.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Authors: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:04 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:38 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -180,6 +180,7 @@
                                         self.settings)
             self.apply_transforms(document)
             output = self.writer.write(document, self.destination)
+            self.writer.assemble_parts()
         except utils.SystemMessage, error:
             if self.settings.traceback:
                 raise
@@ -376,3 +377,63 @@
     pub.set_source(source, source_path)
     pub.set_destination(destination_path=destination_path)
     return pub.publish(enable_exit=enable_exit)
+
+def publish_parts(source, source_path=None, destination_path=None, 
+                  reader=None, reader_name='standalone',
+                  parser=None, parser_name='restructuredtext',
+                  writer=None, writer_name='pseudoxml',
+                  settings=None, settings_spec=None,
+                  settings_overrides=None, config_section=None,
+                  enable_exit=None):
+    """
+    Set up & run a `Publisher`, and return a dictionary of document parts.
+    Dictionary keys are the names of parts, and values are Unicode strings;
+    encoding is up to the client.  For programmatic use with string I/O.
+
+    For encoded string input, be sure to set the "input_encoding" setting to
+    the desired encoding.  Set it to "unicode" for unencoded Unicode string
+    input.  Here's how::
+
+        publish_string(..., settings_overrides={'input_encoding': 'unicode'})
+
+    Parameters:
+
+    - `source`: An input string; required.  This can be an encoded 8-bit
+      string (set the "input_encoding" setting to the correct encoding) or a
+      Unicode string (set the "input_encoding" setting to "unicode").
+    - `source_path`: Path to the file or object that produced `source`;
+      optional.  Only used for diagnostic output.
+    - `destination_path`: Path to the file or object which will receive the
+      output; optional.  Used for determining relative paths (stylesheets,
+      source links, etc.).
+    - `reader`: A `docutils.readers.Reader` object.
+    - `reader_name`: Name or alias of the Reader class to be instantiated if
+      no `reader` supplied.
+    - `parser`: A `docutils.parsers.Parser` object.
+    - `parser_name`: Name or alias of the Parser class to be instantiated if
+      no `parser` supplied.
+    - `writer`: A `docutils.writers.Writer` object.
+    - `writer_name`: Name or alias of the Writer class to be instantiated if
+      no `writer` supplied.
+    - `settings`: Runtime settings object.
+    - `settings_spec`: Extra settings specification; a `docutils.SettingsSpec`
+      subclass.  Used only if no `settings` specified.
+    - `settings_overrides`: A dictionary containing program-specific overrides
+      of component settings.
+    - `config_section`: Name of configuration file section for application.
+      Used only if no `settings` or `settings_spec` specified.
+    - `enable_exit`: Boolean; enable exit status at end of processing?
+    """
+    pub = Publisher(reader, parser, writer, settings=settings,
+                    source_class=io.StringInput,
+                    destination_class=io.NullOutput)
+    pub.set_components(reader_name, parser_name, writer_name)
+    if settings is None:
+        settings = pub.get_settings(settings_spec=settings_spec,
+                                    config_section=config_section)
+    if settings_overrides:
+        settings._update(settings_overrides, 'loose')
+    pub.set_source(source, source_path)
+    pub.set_destination(destination_path=destination_path)
+    pub.publish(enable_exit=enable_exit)
+    return pub.writer.parts

Added: Zope/trunk/lib/python/docutils/examples.py
===================================================================
--- Zope/trunk/lib/python/docutils/examples.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/examples.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -0,0 +1,74 @@
+# Authors: David Goodger
+# Contact: goodger at python.org
+# Revision: $Revision: 1.1.2.1 $
+# Date: $Date: 2004/05/12 19:57:38 $
+# Copyright: This module has been placed in the public domain.
+
+"""
+This module contains practical examples of Docutils client code.
+
+Importing this module is not recommended; its contents are subject to change
+in future Docutils releases.  Instead, it is recommended that you copy and
+paste the parts you need into your own code, modifying as necessary.
+"""
+
+from docutils import core
+
+
+def html_parts(input_string, source_path=None, destination_path=None,
+               input_encoding='unicode', doctitle=1, initial_header_level=1):
+    """
+    Given an input string, returns a dictionary of HTML document parts.
+
+    Dictionary keys are the names of parts, and values are Unicode strings;
+    encoding is up to the client.
+
+    Parameters:
+
+    - `input_string`: A multi-line text string; required.
+    - `source_path`: Path to the source file or object.  Optional, but useful
+      for diagnostic output (system messages).
+    - `destination_path`: Path to the file or object which will receive the
+      output; optional.  Used for determining relative paths (stylesheets,
+      source links, etc.).
+    - `input_encoding`: The encoding of `input_string`.  If it is an encoded
+      8-bit string, provide the correct encoding.  If it is a Unicode string,
+      use "unicode", the default.
+    - `doctitle`: Disable the promotion of a lone top-level section title to
+      document title (and subsequent section title to document subtitle
+      promotion); enabled by default.
+    - `initial_header_level`: The initial level for header elements (e.g. 1
+      for "<h1>").
+    """
+    overrides = {'input_encoding': input_encoding,
+                 'doctitle_xform': doctitle,
+                 'initial_header_level': initial_header_level}
+    parts = core.publish_parts(
+        source=input_string, source_path=source_path,
+        destination_path=destination_path,
+        writer_name='html', settings_overrides=overrides)
+    return parts
+
+def html_fragment(input_string, source_path=None, destination_path=None,
+                  input_encoding='unicode', output_encoding='unicode',
+                  doctitle=1, initial_header_level=1):
+    """
+    Given an input string, returns an HTML fragment as a string.
+
+    The return value is the contents of the <body> tag, less the title,
+    subtitle, and docinfo.
+
+    Parameters (see `html_parts()` for the remainder):
+
+    - `output_encoding`: The desired encoding of the output.  If a Unicode
+      string is desired, use the default value of "unicode" .
+    """
+    parts = html_parts(
+        input_string=input_string, source_path=source_path,
+        destination_path=destination_path,
+        input_encoding=input_encoding, doctitle=doctitle,
+        initial_header_level=initial_header_level)
+    fragment = parts['fragment']
+    if output_encoding != 'unicode':
+        fragment = fragment.encode(output_encoding)
+    return fragment

Modified: Zope/trunk/lib/python/docutils/frontend.py
===================================================================
--- Zope/trunk/lib/python/docutils/frontend.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/frontend.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.7 $
-# Date: $Date: 2003/11/30 15:06:04 $
+# Revision: $Revision: 1.2.10.4.8.1 $
+# Date: $Date: 2004/05/12 19:57:38 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -126,8 +126,7 @@
 def validate_threshold(setting, value, option_parser,
                        config_parser=None, config_section=None):
     try:
-        int(value)
-        return value
+        return int(value)
     except ValueError:
         try:
             return option_parser.thresholds[value.lower()]
@@ -294,6 +293,10 @@
          ('Disable backlinks from footnotes and citations.',
           ['--no-footnote-backlinks'],
           {'dest': 'footnote_backlinks', 'action': 'store_false'}),
+         ('Disable Docutils section numbering',
+          ['--no-section-numbering'],
+          {'action': 'store_false', 'dest': 'sectnum_xform',
+           'default': 1, 'validator': validate_boolean}),
          ('Set verbosity threshold; report system messages at or higher than '
           '<level> (by name or number: "info" or "1", warning/2, error/3, '
           'severe/4; also, "none" or "5").  Default is 2 (warning).',
@@ -346,7 +349,7 @@
           {'metavar': '<name[:handler]>', 'default': 'utf-8',
            'validator': validate_encoding_and_error_handler}),
          (SUPPRESS_HELP,                # usually handled by --output-encoding
-          ['--output_encoding_error_handler'],
+          ['--output-encoding-error-handler'],
           {'default': 'strict', 'validator': validate_encoding_error_handler}),
          ('Specify the text encoding for error output.  Default is ASCII.  '
           'Optionally also specify the encoding error handler for unencodable '
@@ -357,7 +360,7 @@
           {'metavar': '<name[:handler]>', 'default': 'ascii',
            'validator': validate_encoding_and_error_handler}),
          (SUPPRESS_HELP,                # usually handled by --error-encoding
-          ['--error_encoding_error_handler'],
+          ['--error-encoding-error-handler'],
           {'default': default_error_encoding_error_handler,
            'validator': validate_encoding_error_handler}),
          ('Specify the language of input text (ISO 639 2-letter identifier).'

Modified: Zope/trunk/lib/python/docutils/io.py
===================================================================
--- Zope/trunk/lib/python/docutils/io.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/io.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:04 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:38 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -12,7 +12,10 @@
 __docformat__ = 'reStructuredText'
 
 import sys
-import locale
+try:
+    import locale
+except:
+    pass
 from types import UnicodeType
 from docutils import TransformSpec
 
@@ -156,7 +159,7 @@
                     print >>sys.stderr, '%s: %s' % (error.__class__.__name__,
                                                     error)
                     print >>sys.stderr, (
-                        'Unable to open source file for reading (%s).  Exiting.'
+                        'Unable to open source file for reading (%r).  Exiting.'
                         % source_path)
                     sys.exit(1)
             else:
@@ -224,7 +227,7 @@
             print >>sys.stderr, '%s: %s' % (error.__class__.__name__,
                                             error)
             print >>sys.stderr, ('Unable to open destination file for writing '
-                                 '(%s).  Exiting.' % source_path)
+                                 '(%r).  Exiting.' % self.destination_path)
             sys.exit(1)
         self.opened = 1
 

Modified: Zope/trunk/lib/python/docutils/languages/__init__.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/__init__.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/__init__.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:05 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:42 $
 # Copyright: This module has been placed in the public domain.
 
 # Internationalization details are documented in

Modified: Zope/trunk/lib/python/docutils/languages/af.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/af.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/af.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: Jannie Hofmeyr
 # Contact: jhsh at sun.ac.za
-# Revision: $Revision: 1.3 $
-# Date: $Date: 2003/11/30 15:06:05 $
+# Revision: $Revision: 1.1.2.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:42 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please

Added: Zope/trunk/lib/python/docutils/languages/cs.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/cs.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/cs.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -0,0 +1,62 @@
+# Author: Marek Blaha
+# Contact: mb at dat.cz
+# Revision: $Revision: 1.1.2.1 $
+# Date: $Date: 2004/05/12 19:57:42 $
+# Copyright: This module has been placed in the public domain.
+
+# New language mappings are welcome.  Before doing a new translation, please
+# read <http://docutils.sf.net/spec/howto/i18n.html>.  Two files must be
+# translated for each language: one in docutils/languages, the other in
+# docutils/parsers/rst/languages.
+
+"""
+Czech-language mappings for language-dependent features of Docutils.
+"""
+
+__docformat__ = 'reStructuredText'
+
+labels = {
+      # fixed: language-dependent
+      'author': u'Autor',
+      'authors': u'Auto\u0159i',
+      'organization': u'Organizace',
+      'address': u'Adresa',
+      'contact': u'Kontakt',
+      'version': u'Verze',
+      'revision': u'Revize',
+      'status': u'Stav',
+      'date': u'Datum',
+      'copyright': u'Copyright',
+      'dedication': u'V\u011Bnov\u00E1n\u00ED',
+      'abstract': u'Abstrakt',
+      'attention': u'Pozor!',
+      'caution': u'Opatrn\u011B!',
+      'danger': u'!NEBEZPE\u010C\u00CD!',
+      'error': u'Chyba',
+      'hint': u'Rada',
+      'important': u'D\u016Fle\u017Eit\u00E9',
+      'note': u'Pozn\u00E1mka',
+      'tip': u'Tip',
+      'warning': u'Varov\u00E1n\u00ED',
+      'contents': u'Obsah'}
+"""Mapping of node class name to label text."""
+
+bibliographic_fields = {
+      # language-dependent: fixed
+      u'autor': 'author',
+      u'auto\u0159i': 'authors',
+      u'organizace': 'organization',
+      u'adresa': 'address',
+      u'kontakt': 'contact',
+      u'verze': 'version',
+      u'revize': 'revision',
+      u'stav': 'status',
+      u'datum': 'date',
+      u'copyright': 'copyright',
+      u'v\u011Bnov\u00E1n\u00ED': 'dedication',
+      u'abstrakt': 'abstract'}
+"""Czech (lowcased) to canonical name mapping for bibliographic fields."""
+
+author_separators = [';', ',']
+"""List of separator strings for the 'Authors' bibliographic field. Tried in
+order."""

Modified: Zope/trunk/lib/python/docutils/languages/de.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/de.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/de.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Authors:   David Goodger; Gunnar Schwant
 # Contact:   goodger at users.sourceforge.net
-# Revision:  $Revision: 1.5 $
-# Date:      $Date: 2003/11/30 15:06:05 $
+# Revision:  $Revision: 1.2.10.3.8.1 $
+# Date:      $Date: 2004/05/12 19:57:42 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please

Modified: Zope/trunk/lib/python/docutils/languages/en.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/en.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/en.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:05 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:42 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please

Modified: Zope/trunk/lib/python/docutils/languages/eo.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/eo.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/eo.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: Marcelo Huerta San Martin
 # Contact: richieadler at users.sourceforge.net
-# Revision: $Revision: 1.1 $
-# Date: $Date: 2003/11/30 15:06:05 $
+# Revision: $Revision: 1.1.2.1.8.1 $
+# Date: $Date: 2004/05/12 19:57:42 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please

Modified: Zope/trunk/lib/python/docutils/languages/es.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/es.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/es.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,8 +1,8 @@
 # -*- coding: iso-8859-1 -*-
 # Author: Marcelo Huerta San Martín
 # Contact: mghsm at uol.com.ar
-# Revision: $Revision: 1.3 $
-# Date: $Date: 2003/11/30 15:06:05 $
+# Revision: $Revision: 1.1.2.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:42 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please

Modified: Zope/trunk/lib/python/docutils/languages/fr.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/fr.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/fr.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: Stefane Fermigier
 # Contact: sf at fermigier.com
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:05 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:42 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please

Modified: Zope/trunk/lib/python/docutils/languages/it.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/it.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/it.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: Nicola Larosa
 # Contact: docutils at tekNico.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:05 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:42 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please

Added: Zope/trunk/lib/python/docutils/languages/pt_br.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/pt_br.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/pt_br.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -0,0 +1,63 @@
+# -*- coding: iso-8859-1 -*-
+# Author: David Goodger
+# Contact: goodger at users.sourceforge.net
+# Revision: $Revision: 1.1.2.1 $
+# Date: $Date: 2004/05/12 19:57:42 $
+# Copyright: This module has been placed in the public domain.
+
+# New language mappings are welcome.  Before doing a new translation, please
+# read <http://docutils.sf.net/spec/howto/i18n.html>.  Two files must be
+# translated for each language: one in docutils/languages, the other in
+# docutils/parsers/rst/languages.
+
+"""
+Brazilian Portuguese-language mappings for language-dependent features of Docutils.
+"""
+
+__docformat__ = 'reStructuredText'
+
+labels = {
+      # fixed: language-dependent
+      'author': u'Autor',
+      'authors': u'Autores',
+      'organization': unicode('Organização', 'latin1'),
+      'address': unicode('Endereço', 'latin1'),
+      'contact': u'Contato',
+      'version': unicode('Versão', 'latin1'),
+      'revision': unicode('Revisão', 'latin1'),
+      'status': u'Estado',
+      'date': u'Data',
+      'copyright': u'Copyright',
+      'dedication': unicode('Dedicatória', 'latin1'),
+      'abstract': u'Resumo',
+      'attention': unicode('Attenção!', 'latin1'),
+      'caution': u'Cuidado!',
+      'danger': u'PERIGO!',
+      'error': u'Erro',
+      'hint': unicode('Sugestão', 'latin1'),
+      'important': u'Importante',
+      'note': u'Nota',
+      'tip': u'Dica',
+      'warning': u'Aviso',
+      'contents': unicode('Sumário', 'latin1')}
+"""Mapping of node class name to label text."""
+
+bibliographic_fields = {
+      # language-dependent: fixed
+      u'autor': 'author',
+      u'autores': 'authors',
+      unicode('organização', 'latin1'): 'organization',
+      unicode('endereço', 'latin1'): 'address',
+      u'contato': 'contact',
+      unicode('versão', 'latin1'): 'version',
+      unicode('revisão', 'latin1'): 'revision',
+      u'estado': 'status',
+      u'data': 'date',
+      u'copyright': 'copyright',
+      unicode('dedicatória', 'latin1'): 'dedication',
+      u'resumo': 'abstract'}
+"""English (lowcased) to canonical name mapping for bibliographic fields."""
+
+author_separators = [';', ',']
+"""List of separator strings for the 'Authors' bibliographic field. Tried in
+order."""

Modified: Zope/trunk/lib/python/docutils/languages/ru.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/ru.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/ru.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: Roman Suzi
 # Contact: rnd at onego.ru
-# Revision: $Revision: 1.3 $
-# Date: $Date: 2003/11/30 15:06:05 $
+# Revision: $Revision: 1.1.2.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:42 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please

Modified: Zope/trunk/lib/python/docutils/languages/sk.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/sk.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/sk.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # :Author: Miroslav Vasko
 # :Contact: zemiak at zoznam.sk
-# :Revision: $Revision: 1.5 $
-# :Date: $Date: 2003/11/30 15:06:05 $
+# :Revision: $Revision: 1.2.10.3.8.1 $
+# :Date: $Date: 2004/05/12 19:57:42 $
 # :Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please

Modified: Zope/trunk/lib/python/docutils/languages/sv.py
===================================================================
--- Zope/trunk/lib/python/docutils/languages/sv.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/languages/sv.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author:    Adam Chodorowski
 # Contact:   chodorowski at users.sourceforge.net
-# Revision:  $Revision: 1.5 $
-# Date:      $Date: 2003/11/30 15:06:05 $
+# Revision:  $Revision: 1.2.10.3.8.1 $
+# Date:      $Date: 2004/05/12 19:57:42 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please

Modified: Zope/trunk/lib/python/docutils/nodes.py
===================================================================
--- Zope/trunk/lib/python/docutils/nodes.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/nodes.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:04 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:38 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -517,6 +517,9 @@
     its immediate parent is a `TextElement` instance (including subclasses).
     This is handy for nodes like `image` that can appear both inline and as
     standalone body elements.
+
+    If passing children to `__init__()`, make sure to set `text` to
+    ``''`` or some other suitable value.
     """
 
     child_text_separator = ''
@@ -599,6 +602,9 @@
 
     referenced = 0
 
+    indirect_reference_name = None
+    """Holds the whitespace_normalized_name (contains mixed case) of a target"""
+
 class Labeled:
     """Contains a `label` as its first element."""
 
@@ -820,6 +826,7 @@
     def has_name(self, name):
         return self.nameids.has_key(name)
 
+    # "note" here is an imperative verb: "take note of".
     def note_implicit_target(self, target, msgnode=None):
         id = self.set_id(target, msgnode)
         self.set_name_id_map(target, id, msgnode, explicit=None)
@@ -939,6 +946,7 @@
 # ========================
 
 class docinfo(Bibliographic, Element): pass
+class info(Bibliographic, Element): pass
 class author(Bibliographic, TextElement): pass
 class authors(Bibliographic, Element): pass
 class organization(Bibliographic, TextElement): pass
@@ -1182,7 +1190,7 @@
 class emphasis(Inline, TextElement): pass
 class strong(Inline, TextElement): pass
 class literal(Inline, TextElement): pass
-class reference(Inline, Referential, TextElement): pass
+class reference(General, Inline, Referential, TextElement): pass
 class footnote_reference(Inline, Referential, TextElement): pass
 class citation_reference(Inline, Referential, TextElement): pass
 class substitution_reference(Inline, TextElement): pass
@@ -1222,7 +1230,7 @@
         footnote footnote_reference
     generated
     header hint
-    image important inline
+    image important info inline
     label legend line_block list_item literal literal_block
     note
     option option_argument option_group option_list option_list_item
@@ -1273,8 +1281,8 @@
 
         Raise an exception unless overridden.
         """
-        raise NotImplementedError('visiting unknown node type: %s'
-                                  % node.__class__.__name__)
+        raise NotImplementedError('%s visiting unknown node type: %s'
+                                  % (self.__class__, node.__class__.__name__))
 
     def unknown_departure(self, node):
         """
@@ -1282,8 +1290,8 @@
 
         Raise exception unless overridden.
         """
-        raise NotImplementedError('departing unknown node type: %s'
-                                  % node.__class__.__name__)
+        raise NotImplementedError('%s departing unknown node type: %s'
+                                  % (self.__class__, node.__class__.__name__))
 
 
 class SparseNodeVisitor(NodeVisitor):
@@ -1295,16 +1303,6 @@
     subclasses), subclass `NodeVisitor` instead.
     """
 
-def _nop(self, node):
-    pass
-
-# Save typing with dynamic assignments:
-for _name in node_class_names:
-    setattr(SparseNodeVisitor, "visit_" + _name, _nop)
-    setattr(SparseNodeVisitor, "depart_" + _name, _nop)
-del _name, _nop
-
-
 class GenericNodeVisitor(NodeVisitor):
 
     """
@@ -1337,13 +1335,19 @@
 def _call_default_departure(self, node):
     self.default_departure(node)
 
-# Save typing with dynamic assignments:
-for _name in node_class_names:
-    setattr(GenericNodeVisitor, "visit_" + _name, _call_default_visit)
-    setattr(GenericNodeVisitor, "depart_" + _name, _call_default_departure)
-del _name, _call_default_visit, _call_default_departure
+def _nop(self, node):
+    pass
 
+def _add_node_class_names(names):
+    """Save typing with dynamic assignments:"""
+    for _name in names:
+        setattr(GenericNodeVisitor, "visit_" + _name, _call_default_visit)
+        setattr(GenericNodeVisitor, "depart_" + _name, _call_default_departure)
+        setattr(SparseNodeVisitor, 'visit_' + _name, _nop)
+        setattr(SparseNodeVisitor, 'depart' + _name, _nop)
 
+_add_node_class_names(node_class_names)
+
 class TreeCopyVisitor(GenericNodeVisitor):
 
     """

Modified: Zope/trunk/lib/python/docutils/parsers/__init__.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/__init__.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/__init__.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:06 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:45 $
 # Copyright: This module has been placed in the public domain.
 
 """

Modified: Zope/trunk/lib/python/docutils/parsers/rst/__init__.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/__init__.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/__init__.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:07:46 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:46 $
 # Copyright: This module has been placed in the public domain.
 
 """

Modified: Zope/trunk/lib/python/docutils/parsers/rst/directives/__init__.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/directives/__init__.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/directives/__init__.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.6 $
-# Date: $Date: 2003/11/30 15:06:06 $
+# Revision: $Revision: 1.2.10.4.8.1 $
+# Date: $Date: 2004/05/12 19:57:48 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -102,6 +102,7 @@
       'epigraph': ('body', 'epigraph'),
       'highlights': ('body', 'highlights'),
       'pull-quote': ('body', 'pull_quote'),
+      'table': ('body', 'table'),
       #'questions': ('body', 'question_list'),
       'image': ('images', 'image'),
       'figure': ('images', 'figure'),
@@ -117,6 +118,7 @@
       'replace': ('misc', 'replace'),
       'unicode': ('misc', 'unicode_directive'),
       'class': ('misc', 'class_directive'),
+      'role': ('misc', 'role'),
       'restructuredtext-test-directive': ('misc', 'directive_test_function'),}
 """Mapping of directive name to (module name, function name).  The directive
 name is canonical & must be lowercase.  Language-dependent names are defined
@@ -165,23 +167,37 @@
     try:
         modulename, functionname = _directive_registry[canonicalname]
     except KeyError:
+        messages.append(document.reporter.error(
+            'Directive "%s" not registered (canonical name "%s").'
+            % (directive_name, canonicalname), line=document.current_line))
         return None, messages
     if _modules.has_key(modulename):
         module = _modules[modulename]
     else:
         try:
             module = __import__(modulename, globals(), locals())
-        except ImportError:
+        except ImportError, detail:
+            messages.append(document.reporter.error(
+                'Error importing directive module "%s" (directive "%s"):\n%s'
+                % (modulename, directive_name, detail),
+                line=document.current_line))
             return None, messages
     try:
         function = getattr(module, functionname)
         _directives[normname] = function
     except AttributeError:
+        messages.append(document.reporter.error(
+            'No function "%s" in module "%s" (directive "%s").'
+            % (functionname, modulename, directive_name),
+            line=document.current_line))
         return None, messages
     return function, messages
 
 def register_directive(name, directive):
-    """Register a nonstandard application-defined directive function."""
+    """
+    Register a nonstandard application-defined directive function.
+    Language lookups are not needed for such functions.
+    """
     _directives[name] = directive
 
 def flag(argument):
@@ -257,7 +273,10 @@
     """
     if argument is None:
         raise ValueError('argument required but none supplied')
-    return nodes.make_id(argument)
+    class_name = nodes.make_id(argument)
+    if not class_name:
+        raise ValueError('cannot make "%s" into a class name' % argument)
+    return class_name
 
 def format_values(values):
     return '%s, or "%s"' % (', '.join(['"%s"' % s for s in values[:-1]]),

Modified: Zope/trunk/lib/python/docutils/parsers/rst/directives/admonitions.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/directives/admonitions.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/directives/admonitions.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:06 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:48 $
 # Copyright: This module has been placed in the public domain.
 
 """

Modified: Zope/trunk/lib/python/docutils/parsers/rst/directives/body.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/directives/body.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/directives/body.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:06 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:48 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -34,6 +34,7 @@
     title_text = arguments[0]
     textnodes, messages = state.inline_text(title_text, lineno)
     titles = [nodes.title(title_text, '', *textnodes)]
+    # sidebar uses this code
     if options.has_key('subtitle'):
         textnodes, more_messages = state.inline_text(options['subtitle'],
                                                      lineno)
@@ -120,3 +121,38 @@
     return [block_quote] + messages
 
 pull_quote.content = 1
+
+def table(name, arguments, options, content, lineno,
+          content_offset, block_text, state, state_machine):
+    if not content:
+        warning = state_machine.reporter.warning(
+            'Content block expected for the "%s" directive; none found.'
+            % name, nodes.literal_block(block_text, block_text),
+            line=lineno)
+        return [warning]
+    if arguments:
+        title_text = arguments[0]
+        text_nodes, messages = state.inline_text(title_text, lineno)
+        title = nodes.title(title_text, '', *text_nodes)
+    else:
+        title = None
+    node = nodes.Element()          # anonymous container for parsing
+    text = '\n'.join(content)
+    state.nested_parse(content, content_offset, node)
+    if len(node) != 1 or not isinstance(node[0], nodes.table):
+        error = state_machine.reporter.error(
+            'Error parsing content block for the "%s" directive: '
+            'exactly one table expected.'
+            % name, nodes.literal_block(block_text, block_text),
+            line=lineno)
+        return [error]
+    table_node = node[0]
+    if options.has_key('class'):
+        table_node.set_class(options['class'])
+    if title:
+        table_node.insert(0, title)
+    return [table_node]
+
+table.arguments = (0, 1, 1)
+table.options = {'class': directives.class_option}
+table.content = 1

Modified: Zope/trunk/lib/python/docutils/parsers/rst/directives/html.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/directives/html.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/directives/html.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:06 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:48 $
 # Copyright: This module has been placed in the public domain.
 
 """

Modified: Zope/trunk/lib/python/docutils/parsers/rst/directives/images.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/directives/images.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/directives/images.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:06 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:48 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -13,7 +13,8 @@
 
 import sys
 from docutils import nodes, utils
-from docutils.parsers.rst import directives
+from docutils.parsers.rst import directives, states
+from docutils.nodes import whitespace_normalize_name
 
 try:
     import Image                        # PIL
@@ -34,8 +35,23 @@
               nodes.literal_block(block_text, block_text), line=lineno)
         return [error]
     options['uri'] = reference
-    image_node = nodes.image(block_text, **options)
-    return [image_node]
+    if options.has_key('target'):
+        block = states.escape2null(options['target']).splitlines()
+        block = [line for line in block]
+        target_type, data = state.parse_target(block, block_text, lineno)
+        if target_type == 'refuri':
+            node_list = nodes.reference(refuri=data)
+        elif target_type == 'refname':
+            node_list = nodes.reference(
+                refname=data, name=whitespace_normalize_name(options['target']))
+            state.document.note_refname(node_list)
+        else:                           # malformed target
+            node_list = [data]          # data is a system message
+        del options['target']
+    else:
+        node_list = []
+    node_list.append(nodes.image(block_text, **options))
+    return node_list
 
 image.arguments = (1, 0, 1)
 image.options = {'alt': directives.unchanged,
@@ -43,6 +59,7 @@
                  'width': directives.nonnegative_int,
                  'scale': directives.nonnegative_int,
                  'align': align,
+                 'target': directives.unchanged_required,
                  'class': directives.class_option}
 
 def figure(name, arguments, options, content, lineno,

Modified: Zope/trunk/lib/python/docutils/parsers/rst/directives/misc.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/directives/misc.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/directives/misc.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Authors: David Goodger, Dethe Elza
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:06 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:48 $
 # Copyright: This module has been placed in the public domain.
 
 """Miscellaneous directives."""
@@ -11,12 +11,16 @@
 import sys
 import os.path
 import re
-from urllib2 import urlopen, URLError
 from docutils import io, nodes, statemachine, utils
-from docutils.parsers.rst import directives, states
+from docutils.parsers.rst import directives, roles, states
 from docutils.transforms import misc
 
+try:
+    import urllib2
+except ImportError:
+    urllib2 = None
 
+
 def include(name, arguments, options, content, lineno,
             content_offset, block_text, state, state_machine):
     """Include a reST file as part of the content of this reST file."""
@@ -97,9 +101,16 @@
         raw_file.close()
         attributes['source'] = path
     elif options.has_key('url'):
+        if not urllib2:
+            severe = state_machine.reporter.severe(
+                  'Problems with the "%s" directive and its "url" option: '
+                  'unable to access the required functionality (from the '
+                  '"urllib2" module).' % name,
+                  nodes.literal_block(block_text, block_text), line=lineno)
+            return [severe]
         try:
-            raw_file = urlopen(options['url'])
-        except (URLError, IOError, OSError), error:
+            raw_file = urllib2.urlopen(options['url'])
+        except (urllib2.URLError, IOError, OSError), error:
             severe = state_machine.reporter.severe(
                   'Problems with "%s" directive URL "%s":\n%s.'
                   % (name, options['url'], error),
@@ -209,7 +220,7 @@
         return [pending]
     else:
         error = state_machine.reporter.error(
-            'Invalid class attribute value for "%s" directive: %s'
+            'Invalid class attribute value for "%s" directive: "%s".'
             % (name, arguments[0]),
             nodes.literal_block(block_text, block_text), line=lineno)
         return [error]
@@ -217,8 +228,67 @@
 class_directive.arguments = (1, 0, 0)
 class_directive.content = 1
 
+role_arg_pat = re.compile(r'(%s)\s*(\(\s*(%s)\s*\)\s*)?$'
+                          % ((states.Inliner.simplename,) * 2))
+def role(name, arguments, options, content, lineno,
+         content_offset, block_text, state, state_machine):
+    """Dynamically create and register a custom interpreted text role."""
+    if content_offset > lineno or not content:
+        error = state_machine.reporter.error(
+            '"%s" directive requires arguments on the first line.'
+            % name, nodes.literal_block(block_text, block_text), line=lineno)
+        return [error]
+    args = content[0]
+    match = role_arg_pat.match(args)
+    if not match:
+        error = state_machine.reporter.error(
+            '"%s" directive arguments not valid role names: "%s".'
+            % (name, args), nodes.literal_block(block_text, block_text),
+            line=lineno)
+        return [error]
+    new_role_name = match.group(1)
+    base_role_name = match.group(3)
+    messages = []
+    if base_role_name:
+        base_role, messages = roles.role(
+            base_role_name, state_machine.language, lineno, state.reporter)
+        if base_role is None:
+            error = state.reporter.error(
+                'Unknown interpreted text role "%s".' % base_role_name,
+                nodes.literal_block(block_text, block_text), line=lineno)
+            return messages + [error]
+    else:
+        base_role = roles.generic_custom_role
+    assert not hasattr(base_role, 'arguments'), ( 
+        'Supplemental directive arguments for "%s" directive not supported'
+        '(specified by "%r" role).' % (name, base_role))
+    try:
+        (arguments, options, content, content_offset) = (
+            state.parse_directive_block(content[1:], content_offset, base_role,
+                                        option_presets={}))
+    except states.MarkupError, detail:
+        error = state_machine.reporter.error(
+            'Error in "%s" directive:\n%s.' % (name, detail),
+            nodes.literal_block(block_text, block_text), line=lineno)
+        return messages + [error]
+    if not options.has_key('class'):
+        try:
+            options['class'] = directives.class_option(new_role_name)
+        except ValueError, detail:
+            error = state_machine.reporter.error(
+                'Invalid argument for "%s" directive:\n%s.'
+                % (name, detail),
+                nodes.literal_block(block_text, block_text), line=lineno)
+            return messages + [error]
+    role = roles.CustomRole(new_role_name, base_role, options, content)
+    roles.register_local_role(new_role_name, role)
+    return messages
+
+role.content = 1
+
 def directive_test_function(name, arguments, options, content, lineno,
                             content_offset, block_text, state, state_machine):
+    """This directive is useful only for testing purposes."""
     if content:
         text = '\n'.join(content)
         info = state_machine.reporter.info(

Modified: Zope/trunk/lib/python/docutils/parsers/rst/directives/parts.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/directives/parts.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/directives/parts.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger, Dmitry Jemerov
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:06 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:48 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -10,7 +10,7 @@
 
 __docformat__ = 'reStructuredText'
 
-from docutils import nodes
+from docutils import nodes, languages
 from docutils.transforms import parts
 from docutils.parsers.rst import directives
 
@@ -27,17 +27,42 @@
 def contents(name, arguments, options, content, lineno,
              content_offset, block_text, state, state_machine):
     """Table of contents."""
+    document = state_machine.document
+    language = languages.get_language(document.settings.language_code)
+
     if arguments:
         title_text = arguments[0]
         text_nodes, messages = state.inline_text(title_text, lineno)
         title = nodes.title(title_text, '', *text_nodes)
     else:
         messages = []
-        title = None
-    pending = nodes.pending(parts.Contents, {'title': title}, block_text)
+        if options.has_key('local'):
+            title = None
+        else:
+            title = nodes.title('', language.labels['contents'])
+
+    topic = nodes.topic(CLASS='contents')
+
+    cls = options.get('class')
+    if cls:
+        topic.set_class(cls)
+
+    if title:
+        name = title.astext()
+        topic += title
+    else:
+        name = language.labels['contents']
+
+    name = nodes.fully_normalize_name(name)
+    if not document.has_name(name):
+        topic['name'] = name
+    document.note_implicit_target(topic)
+
+    pending = nodes.pending(parts.Contents, rawsource=block_text)
     pending.details.update(options)
-    state_machine.document.note_pending(pending)
-    return [pending] + messages
+    document.note_pending(pending)
+    topic += pending
+    return [topic] + messages
 
 contents.arguments = (0, 1, 1)
 contents.options = {'depth': directives.nonnegative_int,

Modified: Zope/trunk/lib/python/docutils/parsers/rst/directives/references.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/directives/references.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/directives/references.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger, Dmitry Jemerov
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:06 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:48 $
 # Copyright: This module has been placed in the public domain.
 
 """

Modified: Zope/trunk/lib/python/docutils/parsers/rst/languages/__init__.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/__init__.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/__init__.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:07 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:50 $
 # Copyright: This module has been placed in the public domain.
 
 # Internationalization details are documented in

Modified: Zope/trunk/lib/python/docutils/parsers/rst/languages/af.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/af.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/af.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: Jannie Hofmeyr
 # Contact: jhsh at sun.ac.za
-# Revision: $Revision: 1.3 $
-# Date: $Date: 2003/11/30 15:06:07 $
+# Revision: $Revision: 1.1.2.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:50 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please
@@ -36,6 +36,7 @@
       'epigraaf': 'epigraph',
       'hoogtepunte': 'highlights',
       'pull-quote (translation required)': 'pull-quote',
+      'table (translation required)': 'table',
       #'vrae': 'questions',
       #'qa': 'questions',
       #'faq': 'questions',
@@ -48,6 +49,7 @@
       'vervang': 'replace',
       'unicode': 'unicode', # should this be translated? unikode
       'klas': 'class',
+      'role (translation required)': 'role',
       'inhoud': 'contents',
       'sectnum': 'sectnum',
       'section-numbering': 'sectnum',

Added: Zope/trunk/lib/python/docutils/parsers/rst/languages/cs.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/cs.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/cs.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -0,0 +1,96 @@
+# Author: Marek Blaha
+# Contact: mb at dat.cz
+# Revision: $Revision: 1.1.2.1 $
+# Date: $Date: 2004/05/12 19:57:50 $
+# Copyright: This module has been placed in the public domain.
+
+# New language mappings are welcome.  Before doing a new translation, please
+# read <http://docutils.sf.net/spec/howto/i18n.html>.  Two files must be
+# translated for each language: one in docutils/languages, the other in
+# docutils/parsers/rst/languages.
+
+"""
+Czech-language mappings for language-dependent features of
+reStructuredText.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+directives = {
+      # language-dependent: fixed
+      u'pozor': 'attention',
+      u'caution': 'caution',       # jak rozlisit caution a warning?
+      u'nebezpe\u010D\u00ED': 'danger',
+      u'chyba': 'error',
+      u'rada': 'hint',
+      u'd\u016Fle\u017Eit\u00E9': 'important',
+      u'pozn\u00E1mka': 'note',
+      u'tip': 'tip',
+      u'varov\u00E1n\u00ED': 'warning',
+      u'admonition': 'admonition',
+      u'sidebar': 'sidebar',
+      u't\u00E9ma': 'topic',
+      u'line-block': 'line-block',
+      u'parsed-literal': 'parsed-literal',
+      u'odd\u00EDl': 'rubric',
+      u'moto': 'epigraph',
+      u'highlights': 'highlights',
+      u'pull-quote': 'pull-quote',
+      u'table (translation required)': 'table',
+      #'questions': 'questions',
+      #'qa': 'questions',
+      #'faq': 'questions',
+      u'meta': 'meta',
+      #'imagemap': 'imagemap',
+      u'image': 'image',   # obrazek
+      u'figure': 'figure', # a tady?
+      u'include': 'include',
+      u'raw': 'raw',
+      u'replace': 'replace',
+      u'unicode': 'unicode',
+      u't\u0159\u00EDda': 'class',
+      u'role (translation required)': 'role',
+      u'obsah': 'contents',
+      u'sectnum': 'sectnum',
+      u'section-numbering': 'sectnum',
+      #'footnotes': 'footnotes',
+      #'citations': 'citations',
+      u'target-notes': 'target-notes',
+      u'restructuredtext-test-directive': 'restructuredtext-test-directive'}
+"""Czech name to registered (in directives/__init__.py) directive name
+mapping."""
+
+roles = {
+    # language-dependent: fixed
+    u'abbreviation': 'abbreviation',
+    u'ab': 'abbreviation',
+    u'acronym': 'acronym',
+    u'ac': 'acronym',
+    u'index': 'index',
+    u'i': 'index',
+    u'subscript': 'subscript',
+    u'sub': 'subscript',
+    u'superscript': 'superscript',
+    u'sup': 'superscript',
+    u'title-reference': 'title-reference',
+    u'title': 'title-reference',
+    u't': 'title-reference',
+    u'pep-reference': 'pep-reference',
+    u'pep': 'pep-reference',
+    u'rfc-reference': 'rfc-reference',
+    u'rfc': 'rfc-reference',
+    u'emphasis': 'emphasis',
+    u'strong': 'strong',
+    u'literal': 'literal',
+    u'named-reference': 'named-reference',
+    u'anonymous-reference': 'anonymous-reference',
+    u'footnote-reference': 'footnote-reference',
+    u'citation-reference': 'citation-reference',
+    u'substitution-reference': 'substitution-reference',
+    u'target': 'target',
+    u'uri-reference': 'uri-reference',
+    u'uri': 'uri-reference',
+    u'url': 'uri-reference',}
+"""Mapping of Czech role names to canonical role names for interpreted text.
+"""

Modified: Zope/trunk/lib/python/docutils/parsers/rst/languages/de.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/de.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/de.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,8 +1,8 @@
 # -*- coding: iso-8859-1 -*-
 # Author: Engelbert Gruber
 # Contact: grubert at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:07 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:50 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please
@@ -37,6 +37,7 @@
       'epigraph (translation required)': 'epigraph',
       'highlights (translation required)': 'highlights',
       'pull-quote (translation required)': 'pull-quote', # kasten too ?
+      'table (translation required)': 'table',
       #'questions': 'questions',
       #'qa': 'questions',
       #'faq': 'questions',
@@ -49,7 +50,8 @@
                             # einfügung would be the noun. 
       'ersetzung': 'replace', # ersetzen, ersetze
       'unicode': 'unicode',
-      'klasse': 'class',    # offer class too ?
+      'klasse': 'class',    # offer "class" too ?
+      'role (translation required)': 'role',
       'inhalt': 'contents',
       'sectnum': 'sectnum',
       'section-numbering': 'sectnum',

Modified: Zope/trunk/lib/python/docutils/parsers/rst/languages/en.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/en.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/en.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:07 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:50 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please
@@ -37,6 +37,7 @@
       'epigraph': 'epigraph',
       'highlights': 'highlights',
       'pull-quote': 'pull-quote',
+      'table': 'table',
       #'questions': 'questions',
       #'qa': 'questions',
       #'faq': 'questions',
@@ -49,6 +50,7 @@
       'replace': 'replace',
       'unicode': 'unicode',
       'class': 'class',
+      'role': 'role',
       'contents': 'contents',
       'sectnum': 'sectnum',
       'section-numbering': 'sectnum',

Modified: Zope/trunk/lib/python/docutils/parsers/rst/languages/eo.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/eo.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/eo.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: Marcelo Huerta San Martin
 # Contact: richieadler at users.sourceforge.net
-# Revision: $Revision: 1.1 $
-# Date: $Date: 2003/11/30 15:06:07 $
+# Revision: $Revision: 1.1.2.1.8.1 $
+# Date: $Date: 2004/05/12 19:57:50 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please
@@ -40,6 +40,7 @@
       u'elstara\u0135oj': 'highlights',
       u'ekstera-citajxo': 'pull-quote',
       u'ekstera-cita\u0135o': 'pull-quote',
+      u'tabelo': 'table',
       #'questions': 'questions',
       #'qa': 'questions',
       #'faq': 'questions',
@@ -53,6 +54,7 @@
       u'anstata\u016di': 'replace',
       u'unicode': 'unicode',
       u'klaso': 'class',
+      u'rolo': 'role',
       u'enhavo': 'contents',
       u'seknum': 'sectnum',
       u'sekcia-numerado': 'sectnum',

Modified: Zope/trunk/lib/python/docutils/parsers/rst/languages/es.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/es.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/es.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,8 +1,8 @@
 # -*- coding: iso-8859-1 -*-
 # Author: Marcelo Huerta San Martín
 # Contact: mghsm at uol.com.ar
-# Revision: $Revision: 1.3 $
-# Date: $Date: 2003/11/30 15:06:07 $
+# Revision: $Revision: 1.1.2.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:51 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please
@@ -42,6 +42,7 @@
       u'epigrafe': 'epigraph',
       u'destacado': 'highlights',
       u'cita-destacada': 'pull-quote',
+      u'tabla': 'table',
       #'questions': 'questions',
       #'qa': 'questions',
       #'faq': 'questions',
@@ -54,6 +55,7 @@
       u'reemplazar': 'replace',
       u'unicode': 'unicode',
       u'clase': 'class',
+      u'rol': 'role',
       u'contenido': 'contents',
       u'numseccion': 'sectnum',
       u'numsecci\u00f3n': 'sectnum',
@@ -74,8 +76,10 @@
     u'ac': 'acronym',
     u'indice': 'index',
     u'i': 'index',
-    u'subscript (translation required)': 'subscript',
-    u'superscript (translation required)': 'superscript',
+    u'subindice': 'subscript',
+    u'sub\u00edndice': 'subscript',
+    u'superindice': 'superscript',
+    u'super\u00edndice': 'superscript',
     u'referencia-titulo': 'title-reference',
     u'titulo': 'title-reference',
     u't': 'title-reference',

Modified: Zope/trunk/lib/python/docutils/parsers/rst/languages/fr.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/fr.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/fr.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Authors: David Goodger; William Dode
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:07 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:51 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please
@@ -38,6 +38,7 @@
       u'\u00E9pigraphe': 'epigraph',
       u'chapeau': 'highlights',
       u'accroche': 'pull-quote',
+      u'tableau': 'table',
       #u'questions': 'questions',
       #u'qr': 'questions',
       #u'faq': 'questions',
@@ -51,6 +52,7 @@
       u'remplace': 'replace',
       u'unicode': 'unicode',
       u'classe': 'class',
+      u'role (translation required)': 'role',
       u'sommaire': 'contents',
       u'table-des-mati\u00E8res': 'contents',
       u'sectnum': 'sectnum',

Modified: Zope/trunk/lib/python/docutils/parsers/rst/languages/it.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/it.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/it.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,14 +1,9 @@
-# Author: Nicola Larosa
-# Contact: docutils at tekNico.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:07 $
+# Author: Nicola Larosa, Lele Gaifax
+# Contact: docutils at tekNico.net, lele at seldati.it
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:51 $
 # Copyright: This module has been placed in the public domain.
 
-# New language mappings are welcome.  Before doing a new translation, please
-# read <http://docutils.sf.net/spec/howto/i18n.html>.  Two files must be
-# translated for each language: one in docutils/languages, the other in
-# docutils/parsers/rst/languages.
-
 """
 Italian-language mappings for language-dependent features of
 reStructuredText.
@@ -27,15 +22,16 @@
       'nota': 'note',
       'consiglio': 'tip',
       'avvertenza': 'warning',
-      'admonition (translation required)': 'admonition',
-      'sidebar (translation required)': 'sidebar',
+      'ammonizione': 'admonition',
+      'riquadro': 'sidebar',
       'argomento': 'topic',
-      'blocco di linee': 'line-block',
-      'parsed-literal': 'parsed-literal',
-      'rubric (translation required)': 'rubric',
-      'epigraph (translation required)': 'epigraph',
-      'highlights (translation required)': 'highlights',
+      'blocco-di-righe': 'line-block',
+      'blocco-interpretato': 'parsed-literal',
+      'rubrica': 'rubric',
+      'epigrafe': 'epigraph',
+      'evidenzia': 'highlights',
       'pull-quote (translation required)': 'pull-quote',
+      'tabella': 'table',
       #'questions': 'questions',
       #'qa': 'questions',
       #'faq': 'questions',
@@ -47,11 +43,12 @@
       'grezzo': 'raw',
       'sostituisci': 'replace',
       'unicode': 'unicode',
-      'class (translation required)': 'class',
+      'classe': 'class',
+      'ruolo': 'role',
       'indice': 'contents',
       'seznum': 'sectnum',
-      'section-numbering': 'sectnum',
-      'target-notes': 'target-notes',
+      'sezioni-autonumerate': 'sectnum',
+      'annota-riferimenti-esterni': 'target-notes',
       #'footnotes': 'footnotes',
       #'citations': 'citations',
       'restructuredtext-test-directive': 'restructuredtext-test-directive'}
@@ -59,23 +56,23 @@
 mapping."""
 
 roles = {
-      'abbreviation (translation required)': 'abbreviation',
-      'acronym (translation required)': 'acronym',
-      'index (translation required)': 'index',
-      'subscript (translation required)': 'subscript',
-      'superscript (translation required)': 'superscript',
-      'title-reference (translation required)': 'title-reference',
-      'pep-reference (translation required)': 'pep-reference',
-      'rfc-reference (translation required)': 'rfc-reference',
-      'emphasis (translation required)': 'emphasis',
-      'strong (translation required)': 'strong',
-      'literal (translation required)': 'literal',
-      'named-reference (translation required)': 'named-reference',
-      'anonymous-reference (translation required)': 'anonymous-reference',
-      'footnote-reference (translation required)': 'footnote-reference',
-      'citation-reference (translation required)': 'citation-reference',
-      'substitution-reference (translation required)': 'substitution-reference',
-      'target (translation required)': 'target',
-      'uri-reference (translation required)': 'uri-reference',}
+      'abbreviazione': 'abbreviation',
+      'acronimo': 'acronym',
+      'indice': 'index',
+      'deponente': 'subscript',
+      'esponente': 'superscript',
+      'riferimento-titolo': 'title-reference',
+      'riferimento-pep': 'pep-reference',
+      'riferimento-rfc': 'rfc-reference',
+      'enfasi': 'emphasis',
+      'forte': 'strong',
+      'letterale': 'literal',
+      'riferimento-con-nome': 'named-reference',
+      'riferimento-anonimo': 'anonymous-reference',
+      'riferimento-nota': 'footnote-reference',
+      'riferimento-citazione': 'citation-reference',
+      'riferimento-sostituzione': 'substitution-reference',
+      'destinazione': 'target',
+      'riferimento-uri': 'uri-reference',}
 """Mapping of Italian role names to canonical role names for interpreted text.
 """

Added: Zope/trunk/lib/python/docutils/parsers/rst/languages/pt_br.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/pt_br.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/pt_br.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -0,0 +1,97 @@
+# -*- coding: iso-8859-1 -*-
+# Author: David Goodger
+# Contact: goodger at users.sourceforge.net
+# Revision: $Revision: 1.1.2.1 $
+# Date: $Date: 2004/05/12 19:57:51 $
+# Copyright: This module has been placed in the public domain.
+
+# New language mappings are welcome.  Before doing a new translation, please
+# read <http://docutils.sf.net/spec/howto/i18n.html>.  Two files must be
+# translated for each language: one in docutils/languages, the other in
+# docutils/parsers/rst/languages.
+
+"""
+Brazilian Portuguese-language mappings for language-dependent features of
+reStructuredText.
+"""
+
+__docformat__ = 'reStructuredText'
+
+
+directives = {
+      # language-dependent: fixed
+      u'atenção': 'attention',
+      'cuidado': 'caution',
+      'perigo': 'danger',
+      'erro': 'error',
+      u'sugestão': 'hint',
+      'importante': 'important',
+      'nota': 'note',
+      'dica': 'tip',
+      'aviso': 'warning',
+      u'exortação': 'admonition',
+      'barra-lateral': 'sidebar',
+      u'tópico': 'topic',
+      'bloco-de-linhas': 'line-block',
+      'literal-interpretado': 'parsed-literal',
+      'rubrica': 'rubric',
+      u'epígrafo': 'epigraph',
+      'destaques': 'highlights',
+      u'citação-destacada': 'pull-quote',
+      u'table (translation required)': 'table',
+      #'perguntas': 'questions',
+      #'qa': 'questions',
+      #'faq': 'questions',
+      'meta': 'meta',
+      #'imagemap': 'imagemap',
+      'imagem': 'image',
+      'figura': 'figure',
+      u'inclusão': 'include',
+      'cru': 'raw',
+      u'substituição': 'replace',
+      'unicode': 'unicode',
+      'classe': 'class',
+      'role (translation required)': 'role',
+      u'índice': 'contents',
+      'numsec': 'sectnum',
+      u'numeração-de-seções': 'sectnum',
+      #u'notas-de-rorapé': 'footnotes',
+      #u'citações': 'citations',
+      u'links-no-rodapé': 'target-notes',
+      'restructuredtext-test-directive': 'restructuredtext-test-directive'}
+"""English name to registered (in directives/__init__.py) directive name
+mapping."""
+
+roles = {
+    # language-dependent: fixed
+    u'abbreviação': 'abbreviation',
+    'ab': 'abbreviation',
+    u'acrônimo': 'acronym',
+    'ac': 'acronym',
+    u'índice-remissivo': 'index',
+    'i': 'index',
+    'subscrito': 'subscript',
+    'sub': 'subscript',
+    'sobrescrito': 'superscript',
+    'sob': 'superscript',
+    u'referência-a-título': 'title-reference',
+    u'título': 'title-reference',
+    't': 'title-reference',
+    u'referência-a-pep': 'pep-reference',
+    'pep': 'pep-reference',
+    u'referência-a-rfc': 'rfc-reference',
+    'rfc': 'rfc-reference',
+    u'ênfase': 'emphasis',
+    'forte': 'strong',
+    'literal': 'literal',
+    u'referência-por-nome': 'named-reference',
+    u'referência-anônima': 'anonymous-reference',
+    u'referência-a-nota-de-rodapé': 'footnote-reference',
+    u'referência-a-citação': 'citation-reference',
+    u'referência-a-substituição': 'substitution-reference',
+    'alvo': 'target',
+    u'referência-a-uri': 'uri-reference',
+    'uri': 'uri-reference',
+    'url': 'uri-reference',}
+"""Mapping of English role names to canonical role names for interpreted text.
+"""

Modified: Zope/trunk/lib/python/docutils/parsers/rst/languages/ru.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/ru.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/ru.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: Roman Suzi
 # Contact: rnd at onego.ru
-# Revision: $Revision: 1.3 $
-# Date: $Date: 2003/11/30 15:06:07 $
+# Revision: $Revision: 1.1.2.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:51 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please
@@ -23,6 +23,7 @@
  u'parsed-literal',
  u'\u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u0430\u044f-\u0446\u0438\u0442\u0430\u0442\u0430':
  u'pull-quote',
+ u'table (translation required)': 'table',
  u'\u0441\u044b\u0440\u043e\u0439': u'raw',
  u'\u0437\u0430\u043c\u0435\u043d\u0430': u'replace',
  u'\u0442\u0435\u0441\u0442\u043e\u0432\u0430\u044f-\u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u0430-restructuredtext':
@@ -40,6 +41,7 @@
  u'\u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435':
  u'image',
  u'\u043a\u043b\u0430\u0441\u0441': u'class',
+ u'role (translation required)': 'role',
  u'\u043d\u043e\u043c\u0435\u0440-\u0440\u0430\u0437\u0434\u0435\u043b\u0430':
  u'sectnum',
  u'\u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u044f-\u0440\u0430\u0437'

Modified: Zope/trunk/lib/python/docutils/parsers/rst/languages/sk.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/sk.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/sk.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: Miroslav Vasko
 # Contact: zemiak at zoznam.sk
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:07 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:51 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please
@@ -36,6 +36,7 @@
       u'epigraph (translation required)': 'epigraph',
       u'highlights (translation required)': 'highlights',
       u'pull-quote (translation required)': 'pull-quote',
+      u'table (translation required)': 'table',
       #u'questions': 'questions',
       #u'qa': 'questions',
       #u'faq': 'questions',
@@ -48,6 +49,7 @@
       u'nahradi\x9d': 'replace',
       u'unicode': 'unicode',
       u'class (translation required)': 'class',
+      u'role (translation required)': 'role',
       u'obsah': 'contents',
       u'\xe8as\x9d': 'sectnum',
       u'\xe8as\x9d-\xe8\xedslovanie': 'sectnum',

Modified: Zope/trunk/lib/python/docutils/parsers/rst/languages/sv.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/languages/sv.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/languages/sv.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author:    Adam Chodorowski
 # Contact:   chodorowski at users.sourceforge.net
-# Revision:  $Revision: 1.5 $
-# Date:      $Date: 2003/11/30 15:06:07 $
+# Revision:  $Revision: 1.2.10.3.8.1 $
+# Date:      $Date: 2004/05/12 19:57:51 $
 # Copyright: This module has been placed in the public domain.
 
 # New language mappings are welcome.  Before doing a new translation, please
@@ -35,6 +35,7 @@
       u'epigraph (translation required)': 'epigraph',
       u'highlights (translation required)': 'highlights',
       u'pull-quote (translation required)': 'pull-quote',
+      u'table (translation required)': 'table',
       # u'fr\u00e5gor': 'questions',
       # NOTE: A bit long, but recommended by http://www.nada.kth.se/dataterm/:
       # u'fr\u00e5gor-och-svar': 'questions',
@@ -48,6 +49,7 @@
       u'ers\u00e4tt': 'replace', 
       u'unicode': 'unicode',
       u'class (translation required)': 'class',
+      u'role (translation required)': 'role',
       u'inneh\u00e5ll': 'contents',
       u'sektionsnumrering': 'sectnum',
       u'target-notes (translation required)': 'target-notes',

Added: Zope/trunk/lib/python/docutils/parsers/rst/roles.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/roles.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/roles.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -0,0 +1,312 @@
+# Author: Edward Loper
+# Contact: edloper at gradient.cis.upenn.edu
+# Revision: $Revision: 1.1.2.1 $
+# Date: $Date: 2004/05/12 19:57:46 $
+# Copyright: This module has been placed in the public domain.
+
+"""
+This module defines standard interpreted text role functions, a registry for
+interpreted text roles, and an API for adding to and retrieving from the
+registry.
+
+The interface for interpreted role functions is as follows::
+
+    def role_fn(name, rawtext, text, lineno, inliner,
+                options={}, content=[]):
+        code...
+
+    # Set function attributes for customization:
+    role_fn.options = ...
+    role_fn.content = ...
+
+Parameters:
+
+- ``name`` is the local name of the interpreted text role, the role name
+  actually used in the document.
+
+- ``rawtext`` is a string containing the entire interpreted text construct.
+  Return it as a ``problematic`` node linked to a system message if there is a
+  problem.
+
+- ``text`` is the interpreted text content.
+
+- ``lineno`` is the line number where the interpreted text beings.
+
+- ``inliner`` is the Inliner object that called the role function.
+  It defines the following useful attributes: ``reporter``,
+  ``problematic``, ``memo``, ``parent``, ``document``.
+
+- ``options``: A dictionary of directive options for customization, to be
+  interpreted by the role function.  Used for additional attributes for the
+  generated elements and other functionality.
+
+- ``content``: A list of strings, the directive content for customization
+  ("role" directive).  To be interpreted by the role function.
+
+Function attributes for customization, interpreted by the "role" directive:
+
+- ``options``: A dictionary, mapping known option names to conversion
+  functions such as `int` or `float`.  ``None`` or an empty dict implies no
+  options to parse.  Several directive option conversion functions are defined
+  in the `directives` module.
+
+  All role functions implicitly support the "class" option, unless disabled
+  with an explicit ``{'class': None}``.
+
+- ``content``: A boolean; true if content is allowed.  Client code must handle
+  the case where content is required but not supplied (an empty content list
+  will be supplied).
+
+Note that unlike directives, the "arguments" function attribute is not
+supported for role customization.  Directive arguments are handled by the
+"role" directive itself.
+
+Interpreted role functions return a tuple of two values:
+
+- A list of nodes which will be inserted into the document tree at the
+  point where the interpreted role was encountered (can be an empty
+  list).
+
+- A list of system messages, which will be inserted into the document tree
+  immediately after the end of the current inline block (can also be empty).
+"""
+
+__docformat__ = 'reStructuredText'
+
+from docutils import nodes
+from docutils.parsers.rst import directives
+from docutils.parsers.rst.languages import en as _fallback_language_module
+
+DEFAULT_INTERPRETED_ROLE = 'title-reference'
+"""
+The canonical name of the default interpreted role.  This role is used
+when no role is specified for a piece of interpreted text.
+"""
+
+_role_registry = {}
+"""Mapping of canonical role names to role functions.  Language-dependent role
+names are defined in the ``language`` subpackage."""
+
+_roles = {}
+"""Mapping of local or language-dependent interpreted text role names to role
+functions."""
+
+def role(role_name, language_module, lineno, reporter):
+    """
+    Locate and return a role function from its language-dependent name, along
+    with a list of system messages.  If the role is not found in the current
+    language, check English.  Return a 2-tuple: role function (``None`` if the
+    named role cannot be found) and a list of system messages.
+    """
+    normname = role_name.lower()
+    messages = []
+    msg_text = []
+
+    if _roles.has_key(normname):
+        return _roles[normname], messages
+
+    if role_name:
+        canonicalname = None
+        try:
+            canonicalname = language_module.roles[normname]
+        except AttributeError, error:
+            msg_text.append('Problem retrieving role entry from language '
+                            'module %r: %s.' % (language_module, error))
+        except KeyError:
+            msg_text.append('No role entry for "%s" in module "%s".'
+                            % (role_name, language_module.__name__))
+    else:
+        canonicalname = DEFAULT_INTERPRETED_ROLE
+
+    # If we didn't find it, try English as a fallback.
+    if not canonicalname:
+        try:
+            canonicalname = _fallback_language_module.roles[normname]
+            msg_text.append('Using English fallback for role "%s".'
+                            % role_name)
+        except KeyError:
+            msg_text.append('Trying "%s" as canonical role name.'
+                            % role_name)
+            # The canonical name should be an English name, but just in case:
+            canonicalname = normname
+
+    # Collect any messages that we generated.
+    if msg_text:
+        message = reporter.info('\n'.join(msg_text), line=lineno)
+        messages.append(message)
+
+    # Look the role up in the registry, and return it.
+    if _role_registry.has_key(canonicalname):
+        role_fn = _role_registry[canonicalname]
+        register_local_role(normname, role_fn)
+        return role_fn, messages
+    else:
+        return None, messages # Error message will be generated by caller.
+
+def register_canonical_role(name, role_fn):
+    """
+    Register an interpreted text role by its canonical name.
+
+    :Parameters:
+      - `name`: The canonical name of the interpreted role.
+      - `role_fn`: The role function.  See the module docstring.
+    """
+    set_implicit_options(role_fn)
+    _role_registry[name] = role_fn
+
+def register_local_role(name, role_fn):
+    """
+    Register an interpreted text role by its local or language-dependent name.
+
+    :Parameters:
+      - `name`: The local or language-dependent name of the interpreted role.
+      - `role_fn`: The role function.  See the module docstring.
+    """
+    set_implicit_options(role_fn)
+    _roles[name] = role_fn
+
+def set_implicit_options(role_fn):
+    """
+    Add customization options to role functions, unless explicitly set or
+    disabled.
+    """
+    if not hasattr(role_fn, 'options') or role_fn.options is None:
+        role_fn.options = {'class': directives.class_option}
+    elif not role_fn.options.has_key('class'):
+        role_fn.options['class'] = directives.class_option    
+
+def register_generic_role(canonical_name, node_class):
+    """For roles which simply wrap a given `node_class` around the text."""
+    role = GenericRole(canonical_name, node_class)
+    register_canonical_role(canonical_name, role)
+
+
+class GenericRole:
+
+    """
+    Generic interpreted text role, where the interpreted text is simply
+    wrapped with the provided node class.
+    """
+
+    def __init__(self, role_name, node_class):
+        self.name = role_name
+        self.node_class = node_class
+
+    def __call__(self, role, rawtext, text, lineno, inliner,
+                 options={}, content=[]):
+        return [self.node_class(rawtext, text, **options)], []
+
+
+class CustomRole:
+
+    """
+    Wrapper for custom interpreted text roles.
+    """
+
+    def __init__(self, role_name, base_role, options={}, content=[]):
+        self.name = role_name
+        self.base_role = base_role
+        self.options = None
+        if hasattr(base_role, 'options'):
+            self.options = base_role.options
+        self.content = None
+        if hasattr(base_role, 'content'):
+            self.content = base_role.content
+        self.supplied_options = options
+        self.supplied_content = content
+
+    def __call__(self, role, rawtext, text, lineno, inliner,
+                 options={}, content=[]):
+        opts = self.supplied_options.copy()
+        opts.update(options)
+        cont = list(self.supplied_content)
+        if cont and content:
+            cont += '\n'
+        cont.extend(content)
+        return self.base_role(role, rawtext, text, lineno, inliner,
+                              options=opts, content=cont)
+
+
+def generic_custom_role(role, rawtext, text, lineno, inliner,
+                        options={}, content=[]):
+    """"""
+    # Once nested inline markup is implemented, this and other methods should
+    # recursively call inliner.nested_parse().
+    return [nodes.inline(rawtext, text, **options)], []
+
+generic_custom_role.options = {'class': directives.class_option}
+
+
+######################################################################
+# Define and register the standard roles:
+######################################################################
+
+register_generic_role('abbreviation', nodes.abbreviation)
+register_generic_role('acronym', nodes.acronym)
+register_generic_role('emphasis', nodes.emphasis)
+register_generic_role('literal', nodes.literal)
+register_generic_role('strong', nodes.strong)
+register_generic_role('subscript', nodes.subscript)
+register_generic_role('superscript', nodes.superscript)
+register_generic_role('title-reference', nodes.title_reference)
+
+def pep_reference_role(role, rawtext, text, lineno, inliner,
+                       options={}, content=[]):
+    try:
+        pepnum = int(text)
+        if pepnum < 0 or pepnum > 9999:
+            raise ValueError
+    except ValueError:
+        msg = inliner.reporter.error(
+            'PEP number must be a number from 0 to 9999; "%s" is invalid.'
+            % text, line=lineno)
+        prb = inliner.problematic(rawtext, rawtext, msg)
+        return [prb], [msg]
+    # Base URL mainly used by inliner.pep_reference; so this is correct:
+    ref = inliner.pep_url % pepnum
+    return [nodes.reference(rawtext, 'PEP ' + text, refuri=ref, **options)], []
+
+register_canonical_role('pep-reference', pep_reference_role)
+
+def rfc_reference_role(role, rawtext, text, lineno, inliner,
+                       options={}, content=[]):
+    try:
+        rfcnum = int(text)
+        if rfcnum <= 0:
+            raise ValueError
+    except ValueError:
+        msg = inliner.reporter.error(
+            'RFC number must be a number greater than or equal to 1; '
+            '"%s" is invalid.' % text, line=lineno)
+        prb = inliner.problematic(rawtext, rawtext, msg)
+        return [prb], [msg]
+    # Base URL mainly used by inliner.rfc_reference, so this is correct:
+    ref = inliner.rfc_url % rfcnum
+    node = nodes.reference(rawtext, 'RFC ' + text, refuri=ref, **options)
+    return [node], []
+
+register_canonical_role('rfc-reference', rfc_reference_role)
+
+
+######################################################################
+# Register roles that are currently unimplemented.
+######################################################################
+
+def unimplemented_role(role, rawtext, text, lineno, inliner, attributes={}):
+    msg = inliner.reporter.error(
+        'Interpreted text role "%s" not implemented.' % role, line=lineno)
+    prb = inliner.problematic(rawtext, rawtext, msg)
+    return [prb], [msg]
+
+register_canonical_role('index', unimplemented_role)
+register_canonical_role('named-reference', unimplemented_role)
+register_canonical_role('anonymous-reference', unimplemented_role)
+register_canonical_role('uri-reference', unimplemented_role)
+register_canonical_role('footnote-reference', unimplemented_role)
+register_canonical_role('citation-reference', unimplemented_role)
+register_canonical_role('substitution-reference', unimplemented_role)
+register_canonical_role('target', unimplemented_role)
+
+# This should remain unimplemented, for testing purposes:
+register_canonical_role('restructuredtext-unimplemented-role',
+                        unimplemented_role)

Modified: Zope/trunk/lib/python/docutils/parsers/rst/states.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/states.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/states.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:07:46 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:46 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -107,13 +107,14 @@
 
 import sys
 import re
-from docutils import roman
+import roman
 from types import TupleType
 from docutils import nodes, statemachine, utils, urischemes
 from docutils import ApplicationError, DataError
 from docutils.statemachine import StateMachineWS, StateWS
 from docutils.nodes import fully_normalize_name as normalize_name
-from docutils.parsers.rst import directives, languages, tableparser
+from docutils.nodes import whitespace_normalize_name
+from docutils.parsers.rst import directives, languages, tableparser, roles
 from docutils.parsers.rst.languages import en as _fallback_language_module
 
 
@@ -274,7 +275,7 @@
         state_machine.unlink()
         new_offset = state_machine.abs_line_offset()
         # No `block.parent` implies disconnected -- lines aren't in sync:
-        if block.parent:
+        if block.parent and (len(block) - block_length) != 0:
             # Adjustment for block if modified in nested parse:
             self.state_machine.next_line(len(block) - block_length)
         return new_offset
@@ -475,46 +476,6 @@
     Parse inline markup; call the `parse()` method.
     """
 
-    _interpreted_roles = {
-        # Values of ``None`` mean "not implemented yet":
-        'title-reference': 'generic_interpreted_role',
-        'abbreviation': 'generic_interpreted_role',
-        'acronym': 'generic_interpreted_role',
-        'index': None,
-        'subscript': 'generic_interpreted_role',
-        'superscript': 'generic_interpreted_role',
-        'emphasis': 'generic_interpreted_role',
-        'strong': 'generic_interpreted_role',
-        'literal': 'generic_interpreted_role',
-        'named-reference': None,
-        'anonymous-reference': None,
-        'uri-reference': None,
-        'pep-reference': 'pep_reference_role',
-        'rfc-reference': 'rfc_reference_role',
-        'footnote-reference': None,
-        'citation-reference': None,
-        'substitution-reference': None,
-        'target': None,
-        'restructuredtext-unimplemented-role': None}
-    """Mapping of canonical interpreted text role name to method name.
-    Initializes a name to bound-method mapping in `__init__`."""
-
-    default_interpreted_role = 'title-reference'
-    """The role to use when no explicit role is given.
-    Override in subclasses."""
-
-    generic_roles = {'abbreviation': nodes.abbreviation,
-                     'acronym': nodes.acronym,
-                     'emphasis': nodes.emphasis,
-                     'literal': nodes.literal,
-                     'strong': nodes.strong,
-                     'subscript': nodes.subscript,
-                     'superscript': nodes.superscript,
-                     'title-reference': nodes.title_reference,}
-    """Mapping of canonical interpreted text role name to node class.
-    Used by the `generic_interpreted_role` method for simple, straightforward
-    roles (simple wrapping; no extra processing)."""
-
     def __init__(self, roles=None):
         """
         `roles` is a mapping of canonical role name to role function or bound
@@ -525,17 +486,6 @@
         """List of (pattern, bound method) tuples, used by
         `self.implicit_inline`."""
 
-        self.interpreted_roles = {}
-        """Mapping of canonical role name to role function or bound method.
-        Items removed from this mapping will be disabled."""
-
-        for canonical, method in self._interpreted_roles.items():
-            if method:
-                self.interpreted_roles[canonical] = getattr(self, method)
-            else:
-                self.interpreted_roles[canonical] = None
-        self.interpreted_roles.update(roles or {})
-
     def init_customizations(self, settings):
         """Setting-based customizations; run when parsing begins."""
         if settings.pep_references:
@@ -546,6 +496,8 @@
                                            self.rfc_reference))
 
     def parse(self, text, lineno, memo, parent):
+        # Needs to be refactored for nested inline markup.
+        # Add nested_parse() method?
         """
         Return 2 lists: nodes (text and inline elements), and system_messages.
 
@@ -601,11 +553,12 @@
     non_whitespace_after = r'(?![ \n])'
     # Alphanumerics with isolated internal [-._] chars (i.e. not 2 together):
     simplename = r'(?:(?!_)\w)+(?:[-._](?:(?!_)\w)+)*'
-    # Valid URI characters (see RFC 2396 & RFC 2732):
-    uric = r"""[-_.!~*'()[\];/:@&=+$,%a-zA-Z0-9]"""
+    # Valid URI characters (see RFC 2396 & RFC 2732);
+    # final \x00 allows backslash escapes in URIs:
+    uric = r"""[-_.!~*'()[\];/:@&=+$,%a-zA-Z0-9\x00]"""
     # Last URI character; same as uric but no punctuation:
     urilast = r"""[_~/a-zA-Z0-9]"""
-    emailc = r"""[-_!~*'{|}/#?^`&=+$%a-zA-Z0-9]"""
+    emailc = r"""[-_!~*'{|}/#?^`&=+$%a-zA-Z0-9\x00]"""
     email_pattern = r"""
           %(emailc)s+(?:\.%(emailc)s+)*   # name
           @                               # at
@@ -659,10 +612,10 @@
           embedded_uri=re.compile(
               r"""
               (
-                [ \n]+                  # spaces or beginning of line
+                (?:[ \n]+|^)            # spaces or beginning of line/string
                 <                       # open bracket
                 %(non_whitespace_after)s
-                ([^<>\0]+)              # anything but angle brackets & nulls
+                ([^<>\x00]+)            # anything but angle brackets & nulls
                 %(non_whitespace_before)s
                 >                       # close bracket w/o whitespace before
               )
@@ -823,26 +776,11 @@
                 return self.phrase_ref(string[:matchstart], string[textend:],
                                        rawsource, escaped, text)
             else:
-                try:
-                    return self.interpreted(
-                        string[:rolestart], string[textend:],
-                        rawsource, text, role, lineno)
-                except UnknownInterpretedRoleError, detail:
-                    msg = self.reporter.error(
-                        'Unknown interpreted text role "%s".' % role,
-                        line=lineno)
-                    text = unescape(string[rolestart:textend], 1)
-                    prb = self.problematic(text, text, msg)
-                    return (string[:rolestart], [prb], string[textend:],
-                            detail.args[0] + [msg])
-                except InterpretedRoleNotImplementedError, detail:
-                    msg = self.reporter.error(
-                        'Interpreted text role "%s" not implemented.' % role,
-                        line=lineno)
-                    text = unescape(string[rolestart:textend], 1)
-                    prb = self.problematic(text, text, msg)
-                    return (string[:rolestart], [prb], string[textend:],
-                            detail.args[0] + [msg])
+                rawsource = unescape(string[rolestart:textend], 1)
+                nodelist, messages = self.interpreted(rawsource, text, role,
+                                                      lineno)
+                return (string[:rolestart], nodelist,
+                        string[textend:], messages)
         msg = self.reporter.warning(
               'Inline interpreted text or phrase reference start-string '
               'without end-string.', line=lineno)
@@ -861,10 +799,13 @@
                 target = nodes.target(match.group(1), refuri=uri)
             else:
                 raise ApplicationError('problem with URI: %r' % uri_text)
+            if not text:
+                text = uri
         else:
             target = None
         refname = normalize_name(text)
-        reference = nodes.reference(rawsource, text)
+        reference = nodes.reference(rawsource, text,
+                                    name=whitespace_normalize_name(text))
         node_list = [reference]
         if rawsource[-2:] == '__':
             if target:
@@ -891,51 +832,19 @@
         else:
             return uri
 
-    def interpreted(self, before, after, rawsource, text, role, lineno):
-        role_function, canonical, messages = self.get_role_function(role,
-                                                                    lineno)
-        if role_function:
-            nodelist, messages2 = role_function(canonical, rawsource, text,
-                                                lineno)
-            messages.extend(messages2)
-            return before, nodelist, after, messages
+    def interpreted(self, rawsource, text, role, lineno):
+        role_fn, messages = roles.role(role, self.language, lineno,
+                                       self.reporter)
+        if role_fn:
+            nodes, messages2 = role_fn(role, rawsource, text, lineno, self)
+            return nodes, messages + messages2
         else:
-            raise InterpretedRoleNotImplementedError(messages)
+            msg = self.reporter.error(
+                'Unknown interpreted text role "%s".' % role,
+                line=lineno)
+            return ([self.problematic(rawsource, rawsource, msg)],
+                    messages + [msg])
 
-    def get_role_function(self, role, lineno):
-        messages = []
-        msg_text = []
-        if role:
-            name = role.lower()
-        else:
-            name = self.default_interpreted_role
-        canonical = None
-        try:
-            canonical = self.language.roles[name]
-        except AttributeError, error:
-            msg_text.append('Problem retrieving role entry from language '
-                            'module %r: %s.' % (self.language, error))
-        except KeyError:
-            msg_text.append('No role entry for "%s" in module "%s".'
-                            % (name, self.language.__name__))
-        if not canonical:
-            try:
-                canonical = _fallback_language_module.roles[name]
-                msg_text.append('Using English fallback for role "%s".'
-                                % name)
-            except KeyError:
-                msg_text.append('Trying "%s" as canonical role name.'
-                                % name)
-                # Should be an English name, but just in case:
-                canonical = name
-        if msg_text:
-            message = self.reporter.info('\n'.join(msg_text), line=lineno)
-            messages.append(message)
-        try:
-            return self.interpreted_roles[canonical], canonical, messages
-        except KeyError:
-            raise UnknownInterpretedRoleError(messages)
-
     def literal(self, match, lineno):
         before, inlines, remaining, sysmessages, endstring = self.inline_obj(
               match, lineno, self.patterns.literal, nodes.literal,
@@ -1014,8 +923,9 @@
     def reference(self, match, lineno, anonymous=None):
         referencename = match.group('refname')
         refname = normalize_name(referencename)
-        referencenode = nodes.reference(referencename + match.group('refend'),
-                                        referencename)
+        referencenode = nodes.reference(
+            referencename + match.group('refend'), referencename,
+            name=whitespace_normalize_name(referencename))
         if anonymous:
             referencenode['anonymous'] = 1
             self.document.note_anonymous_ref(referencenode)
@@ -1104,45 +1014,7 @@
                 '_': reference,
                 '__': anonymous_reference}
 
-    def generic_interpreted_role(self, role, rawtext, text, lineno):
-        try:
-            role_class = self.generic_roles[role]
-        except KeyError:
-            msg = self.reporter.error('Unknown interpreted text role: "%s".'
-                                      % role, line=lineno)
-            prb = self.problematic(text, text, msg)
-            return [prb], [msg]
-        return [role_class(rawtext, text)], []
 
-    def pep_reference_role(self, role, rawtext, text, lineno):
-        try:
-            pepnum = int(text)
-            if pepnum < 0 or pepnum > 9999:
-                raise ValueError
-        except ValueError:
-            msg = self.reporter.error(
-                'PEP number must be a number from 0 to 9999; "%s" is invalid.'
-                % text, line=lineno)
-            prb = self.problematic(text, text, msg)
-            return [prb], [msg]
-        ref = self.pep_url % pepnum
-        return [nodes.reference(rawtext, 'PEP ' + text, refuri=ref)], []
-
-    def rfc_reference_role(self, role, rawtext, text, lineno):
-        try:
-            rfcnum = int(text)
-            if rfcnum <= 0:
-                raise ValueError
-        except ValueError:
-            msg = self.reporter.error(
-                'RFC number must be a number greater than or equal to 1; '
-                '"%s" is invalid.' % text, line=lineno)
-            prb = self.problematic(text, text, msg)
-            return [prb], [msg]
-        ref = self.rfc_url % rfcnum
-        return [nodes.reference(rawtext, 'RFC ' + text, refuri=ref)], []
-
-
 class Body(RSTState):
 
     """
@@ -1472,15 +1344,15 @@
 
     def field_marker(self, match, context, next_state):
         """Field list item."""
-        fieldlist = nodes.field_list()
-        self.parent += fieldlist
+        field_list = nodes.field_list()
+        self.parent += field_list
         field, blank_finish = self.field(match)
-        fieldlist += field
+        field_list += field
         offset = self.state_machine.line_offset + 1   # next line
         newline_offset, blank_finish = self.nested_list_parse(
               self.state_machine.input_lines[offset:],
               input_offset=self.state_machine.abs_line_offset() + 1,
-              node=fieldlist, initial_state='FieldList',
+              node=field_list, initial_state='FieldList',
               blank_finish=blank_finish)
         self.goto_line(newline_offset)
         if not blank_finish:
@@ -1492,14 +1364,15 @@
         lineno = self.state_machine.abs_line_number()
         indented, indent, line_offset, blank_finish = \
               self.state_machine.get_first_known_indented(match.end())
-        fieldnode = nodes.field()
-        fieldnode.line = lineno
-        fieldnode += nodes.field_name(name, name)
-        fieldbody = nodes.field_body('\n'.join(indented))
-        fieldnode += fieldbody
+        field_node = nodes.field()
+        field_node.line = lineno
+        name_nodes, name_messages = self.inline_text(name, lineno)
+        field_node += nodes.field_name(name, '', *name_nodes)
+        field_body = nodes.field_body('\n'.join(indented), *name_messages)
+        field_node += field_body
         if indented:
-            self.parse_field_body(indented, line_offset, fieldbody)
-        return fieldnode, blank_finish
+            self.parse_field_body(indented, line_offset, field_body)
+        return field_node, blank_finish
 
     def parse_field_marker(self, match):
         """Extract & return field name from a field marker match."""
@@ -1876,39 +1749,59 @@
                 raise MarkupError('malformed hyperlink target.', lineno)
         del block[:blockindex]
         block[0] = (block[0] + ' ')[targetmatch.end()-len(escaped)-1:].strip()
+        target = self.make_target(block, blocktext, lineno,
+                                  targetmatch.group('name'))
+        return [target], blank_finish
+
+    def make_target(self, block, block_text, lineno, target_name):
+        target_type, data = self.parse_target(block, block_text, lineno)
+        if target_type == 'refname':
+            target = nodes.target(block_text, '', refname=normalize_name(data))
+            target.indirect_reference_name = data
+            self.add_target(target_name, '', target, lineno)
+            self.document.note_indirect_target(target)
+            return target
+        elif target_type == 'refuri':
+            target = nodes.target(block_text, '')
+            self.add_target(target_name, data, target, lineno)
+            return target
+        else:
+            return data
+
+    def parse_target(self, block, block_text, lineno):
+        """
+        Determine the type of reference of a target.
+
+        :Return: A 2-tuple, one of:
+
+            - 'refname' and the indirect reference name
+            - 'refuri' and the URI
+            - 'malformed' and a system_message node
+        """
         if block and block[-1].strip()[-1:] == '_': # possible indirect target
             reference = ' '.join([line.strip() for line in block])
             refname = self.is_reference(reference)
             if refname:
-                target = nodes.target(blocktext, '', refname=refname)
-                target.line = lineno
-                self.add_target(targetmatch.group('name'), '', target)
-                self.document.note_indirect_target(target)
-                return [target], blank_finish
-        nodelist = []
+                return 'refname', refname
         reference = ''.join([line.strip() for line in block])
-        if reference.find(' ') != -1:
+        if reference.find(' ') == -1:
+            return 'refuri', unescape(reference)
+        else:
             warning = self.reporter.warning(
                   'Hyperlink target contains whitespace. Perhaps a footnote '
                   'was intended?',
-                  nodes.literal_block(blocktext, blocktext), line=lineno)
-            nodelist.append(warning)
-        else:
-            unescaped = unescape(reference)
-            target = nodes.target(blocktext, '')
-            target.line = lineno
-            self.add_target(targetmatch.group('name'), unescaped, target)
-            nodelist.append(target)
-        return nodelist, blank_finish
+                  nodes.literal_block(block_text, block_text), line=lineno)
+            return 'malformed', warning
 
     def is_reference(self, reference):
         match = self.explicit.patterns.reference.match(
-            normalize_name(reference))
+            whitespace_normalize_name(reference))
         if not match:
             return None
         return unescape(match.group('simple') or match.group('phrase'))
 
-    def add_target(self, targetname, refuri, target):
+    def add_target(self, targetname, refuri, target, lineno):
+        target.line = lineno
         if targetname:
             name = normalize_name(unescape(targetname))
             target['name'] = name
@@ -1988,17 +1881,18 @@
             return [msg], blank_finish
 
     def directive(self, match, **option_presets):
+        """Returns a 2-tuple: list of nodes, and a "blank finish" boolean."""
         type_name = match.group(1)
         directive_function, messages = directives.directive(
             type_name, self.memo.language, self.document)
         self.parent += messages
         if directive_function:
-            return self.parse_directive(
+            return self.run_directive(
                 directive_function, match, type_name, option_presets)
         else:
             return self.unknown_directive(type_name)
 
-    def parse_directive(self, directive_fn, match, type_name, option_presets):
+    def run_directive(self, directive_fn, match, type_name, option_presets):
         """
         Parse a directive then run its directive function.
 
@@ -2020,13 +1914,6 @@
 
         Returns a 2-tuple: list of nodes, and a "blank finish" boolean.
         """
-        arguments = []
-        options = {}
-        argument_spec = getattr(directive_fn, 'arguments', None)
-        if argument_spec and argument_spec[:2] == (0, 0):
-            argument_spec = None
-        option_spec = getattr(directive_fn, 'options', None)
-        content_spec = getattr(directive_fn, 'content', None)
         lineno = self.state_machine.abs_line_number()
         initial_line_offset = self.state_machine.line_offset
         indented, indent, line_offset, blank_finish \
@@ -2034,6 +1921,30 @@
                                                                 strip_top=0)
         block_text = '\n'.join(self.state_machine.input_lines[
             initial_line_offset : self.state_machine.line_offset + 1])
+        try:
+            arguments, options, content, content_offset = (
+                self.parse_directive_block(indented, line_offset,
+                                           directive_fn, option_presets))
+        except MarkupError, detail:
+            error = self.reporter.error(
+                'Error in "%s" directive:\n%s.' % (type_name, detail),
+                nodes.literal_block(block_text, block_text), line=lineno)
+            return [error], blank_finish
+        result = directive_fn(type_name, arguments, options, content, lineno,
+                              content_offset, block_text, self,
+                              self.state_machine)
+        return (result,
+                blank_finish or self.state_machine.is_next_line_blank())
+
+    def parse_directive_block(self, indented, line_offset, directive_fn,
+                              option_presets):
+        arguments = []
+        options = {}
+        argument_spec = getattr(directive_fn, 'arguments', None)
+        if argument_spec and argument_spec[:2] == (0, 0):
+            argument_spec = None
+        option_spec = getattr(directive_fn, 'options', None)
+        content_spec = getattr(directive_fn, 'content', None)
         if indented and not indented[0].strip():
             indented.trim_start()
             line_offset += 1
@@ -2055,24 +1966,15 @@
         while content and not content[0].strip():
             content.trim_start()
             content_offset += 1
-        try:
-            if option_spec:
-                options, arg_block = self.parse_directive_options(
-                    option_presets, option_spec, arg_block)
-            if argument_spec:
-                arguments = self.parse_directive_arguments(argument_spec,
-                                                           arg_block)
-            if content and not content_spec:
-                raise MarkupError('no content permitted')
-        except MarkupError, detail:
-            error = self.reporter.error(
-                'Error in "%s" directive:\n%s.' % (type_name, detail),
-                nodes.literal_block(block_text, block_text), line=lineno)
-            return [error], blank_finish
-        result = directive_fn(
-            type_name, arguments, options, content, lineno, content_offset,
-            block_text, self, self.state_machine)
-        return result, blank_finish or self.state_machine.is_next_line_blank()
+        if option_spec:
+            options, arg_block = self.parse_directive_options(
+                option_presets, option_spec, arg_block)
+        if argument_spec:
+            arguments = self.parse_directive_arguments(
+                argument_spec, arg_block)
+        if content and not content_spec:
+            raise MarkupError('no content permitted')
+        return (arguments, options, content, content_offset)
 
     def parse_directive_options(self, option_presets, option_spec, arg_block):
         options = option_presets.copy()
@@ -2251,38 +2153,14 @@
         return [], next_state, []
 
     def anonymous_target(self, match):
+        lineno = self.state_machine.abs_line_number()
         block, indent, offset, blank_finish \
               = self.state_machine.get_first_known_indented(match.end(),
                                                             until_blank=1)
         blocktext = match.string[:match.end()] + '\n'.join(block)
-        if block and block[-1].strip()[-1:] == '_': # possible indirect target
-            reference = escape2null(' '.join([line.strip()
-                                              for line in block]))
-            refname = self.is_reference(reference)
-            if refname:
-                target = nodes.target(blocktext, '', refname=refname,
-                                      anonymous=1)
-                self.document.note_anonymous_target(target)
-                self.document.note_indirect_target(target)
-                return [target], blank_finish
-        nodelist = []
-        reference = escape2null(''.join([line.strip() for line in block]))
-        if reference.find(' ') != -1:
-            lineno = self.state_machine.abs_line_number() - len(block) + 1
-            warning = self.reporter.warning(
-                  'Anonymous hyperlink target contains whitespace. Perhaps a '
-                  'footnote was intended?',
-                  nodes.literal_block(blocktext, blocktext),
-                  line=lineno)
-            nodelist.append(warning)
-        else:
-            target = nodes.target(blocktext, '', anonymous=1)
-            if reference:
-                unescaped = unescape(reference)
-                target['refuri'] = unescaped
-            self.document.note_anonymous_target(target)
-            nodelist.append(target)
-        return nodelist, blank_finish
+        block = [escape2null(line) for line in block]
+        target = self.make_target(block, blocktext, lineno, '')
+        return [target], blank_finish
 
     def line(self, match, context, next_state):
         """Section title overline or transition marker."""
@@ -2660,20 +2538,29 @@
         """Return a list of nodes."""
         indented, indent, offset, blank_finish = \
               self.state_machine.get_indented()
-        nodelist = []
         while indented and not indented[-1].strip():
             indented.trim_end()
-        if indented:
-            data = '\n'.join(indented)
-            nodelist.append(nodes.literal_block(data, data))
-            if not blank_finish:
-                nodelist.append(self.unindent_warning('Literal block'))
-        else:
-            nodelist.append(self.reporter.warning(
-                  'Literal block expected; none found.',
-                  line=self.state_machine.abs_line_number()))
+        if not indented:
+            return self.quoted_literal_block()
+        nodelist = []
+        data = '\n'.join(indented)
+        nodelist.append(nodes.literal_block(data, data))
+        if not blank_finish:
+            nodelist.append(self.unindent_warning('Literal block'))
         return nodelist
 
+    def quoted_literal_block(self):
+        abs_line_offset = self.state_machine.abs_line_offset()
+        offset = self.state_machine.line_offset
+        parent_node = nodes.Element()
+        new_abs_offset = self.nested_parse(
+            self.state_machine.input_lines[offset:],
+            input_offset=abs_line_offset, node=parent_node, match_titles=0,
+            state_machine_kwargs={'state_classes': (QuotedLiteralBlock,),
+                                  'initial_state': 'QuotedLiteralBlock'})
+        self.goto_line(new_abs_offset)
+        return parent_node.children
+
     def definition_list_item(self, termline):
         indented, indent, line_offset, blank_finish = \
               self.state_machine.get_indented()
@@ -2687,8 +2574,8 @@
         definitionlistitem += definition
         if termline[0][-2:] == '::':
             definition += self.reporter.info(
-                  'Blank line missing before literal block? Interpreted as a '
-                  'definition list item.', line=line_offset + 1)
+                  'Blank line missing before literal block (after the "::")? '
+                  'Interpreted as a definition list item.', line=line_offset+1)
         self.nested_parse(indented, input_offset=line_offset, node=definition)
         return definitionlistitem, blank_finish
 
@@ -2890,6 +2777,77 @@
         raise statemachine.StateCorrection('Body', 'text')
 
 
+class QuotedLiteralBlock(RSTState):
+
+    """
+    Nested parse handler for quoted (unindented) literal blocks.
+
+    Special-purpose.  Not for inclusion in `state_classes`.
+    """
+
+    patterns = {'initial_quoted': r'(%(nonalphanum7bit)s)' % Body.pats,
+                'text': r''}
+    initial_transitions = ('initial_quoted', 'text')
+
+    def __init__(self, state_machine, debug=0):
+        RSTState.__init__(self, state_machine, debug)
+        self.messages = []
+        self.initial_lineno = None
+
+    def blank(self, match, context, next_state):
+        if context:
+            raise EOFError
+        else:
+            return context, next_state, []
+
+    def eof(self, context):
+        if context:
+            text = '\n'.join(context)
+            literal_block = nodes.literal_block(text, text)
+            literal_block.line = self.initial_lineno
+            self.parent += literal_block
+        else:
+            self.parent += self.reporter.warning(
+                'Literal block expected; none found.',
+                line=self.state_machine.abs_line_number())
+            self.state_machine.previous_line()
+        self.parent += self.messages
+        return []
+
+    def indent(self, match, context, next_state):
+        assert context, ('QuotedLiteralBlock.indent: context should not '
+                         'be empty!')
+        self.messages.append(
+            self.reporter.error('Unexpected indentation.',
+                                line=self.state_machine.abs_line_number()))
+        self.state_machine.previous_line()
+        raise EOFError
+
+    def initial_quoted(self, match, context, next_state):
+        """Match arbitrary quote character on the first line only."""
+        self.remove_transition('initial_quoted')
+        quote = match.string[0]
+        pattern = re.compile(re.escape(quote))
+        # New transition matches consistent quotes only:
+        self.add_transition('quoted',
+                            (pattern, self.quoted, self.__class__.__name__))
+        self.initial_lineno = self.state_machine.abs_line_number()
+        return [match.string], next_state, []
+
+    def quoted(self, match, context, next_state):
+        """Match consistent quotes on subsequent lines."""
+        context.append(match.string)
+        return context, next_state, []
+
+    def text(self, match, context, next_state):
+        if context:
+            self.messages.append(
+                self.reporter.error('Inconsistent literal block quoting.',
+                                    line=self.state_machine.abs_line_number()))
+            self.state_machine.previous_line()
+        raise EOFError
+
+
 state_classes = (Body, BulletList, DefinitionList, EnumeratedList, FieldList,
                  OptionList, ExtensionOptions, Explicit, Text, Definition,
                  Line, SubstitutionDef, RFC2822Body, RFC2822List)

Modified: Zope/trunk/lib/python/docutils/parsers/rst/tableparser.py
===================================================================
--- Zope/trunk/lib/python/docutils/parsers/rst/tableparser.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/parsers/rst/tableparser.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:07:46 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:47 $
 # Copyright: This module has been placed in the public domain.
 
 """

Modified: Zope/trunk/lib/python/docutils/readers/__init__.py
===================================================================
--- Zope/trunk/lib/python/docutils/readers/__init__.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/readers/__init__.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Authors: David Goodger; Ueli Schlaepfer
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:08 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:52 $
 # Copyright: This module has been placed in the public domain.
 
 """

Modified: Zope/trunk/lib/python/docutils/readers/pep.py
===================================================================
--- Zope/trunk/lib/python/docutils/readers/pep.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/readers/pep.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:08 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:52 $
 # Copyright: This module has been placed in the public domain.
 
 """

Modified: Zope/trunk/lib/python/docutils/readers/python/__init__.py
===================================================================
--- Zope/trunk/lib/python/docutils/readers/python/__init__.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/readers/python/__init__.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.3 $
-# Date: $Date: 2003/11/30 15:06:08 $
+# Revision: $Revision: 1.3.2.1.8.1 $
+# Date: $Date: 2004/05/12 19:57:53 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -13,9 +13,117 @@
 
 import sys
 import docutils.readers
+from docutils.readers.python import moduleparser
+from docutils import parsers
+from docutils import nodes
+from docutils.readers.python import pynodes
+from docutils import readers
 
-
 class Reader(docutils.readers.Reader):
 
     config_section = 'python reader'
     config_section_dependencies = ('readers',)
+
+    default_parser = 'restructuredtext'
+
+    def parse(self):
+        """Parse `self.input` into a document tree."""
+        self.document = document = self.new_document()
+        module_section = moduleparser.parse_module(self.input,
+                                                   self.source.source_path)
+        module_section.walk(DocformatVisitor(self.document))
+        visitor = DocstringFormattingVisitor(
+            document=document,
+            default_parser=self.default_parser)
+        module_section.walk(visitor)
+        self.document.append(module_section)
+
+
+class DocformatVisitor(nodes.SparseNodeVisitor):
+
+    """
+    This sets docformat attributes in a module.  Wherever an assignment
+    to __docformat__ is found, we look for the enclosing scope -- a class,
+    a module, or a function -- and set the docformat attribute there.
+
+    We can't do this during the DocstringFormattingVisitor walking,
+    because __docformat__ may appear below a docstring in that format
+    (typically below the module docstring).
+    """
+
+    def visit_attribute(self, node):
+        assert isinstance(node[0], pynodes.object_name)
+        name = node[0][0].data
+        if name != '__docformat__':
+            return
+        value = None
+        for child in children:
+            if isinstance(child, pynodes.expression_value):
+                value = child[0].data
+                break
+        assert value.startswith("'") or value.startswith('"'), "__docformat__ must be assigned a string literal (not %s); line: %s" % (value, node['lineno'])
+        name = name[1:-1]
+        looking_in = node.parent
+        while not isinstance(looking_in, (pynodes.module_section,
+                                          pynodes.function_section,
+                                          pynodes.class_section)):
+            looking_in = looking_in.parent
+        looking_in['docformat'] = name
+
+
+class DocstringFormattingVisitor(nodes.SparseNodeVisitor):
+
+    def __init__(self, document, default_parser):
+        self.document = document
+        self.default_parser = default_parser
+        self.parsers = {}
+
+    def visit_docstring(self, node):
+        text = node[0].data
+        docformat = self.find_docformat(node)
+        del node[0]
+        node['docformat'] = docformat
+        parser = self.get_parser(docformat)
+        parser.parse(text, self.document)
+        for child in self.document.get_children():
+            node.append(child)
+        self.document.current_source = self.document.current_line = None
+        del self.document[:]
+
+    def get_parser(self, parser_name):
+        """
+        Get a parser based on its name.  We reuse parsers during this
+        visitation, so parser instances are cached.
+        """
+        parser_name = parsers._parser_aliases.get(parser_name, parser_name)
+        if not self.parsers.has_key(parser_name):
+            cls = parsers.get_parser_class(parser_name)
+            self.parsers[parser_name] = cls()
+        return self.parsers[parser_name]
+
+    def find_docformat(self, node):
+        """
+        Find the __docformat__ closest to this node (i.e., look in the
+        class or module)
+        """
+        while node:
+            if node.get('docformat'):
+                return node['docformat']
+            node = node.parent
+        return self.default_parser
+
+
+if __name__ == '__main__':
+    try:
+        import locale
+        locale.setlocale(locale.LC_ALL, '')
+    except:
+        pass
+
+    from docutils.core import publish_cmdline, default_description
+
+    description = ('Generates pseudo-XML from Python modules '
+                   '(for testing purposes).  ' + default_description)
+
+    publish_cmdline(description=description,
+                    reader=Reader())

Modified: Zope/trunk/lib/python/docutils/readers/python/moduleparser.py
===================================================================
--- Zope/trunk/lib/python/docutils/readers/python/moduleparser.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/readers/python/moduleparser.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,17 +1,16 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.3 $
-# Date: $Date: 2003/11/30 15:06:08 $
+# Revision: $Revision: 1.3.2.1.8.1 $
+# Date: $Date: 2004/05/12 19:57:53 $
 # Copyright: This module has been placed in the public domain.
 
 """
 Parser for Python modules.
 
-The `parse_module()` function takes a module's text and file name, runs it
-through the module parser (using compiler.py and tokenize.py) and produces a
-"module documentation tree": a high-level AST full of nodes that are
-interesting from an auto-documentation standpoint.  For example, given this
-module (x.py)::
+The `parse_module()` function takes a module's text and file name,
+runs it through the module parser (using compiler.py and tokenize.py)
+and produces a parse tree of the source code, using the nodes as found
+in pynodes.py.  For example, given this module (x.py)::
 
     # comment
 
@@ -50,69 +49,95 @@
 
 The module parser will produce this module documentation tree::
 
-    <Module filename="test data">
-        <Comment lineno=1>
-            comment
-        <Docstring>
+    <module_section filename="test data">
+        <docstring>
             Docstring
-        <Docstring lineno="5">
+        <docstring lineno="5">
             Additional docstring
-        <Attribute lineno="7" name="__docformat__">
-            <Expression lineno="7">
+        <attribute lineno="7">
+	    <object_name>
+	        __docformat__
+            <expression_value lineno="7">
                 'reStructuredText'
-        <Attribute lineno="9" name="a">
-            <Expression lineno="9">
+        <attribute lineno="9">
+	    <object_name>
+	        a
+            <expression_value lineno="9">
                 1
-            <Docstring lineno="10">
+            <docstring lineno="10">
                 Attribute docstring
-        <Class bases="Super" lineno="12" name="C">
-            <Docstring lineno="12">
+        <class_section lineno="12">
+	    <object_name>
+	        C
+            <class_base>
+	        Super
+            <docstring lineno="12">
                 C's docstring
-            <Attribute lineno="16" name="class_attribute">
-                <Expression lineno="16">
+            <attribute lineno="16">
+	        <object_name>
+		    class_attribute
+                <expression_value lineno="16">
                     1
-                <Docstring lineno="17">
+                <docstring lineno="17">
                     class_attribute's docstring
-            <Method lineno="19" name="__init__">
-                <Docstring lineno="19">
+            <method_section lineno="19">
+	        <object_name>
+		    __init__
+                <docstring lineno="19">
                     __init__'s docstring
-                <ParameterList lineno="19">
-                    <Parameter lineno="19" name="self">
-                    <Parameter lineno="19" name="text">
-                        <Default lineno="19">
+                <parameter_list lineno="19">
+                    <parameter lineno="19">
+		        <object_name>
+			    self
+                    <parameter lineno="19">
+		        <object_name>
+			    text
+                        <parameter_default lineno="19">
                             None
-                <Attribute lineno="22" name="self.instance_attribute">
-                    <Expression lineno="22">
+                <attribute lineno="22">
+		    <object_name>
+		        self.instance_attribute
+                    <expression_value lineno="22">
                         (text * 7 + ' whaddyaknow')
-                    <Docstring lineno="24">
+                    <docstring lineno="24">
                         instance_attribute's docstring
-        <Function lineno="27" name="f">
-            <Docstring lineno="27">
+        <function_section lineno="27">
+	    <object_name>
+	        f
+            <docstring lineno="27">
                 f's docstring
-            <ParameterList lineno="27">
-                <Parameter lineno="27" name="x">
-                    <Comment>
+            <parameter_list lineno="27">
+                <parameter lineno="27">
+		    <object_name>
+		        x
+                    <comment>
                         # parameter x
-                <Parameter lineno="27" name="y">
-                    <Default lineno="27">
+                <parameter lineno="27">
+		    <object_name>
+		        y
+                    <parameter_default lineno="27">
                         a * 5
-                    <Comment>
+                    <comment>
                         # parameter y
-                <ExcessPositionalArguments lineno="27" name="args">
-                    <Comment>
+                <parameter excess_positional="1" lineno="27">
+		    <object_name>
+		        args
+                    <comment>
                         # parameter args
-        <Attribute lineno="33" name="f.function_attribute">
-            <Expression lineno="33">
+        <attribute lineno="33">
+	    <object_name>
+	        f.function_attribute
+            <expression_value lineno="33">
                 1
-            <Docstring lineno="34">
+            <docstring lineno="34">
                 f.function_attribute's docstring
 
 (Comments are not implemented yet.)
 
 compiler.parse() provides most of what's needed for this doctree, and
-"tokenize" can be used to get the rest.  We can determine the line number from
-the compiler.parse() AST, and the TokenParser.rhs(lineno) method provides the
-rest.
+"tokenize" can be used to get the rest.  We can determine the line
+number from the compiler.parse() AST, and the TokenParser.rhs(lineno)
+method provides the rest.
 
 The Docutils Python reader component will transform this module doctree into a
 Python-specific Docutils doctree, and then a `stylist transform`_ will
@@ -190,6 +215,8 @@
 from compiler.consts import OP_ASSIGN
 from compiler.visitor import ASTVisitor
 from types import StringType, UnicodeType, TupleType
+from docutils.readers.python import pynodes
+from docutils.nodes import Text
 
 
 def parse_module(module_text, filename):
@@ -200,168 +227,6 @@
     compiler.walk(ast, visitor, walker=visitor)
     return visitor.module
 
-
-class Node:
-
-    """
-    Base class for module documentation tree nodes.
-    """
-
-    def __init__(self, node):
-        self.children = []
-        """List of child nodes."""
-
-        self.lineno = node.lineno
-        """Line number of this node (or ``None``)."""
-
-    def __str__(self, indent='    ', level=0):
-        return ''.join(['%s%s\n' % (indent * level, repr(self))] +
-                       [child.__str__(indent, level+1)
-                        for child in self.children])
-
-    def __repr__(self):
-        parts = [self.__class__.__name__]
-        for name, value in self.attlist():
-            parts.append('%s="%s"' % (name, value))
-        return '<%s>' % ' '.join(parts)
-
-    def attlist(self, **atts):
-        if self.lineno is not None:
-            atts['lineno'] = self.lineno
-        attlist = atts.items()
-        attlist.sort()
-        return attlist
-
-    def append(self, node):
-        self.children.append(node)
-
-    def extend(self, node_list):
-        self.children.extend(node_list)
-
-
-class TextNode(Node):
-
-    def __init__(self, node, text):
-        Node.__init__(self, node)
-        self.text = trim_docstring(text)
-
-    def __str__(self, indent='    ', level=0):
-        prefix = indent * (level + 1)
-        text = '\n'.join([prefix + line for line in self.text.splitlines()])
-        return Node.__str__(self, indent, level) + text + '\n'
-
-
-class Module(Node):
-
-    def __init__(self, node, filename):
-        Node.__init__(self, node)
-        self.filename = filename
-
-    def attlist(self):
-        return Node.attlist(self, filename=self.filename)
-
-
-class Docstring(TextNode): pass
-
-
-class Comment(TextNode): pass
-
-
-class Import(Node):
-
-    def __init__(self, node, names, from_name=None):
-        Node.__init__(self, node)
-        self.names = names
-        self.from_name = from_name
-
-    def __str__(self, indent='    ', level=0):
-        prefix = indent * (level + 1)
-        lines = []
-        for name, as in self.names:
-            if as:
-                lines.append('%s%s as %s' % (prefix, name, as))
-            else:
-                lines.append('%s%s' % (prefix, name))
-        text = '\n'.join(lines)
-        return Node.__str__(self, indent, level) + text + '\n'
-
-    def attlist(self):
-        if self.from_name:
-            atts = {'from': self.from_name}
-        else:
-            atts = {}
-        return Node.attlist(self, **atts)
-
-
-class Attribute(Node):
-
-    def __init__(self, node, name):
-        Node.__init__(self, node)
-        self.name = name
-
-    def attlist(self):
-        return Node.attlist(self, name=self.name)
-
-
-class AttributeTuple(Node):
-
-    def __init__(self, node, names):
-        Node.__init__(self, node)
-        self.names = names
-
-    def attlist(self):
-        return Node.attlist(self, names=' '.join(self.names))
-
-
-class Expression(TextNode):
-
-    def __str__(self, indent='    ', level=0):
-        prefix = indent * (level + 1)
-        return '%s%s%s\n' % (Node.__str__(self, indent, level),
-                             prefix, self.text.encode('unicode-escape'))
-
-
-class Function(Attribute): pass
-
-
-class ParameterList(Node): pass
-
-
-class Parameter(Attribute): pass
-
-
-class ParameterTuple(AttributeTuple):
-
-    def attlist(self):
-        return Node.attlist(self, names=normalize_parameter_name(self.names))
-
-
-class ExcessPositionalArguments(Parameter): pass
-
-
-class ExcessKeywordArguments(Parameter): pass
-
-
-class Default(Expression): pass
-
-
-class Class(Node):
-
-    def __init__(self, node, name, bases=None):
-        Node.__init__(self, node)
-        self.name = name
-        self.bases = bases or []
-
-    def attlist(self):
-        atts = {'name': self.name}
-        if self.bases:
-            atts['bases'] = ' '.join(self.bases)
-        return Node.attlist(self, **atts)
-
-
-class Method(Function): pass
-
-
 class BaseVisitor(ASTVisitor):
 
     def __init__(self, token_parser):
@@ -389,7 +254,7 @@
     def visitConst(self, node):
         if self.documentable:
             if type(node.value) in (StringType, UnicodeType):
-                self.documentable.append(Docstring(node, node.value))
+                self.documentable.append(make_docstring(node.value, node.lineno))
             else:
                 self.documentable = None
 
@@ -418,25 +283,28 @@
         self.module = None
 
     def visitModule(self, node):
-        self.module = module = Module(node, self.filename)
-        if node.doc is not None:
-            module.append(Docstring(node, node.doc))
+        self.module = module = pynodes.module_section()
+        module['filename'] = self.filename
+        append_docstring(module, node.doc, node.lineno)
         self.context.append(module)
         self.documentable = module
         self.visit(node.node)
         self.context.pop()
 
     def visitImport(self, node):
-        self.context[-1].append(Import(node, node.names))
+        self.context[-1] += make_import_group(names=node.names,
+                                              lineno=node.lineno)
         self.documentable = None
 
     def visitFrom(self, node):
         self.context[-1].append(
-            Import(node, node.names, from_name=node.modname))
+            make_import_group(names=node.names, from_name=node.modname,
+                              lineno=node.lineno))
         self.documentable = None
 
     def visitFunction(self, node):
-        visitor = FunctionVisitor(self.token_parser)
+        visitor = FunctionVisitor(self.token_parser,
+                                  function_class=pynodes.function_section)
         compiler.walk(node, visitor, walker=visitor)
         self.context[-1].append(visitor.function)
 
@@ -450,29 +318,32 @@
 
     def __init__(self, token_parser):
         BaseVisitor.__init__(self, token_parser)
-        self.attributes = []
+        self.attributes = pynodes.class_attribute_section()
 
     def visitAssign(self, node):
         # Don't visit the expression itself, just the attribute nodes:
         for child in node.nodes:
             self.dispatch(child)
         expression_text = self.token_parser.rhs(node.lineno)
-        expression = Expression(node, expression_text)
+        expression = pynodes.expression_value()
+        expression.append(Text(expression_text))
         for attribute in self.attributes:
             attribute.append(expression)
 
     def visitAssName(self, node):
-        self.attributes.append(Attribute(node, node.name))
+        self.attributes.append(make_attribute(node.name,
+                                              lineno=node.lineno))
 
     def visitAssTuple(self, node):
         attributes = self.attributes
         self.attributes = []
         self.default_visit(node)
-        names = [attribute.name for attribute in self.attributes]
-        att_tuple = AttributeTuple(node, names)
-        att_tuple.lineno = self.attributes[0].lineno
+        n = pynodes.attribute_tuple()
+        n.extend(self.attributes)
+        n['lineno'] = self.attributes[0]['lineno']
+        attributes.append(n)
         self.attributes = attributes
-        self.attributes.append(att_tuple)
+        #self.attributes.append(att_tuple)
 
     def visitAssAttr(self, node):
         self.default_visit(node, node.attrname)
@@ -481,23 +352,29 @@
         self.default_visit(node, node.attrname + '.' + suffix)
 
     def visitName(self, node, suffix):
-        self.attributes.append(Attribute(node, node.name + '.' + suffix))
+        self.attributes.append(make_attribute(node.name + '.' + suffix,
+                                              lineno=node.lineno))
 
 
 class FunctionVisitor(DocstringVisitor):
 
     in_function = 0
-    function_class = Function
 
+    def __init__(self, token_parser, function_class):
+        DocstringVisitor.__init__(self, token_parser)
+        self.function_class = function_class
+
     def visitFunction(self, node):
         if self.in_function:
             self.documentable = None
             # Don't bother with nested function definitions.
             return
         self.in_function = 1
-        self.function = function = self.function_class(node, node.name)
-        if node.doc is not None:
-            function.append(Docstring(node, node.doc))
+        self.function = function = make_function_like_section(
+            name=node.name,
+            lineno=node.lineno,
+            doc=node.doc,
+            function_class=self.function_class)
         self.context.append(function)
         self.documentable = function
         self.parse_parameter_list(node)
@@ -509,10 +386,11 @@
         special = []
         argnames = list(node.argnames)
         if node.kwargs:
-            special.append(ExcessKeywordArguments(node, argnames[-1]))
+            special.append(make_parameter(argnames[-1], excess_keyword=1))
             argnames.pop()
         if node.varargs:
-            special.append(ExcessPositionalArguments(node, argnames[-1]))
+            special.append(make_parameter(argnames[-1],
+                                          excess_positional=1))
             argnames.pop()
         defaults = list(node.defaults)
         defaults = [None] * (len(argnames) - len(defaults)) + defaults
@@ -521,17 +399,21 @@
         #print >>sys.stderr, function_parameters
         for argname, default in zip(argnames, defaults):
             if type(argname) is TupleType:
-                parameter = ParameterTuple(node, argname)
+                parameter = pynodes.parameter_tuple()
+                for tuplearg in argname:
+                    parameter.append(make_parameter(tuplearg))
                 argname = normalize_parameter_name(argname)
             else:
-                parameter = Parameter(node, argname)
+                parameter = make_parameter(argname)
             if default:
-                parameter.append(Default(node, function_parameters[argname]))
+                n_default = pynodes.parameter_default()
+                n_default.append(Text(function_parameters[argname]))
+                parameter.append(n_default)
             parameters.append(parameter)
         if parameters or special:
             special.reverse()
             parameters.extend(special)
-            parameter_list = ParameterList(node)
+            parameter_list = pynodes.parameter_list()
             parameter_list.extend(parameters)
             self.function.append(parameter_list)
 
@@ -554,9 +436,9 @@
         #pdb.set_trace()
         for base in node.bases:
             self.visit(base)
-        self.klass = klass = Class(node, node.name, self.bases)
-        if node.doc is not None:
-            klass.append(Docstring(node, node.doc))
+        self.klass = klass = make_class_section(node.name, self.bases,
+                                                doc=node.doc,
+                                                lineno=node.lineno)
         self.context.append(klass)
         self.documentable = klass
         self.visit(node.code)
@@ -578,21 +460,19 @@
 
     def visitFunction(self, node):
         if node.name == '__init__':
-            visitor = InitMethodVisitor(self.token_parser)
+            visitor = InitMethodVisitor(self.token_parser,
+                                        function_class=pynodes.method_section)
+            compiler.walk(node, visitor, walker=visitor)
         else:
-            visitor = MethodVisitor(self.token_parser)
-        compiler.walk(node, visitor, walker=visitor)
+            visitor = FunctionVisitor(self.token_parser,
+                                      function_class=pynodes.method_section)
+            compiler.walk(node, visitor, walker=visitor)
         self.context[-1].append(visitor.function)
 
 
-class MethodVisitor(FunctionVisitor):
+class InitMethodVisitor(FunctionVisitor, AssignmentVisitor): pass
 
-    function_class = Method
 
-
-class InitMethodVisitor(MethodVisitor, AssignmentVisitor): pass
-
-
 class TokenParser:
 
     def __init__(self, text):
@@ -744,6 +624,85 @@
         return parameters
 
 
+def make_docstring(doc, lineno):
+    n = pynodes.docstring()
+    if lineno:
+        # Really, only module docstrings don't have a line
+        # (@@: but maybe they should)
+        n['lineno'] = lineno
+    n.append(Text(doc))
+    return n
+
+def append_docstring(node, doc, lineno):
+    if doc:
+        node.append(make_docstring(doc, lineno))
+
+def make_class_section(name, bases, lineno, doc):
+    n = pynodes.class_section()
+    n['lineno'] = lineno
+    n.append(make_object_name(name))
+    for base in bases:
+        b = pynodes.class_base()
+        b.append(make_object_name(base))
+        n.append(b)
+    append_docstring(n, doc, lineno)
+    return n
+
+def make_object_name(name):
+    n = pynodes.object_name()
+    n.append(Text(name))
+    return n
+
+def make_function_like_section(name, lineno, doc, function_class):
+    n = function_class()
+    n['lineno'] = lineno
+    n.append(make_object_name(name))
+    append_docstring(n, doc, lineno)
+    return n
+
+def make_import_group(names, lineno, from_name=None):
+    n = pynodes.import_group()
+    n['lineno'] = lineno
+    if from_name:
+        n_from = pynodes.import_from()
+        n_from.append(Text(from_name))
+        n.append(n_from)
+    for name, alias in names:
+        n_name = pynodes.import_name()
+        n_name.append(Text(name))
+        if alias:
+            n_alias = pynodes.import_alias()
+            n_alias.append(Text(alias))
+            n_name.append(n_alias)
+        n.append(n_name)
+    return n
+
+def make_class_attribute(name, lineno):
+    n = pynodes.class_attribute()
+    n['lineno'] = lineno
+    n.append(Text(name))
+    return n
+
+def make_attribute(name, lineno):
+    n = pynodes.attribute()
+    n['lineno'] = lineno
+    n.append(make_object_name(name))
+    return n
+
+def make_parameter(name, excess_keyword=0, excess_positional=0):
+    """
+    excess_keyword and excess_positional must be either 1 or 0, and
+    not both of them can be 1.
+    """
+    n = pynodes.parameter()
+    n.append(make_object_name(name))
+    assert not excess_keyword or not excess_positional
+    if excess_keyword:
+        n['excess_keyword'] = 1
+    if excess_positional:
+        n['excess_positional'] = 1
+    return n
+
 def trim_docstring(text):
     """
     Trim indentation and blank lines from docstring text & return it.
@@ -782,3 +741,18 @@
         return '(%s)' % ', '.join([normalize_parameter_name(n) for n in name])
     else:
         return name
+
+if __name__ == '__main__':
+    import sys
+    args = sys.argv[1:]
+    if args[0] == '-v':
+        filename = args[1]
+        module_text = open(filename).read()
+        ast = compiler.parse(module_text)
+        visitor = compiler.visitor.ExampleASTVisitor()
+        compiler.walk(ast, visitor, walker=visitor, verbose=1)
+    else:
+        filename = args[0]
+        content = open(filename).read()
+        print parse_module(content, filename).pformat()
+

Added: Zope/trunk/lib/python/docutils/readers/python/pynodes.py
===================================================================
--- Zope/trunk/lib/python/docutils/readers/python/pynodes.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/readers/python/pynodes.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -0,0 +1,87 @@
+#! /usr/bin/env python
+
+"""
+:Author: David Goodger
+:Contact: goodger at users.sourceforge.net
+:Revision: $Revision: 1.1.2.1 $
+:Date: $Date: 2004/05/12 19:57:53 $
+:Copyright: This module has been placed in the public domain.
+
+"""
+
+from docutils import nodes
+from docutils.nodes import Element, TextElement, Structural, Inline, Part, \
+     Text
+import types
+
+# This is the parent class of all the other pynode classes:
+class PythonStructural(Structural): pass
+
+# =====================
+#  Structural Elements
+# =====================
+
+class module_section(PythonStructural, Element): pass    
+class class_section(PythonStructural, Element): pass
+class class_base(PythonStructural, Element): pass
+class method_section(PythonStructural, Element): pass
+class attribute(PythonStructural, Element): pass
+class function_section(PythonStructural, Element): pass
+class class_attribute_section(PythonStructural, Element): pass
+class class_attribute(PythonStructural, Element): pass
+class expression_value(PythonStructural, Element): pass
+class attribute(PythonStructural, Element): pass
+
+# Structural Support Elements
+# ---------------------------
+
+class parameter_list(PythonStructural, Element): pass
+class parameter_tuple(PythonStructural, Element): pass
+class parameter_default(PythonStructural, TextElement): pass
+class import_group(PythonStructural, TextElement): pass
+class import_from(PythonStructural, TextElement): pass
+class import_name(PythonStructural, TextElement): pass
+class import_alias(PythonStructural, TextElement): pass
+class docstring(PythonStructural, Element): pass
+
+# =================
+#  Inline Elements
+# =================
+
+# These elements cannot become references until the second
+# pass.  Initially, we'll use "reference" or "name".
+
+class object_name(PythonStructural, TextElement): pass
+class parameter_list(PythonStructural, TextElement): pass
+class parameter(PythonStructural, TextElement): pass
+class parameter_default(PythonStructural, TextElement): pass
+class class_attribute(PythonStructural, TextElement): pass
+class attribute_tuple(PythonStructural, TextElement): pass
+
+# =================
+#  Unused Elements
+# =================
+
+# These were part of the model, and maybe should be in the future, but
+# aren't now.
+#class package_section(PythonStructural, Element): pass
+#class module_attribute_section(PythonStructural, Element): pass
+#class instance_attribute_section(PythonStructural, Element): pass
+#class module_attribute(PythonStructural, TextElement): pass
+#class instance_attribute(PythonStructural, TextElement): pass
+#class exception_class(PythonStructural, TextElement): pass
+#class warning_class(PythonStructural, TextElement): pass
+
+
+# Collect all the classes we've written above
+def install_node_class_names():
+    node_class_names = []
+    for name, var in globals().items():
+        if (type(var) is types.ClassType
+            and issubclass(var, PythonStructural) \
+            and name.lower() == name):
+            node_class_names.append(var.tagname or name)
+    # Register the new node names with GenericNodeVisitor and
+    # SpecificNodeVisitor:
+    nodes._add_node_class_names(node_class_names)
+install_node_class_names()

Modified: Zope/trunk/lib/python/docutils/readers/standalone.py
===================================================================
--- Zope/trunk/lib/python/docutils/readers/standalone.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/readers/standalone.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:08 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:52 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -14,7 +14,6 @@
 import sys
 from docutils import frontend, readers
 from docutils.transforms import frontmatter, references
-from docutils.parsers.rst import Parser
 
 
 class Reader(readers.Reader):

Modified: Zope/trunk/lib/python/docutils/statemachine.py
===================================================================
--- Zope/trunk/lib/python/docutils/statemachine.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/statemachine.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:04 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:39 $
 # Copyright: This module has been placed in the public domain.
 
 """

Modified: Zope/trunk/lib/python/docutils/transforms/__init__.py
===================================================================
--- Zope/trunk/lib/python/docutils/transforms/__init__.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/transforms/__init__.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Authors: David Goodger, Ueli Schlaepfer
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:55 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -59,6 +59,7 @@
         self.language = languages.get_language(
             document.settings.language_code)
         """Language module local to this document."""
+        
 
     def apply(self):
         """Override to apply the transform to the document tree."""
@@ -76,7 +77,8 @@
 
     default_transforms = (universal.Decorations,
                           universal.FinalChecks,
-                          universal.Messages)
+                          universal.Messages,
+                          universal.FilterMessages)
     """These transforms are applied to all document trees."""
 
     def __init__(self, document):
@@ -84,6 +86,9 @@
         """List of transforms to apply.  Each item is a 3-tuple:
         ``(priority string, transform class, pending node or None)``."""
 
+        self.unknown_reference_resolvers = []
+        """List of hook functions which assist in resolving references"""
+
         self.document = document
         """The `nodes.document` object this Transformer is attached to."""
 
@@ -149,7 +154,17 @@
             self.add_transforms(component.default_transforms)
             self.components[component.component_type] = component
         self.sorted = 0
+        # Setup all of the reference resolvers for this transformer. Each
+        # component of this transformer is able to register its own helper
+        # functions to help resolve references.
+        unknown_reference_resolvers = []
+        for i in components:
+            unknown_reference_resolvers.extend(i.unknown_reference_resolvers)
+        decorated_list = [(f.priority, f) for f in unknown_reference_resolvers]
+        decorated_list.sort()
+        self.unknown_reference_resolvers.extend([f[1] for f in decorated_list])
 
+
     def apply_transforms(self):
         """Apply all of the stored transforms, in priority order."""
         self.document.reporter.attach_observer(

Modified: Zope/trunk/lib/python/docutils/transforms/components.py
===================================================================
--- Zope/trunk/lib/python/docutils/transforms/components.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/transforms/components.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:55 $
 # Copyright: This module has been placed in the public domain.
 
 """

Modified: Zope/trunk/lib/python/docutils/transforms/frontmatter.py
===================================================================
--- Zope/trunk/lib/python/docutils/transforms/frontmatter.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/transforms/frontmatter.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Authors: David Goodger, Ueli Schlaepfer
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:55 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -334,10 +334,10 @@
         return 1
 
     rcs_keyword_substitutions = [
-          (re.compile(r'\$' r'Date: (\d\d\d\d)/(\d\d)/(\d\d) [\d:]+ \$$',
+          (re.compile(r'\$' r'Date: (\d\d\d\d)/(\d\d)/(\d\d) [\d:]+ \$',
                       re.IGNORECASE), r'\1-\2-\3'),
-          (re.compile(r'\$' r'RCSfile: (.+),v \$$', re.IGNORECASE), r'\1'),
-          (re.compile(r'\$[a-zA-Z]+: (.+) \$$'), r'\1'),]
+          (re.compile(r'\$' r'RCSfile: (.+),v \$', re.IGNORECASE), r'\1'),
+          (re.compile(r'\$[a-zA-Z]+: (.+) \$'), r'\1'),]
 
     def extract_authors(self, field, name, docinfo):
         try:

Modified: Zope/trunk/lib/python/docutils/transforms/misc.py
===================================================================
--- Zope/trunk/lib/python/docutils/transforms/misc.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/transforms/misc.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:55 $
 # Copyright: This module has been placed in the public domain.
 
 """

Modified: Zope/trunk/lib/python/docutils/transforms/parts.py
===================================================================
--- Zope/trunk/lib/python/docutils/transforms/parts.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/transforms/parts.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Authors: David Goodger, Ueli Schlaepfer, Dmitry Jemerov
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:55 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -34,7 +34,8 @@
     def apply(self):
         self.maxdepth = self.startnode.details.get('depth', sys.maxint)
         self.startnode.parent.remove(self.startnode)
-        self.update_section_numbers(self.document)
+        if self.document.settings.sectnum_xform:
+            self.update_section_numbers(self.document)
 
     def update_section_numbers(self, node, prefix=(), depth=0):
         depth += 1
@@ -58,11 +59,11 @@
     """
     This transform generates a table of contents from the entire document tree
     or from a single branch.  It locates "section" elements and builds them
-    into a nested bullet list, which is placed within a "topic".  A title is
-    either explicitly specified, taken from the appropriate language module,
-    or omitted (local table of contents).  The depth may be specified.
-    Two-way references between the table of contents and section titles are
-    generated (requires Writer support).
+    into a nested bullet list, which is placed within a "topic" created by the
+    contents directive.  A title is either explicitly specified, taken from
+    the appropriate language module, or omitted (local table of contents).
+    The depth may be specified.  Two-way references between the table of
+    contents and section titles are generated (requires Writer support).
 
     This transform requires a startnode, which which contains generation
     options and provides the location for the generated table of contents (the
@@ -72,41 +73,26 @@
     default_priority = 720
 
     def apply(self):
-        topic = nodes.topic(CLASS='contents')
         details = self.startnode.details
-        if details.has_key('class'):
-            topic.set_class(details['class'])
-        title = details['title']
         if details.has_key('local'):
-            startnode = self.startnode.parent
+            startnode = self.startnode.parent.parent
             # @@@ generate an error if the startnode (directive) not at
             # section/document top-level? Drag it up until it is?
             while not isinstance(startnode, nodes.Structural):
                 startnode = startnode.parent
         else:
             startnode = self.document
-            if not title:
-                title = nodes.title('', self.language.labels['contents'])
-        if title:
-            name = title.astext()
-            topic += title
-        else:
-            name = self.language.labels['contents']
-        name = nodes.fully_normalize_name(name)
-        if not self.document.has_name(name):
-            topic['name'] = name
-        self.document.note_implicit_target(topic)
-        self.toc_id = topic['id']
+
+        self.toc_id = self.startnode.parent['id']
         if details.has_key('backlinks'):
             self.backlinks = details['backlinks']
         else:
             self.backlinks = self.document.settings.toc_backlinks
         contents = self.build_contents(startnode)
         if len(contents):
-            topic += contents
-            self.startnode.parent.replace(self.startnode, topic)
+            self.startnode.parent.replace(self.startnode, contents)
         else:
-            self.startnode.parent.remove(self.startnode)
+            self.startnode.parent.parent.remove(self.startnode.parent)
 
     def build_contents(self, node, level=0):
         level += 1

Modified: Zope/trunk/lib/python/docutils/transforms/peps.py
===================================================================
--- Zope/trunk/lib/python/docutils/transforms/peps.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/transforms/peps.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:55 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -19,7 +19,7 @@
 import os
 import re
 import time
-from docutils import nodes, utils
+from docutils import nodes, utils, languages
 from docutils import ApplicationError, DataError
 from docutils.transforms import Transform, TransformError
 from docutils.transforms import parts, references, misc
@@ -137,15 +137,24 @@
 class Contents(Transform):
 
     """
-    Insert a table of contents transform placeholder into the document after
-    the RFC 2822 header.
+    Insert an empty table of contents topic and a transform placeholder into
+    the document after the RFC 2822 header.
     """
 
     default_priority = 380
 
     def apply(self):
-        pending = nodes.pending(parts.Contents, {'title': None})
-        self.document.insert(1, pending)
+        language = languages.get_language(self.document.settings.language_code)
+        name = language.labels['contents']
+        title = nodes.title('', name)
+        topic = nodes.topic('', title, CLASS='contents')
+        name = nodes.fully_normalize_name(name)
+        if not self.document.has_name(name):
+            topic['name'] = name
+        self.document.note_implicit_target(topic)
+        pending = nodes.pending(parts.Contents)
+        topic += pending
+        self.document.insert(1, topic)
         self.document.note_pending(pending)
 
 

Modified: Zope/trunk/lib/python/docutils/transforms/references.py
===================================================================
--- Zope/trunk/lib/python/docutils/transforms/references.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/transforms/references.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:55 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -216,7 +216,13 @@
         refname = target['refname']
         reftarget_id = self.document.nameids.get(refname)
         if not reftarget_id:
-            self.nonexistent_indirect_target(target)
+            # Check the unknown_reference_resolvers
+            for resolver_function in (self.document.transformer
+                                      .unknown_reference_resolvers):
+                if resolver_function(target):
+                    break
+            else:
+                self.nonexistent_indirect_target(target)
             return
         reftarget = self.document.ids[reftarget_id]
         if isinstance(reftarget, nodes.target) \
@@ -248,7 +254,11 @@
         reftarget.referenced = 1
 
     def nonexistent_indirect_target(self, target):
-        self.indirect_target_error(target, 'which does not exist')
+        if self.document.nameids.has_key(target['refname']):
+            self.indirect_target_error(target, 'which is a duplicate, and '
+                                       'cannot be used as a unique reference')
+        else:
+            self.indirect_target_error(target, 'which does not exist')
 
     def circular_indirect_reference(self, target):
         self.indirect_target_error(target, 'forming a circular reference')
@@ -353,7 +363,8 @@
                 try:
                     reflist = self.document.refnames[name]
                 except KeyError, instance:
-                    if target.referenced:
+                    # @@@ First clause correct???
+                    if not isinstance(target, nodes.target) or target.referenced:
                         continue
                     msg = self.document.reporter.info(
                           'External hyperlink target "%s" is not referenced.'

Modified: Zope/trunk/lib/python/docutils/transforms/universal.py
===================================================================
--- Zope/trunk/lib/python/docutils/transforms/universal.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/transforms/universal.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Authors: David Goodger, Ueli Schlaepfer
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:55 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -111,6 +111,29 @@
             self.document += section
 
 
+class FilterMessages(Transform):
+
+    """
+    Remove system messages below verbosity threshold.
+    """
+
+    default_priority = 870
+
+    def apply(self):
+        visitor = SystemMessageFilterVisitor(self.document)
+        self.document.walk(visitor)
+
+
+class SystemMessageFilterVisitor(nodes.SparseNodeVisitor):
+
+    def unknown_visit(self, node):
+        pass
+
+    def visit_system_message(self, node):
+        if node['level'] < self.document.reporter['writer'].report_level:
+            node.parent.remove(node)
+
+
 class TestMessages(Transform):
 
     """
@@ -136,7 +159,9 @@
     default_priority = 840
 
     def apply(self):
-        visitor = FinalCheckVisitor(self.document)
+        visitor = FinalCheckVisitor(
+            self.document,
+            self.document.transformer.unknown_reference_resolvers)
         self.document.walk(visitor)
         if self.document.settings.expose_internals:
             visitor = InternalAttributeExposer(self.document)
@@ -144,6 +169,11 @@
 
 
 class FinalCheckVisitor(nodes.SparseNodeVisitor):
+    
+    def __init__(self, document, unknown_reference_resolvers):
+        nodes.SparseNodeVisitor.__init__(self, document)
+        self.document = document
+        self.unknown_reference_resolvers = unknown_reference_resolvers
 
     def unknown_visit(self, node):
         pass
@@ -154,15 +184,24 @@
         refname = node['refname']
         id = self.document.nameids.get(refname)
         if id is None:
-            msg = self.document.reporter.error(
-                  'Unknown target name: "%s".' % (node['refname']),
-                  base_node=node)
-            msgid = self.document.set_id(msg)
-            prb = nodes.problematic(
-                  node.rawsource, node.rawsource, refid=msgid)
-            prbid = self.document.set_id(prb)
-            msg.add_backref(prbid)
-            node.parent.replace(node, prb)
+            for resolver_function in self.unknown_reference_resolvers:
+                if resolver_function(node):
+                    break
+            else:
+                if self.document.nameids.has_key(refname):
+                    msg = self.document.reporter.error(
+                        'Duplicate target name, cannot be used as a unique '
+                        'reference: "%s".' % (node['refname']), base_node=node)
+                else:
+                    msg = self.document.reporter.error(
+                        'Unknown target name: "%s".' % (node['refname']),
+                        base_node=node)
+                msgid = self.document.set_id(msg)
+                prb = nodes.problematic(
+                      node.rawsource, node.rawsource, refid=msgid)
+                prbid = self.document.set_id(prb)
+                msg.add_backref(prbid)
+                node.parent.replace(node, prb)
         else:
             del node['refname']
             node['refid'] = id

Modified: Zope/trunk/lib/python/docutils/urischemes.py
===================================================================
--- Zope/trunk/lib/python/docutils/urischemes.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/urischemes.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,8 @@
 """
 `schemes` is a dictionary with lowercase URI addressing schemes as
 keys and descriptions as values. It was compiled from the index at
-http://www.w3.org/Addressing/schemes.html (revised 2001-08-20).
+http://www.iana.org/assignments/uri-schemes (revised 2003-11-26)
+and an older list at http://www.w3.org/Addressing/schemes.html.
 """
 
 # Many values are blank and should be filled in with useful descriptions.
@@ -26,10 +27,12 @@
               'specialized to justify their own schemes'),
       'fax': ('a connection to a terminal that can handle telefaxes '
               '(facsimiles); RFC 2806'),
+      'feed' : 'NetNewsWire feed',
       'file': 'Host-specific file names',
       'finger': '',
       'freenet': '',
       'ftp': 'File Transfer Protocol',
+      'go': 'go; RFC3368',
       'gopher': 'The Gopher Protocol',
       'gsm-sms': ('Global System for Mobile Communications Short Message '
                   'Service'),
@@ -40,16 +43,19 @@
       'hnews': 'an HTTP-tunneling variant of the NNTP news protocol',
       'http': 'Hypertext Transfer Protocol',
       'https': 'HTTP over SSL',
+      'hydra': 'SubEthaEdit URI.  See http://www.codingmonkeys.de/subethaedit.',
       'iioploc': 'Internet Inter-ORB Protocol Location?',
       'ilu': 'Inter-Language Unification',
+      'im': 'Instant Messaging',
       'imap': 'Internet Message Access Protocol',
       'ior': 'CORBA interoperable object reference',
       'ipp': 'Internet Printing Protocol',
       'irc': 'Internet Relay Chat',
+      'iseek' : 'See www.ambrosiasw.com;  a little util for OS X.',
       'jar': 'Java archive',
       'javascript': ('JavaScript code; evaluates the expression after the '
                      'colon'),
-      'jdbc': '',
+      'jdbc': 'JDBC connection URI.',
       'ldap': 'Lightweight Directory Access Protocol',
       'lifn': '',
       'livescript': '',
@@ -62,6 +68,7 @@
       'mocha': '',
       'modem': ('a connection to a terminal that can handle incoming data '
                 'calls; RFC 2806'),
+      'mupdate': 'Mailbox Update (MUPDATE) Protocol',
       'news': 'USENET news',
       'nfs': 'Network File System protocol',
       'nntp': 'USENET news using NNTP access',
@@ -69,8 +76,10 @@
       'phone': '',
       'pop': 'Post Office Protocol',
       'pop3': 'Post Office Protocol v3',
+      'pres': 'Presence',
       'printer': '',
       'prospero': 'Prospero Directory Service',
+      'rdar' : 'URLs found in Darwin source (http://www.opensource.apple.com/darwinsource/).',
       'res': '',
       'rtsp': 'real time streaming protocol',
       'rvp': '',
@@ -80,8 +89,12 @@
       'service': 'service location',
       'shttp': 'secure hypertext transfer protocol',
       'sip': 'Session Initiation Protocol',
-      'smb': '',
+      'sips': 'secure session intitiaion protocol',
+      'smb': 'SAMBA filesystems.',
       'snews': 'For NNTP postings via SSL',
+      'soap.beep': '',
+      'soap.beeps': '',
+      'ssh': 'Reference to interactive sessions via ssh.',
       't120': 'real time data conferencing (audiographics)',
       'tcp': '',
       'tel': ('a connection to a terminal that handles normal voice '
@@ -90,6 +103,7 @@
               'RFC 2806.'),
       'telephone': 'telephone',
       'telnet': 'Reference to interactive sessions',
+      'tftp': 'Trivial File Transfer Protocol',
       'tip': 'Transaction Internet Protocol',
       'tn3270': 'Interactive 3270 emulation sessions',
       'tv': '',
@@ -101,5 +115,8 @@
       'wais': 'Wide Area Information Servers',
       'whodp': '',
       'whois++': 'Distributed directory service.',
+      'x-man-page': 'Opens man page in Terminal.app on OS X (see macosxhints.com)',
+      'xmlrpc.beep': '',
+      'xmlrpc.beeps': '',
       'z39.50r': 'Z39.50 Retrieval',
       'z39.50s': 'Z39.50 Session',}

Modified: Zope/trunk/lib/python/docutils/utils.py
===================================================================
--- Zope/trunk/lib/python/docutils/utils.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/utils.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:04 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:39 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -324,7 +324,9 @@
     """
     options = {}
     for name, value in option_list:
-        convertor = options_spec[name]       # raises KeyError if unknown
+        convertor = options_spec[name]  # raises KeyError if unknown
+        if convertor is None:
+            raise KeyError(name)        # or if explicitly disabled
         if options.has_key(name):
             raise DuplicateOptionError('duplicate option "%s"' % name)
         try:
@@ -406,7 +408,7 @@
     if len(paragraph) == 1 and isinstance(paragraph[0], nodes.Text):
         textnode = paragraph[0]
         for pattern, substitution in keyword_substitutions:
-            match = pattern.match(textnode.data)
+            match = pattern.search(textnode.data)
             if match:
                 textnode.data = pattern.sub(substitution, textnode.data)
                 return

Modified: Zope/trunk/lib/python/docutils/writers/__init__.py
===================================================================
--- Zope/trunk/lib/python/docutils/writers/__init__.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/writers/__init__.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Authors: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:57 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -26,25 +26,43 @@
     Each writer must support all standard node types listed in
     `docutils.nodes.node_class_names`.
 
-    Call `write()` to process a document.
+    The `write()` method is the main entry point.
     """
 
     component_type = 'writer'
     config_section = 'writers'
 
     document = None
-    """The document to write."""
+    """The document to write (Docutils doctree); set by `write`."""
 
+    output = None
+    """Final translated form of `document`; set by `translate`."""
+
     language = None
-    """Language module for the document."""
+    """Language module for the document; set by `write`."""
 
     destination = None
-    """`docutils.io` IO object; where to write the document."""
+    """`docutils.io` IO object; where to write the document.  Set by `write`."""
 
     def __init__(self):
-        """Initialize the Writer instance."""
 
+        # Currently only used by HTML writer for output fragments:
+        self.parts = {}
+        """Mapping of document part names to fragments of `self.output`.
+        Values are Unicode strings; encoding is up to the client.  The 'whole'
+        key should contain the entire document output.
+        """
+
     def write(self, document, destination):
+        """
+        Process a document into its final form.
+
+        Translate `document` (a Docutils document tree) into the Writer's
+        native format, and write it out to its `destination` (a
+        `docutils.io.Output` subclass object).
+
+        Normally not overridden or extended in subclasses.
+        """
         self.document = document
         self.language = languages.get_language(
             document.settings.language_code)
@@ -55,9 +73,10 @@
 
     def translate(self):
         """
-        Override to do final document tree translation.
+        Do final translation of `self.document` into `self.output`.
+        Called from `write`.  Override in subclasses.
 
-        This is usually done with a `docutils.nodes.NodeVisitor` subclass, in
+        Usually done with a `docutils.nodes.NodeVisitor` subclass, in
         combination with a call to `docutils.nodes.Node.walk()` or
         `docutils.nodes.Node.walkabout()`.  The ``NodeVisitor`` subclass must
         support all standard elements (listed in
@@ -66,7 +85,11 @@
         """
         raise NotImplementedError('subclass must override this method')
 
+    def assemble_parts(self):
+        """Assemble the `self.parts` dictionary.  Extend in subclasses."""
+        self.parts['whole'] = self.output
 
+
 _writer_aliases = {
       'html': 'html4css1',
       'latex': 'latex2e',

Modified: Zope/trunk/lib/python/docutils/writers/docutils_xml.py
===================================================================
--- Zope/trunk/lib/python/docutils/writers/docutils_xml.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/writers/docutils_xml.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Authors: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:57 $
 # Copyright: This module has been placed in the public domain.
 
 """

Modified: Zope/trunk/lib/python/docutils/writers/html4css1.py
===================================================================
--- Zope/trunk/lib/python/docutils/writers/html4css1.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/writers/html4css1.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:57 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -22,6 +22,10 @@
 import time
 import re
 from types import ListType
+try:
+    import Image                        # check for the Python Imaging Library
+except ImportError:
+    Image = None
 import docutils
 from docutils import frontend, nodes, utils, writers, languages
 
@@ -55,6 +59,11 @@
           'stylesheet, do not embed it.',
           ['--embed-stylesheet'],
           {'action': 'store_true', 'validator': frontend.validate_boolean}),
+         ('Specify the initial header level.  Default is 1 for "<h1>".  '
+          'Does not affect document title & subtitle (see --no-doc-title).',
+          ['--initial-header-level'],
+          {'choices': '1 2 3 4 5 6'.split(), 'default': '1',
+           'metavar': '<level>'}),
          ('Format for footnote references: one of "superscript" or '
           '"brackets".  Default is "superscript".',
           ['--footnote-references'],
@@ -85,9 +94,6 @@
     config_section = 'html4css1 writer'
     config_section_dependencies = ('writers',)
 
-    output = None
-    """Final translated form of `document`."""
-
     def __init__(self):
         writers.Writer.__init__(self)
         self.translator_class = HTMLTranslator
@@ -96,16 +102,19 @@
         visitor = self.translator_class(self.document)
         self.document.walkabout(visitor)
         self.output = visitor.astext()
-        self.head_prefix = visitor.head_prefix
-        self.stylesheet = visitor.stylesheet
-        self.head = visitor.head
-        self.body_prefix = visitor.body_prefix
-        self.body_pre_docinfo = visitor.body_pre_docinfo
-        self.docinfo = visitor.docinfo
-        self.body = visitor.body
-        self.body_suffix = visitor.body_suffix
+        self.visitor = visitor
+        for attr in ('head_prefix', 'stylesheet', 'head', 'body_prefix',
+                     'body_pre_docinfo', 'docinfo', 'body', 'fragment',
+                     'body_suffix'):
+            setattr(self, attr, getattr(visitor, attr))
 
+    def assemble_parts(self):
+        writers.Writer.assemble_parts(self)
+        for part in ('title', 'subtitle', 'docinfo', 'body', 'header',
+                     'footer', 'meta', 'stylesheet', 'fragment'):
+            self.parts[part] = ''.join(getattr(self.visitor, part))
 
+
 class HTMLTranslator(nodes.NodeVisitor):
 
     """
@@ -143,14 +152,14 @@
     - Regardless of the above, in definitions, table cells, field bodies,
       option descriptions, and list items, mark the first child with
       'class="first"' and the last child with 'class="last"'.  The stylesheet
-      sets the margins (top & bottom respecively) to 0 for these elements.
+      sets the margins (top & bottom respectively) to 0 for these elements.
 
     The ``no_compact_lists`` setting (``--no-compact-lists`` command-line
     option) disables list whitespace optimization.
     """
 
     xml_declaration = '<?xml version="1.0" encoding="%s" ?>\n'
-    doctype = ('<!DOCTYPE html' 
+    doctype = ('<!DOCTYPE html'
                ' PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
                ' "http://www.w3.org/TR/xhtml1/DTD/'
                'xhtml1-transitional.dtd">\n')
@@ -171,11 +180,12 @@
         self.settings = settings = document.settings
         lcode = settings.language_code
         self.language = languages.get_language(lcode)
+        self.meta = [self.content_type % settings.output_encoding,
+                     self.generator % docutils.__version__]
         self.head_prefix = [
               self.doctype,
-              self.html_head % (lcode, lcode),
-              self.content_type % settings.output_encoding,
-              self.generator % docutils.__version__]
+              self.html_head % (lcode, lcode)]
+        self.head_prefix.extend(self.meta)
         if settings.xml_declaration:
             self.head_prefix.insert(0, self.xml_declaration
                                     % settings.output_encoding)
@@ -192,11 +202,17 @@
             else:
                 self.stylesheet = []
         self.body_prefix = ['</head>\n<body>\n']
+        # document title, subtitle display
         self.body_pre_docinfo = []
+        # author, date, etc.
         self.docinfo = []
         self.body = []
+        self.fragment = []
         self.body_suffix = ['</body>\n</html>\n']
         self.section_level = 0
+        self.initial_header_level = int(settings.initial_header_level)
+        # A heterogenous stack used in conjunction with the tree traversal.
+        # Make sure that the pops correspond to the pushes:
         self.context = []
         self.topic_class = ''
         self.colspecs = []
@@ -204,6 +220,11 @@
         self.compact_simple = None
         self.in_docinfo = None
         self.in_sidebar = None
+        self.title = []
+        self.subtitle = []
+        self.header = []
+        self.footer = []
+        self.in_document_title = 0
 
     def get_stylesheet_reference(self, relative_to=None):
         settings = self.settings
@@ -267,8 +288,11 @@
                 parts.append('%s="%s"' % (name.lower(),
                                           self.attval(' '.join(values))))
             else:
-                parts.append('%s="%s"' % (name.lower(),
-                                          self.attval(unicode(value))))
+                try:
+                    uval = unicode(value)
+                except TypeError:       # for Python 2.1 compatibility:
+                    uval = unicode(str(value))
+                parts.append('%s="%s"' % (name.lower(), self.attval(uval)))
         return '<%s%s>%s' % (' '.join(parts), infix, suffix)
 
     def emptytag(self, node, tagname, suffix='\n', **attributes):
@@ -307,7 +331,7 @@
         self.body.append(self.starttag(node, 'div',
                                         CLASS=(name or 'admonition')))
         if name:
-            self.body.append('<p class="admonition-title">'
+            self.body.append('<p class="admonition-title first">'
                              + self.language.labels[name] + '</p>\n')
 
     def depart_admonition(self, node=None):
@@ -519,14 +543,14 @@
         self.body.append('</tbody>\n</table>\n')
         self.in_docinfo = None
         start = self.context.pop()
-        self.body_pre_docinfo = self.body[:start]
         self.docinfo = self.body[start:]
         self.body = []
 
     def visit_docinfo_item(self, node, name, meta=1):
         if meta:
-            self.head.append('<meta name="%s" content="%s" />\n'
-                             % (name, self.attval(node.astext())))
+            meta_tag = '<meta name="%s" content="%s" />\n' \
+                       % (name, self.attval(node.astext()))
+            self.add_meta(meta_tag)
         self.body.append(self.starttag(node, 'tr', ''))
         self.body.append('<th class="docinfo-name">%s:</th>\n<td>'
                          % self.language.labels[name])
@@ -546,9 +570,14 @@
         self.body.append('\n</pre>\n')
 
     def visit_document(self, node):
-        self.body.append(self.starttag(node, 'div', CLASS='document'))
+        # empty or untitled document?
+        if not len(node) or not isinstance(node[0], nodes.title):
+            # for XHTML conformance, modulo IE6 appeasement:
+            self.head.insert(0, '<title></title>\n')
 
     def depart_document(self, node):
+        self.fragment.extend(self.body)
+        self.body.insert(0, self.starttag(node, 'div', CLASS='document'))
         self.body.append('</div>\n')
 
     def visit_emphasis(self, node):
@@ -671,6 +700,7 @@
         footer = (['<hr class="footer" />\n',
                    self.starttag(node, 'div', CLASS='footer')]
                   + self.body[start:] + ['</div>\n'])
+        self.footer.extend(footer)
         self.body_suffix[:0] = footer
         del self.body[start:]
 
@@ -739,9 +769,11 @@
 
     def depart_header(self, node):
         start = self.context.pop()
-        self.body_prefix.append(self.starttag(node, 'div', CLASS='header'))
-        self.body_prefix.extend(self.body[start:])
-        self.body_prefix.append('<hr />\n</div>\n')
+        header = [self.starttag(node, 'div', CLASS='header')]
+        header.extend(self.body[start:])
+        header.append('<hr />\n</div>\n')
+        self.body_prefix.extend(header)
+        self.header = header
         del self.body[start:]
 
     def visit_hint(self, node):
@@ -756,6 +788,27 @@
             del atts['class']           # prevent duplication with node attrs
         atts['src'] = atts['uri']
         del atts['uri']
+        if atts.has_key('scale'):
+            if Image and not (atts.has_key('width')
+                              and atts.has_key('height')):
+                try:
+                    im = Image.open(str(atts['src']))
+                except (IOError, # Source image can't be found or opened
+                        UnicodeError):  # PIL doesn't like Unicode paths.
+                    pass
+                else:
+                    if not atts.has_key('width'):
+                        atts['width'] = im.size[0]
+                    if not atts.has_key('height'):
+                        atts['height'] = im.size[1]
+                    del im
+            if atts.has_key('width'):
+                atts['width'] = int(round(atts['width']
+                                          * (float(atts['scale']) / 100)))
+            if atts.has_key('height'):
+                atts['height'] = int(round(atts['height']
+                                           * (float(atts['scale']) / 100)))
+            del atts['scale']
         if not atts.has_key('alt'):
             atts['alt'] = atts['src']
         if isinstance(node.parent, nodes.TextElement):
@@ -837,11 +890,16 @@
         self.body.append('\n</pre>\n')
 
     def visit_meta(self, node):
-        self.head.append(self.emptytag(node, 'meta', **node.attributes))
+        meta = self.emptytag(node, 'meta', **node.attributes)
+        self.add_meta(meta)
 
     def depart_meta(self, node):
         pass
 
+    def add_meta(self, tag):
+        self.meta.append(tag)
+        self.head.append(tag)
+
     def visit_note(self, node):
         self.visit_admonition(node, 'note')
 
@@ -941,6 +999,11 @@
         raise nodes.SkipNode
 
     def visit_reference(self, node):
+        if isinstance(node.parent, nodes.TextElement):
+            self.context.append('')
+        else:
+            self.body.append('<p>')
+            self.context.append('</p>\n')
         if node.has_key('refuri'):
             href = node['refuri']
         elif node.has_key('refid'):
@@ -952,6 +1015,7 @@
 
     def depart_reference(self, node):
         self.body.append('</a>')
+        self.body.append(self.context.pop())
 
     def visit_revision(self, node):
         self.visit_docinfo_item(node, 'revision', meta=None)
@@ -1017,12 +1081,18 @@
             self.body.append(self.starttag(node, 'p', '',
                                            CLASS='sidebar-subtitle'))
             self.context.append('</p>\n')
-        else:
+        elif isinstance(node.parent, nodes.document):
             self.body.append(self.starttag(node, 'h2', '', CLASS='subtitle'))
             self.context.append('</h2>\n')
+            self.in_document_title = len(self.body)
 
     def depart_subtitle(self, node):
         self.body.append(self.context.pop())
+        if self.in_document_title:
+            self.subtitle = self.body[self.in_document_title:-1]
+            self.in_document_title = 0
+            self.body_pre_docinfo.extend(self.body)
+            del self.body[:]
 
     def visit_superscript(self, node):
         self.body.append(self.starttag(node, 'sup', ''))
@@ -1135,27 +1205,35 @@
     def visit_title(self, node):
         """Only 6 section levels are supported by HTML."""
         check_id = 0
+        close_tag = '</p>\n'
         if isinstance(node.parent, nodes.topic):
             self.body.append(
-                  self.starttag(node, 'p', '', CLASS='topic-title'))
+                  self.starttag(node, 'p', '', CLASS='topic-title first'))
             check_id = 1
         elif isinstance(node.parent, nodes.sidebar):
             self.body.append(
-                  self.starttag(node, 'p', '', CLASS='sidebar-title'))
+                  self.starttag(node, 'p', '', CLASS='sidebar-title first'))
             check_id = 1
         elif isinstance(node.parent, nodes.admonition):
             self.body.append(
-                  self.starttag(node, 'p', '', CLASS='admonition-title'))
+                  self.starttag(node, 'p', '', CLASS='admonition-title first'))
             check_id = 1
+        elif isinstance(node.parent, nodes.table):
+            self.body.append(
+                  self.starttag(node, 'caption', ''))
+            check_id = 1
+            close_tag = '</caption>\n'
         elif self.section_level == 0:
             # document title
             self.head.append('<title>%s</title>\n'
                              % self.encode(node.astext()))
             self.body.append(self.starttag(node, 'h1', '', CLASS='title'))
             self.context.append('</h1>\n')
+            self.in_document_title = len(self.body)
         else:
+            h_level = self.section_level + self.initial_header_level - 1
             self.body.append(
-                  self.starttag(node, 'h%s' % self.section_level, ''))
+                  self.starttag(node, 'h%s' % h_level, ''))
             atts = {}
             if node.parent.hasattr('id'):
                 atts['name'] = node.parent['id']
@@ -1163,17 +1241,22 @@
                 atts['class'] = 'toc-backref'
                 atts['href'] = '#' + node['refid']
             self.body.append(self.starttag({}, 'a', '', **atts))
-            self.context.append('</a></h%s>\n' % (self.section_level))
+            self.context.append('</a></h%s>\n' % (h_level))
         if check_id:
             if node.parent.hasattr('id'):
                 self.body.append(
                     self.starttag({}, 'a', '', name=node.parent['id']))
-                self.context.append('</a></p>\n')
+                self.context.append('</a>' + close_tag)
             else:
-                self.context.append('</p>\n')
+                self.context.append(close_tag)
 
     def depart_title(self, node):
         self.body.append(self.context.pop())
+        if self.in_document_title:
+            self.title = self.body[self.in_document_title:-1]
+            self.in_document_title = 0
+            self.body_pre_docinfo.extend(self.body)
+            del self.body[:]
 
     def visit_title_reference(self, node):
         self.body.append(self.starttag(node, 'cite', ''))

Modified: Zope/trunk/lib/python/docutils/writers/latex2e.py
===================================================================
--- Zope/trunk/lib/python/docutils/writers/latex2e.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/writers/latex2e.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,8 +1,8 @@
 """
 :Author: Engelbert Gruber
 :Contact: grubert at users.sourceforge.net
-:Revision: $Revision: 1.3 $
-:Date: $Date: 2003/11/30 15:06:09 $
+:Revision: $Revision: 1.1.2.3.8.1 $
+:Date: $Date: 2004/05/12 19:57:57 $
 :Copyright: This module has been placed in the public domain.
 
 LaTeX2e document tree Writer.
@@ -11,7 +11,7 @@
 __docformat__ = 'reStructuredText'
 
 # code contributions from several people included, thanks too all.
-# some named: David Abrahams, Julien Letessier, who is missing.
+# some named: David Abrahams, Julien Letessier, Lele Gaifax, and others.
 #
 # convention deactivate code by two # e.g. ##.
 
@@ -76,13 +76,43 @@
           ['--use-latex-toc'],
           {'default': 0, 'action': 'store_true',
            'validator': frontend.validate_boolean}),
-         ('Let LaTeX print author and date, donot show it in docutils document info.',
+         ('Let LaTeX print author and date, do not show it in docutils '
+          'document info.',
           ['--use-latex-docinfo'],
           {'default': 0, 'action': 'store_true',
            'validator': frontend.validate_boolean}),
          ('Color of any hyperlinks embedded in text '
           '(default: "blue", "0" to disable).',
-          ['--hyperlink-color'], {'default': 'blue'}),))
+          ['--hyperlink-color'], {'default': 'blue'}),
+         ('Enable compound enumerators for nested enumerated lists '
+          '(e.g. "1.2.a.ii").  Default: disabled.',
+          ['--compound-enumerators'],
+          {'default': None, 'action': 'store_true',
+           'validator': frontend.validate_boolean}),
+         ('Disable compound enumerators for nested enumerated lists.  This is '
+          'the default.',
+          ['--no-compound-enumerators'],
+          {'action': 'store_false', 'dest': 'compound_enumerators'}),
+         ('Enable section ("." subsection ...) prefixes for compound '
+          'enumerators.  This has no effect without --compound-enumerators.  '
+          'Default: disabled.',
+          ['--section-prefix-for-enumerators'],
+          {'default': None, 'action': 'store_true',
+           'validator': frontend.validate_boolean}),
+         ('Disable section prefixes for compound enumerators.  '
+          'This is the default.',
+          ['--no-section-prefix-for-enumerators'],
+          {'action': 'store_false', 'dest': 'section_prefix_for_enumerators'}),
+         ('Set the separator between section number and enumerator '
+          'for compound enumerated lists.  Default is "-".',
+          ['--section-enumerator-separator'],
+          {'default': '-', 'metavar': '<char>'}),
+         ('When possibile, use verbatim for literal-blocks.'
+          'Default is to always use the mbox environment.',
+          ['--use-verbatim-when-possible'],
+          {'default': 0, 'action': 'store_true',
+           'validator': frontend.validate_boolean}),
+          ))
 
     settings_defaults = {'output_encoding': 'latin-1'}
 
@@ -245,11 +275,39 @@
             '% some commands, that could be overwritten in the style file.\n'
             '\\newcommand{\\rubric}[1]'
             '{\\subsection*{~\\hfill {\\it #1} \\hfill ~}}\n'
+            '\\newcommand{\\titlereference}[1]{\\textsl{#1}}\n'
             '% end of "some commands"\n',
          ]
         }
 
+class DocumentClass:
+    """Details of a LaTeX document class."""
 
+    # BUG: LaTeX has no deeper sections (actually paragrah is no
+    # section either).
+    _class_sections = {
+        'book': ( 'chapter', 'section', 'subsection', 'subsubsection' ),
+        'report': ( 'chapter', 'section', 'subsection', 'subsubsection' ),
+        'article': ( 'section', 'subsection', 'subsubsection' ),
+        }
+    _deepest_section = 'subsubsection'
+
+    def __init__(self, document_class):
+        self.document_class = document_class
+
+    def section(self, level):
+        """ Return the section name at the given level for the specific
+            document class.
+
+            Level is 1,2,3..., as level 0 is the title."""
+
+        sections = self._class_sections[self.document_class]
+        if level <= len(sections):
+            return sections[level-1]
+        else:
+            return self._deepest_section
+
+
 class LaTeXTranslator(nodes.NodeVisitor):
     # When options are given to the documentclass, latex will pass them
     # to other packages, as done with babel.
@@ -277,6 +335,16 @@
     # list environment for docinfo. else tabularx
     use_optionlist_for_docinfo = 0 # NOT YET IN USE
 
+    # Use compound enumerations (1.A.1.)
+    compound_enumerators = 0
+
+    # If using compound enumerations, include section information.
+    section_prefix_for_enumerators = 0
+
+    # This is the character that separates the section ("." subsection ...)
+    # prefix from the regular list enumerator.
+    section_enumerator_separator = '-'
+
     # default link color
     hyperlink_color = "blue"
 
@@ -287,6 +355,11 @@
         self.use_latex_docinfo = settings.use_latex_docinfo
         self.use_latex_footnotes = settings.use_latex_footnotes
         self.hyperlink_color = settings.hyperlink_color
+        self.compound_enumerators = settings.compound_enumerators
+        self.section_prefix_for_enumerators = (
+            settings.section_prefix_for_enumerators)
+        self.section_enumerator_separator = (
+            settings.section_enumerator_separator.replace('_', '\\_'))
         if self.hyperlink_color == '0':
             self.hyperlink_color = 'black'
             self.colorlinks = 'false'
@@ -302,6 +375,9 @@
         if self.babel.get_language():
             self.d_options += ',%s' % \
                     self.babel.get_language()
+
+        self.d_class = DocumentClass(settings.documentclass)
+
         self.head_prefix = [
               self.latex_head % (self.d_options,self.settings.documentclass),
               '\\usepackage{babel}\n',     # language is in documents settings.
@@ -333,7 +409,7 @@
               '\\newlength{\\docinfowidth}\n',
               '\\setlength{\\docinfowidth}{0.9\\textwidth}\n'
               # linewidth of current environment, so tables are not wider
-              # than the sidebar: using locallinewidth seams to defer evaluation
+              # than the sidebar: using locallinewidth seems to defer evaluation
               # of linewidth, this is fixing it.
               '\\newlength{\\locallinewidth}\n',
               # will be set later.
@@ -368,6 +444,7 @@
         self.topic_class = ''
         # column specification for tables
         self.colspecs = []
+        self.table_caption = None
         # do we have one or more authors
         self.author_stack = None
         # Flags to encode
@@ -383,11 +460,24 @@
 
         # enumeration is done by list environment.
         self._enum_cnt = 0
+
+        # Stack of section counters so that we don't have to use_latex_toc.
+        # This will grow and shrink as processing occurs.
+        # Initialized for potential first-level sections.
+        self._section_number = [0]
+
+        # The current stack of enumerations so that we can expand
+        # them into a compound enumeration
+        self._enumeration_counters = []
+
         # docinfo.
         self.docinfo = None
         # inside literal block: no quote mangling.
         self.literal_block = 0
+        self.literal_block_stack = []
         self.literal = 0
+        # true when encoding in math mode
+        self.mathmode = 0
 
     def get_stylesheet_reference(self):
         if self.settings.stylesheet_path:
@@ -465,7 +555,7 @@
 
         # then dollar
         text = text.replace("$", '{\\$}')
-        if not ( self.literal_block or self.literal ):
+        if not ( self.literal_block or self.literal or self.mathmode ):
             # the vertical bar: in mathmode |,\vert or \mid
             #   in textmode \textbar
             text = text.replace("|", '{\\textbar}')
@@ -492,7 +582,13 @@
             # ! LaTeX Error: There's no line here to end.
             text = text.replace("\n", '~\\\\\n')
         elif self.mbox_newline:
-            text = text.replace("\n", '}\\\\\n\\mbox{')
+            if self.literal_block:
+                closings = "}" * len(self.literal_block_stack)
+                openings = "".join(self.literal_block_stack)
+            else:
+                closings = ""
+                openings = ""
+            text = text.replace("\n", "%s}\\\\\n\\mbox{%s" % (closings,openings))
         if self.insert_none_breaking_blanks:
             text = text.replace(' ', '~')
         # unicode !!!
@@ -528,14 +624,15 @@
     def depart_address(self, node):
         self.depart_docinfo_item(node)
 
-    def visit_admonition(self, node, name):
+    def visit_admonition(self, node, name=''):
         self.body.append('\\begin{center}\\begin{sffamily}\n')
         self.body.append('\\fbox{\\parbox{\\admonitionwidth}{\n')
-        self.body.append('\\textbf{\\large '+ self.language.labels[name] + '}\n');
+        if name:
+            self.body.append('\\textbf{\\large '+ self.language.labels[name] + '}\n');
         self.body.append('\\vspace{2mm}\n')
 
 
-    def depart_admonition(self):
+    def depart_admonition(self, node=None):
         self.body.append('}}\n') # end parbox fbox
         self.body.append('\\end{sffamily}\n\\end{center}\n');
 
@@ -582,6 +679,24 @@
         else:
             self.body.append( '\\end{itemize}\n' )
 
+    # Imperfect superscript/subscript handling: mathmode italicizes
+    # all letters by default.
+    def visit_superscript(self, node):
+        self.body.append('$^{')
+        self.mathmode = 1
+
+    def depart_superscript(self, node):
+        self.body.append('}$')
+        self.mathmode = 0
+
+    def visit_subscript(self, node):
+        self.body.append('$_{')
+        self.mathmode = 1
+
+    def depart_subscript(self, node):
+        self.body.append('}$')
+        self.mathmode = 0
+
     def visit_caption(self, node):
         self.body.append( '\\caption{' )
 
@@ -601,11 +716,10 @@
         self.depart_footnote(node)
 
     def visit_title_reference(self, node):
-        # BUG title-references are what?
-        pass
+        self.body.append( '\\titlereference{' )
 
     def depart_title_reference(self, node):
-        pass
+        self.body.append( '}' )
 
     def visit_citation_reference(self, node):
         href = ''
@@ -767,9 +881,11 @@
 
     def visit_emphasis(self, node):
         self.body.append('\\emph{')
+        self.literal_block_stack.append('\\emph{')
 
     def depart_emphasis(self, node):
         self.body.append('}')
+        self.literal_block_stack.pop()
 
     def visit_entry(self, node):
         # cell separation
@@ -781,13 +897,15 @@
 
         # multi{row,column}
         if node.has_key('morerows') and node.has_key('morecols'):
-            raise NotImplementedError('LaTeX can\'t handle cells that'
+            raise NotImplementedError('LaTeX can\'t handle cells that '
             'span multiple rows *and* columns, sorry.')
         atts = {}
         if node.has_key('morerows'):
+            raise NotImplementedError('multiple rows are not working (yet), sorry.')
             count = node['morerows'] + 1
             self.body.append('\\multirow{%d}*{' % count)
             self.context.append('}')
+            # BUG following rows must have empty cells.
         elif node.has_key('morecols'):
             # the vertical bar before column is missing if it is the first column.
             # the one after always.
@@ -830,13 +948,22 @@
         enum_prefix = ""
         if node.has_key('prefix'):
             enum_prefix = node['prefix']
-
+        if self.compound_enumerators:
+            pref = ""
+            if self.section_prefix_for_enumerators and self.section_level:
+                for i in range(self.section_level):
+                    pref += '%d.' % self._section_number[i]
+                pref = pref[:-1] + self.section_enumerator_separator
+                enum_prefix += pref
+            for counter in self._enumeration_counters:
+                enum_prefix += counter + '.'
         enum_type = "arabic"
         if node.has_key('enumtype'):
             enum_type = node['enumtype']
         if enum_style.has_key(enum_type):
             enum_type = enum_style[enum_type]
         counter_name = "listcnt%d" % self._enum_cnt;
+        self._enumeration_counters.append("\\%s{%s}" % (enum_type,counter_name))
         self.body.append('\\newcounter{%s}\n' % counter_name)
         self.body.append('\\begin{list}{%s\\%s{%s}%s}\n' % \
             (enum_prefix,enum_type,counter_name,enum_suffix))
@@ -852,6 +979,7 @@
 
     def depart_enumerated_list(self, node):
         self.body.append('\\end{list}\n')
+        self._enumeration_counters.pop()
 
     def visit_error(self, node):
         self.visit_admonition(node, 'error')
@@ -964,6 +1092,7 @@
             return
         self.body.append('}%s' % self.context.pop())
 
+    # elements generated by the framework e.g. section numbers.
     def visit_generated(self, node):
         pass
 
@@ -987,17 +1116,15 @@
         self.depart_admonition()
 
     def visit_image(self, node):
-        attrs = node.attributes.copy()
+        attrs = node.attributes
         pre = []                        # in reverse order
         post = ['\\includegraphics{%s}' % attrs['uri']]
-        def prepost(pre_append, post_append):
-            pre.append(pre_append)
-            post.append(post_append)
         inline = isinstance(node.parent, nodes.TextElement)
         if 'scale' in attrs:
             # Could also be done with ``scale`` option to
             # ``\includegraphics``; doing it this way for consistency.
-            prepost('\\scalebox{%f}{' % (attrs['scale'] / 100.0,), '}')
+            pre.append('\\scalebox{%f}{' % (attrs['scale'] / 100.0,))
+            post.append('}')
         if 'align' in attrs:
             align_prepost = {
                 # By default latex aligns the top of an image.
@@ -1011,11 +1138,13 @@
                 (0, 'left'): ('{', '\\hfill}'),
                 (0, 'right'): ('{\\hfill', '}'),}
             try:
-                prepost(*align_prepost[inline, attrs['align']])
+                pre.append(align_prepost[inline, attrs['align']][0])
+                post.append(align_prepost[inline, attrs['align']][1])
             except KeyError:
-                pass                    # complain here?
+                pass                    # XXX complain here?
         if not inline:
-            prepost('\n', '\n')
+            pre.append('\n')
+            post.append('\n')
         pre.reverse()
         self.body.extend(pre + post)
 
@@ -1054,6 +1183,8 @@
         * whitespace (including linebreaks) is significant
         * inline markup is supported.
         * serif typeface
+
+        mbox would stop LaTeX from wrapping long lines.
         """
         self.body.append('\\begin{flushleft}\n')
         self.insert_none_breaking_blanks = 1
@@ -1074,7 +1205,9 @@
         self.body.append('\n\\end{flushleft}\n')
 
     def visit_list_item(self, node):
-        self.body.append('\\item ')
+        # HACK append "{}" in case the next character is "[", which would break
+        # LaTeX's list environment (no numbering and the "[" is not printed).
+        self.body.append('\\item {} ')
 
     def depart_list_item(self, node):
         self.body.append('\n')
@@ -1089,31 +1222,51 @@
 
     def visit_literal_block(self, node):
         """
-        .. parsed-literal::
+        Render a literal-block.
+
+        Literal blocks are used for "::"-prefixed literal-indented
+        blocks of text, where the inline markup is not recognized,
+        but are also the product of the parsed-literal directive,
+        where the markup is respected.
+        
+        mbox stops LaTeX from wrapping long lines.
         """
-        # typically in a typewriter/monospaced typeface.
-        # care must be taken with the text, because inline markup is recognized.
+        # In both cases, we want to use a typewriter/monospaced typeface.
+        # For "real" literal-blocks, we can use \verbatim, while for all
+        # the others we must use \mbox.
         #
-        # possibilities:
-        # * verbatim: is no possibility, as inline markup does not work.
-        # * obey..: is from julien and never worked for me (grubert).
-        self.use_for_literal_block = "mbox"
-        self.literal_block = 1
-        if (self.use_for_literal_block == "mbox"):
+        # We can distinguish between the two kinds by the number of
+        # siblings the compose this node: if it is composed by a
+        # single element, it's surely is either a real one, otherwise
+        # it's a parsed-literal that does not contain any markup.
+        # 
+        if (self.settings.use_verbatim_when_possible and (len(node) == 1)
+              # in case of a parsed-literal containing just a "**bold**" word:
+              and isinstance(node[0], nodes.Text)):
+            self.verbatim = 1
+            self.body.append('\\begin{verbatim}\n')
+        else:
+            self.literal_block = 1
+            self.insert_none_breaking_blanks = 1
+            self.body.append('\\begin{ttfamily}\\begin{flushleft}\n')
             self.mbox_newline = 1
-            self.insert_none_breaking_blanks = 1
-            self.body.append('\\begin{ttfamily}\\begin{flushleft}\n\\mbox{')
-        else:
-            self.body.append('{\\obeylines\\obeyspaces\\ttfamily\n')
+            if self.mbox_newline:
+                self.body.append('\\mbox{')
+            # * obey..: is from julien and never worked for me (grubert).
+            #   self.body.append('{\\obeylines\\obeyspaces\\ttfamily\n')
 
     def depart_literal_block(self, node):
-        if (self.use_for_literal_block == "mbox"):
-            self.body.append('}\n\\end{flushleft}\\end{ttfamily}\n')
+        if self.verbatim:
+            self.body.append('\n\\end{verbatim}\n')
+            self.verbatim = 0
+        else:
+            if self.mbox_newline:
+                self.body.append('}')
+            self.body.append('\n\\end{flushleft}\\end{ttfamily}\n')
             self.insert_none_breaking_blanks = 0
             self.mbox_newline = 0
-        else:
-            self.body.append('}\n')
-        self.literal_block = 0
+            # obey end: self.body.append('}\n')
+            self.literal_block = 0
 
     def visit_meta(self, node):
         self.body.append('[visit_meta]\n')
@@ -1226,13 +1379,14 @@
         # BUG: hash_char "#" is trouble some in LaTeX.
         # mbox and other environment do not like the '#'.
         hash_char = '\\#'
-
         if node.has_key('refuri'):
-            href = node['refuri']
+            href = node['refuri'].replace('#',hash_char)
         elif node.has_key('refid'):
             href = hash_char + node['refid']
         elif node.has_key('refname'):
             href = hash_char + self.document.nameids[node['refname']]
+        else:
+            raise AssertionError('Unknown reference.')
         self.body.append('\\href{%s}{' % href)
 
     def depart_reference(self, node):
@@ -1250,11 +1404,18 @@
     def depart_row(self, node):
         self.context.pop()  # remove cell counter
         self.body.append(' \\\\ \\hline\n')
+        # BUG if multirow cells \cline{x-y}
 
     def visit_section(self, node):
         self.section_level += 1
+        # Initialize counter for potential subsections:
+        self._section_number.append(0)
+        # Counter for this section's level (initialized by parent section):
+        self._section_number[self.section_level - 1] += 1
 
     def depart_section(self, node):
+        # Remove counter for potential subsections:
+        self._section_number.pop()
         self.section_level -= 1
 
     def visit_sidebar(self, node):
@@ -1292,9 +1453,11 @@
 
     def visit_strong(self, node):
         self.body.append('\\textbf{')
+        self.literal_block_stack.append('\\textbf{')
 
     def depart_strong(self, node):
         self.body.append('}')
+        self.literal_block_stack.pop()
 
     def visit_substitution_definition(self, node):
         raise nodes.SkipNode
@@ -1328,13 +1491,20 @@
         Return column specification for longtable.
 
         Assumes reST line length being 80 characters.
+        Table width is hairy.
+
+        === ===
+        ABC DEF
+        === ===
+
+        usually gets to narrow, therefore we add 1 (fiddlefactor).
         """
         width = 80
 
         total_width = 0.0
         # first see if we get too wide.
         for node in self.colspecs:
-            colwidth = float(node['colwidth']) / width
+            colwidth = float(node['colwidth']+1) / width
             total_width += colwidth
         # donot make it full linewidth
         factor = 0.93
@@ -1343,8 +1513,8 @@
 
         latex_table_spec = ""
         for node in self.colspecs:
-            colwidth = factor * float(node['colwidth']) / width
-            latex_table_spec += "|p{%.2f\\locallinewidth}" % colwidth
+            colwidth = factor * float(node['colwidth']+1) / width
+            latex_table_spec += "|p{%.2f\\locallinewidth}" % (colwidth+0.005)
         self.colspecs = []
         return latex_table_spec+"|"
 
@@ -1369,6 +1539,9 @@
     def table_preamble(self):
         if self.use_longtable:
             self.body.append('{%s}\n' % self.get_colspecs())
+            if self.table_caption:
+                self.body.append('\\caption{%s}\\\\\n' % self.table_caption)
+                self.table_caption = None
         else:
             if self.context[-1] != 'table_sentinel':
                 self.body.append('{%s}' % ('|X' * self.context.pop() + '|'))
@@ -1476,6 +1649,10 @@
         elif isinstance(node.parent, nodes.sidebar):
             self.body.append('\\textbf{\\large ')
             self.context.append('}\n\\smallskip\n')
+        elif isinstance(node.parent, nodes.table):
+            # caption must be written after column spec
+            self.table_caption = node.astext()
+            raise nodes.SkipNode
         elif self.section_level == 0:
             # document title
             self.title = self.encode(node.astext())
@@ -1487,21 +1664,15 @@
             self.body.append('%' + '_' * 75)
             self.body.append('\n\n')
             self.bookmark(node)
-            # section_level 0 is title and handled above.
-            # BUG: latex has no deeper sections (actually paragrah is no section either).
+
             if self.use_latex_toc:
                 section_star = ""
             else:
                 section_star = "*"
-            if (self.section_level<=3):  # 1,2,3
-                self.body.append('\\%ssection%s{' % ('sub'*(self.section_level-1),section_star))
-            elif (self.section_level==4):
-                #self.body.append('\\paragraph*{')
-                self.body.append('\\subsubsection%s{' % (section_star))
-            else:
-                #self.body.append('\\subparagraph*{')
-                self.body.append('\\subsubsection%s{' % (section_star))
-            # BUG: self.body.append( '\\label{%s}\n' % name)
+
+            section_name = self.d_class.section(self.section_level)
+            self.body.append('\\%s%s{' % (section_name, section_star))
+
             self.context.append('}\n')
 
     def depart_title(self, node):

Modified: Zope/trunk/lib/python/docutils/writers/pep_html.py
===================================================================
--- Zope/trunk/lib/python/docutils/writers/pep_html.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/writers/pep_html.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Author: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:57 $
 # Copyright: This module has been placed in the public domain.
 
 """
@@ -88,15 +88,6 @@
 
 class HTMLTranslator(html4css1.HTMLTranslator):
 
-    def get_stylesheet_reference(self, relative_to=None):
-        settings = self.settings
-        if relative_to == None:
-            relative_to = settings._destination
-        if settings.stylesheet_path:
-            return utils.relative_path(relative_to, settings.stylesheet_path)
-        else:
-            return settings.stylesheet
-
     def depart_field_list(self, node):
         html4css1.HTMLTranslator.depart_field_list(self, node)
         if node.get('class') == 'rfc2822':

Modified: Zope/trunk/lib/python/docutils/writers/pseudoxml.py
===================================================================
--- Zope/trunk/lib/python/docutils/writers/pseudoxml.py	2004-05-13 14:53:16 UTC (rev 24624)
+++ Zope/trunk/lib/python/docutils/writers/pseudoxml.py	2004-05-13 15:25:53 UTC (rev 24625)
@@ -1,7 +1,7 @@
 # Authors: David Goodger
 # Contact: goodger at users.sourceforge.net
-# Revision: $Revision: 1.5 $
-# Date: $Date: 2003/11/30 15:06:09 $
+# Revision: $Revision: 1.2.10.3.8.1 $
+# Date: $Date: 2004/05/12 19:57:57 $
 # Copyright: This module has been placed in the public domain.
 
 """




More information about the Zope-Checkins mailing list