[Zope-Checkins] CVS: Zope/lib/python/docutils/writers -
__init__.py:1.2.10.3.8.1 docutils_xml.py:1.2.10.3.8.1
html4css1.py:1.2.10.3.8.1 latex2e.py:1.1.2.3.8.1
pep_html.py:1.2.10.3.8.1 pseudoxml.py:1.2.10.3.8.1
Christian 'Tiran' Heimes
heimes at faho.rwth-aachen.de
Wed May 12 15:58:01 EDT 2004
Update of /cvs-repository/Zope/lib/python/docutils/writers
In directory cvs.zope.org:/tmp/cvs-serv1763/lib/python/docutils/writers
Modified Files:
Tag: tiran-restfixing-branch
__init__.py docutils_xml.py html4css1.py latex2e.py
pep_html.py pseudoxml.py
Log Message:
Installed docutils 0.3.4
=== Zope/lib/python/docutils/writers/__init__.py 1.2.10.3 => 1.2.10.3.8.1 ===
--- Zope/lib/python/docutils/writers/__init__.py:1.2.10.3 Sun Nov 30 11:05:26 2003
+++ Zope/lib/python/docutils/writers/__init__.py Wed May 12 15:57:57 2004
@@ -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
@@ -65,6 +84,10 @@
used by the current Reader as well.
"""
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 = {
=== Zope/lib/python/docutils/writers/docutils_xml.py 1.2.10.3 => 1.2.10.3.8.1 ===
=== Zope/lib/python/docutils/writers/html4css1.py 1.2.10.3 => 1.2.10.3.8.1 ===
--- Zope/lib/python/docutils/writers/html4css1.py:1.2.10.3 Sun Nov 30 11:05:26 2003
+++ Zope/lib/python/docutils/writers/html4css1.py Wed May 12 15:57:57 2004
@@ -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,14 +102,17 @@
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', ''))
=== Zope/lib/python/docutils/writers/latex2e.py 1.1.2.3 => 1.1.2.3.8.1 ===
--- Zope/lib/python/docutils/writers/latex2e.py:1.1.2.3 Sun Nov 30 11:05:26 2003
+++ Zope/lib/python/docutils/writers/latex2e.py Wed May 12 15:57:57 2004
@@ -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,10 +275,38 @@
'% 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
@@ -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"):
- self.mbox_newline = 1
- self.insert_none_breaking_blanks = 1
- self.body.append('\\begin{ttfamily}\\begin{flushleft}\n\\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.body.append('{\\obeylines\\obeyspaces\\ttfamily\n')
+ self.literal_block = 1
+ self.insert_none_breaking_blanks = 1
+ self.body.append('\\begin{ttfamily}\\begin{flushleft}\n')
+ self.mbox_newline = 1
+ 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):
=== Zope/lib/python/docutils/writers/pep_html.py 1.2.10.3 => 1.2.10.3.8.1 ===
--- Zope/lib/python/docutils/writers/pep_html.py:1.2.10.3 Sun Nov 30 11:05:26 2003
+++ Zope/lib/python/docutils/writers/pep_html.py Wed May 12 15:57:57 2004
@@ -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':
=== Zope/lib/python/docutils/writers/pseudoxml.py 1.2.10.3 => 1.2.10.3.8.1 ===
More information about the Zope-Checkins
mailing list