diff --git a/docutils/__init__.py b/docutils/__init__.py deleted file mode 100644 index 9f1798144..000000000 --- a/docutils/__init__.py +++ /dev/null @@ -1,214 +0,0 @@ -# $Id: __init__.py 7446 2012-06-17 20:47:10Z grubert $ -# Author: David Goodger -# Copyright: This module has been placed in the public domain. - -""" -This is the Docutils (Python Documentation Utilities) package. - -Package Structure -================= - -Modules: - -- __init__.py: Contains component base classes, exception classes, and - Docutils version information. - -- core.py: Contains the ``Publisher`` class and ``publish_*()`` convenience - functions. - -- frontend.py: Runtime settings (command-line interface, configuration files) - processing, for Docutils front-ends. - -- io.py: Provides a uniform API for low-level input and output. - -- nodes.py: Docutils document tree (doctree) node class library. - -- statemachine.py: A finite state machine specialized for - regular-expression-based text filters. - -- urischemes.py: Contains a complete mapping of known URI addressing - scheme names to descriptions. - -Subpackages: - -- languages: Language-specific mappings of terms. - -- parsers: Syntax-specific input parser modules or packages. - -- readers: Context-specific input handlers which understand the data - source and manage a parser. - -- transforms: Modules used by readers and writers to modify DPS - doctrees. - -- utils: Contains the ``Reporter`` system warning class and miscellaneous - utilities used by readers, writers, and transforms. - -- writers: Format-specific output translators. -""" - -__docformat__ = 'reStructuredText' - -__version__ = '0.9.1' -"""``major.minor.micro`` version number. The micro number is bumped for API -changes, for new functionality, and for interim project releases. The minor -number is bumped whenever there is a significant 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.""" - -__version_details__ = 'release' -"""Extra version details (e.g. 'snapshot 2005-05-29, r3410', 'repository', -'release'), modified automatically & manually.""" - -import sys - -class ApplicationError(StandardError): - # Workaround: - # In Python < 2.6, unicode() calls `str` on the - # arg and therefore, e.g., unicode(StandardError(u'\u234')) fails - # with UnicodeDecodeError. - if sys.version_info < (2,6): - def __unicode__(self): - return u', '.join(self.args) - -class DataError(ApplicationError): pass - - -class SettingsSpec: - - """ - Runtime setting specification base class. - - SettingsSpec subclass objects used by `docutils.frontend.OptionParser`. - """ - - settings_spec = () - """Runtime settings specification. Override in subclasses. - - Defines runtime settings and associated command-line options, as used by - `docutils.frontend.OptionParser`. This is a tuple of: - - - Option group title (string or `None` which implies no group, just a list - of single options). - - - Description (string or `None`). - - - A sequence of option tuples. Each consists of: - - - Help text (string) - - - List of option strings (e.g. ``['-Q', '--quux']``). - - - Dictionary of keyword arguments sent to the OptionParser/OptionGroup - ``add_option`` method. - - Runtime setting names are derived implicitly from long option names - ('--a-setting' becomes ``settings.a_setting``) or explicitly from the - 'dest' keyword argument. - - Most settings will also have a 'validator' keyword & function. The - validator function validates setting values (from configuration files - and command-line option arguments) and converts them to appropriate - types. For example, the ``docutils.frontend.validate_boolean`` - function, **required by all boolean settings**, converts true values - ('1', 'on', 'yes', and 'true') to 1 and false values ('0', 'off', - 'no', 'false', and '') to 0. Validators need only be set once per - setting. See the `docutils.frontend.validate_*` functions. - - See the optparse docs for more details. - - - More triples of group title, description, options, as many times as - needed. Thus, `settings_spec` tuples can be simply concatenated. - """ - - settings_defaults = None - """A dictionary of defaults for settings not in `settings_spec` (internal - settings, intended to be inaccessible by command-line and config file). - Override in subclasses.""" - - settings_default_overrides = None - """A dictionary of auxiliary defaults, to override defaults for settings - defined in other components. Override in subclasses.""" - - relative_path_settings = () - """Settings containing filesystem paths. Override in subclasses. - Settings listed here are to be interpreted relative to the current working - directory.""" - - config_section = None - """The name of the config file section specific to this component - (lowercase, no brackets). Override in subclasses.""" - - config_section_dependencies = None - """A list of names of config file sections that are to be applied before - `config_section`, in order (from general to specific). In other words, - the settings in `config_section` are to be overlaid on top of the settings - from these sections. The "general" section is assumed implicitly. - Override in subclasses.""" - - -class TransformSpec: - - """ - Runtime transform specification base class. - - TransformSpec subclass objects used by `docutils.transforms.Transformer`. - """ - - def get_transforms(self): - """Transforms required by this class. Override in subclasses.""" - if self.default_transforms != (): - import warnings - warnings.warn('default_transforms attribute deprecated.\n' - 'Use get_transforms() method instead.', - DeprecationWarning) - return list(self.default_transforms) - return [] - - # Deprecated; for compatibility. - default_transforms = () - - unknown_reference_resolvers = () - """List of functions to try to resolve unknown references. Unknown - references have a 'refname' attribute which doesn't correspond to any - target in the document. Called when the transforms in - `docutils.tranforms.references` are 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.''' - - If the function is able to resolve the reference, it should also remove - the 'refname' attribute and mark the node as resolved:: - - del node['refname'] - node.resolved = 1 - - 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 - """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? - - To be used by transforms to ask the dependent component if it supports - a certain input context or output format. - """ - return format in self.supported diff --git a/docutils/_compat.py b/docutils/_compat.py deleted file mode 100644 index 99f346666..000000000 --- a/docutils/_compat.py +++ /dev/null @@ -1,37 +0,0 @@ -# $Id: _compat.py 7316 2012-01-19 11:31:58Z milde $ -# Author: Georg Brandl -# Copyright: This module has been placed in the public domain. - -""" -Python 2/3 compatibility definitions. - -This module currently provides the following helper symbols: - -* bytes (name of byte string type; str in 2.x, bytes in 3.x) -* b (function converting a string literal to an ASCII byte string; - can be also used to convert a Unicode string into a byte string) -* u_prefix (unicode repr prefix: 'u' in 2.x, '' in 3.x) - (Required in docutils/test/test_publisher.py) -* BytesIO (a StringIO class that works with bytestrings) -""" - -import sys - -if sys.version_info < (3,0): - b = bytes = str - u_prefix = 'u' - from StringIO import StringIO as BytesIO -else: - import builtins - bytes = builtins.bytes - u_prefix = '' - def b(s): - if isinstance(s, str): - return s.encode('latin1') - elif isinstance(s, bytes): - return s - else: - raise TypeError("Invalid argument %r for b()" % (s,)) - # using this hack since 2to3 "fixes" the relative import - # when using ``from io import BytesIO`` - BytesIO = __import__('io').BytesIO diff --git a/docutils/_string_template_compat.py b/docutils/_string_template_compat.py deleted file mode 100644 index 38929c296..000000000 --- a/docutils/_string_template_compat.py +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf8 -*- - -# string_template_compat.py: string.Template for Python <= 2.4 -# ===================================================== - -# This is just an excerpt of the standard string module to provide backwards -# compatibility. - -import re as _re - -class _multimap: - """Helper class for combining multiple mappings. - - Used by .{safe_,}substitute() to combine the mapping and keyword - arguments. - """ - def __init__(self, primary, secondary): - self._primary = primary - self._secondary = secondary - - def __getitem__(self, key): - try: - return self._primary[key] - except KeyError: - return self._secondary[key] - - -class _TemplateMetaclass(type): - pattern = r""" - %(delim)s(?: - (?P%(delim)s) | # Escape sequence of two delimiters - (?P%(id)s) | # delimiter and a Python identifier - {(?P%(id)s)} | # delimiter and a braced identifier - (?P) # Other ill-formed delimiter exprs - ) - """ - - def __init__(cls, name, bases, dct): - super(_TemplateMetaclass, cls).__init__(name, bases, dct) - if 'pattern' in dct: - pattern = cls.pattern - else: - pattern = _TemplateMetaclass.pattern % { - 'delim' : _re.escape(cls.delimiter), - 'id' : cls.idpattern, - } - cls.pattern = _re.compile(pattern, _re.IGNORECASE | _re.VERBOSE) - - -class Template: - """A string class for supporting $-substitutions.""" - __metaclass__ = _TemplateMetaclass - - delimiter = '$' - idpattern = r'[_a-z][_a-z0-9]*' - - def __init__(self, template): - self.template = template - - # Search for $$, $identifier, ${identifier}, and any bare $'s - - def _invalid(self, mo): - i = mo.start('invalid') - lines = self.template[:i].splitlines(True) - if not lines: - colno = 1 - lineno = 1 - else: - colno = i - len(''.join(lines[:-1])) - lineno = len(lines) - raise ValueError('Invalid placeholder in string: line %d, col %d' % - (lineno, colno)) - - def substitute(self, *args, **kws): - if len(args) > 1: - raise TypeError('Too many positional arguments') - if not args: - mapping = kws - elif kws: - mapping = _multimap(kws, args[0]) - else: - mapping = args[0] - # Helper function for .sub() - def convert(mo): - # Check the most common path first. - named = mo.group('named') or mo.group('braced') - if named is not None: - val = mapping[named] - # We use this idiom instead of str() because the latter will - # fail if val is a Unicode containing non-ASCII characters. - return '%s' % (val,) - if mo.group('escaped') is not None: - return self.delimiter - if mo.group('invalid') is not None: - self._invalid(mo) - raise ValueError('Unrecognized named group in pattern', - self.pattern) - return self.pattern.sub(convert, self.template) - - def safe_substitute(self, *args, **kws): - if len(args) > 1: - raise TypeError('Too many positional arguments') - if not args: - mapping = kws - elif kws: - mapping = _multimap(kws, args[0]) - else: - mapping = args[0] - # Helper function for .sub() - def convert(mo): - named = mo.group('named') - if named is not None: - try: - # We use this idiom instead of str() because the latter - # will fail if val is a Unicode containing non-ASCII - return '%s' % (mapping[named],) - except KeyError: - return self.delimiter + named - braced = mo.group('braced') - if braced is not None: - try: - return '%s' % (mapping[braced],) - except KeyError: - return self.delimiter + '{' + braced + '}' - if mo.group('escaped') is not None: - return self.delimiter - if mo.group('invalid') is not None: - return self.delimiter - raise ValueError('Unrecognized named group in pattern', - self.pattern) - return self.pattern.sub(convert, self.template) - diff --git a/docutils/core.py b/docutils/core.py deleted file mode 100644 index 0dea4ffc4..000000000 --- a/docutils/core.py +++ /dev/null @@ -1,667 +0,0 @@ -# $Id: core.py 7384 2012-03-19 22:59:09Z milde $ -# Author: David Goodger -# Copyright: This module has been placed in the public domain. - -""" -Calling the ``publish_*`` convenience functions (or instantiating a -`Publisher` object) with component names will result in default -behavior. For custom behavior (setting component options), create -custom component objects first, and pass *them* to -``publish_*``/`Publisher`. See `The Docutils Publisher`_. - -.. _The Docutils Publisher: http://docutils.sf.net/docs/api/publisher.html -""" - -__docformat__ = 'reStructuredText' - -import sys -import pprint -from docutils import __version__, __version_details__, SettingsSpec -from docutils import frontend, io, utils, readers, writers -from docutils.frontend import OptionParser -from docutils.transforms import Transformer -from docutils.error_reporting import ErrorOutput, ErrorString -import docutils.readers.doctree - -class Publisher: - - """ - A facade encapsulating the high-level logic of a Docutils system. - """ - - def __init__(self, reader=None, parser=None, writer=None, - source=None, source_class=io.FileInput, - destination=None, destination_class=io.FileOutput, - settings=None): - """ - Initial setup. If any of `reader`, `parser`, or `writer` are not - specified, the corresponding ``set_...`` method should be called with - a component name (`set_reader` sets the parser as well). - """ - - self.document = None - """The document tree (`docutils.nodes` objects).""" - - self.reader = reader - """A `docutils.readers.Reader` instance.""" - - self.parser = parser - """A `docutils.parsers.Parser` instance.""" - - self.writer = writer - """A `docutils.writers.Writer` instance.""" - - for component in 'reader', 'parser', 'writer': - assert not isinstance(getattr(self, component), str), ( - 'passed string "%s" as "%s" parameter; pass an instance, ' - 'or use the "%s_name" parameter instead (in ' - 'docutils.core.publish_* convenience functions).' - % (getattr(self, component), component, component)) - - self.source = source - """The source of input data, a `docutils.io.Input` instance.""" - - self.source_class = source_class - """The class for dynamically created source objects.""" - - self.destination = destination - """The destination for docutils output, a `docutils.io.Output` - instance.""" - - self.destination_class = destination_class - """The class for dynamically created destination objects.""" - - self.settings = settings - """An object containing Docutils settings as instance attributes. - Set by `self.process_command_line()` or `self.get_settings()`.""" - - self._stderr = ErrorOutput() - - def set_reader(self, reader_name, parser, parser_name): - """Set `self.reader` by name.""" - reader_class = readers.get_reader_class(reader_name) - self.reader = reader_class(parser, parser_name) - self.parser = self.reader.parser - - def set_writer(self, writer_name): - """Set `self.writer` by name.""" - writer_class = writers.get_writer_class(writer_name) - self.writer = writer_class() - - def set_components(self, reader_name, parser_name, writer_name): - if self.reader is None: - self.set_reader(reader_name, self.parser, parser_name) - if self.parser is None: - if self.reader.parser is None: - self.reader.set_parser(parser_name) - self.parser = self.reader.parser - if self.writer is None: - self.set_writer(writer_name) - - def setup_option_parser(self, usage=None, description=None, - settings_spec=None, config_section=None, - **defaults): - if config_section: - if not settings_spec: - settings_spec = SettingsSpec() - settings_spec.config_section = config_section - parts = config_section.split() - if len(parts) > 1 and parts[-1] == 'application': - settings_spec.config_section_dependencies = ['applications'] - #@@@ Add self.source & self.destination to components in future? - option_parser = OptionParser( - components=(self.parser, self.reader, self.writer, settings_spec), - defaults=defaults, read_config_files=True, - usage=usage, description=description) - return option_parser - - def get_settings(self, usage=None, description=None, - settings_spec=None, config_section=None, **defaults): - """ - Set and return default settings (overrides in `defaults` dict). - - Set components first (`self.set_reader` & `self.set_writer`). - Explicitly setting `self.settings` disables command line option - processing from `self.publish()`. - """ - option_parser = self.setup_option_parser( - usage, description, settings_spec, config_section, **defaults) - self.settings = option_parser.get_default_values() - return self.settings - - def process_programmatic_settings(self, settings_spec, - settings_overrides, - config_section): - if self.settings is None: - defaults = (settings_overrides or {}).copy() - # Propagate exceptions by default when used programmatically: - defaults.setdefault('traceback', True) - self.get_settings(settings_spec=settings_spec, - config_section=config_section, - **defaults) - - def process_command_line(self, argv=None, usage=None, description=None, - settings_spec=None, config_section=None, - **defaults): - """ - Pass an empty list to `argv` to avoid reading `sys.argv` (the - default). - - Set components first (`self.set_reader` & `self.set_writer`). - """ - option_parser = self.setup_option_parser( - usage, description, settings_spec, config_section, **defaults) - if argv is None: - argv = sys.argv[1:] - # converting to Unicode (Python 3 does this automatically): - if sys.version_info < (3,0): - # TODO: make this failsafe and reversible? - argv_encoding = (frontend.locale_encoding or 'ascii') - argv = [a.decode(argv_encoding) for a in argv] - self.settings = option_parser.parse_args(argv) - - def set_io(self, source_path=None, destination_path=None): - if self.source is None: - self.set_source(source_path=source_path) - if self.destination is None: - self.set_destination(destination_path=destination_path) - - def set_source(self, source=None, source_path=None): - if source_path is None: - source_path = self.settings._source - else: - self.settings._source = source_path - # Raise IOError instead of system exit with `tracback == True` - # TODO: change io.FileInput's default behaviour and remove this hack - try: - self.source = self.source_class( - source=source, source_path=source_path, - encoding=self.settings.input_encoding, - handle_io_errors=False) - except TypeError: - self.source = self.source_class( - source=source, source_path=source_path, - encoding=self.settings.input_encoding) - - def set_destination(self, destination=None, destination_path=None): - if destination_path is None: - destination_path = self.settings._destination - else: - self.settings._destination = destination_path - self.destination = self.destination_class( - destination=destination, destination_path=destination_path, - encoding=self.settings.output_encoding, - error_handler=self.settings.output_encoding_error_handler) - # Raise IOError instead of system exit with `tracback == True` - # TODO: change io.FileInput's default behaviour and remove this hack - self.destination.handle_io_errors=False - - def apply_transforms(self): - self.document.transformer.populate_from_components( - (self.source, self.reader, self.reader.parser, self.writer, - self.destination)) - self.document.transformer.apply_transforms() - - def publish(self, argv=None, usage=None, description=None, - settings_spec=None, settings_overrides=None, - config_section=None, enable_exit_status=False): - """ - Process command line options and arguments (if `self.settings` not - already set), run `self.reader` and then `self.writer`. Return - `self.writer`'s output. - """ - exit = None - try: - if self.settings is None: - self.process_command_line( - argv, usage, description, settings_spec, config_section, - **(settings_overrides or {})) - self.set_io() - self.document = self.reader.read(self.source, self.parser, - self.settings) - self.apply_transforms() - output = self.writer.write(self.document, self.destination) - self.writer.assemble_parts() - except SystemExit, error: - exit = 1 - exit_status = error.code - except Exception, error: - if not self.settings: # exception too early to report nicely - raise - if self.settings.traceback: # Propagate exceptions? - self.debugging_dumps() - raise - self.report_Exception(error) - exit = True - exit_status = 1 - self.debugging_dumps() - if (enable_exit_status and self.document - and (self.document.reporter.max_level - >= self.settings.exit_status_level)): - sys.exit(self.document.reporter.max_level + 10) - elif exit: - sys.exit(exit_status) - return output - - def debugging_dumps(self): - if not self.document: - return - if self.settings.dump_settings: - print >>self._stderr, '\n::: Runtime settings:' - print >>self._stderr, pprint.pformat(self.settings.__dict__) - if self.settings.dump_internals: - print >>self._stderr, '\n::: Document internals:' - print >>self._stderr, pprint.pformat(self.document.__dict__) - if self.settings.dump_transforms: - print >>self._stderr, '\n::: Transforms applied:' - print >>self._stderr, (' (priority, transform class, ' - 'pending node details, keyword args)') - print >>self._stderr, pprint.pformat( - [(priority, '%s.%s' % (xclass.__module__, xclass.__name__), - pending and pending.details, kwargs) - for priority, xclass, pending, kwargs - in self.document.transformer.applied]) - if self.settings.dump_pseudo_xml: - print >>self._stderr, '\n::: Pseudo-XML:' - print >>self._stderr, self.document.pformat().encode( - 'raw_unicode_escape') - - def report_Exception(self, error): - if isinstance(error, utils.SystemMessage): - self.report_SystemMessage(error) - elif isinstance(error, UnicodeEncodeError): - self.report_UnicodeError(error) - elif isinstance(error, io.InputError): - self._stderr.write(u'Unable to open source file for reading:\n' - u' %s\n' % ErrorString(error)) - elif isinstance(error, io.OutputError): - self._stderr.write( - u'Unable to open destination file for writing:\n' - u' %s\n' % ErrorString(error)) - else: - print >>self._stderr, u'%s' % ErrorString(error) - print >>self._stderr, ("""\ -Exiting due to error. Use "--traceback" to diagnose. -Please report errors to . -Include "--traceback" output, Docutils version (%s [%s]), -Python version (%s), your OS type & version, and the -command line used.""" % (__version__, __version_details__, - sys.version.split()[0])) - - def report_SystemMessage(self, error): - print >>self._stderr, ('Exiting due to level-%s (%s) system message.' - % (error.level, - utils.Reporter.levels[error.level])) - - def report_UnicodeError(self, error): - data = error.object[error.start:error.end] - self._stderr.write( - '%s\n' - '\n' - 'The specified output encoding (%s) cannot\n' - 'handle all of the output.\n' - 'Try setting "--output-encoding-error-handler" to\n' - '\n' - '* "xmlcharrefreplace" (for HTML & XML output);\n' - ' the output will contain "%s" and should be usable.\n' - '* "backslashreplace" (for other output formats);\n' - ' look for "%s" in the output.\n' - '* "replace"; look for "?" in the output.\n' - '\n' - '"--output-encoding-error-handler" is currently set to "%s".\n' - '\n' - 'Exiting due to error. Use "--traceback" to diagnose.\n' - 'If the advice above doesn\'t eliminate the error,\n' - 'please report it to .\n' - 'Include "--traceback" output, Docutils version (%s),\n' - 'Python version (%s), your OS type & version, and the\n' - 'command line used.\n' - % (ErrorString(error), - self.settings.output_encoding, - data.encode('ascii', 'xmlcharrefreplace'), - data.encode('ascii', 'backslashreplace'), - self.settings.output_encoding_error_handler, - __version__, sys.version.split()[0])) - -default_usage = '%prog [options] [ []]' -default_description = ('Reads from (default is stdin) and writes to ' - ' (default is stdout). See ' - ' for ' - 'the full reference.') - -def publish_cmdline(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_status=True, argv=None, - usage=default_usage, description=default_description): - """ - Set up & run a `Publisher` for command-line-based file I/O (input and - output file paths taken automatically from the command line). Return the - encoded string output also. - - Parameters: see `publish_programmatically` for the remainder. - - - `argv`: Command-line argument list to use instead of ``sys.argv[1:]``. - - `usage`: Usage string, output if there's a problem parsing the command - line. - - `description`: Program description, output for the "--help" option - (along with command-line option descriptions). - """ - pub = Publisher(reader, parser, writer, settings=settings) - pub.set_components(reader_name, parser_name, writer_name) - output = pub.publish( - argv, usage, description, settings_spec, settings_overrides, - config_section=config_section, enable_exit_status=enable_exit_status) - return output - -def publish_file(source=None, source_path=None, - destination=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_status=False): - """ - Set up & run a `Publisher` for programmatic use with file-like I/O. - Return the encoded string output also. - - Parameters: see `publish_programmatically`. - """ - output, pub = publish_programmatically( - source_class=io.FileInput, source=source, source_path=source_path, - destination_class=io.FileOutput, - destination=destination, destination_path=destination_path, - reader=reader, reader_name=reader_name, - parser=parser, parser_name=parser_name, - writer=writer, writer_name=writer_name, - settings=settings, settings_spec=settings_spec, - settings_overrides=settings_overrides, - config_section=config_section, - enable_exit_status=enable_exit_status) - return output - -def publish_string(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_status=False): - """ - Set up & run a `Publisher` for programmatic use with string I/O. Return - the encoded string or Unicode string output. - - For encoded string output, be sure to set the 'output_encoding' setting to - the desired encoding. Set it to 'unicode' for unencoded Unicode string - output. Here's one way:: - - publish_string(..., settings_overrides={'output_encoding': 'unicode'}) - - Similarly for Unicode string input (`source`):: - - publish_string(..., settings_overrides={'input_encoding': 'unicode'}) - - Parameters: see `publish_programmatically`. - """ - output, pub = publish_programmatically( - source_class=io.StringInput, source=source, source_path=source_path, - destination_class=io.StringOutput, - destination=None, destination_path=destination_path, - reader=reader, reader_name=reader_name, - parser=parser, parser_name=parser_name, - writer=writer, writer_name=writer_name, - settings=settings, settings_spec=settings_spec, - settings_overrides=settings_overrides, - config_section=config_section, - enable_exit_status=enable_exit_status) - return output - -def publish_parts(source, source_path=None, source_class=io.StringInput, - 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_status=False): - """ - 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_parts(..., settings_overrides={'input_encoding': 'unicode'}) - - Parameters: see `publish_programmatically`. - """ - output, pub = publish_programmatically( - source=source, source_path=source_path, source_class=source_class, - destination_class=io.StringOutput, - destination=None, destination_path=destination_path, - reader=reader, reader_name=reader_name, - parser=parser, parser_name=parser_name, - writer=writer, writer_name=writer_name, - settings=settings, settings_spec=settings_spec, - settings_overrides=settings_overrides, - config_section=config_section, - enable_exit_status=enable_exit_status) - return pub.writer.parts - -def publish_doctree(source, source_path=None, - source_class=io.StringInput, - reader=None, reader_name='standalone', - parser=None, parser_name='restructuredtext', - settings=None, settings_spec=None, - settings_overrides=None, config_section=None, - enable_exit_status=False): - """ - Set up & run a `Publisher` for programmatic use with string I/O. - Return the document tree. - - 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 one way:: - - publish_doctree(..., settings_overrides={'input_encoding': 'unicode'}) - - Parameters: see `publish_programmatically`. - """ - pub = Publisher(reader=reader, parser=parser, writer=None, - settings=settings, - source_class=source_class, - destination_class=io.NullOutput) - pub.set_components(reader_name, parser_name, 'null') - pub.process_programmatic_settings( - settings_spec, settings_overrides, config_section) - pub.set_source(source, source_path) - pub.set_destination(None, None) - output = pub.publish(enable_exit_status=enable_exit_status) - return pub.document - -def publish_from_doctree(document, destination_path=None, - writer=None, writer_name='pseudoxml', - settings=None, settings_spec=None, - settings_overrides=None, config_section=None, - enable_exit_status=False): - """ - Set up & run a `Publisher` to render from an existing document - tree data structure, for programmatic use with string I/O. Return - the encoded string output. - - Note that document.settings is overridden; if you want to use the settings - of the original `document`, pass settings=document.settings. - - Also, new document.transformer and document.reporter objects are - generated. - - For encoded string output, be sure to set the 'output_encoding' setting to - the desired encoding. Set it to 'unicode' for unencoded Unicode string - output. Here's one way:: - - publish_from_doctree( - ..., settings_overrides={'output_encoding': 'unicode'}) - - Parameters: `document` is a `docutils.nodes.document` object, an existing - document tree. - - Other parameters: see `publish_programmatically`. - """ - reader = docutils.readers.doctree.Reader(parser_name='null') - pub = Publisher(reader, None, writer, - source=io.DocTreeInput(document), - destination_class=io.StringOutput, settings=settings) - if not writer and writer_name: - pub.set_writer(writer_name) - pub.process_programmatic_settings( - settings_spec, settings_overrides, config_section) - pub.set_destination(None, destination_path) - return pub.publish(enable_exit_status=enable_exit_status) - -def publish_cmdline_to_binary(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_status=True, argv=None, - usage=default_usage, description=default_description, - destination=None, destination_class=io.BinaryFileOutput - ): - """ - Set up & run a `Publisher` for command-line-based file I/O (input and - output file paths taken automatically from the command line). Return the - encoded string output also. - - This is just like publish_cmdline, except that it uses - io.BinaryFileOutput instead of io.FileOutput. - - Parameters: see `publish_programmatically` for the remainder. - - - `argv`: Command-line argument list to use instead of ``sys.argv[1:]``. - - `usage`: Usage string, output if there's a problem parsing the command - line. - - `description`: Program description, output for the "--help" option - (along with command-line option descriptions). - """ - pub = Publisher(reader, parser, writer, settings=settings, - destination_class=destination_class) - pub.set_components(reader_name, parser_name, writer_name) - output = pub.publish( - argv, usage, description, settings_spec, settings_overrides, - config_section=config_section, enable_exit_status=enable_exit_status) - return output - -def publish_programmatically(source_class, source, source_path, - destination_class, destination, destination_path, - reader, reader_name, - parser, parser_name, - writer, writer_name, - settings, settings_spec, - settings_overrides, config_section, - enable_exit_status): - """ - Set up & run a `Publisher` for custom programmatic use. Return the - encoded string output and the Publisher object. - - Applications should not need to call this function directly. If it does - seem to be necessary to call this function directly, please write to the - Docutils-develop mailing list - . - - Parameters: - - * `source_class` **required**: The class for dynamically created source - objects. Typically `io.FileInput` or `io.StringInput`. - - * `source`: Type depends on `source_class`: - - - If `source_class` is `io.FileInput`: Either a file-like object - (must have 'read' and 'close' methods), or ``None`` - (`source_path` is opened). If neither `source` nor - `source_path` are supplied, `sys.stdin` is used. - - - If `source_class` is `io.StringInput` **required**: The input - string, either 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`: Type depends on `source_class`: - - - `io.FileInput`: Path to the input file, opened if no `source` - supplied. - - - `io.StringInput`: Optional. Path to the file or object that produced - `source`. Only used for diagnostic output. - - * `destination_class` **required**: The class for dynamically created - destination objects. Typically `io.FileOutput` or `io.StringOutput`. - - * `destination`: Type depends on `destination_class`: - - - `io.FileOutput`: Either a file-like object (must have 'write' and - 'close' methods), or ``None`` (`destination_path` is opened). If - neither `destination` nor `destination_path` are supplied, - `sys.stdout` is used. - - - `io.StringOutput`: Not used; pass ``None``. - - * `destination_path`: Type depends on `destination_class`: - - - `io.FileOutput`: Path to the output file. Opened if no `destination` - supplied. - - - `io.StringOutput`: 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`: A runtime settings (`docutils.frontend.Values`) object, for - dotted-attribute access to runtime settings. It's the end result of the - `SettingsSpec`, config file, and option processing. If `settings` is - passed, it's assumed to be complete and no further setting/config/option - processing is done. - - * `settings_spec`: A `docutils.SettingsSpec` subclass or object. Provides - extra application-specific settings definitions independently of - components. In other words, the application becomes a component, and - its settings data is processed along with that of the other components. - Used only if no `settings` specified. - - * `settings_overrides`: A dictionary containing application-specific - settings defaults that override the defaults of other components. - Used only if no `settings` specified. - - * `config_section`: A string, the name of the configuration file section - for this application. Overrides the ``config_section`` attribute - defined by `settings_spec`. Used only if no `settings` specified. - - * `enable_exit_status`: Boolean; enable exit status at end of processing? - """ - pub = Publisher(reader, parser, writer, settings=settings, - source_class=source_class, - destination_class=destination_class) - pub.set_components(reader_name, parser_name, writer_name) - pub.process_programmatic_settings( - settings_spec, settings_overrides, config_section) - pub.set_source(source, source_path) - pub.set_destination(destination, destination_path) - output = pub.publish(enable_exit_status=enable_exit_status) - return output, pub diff --git a/docutils/docutils.conf b/docutils/docutils.conf deleted file mode 100644 index cdce8d629..000000000 --- a/docutils/docutils.conf +++ /dev/null @@ -1,5 +0,0 @@ -# This configuration file is to prevent tools/buildhtml.py from -# processing text files in and below this directory. - -[buildhtml application] -prune: . diff --git a/docutils/error_reporting.py b/docutils/error_reporting.py deleted file mode 100644 index 797dc41c0..000000000 --- a/docutils/error_reporting.py +++ /dev/null @@ -1,207 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf8 -*- - -# :Id: $Id: error_reporting.py 7423 2012-05-03 11:01:54Z milde $ -# :Copyright: © 2011 Günter Milde. -# :License: Released under the terms of the `2-Clause BSD license`_, in short: -# -# Copying and distribution of this file, with or without modification, -# are permitted in any medium without royalty provided the copyright -# notice and this notice are preserved. -# This file is offered as-is, without any warranty. -# -# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause - -""" -Error reporting should be safe from encoding/decoding errors. -However, implicit conversions of strings and exceptions like - ->>> u'%s world: %s' % ('H\xe4llo', Exception(u'H\xe4llo') - -fail in some Python versions: - -* In Python <= 2.6, ``unicode()`` uses - `__str__` and fails with non-ASCII chars in`unicode` arguments. - (work around http://bugs.python.org/issue2517): - -* In Python 2, unicode() fails, with non-ASCII - chars in arguments. (Use case: in some locales, the errstr - argument of IOError contains non-ASCII chars.) - -* In Python 2, str() fails, with non-ASCII chars - in `unicode` arguments. - -The `SafeString`, `ErrorString` and `ErrorOutput` classes handle -common exceptions. -""" - -import sys, codecs - -# Guess the locale's encoding. -# If no valid guess can be made, locale_encoding is set to `None`: -try: - import locale # module missing in Jython -except ImportError: - locale_encoding = None -else: - locale_encoding = locale.getlocale()[1] or locale.getdefaultlocale()[1] - # locale.getpreferredencoding([do_setlocale=True|False]) - # has side-effects | might return a wrong guess. - # (cf. Update 1 in http://stackoverflow.com/questions/4082645/using-python-2-xs-locale-module-to-format-numbers-and-currency) - try: - codecs.lookup(locale_encoding or '') # None -> '' - except LookupError: - locale_encoding = None - - - -class SafeString(object): - """ - A wrapper providing robust conversion to `str` and `unicode`. - """ - - def __init__(self, data, encoding=None, encoding_errors='backslashreplace', - decoding_errors='replace'): - self.data = data - self.encoding = (encoding or getattr(data, 'encoding', None) or - locale_encoding or 'ascii') - self.encoding_errors = encoding_errors - self.decoding_errors = decoding_errors - - - def __str__(self): - try: - return str(self.data) - except UnicodeEncodeError, err: - if isinstance(self.data, Exception): - args = [str(SafeString(arg, self.encoding, - self.encoding_errors)) - for arg in self.data.args] - return ', '.join(args) - if isinstance(self.data, unicode): - return self.data.encode(self.encoding, self.encoding_errors) - raise - - def __unicode__(self): - """ - Return unicode representation of `self.data`. - - Try ``unicode(self.data)``, catch `UnicodeError` and - - * if `self.data` is an Exception instance, work around - http://bugs.python.org/issue2517 with an emulation of - Exception.__unicode__, - - * else decode with `self.encoding` and `self.decoding_errors`. - """ - try: - u = unicode(self.data) - if isinstance(self.data, EnvironmentError): - u = u.replace(": u'", ": '") # normalize filename quoting - return u - except UnicodeError, error: # catch ..Encode.. and ..Decode.. errors - if isinstance(self.data, EnvironmentError): - return u"[Errno %s] %s: '%s'" % (self.data.errno, - SafeString(self.data.strerror, self.encoding, - self.decoding_errors), - SafeString(self.data.filename, self.encoding, - self.decoding_errors)) - if isinstance(self.data, Exception): - args = [unicode(SafeString(arg, self.encoding, - decoding_errors=self.decoding_errors)) - for arg in self.data.args] - return u', '.join(args) - if isinstance(error, UnicodeDecodeError): - return unicode(self.data, self.encoding, self.decoding_errors) - raise - -class ErrorString(SafeString): - """ - Safely report exception type and message. - """ - def __str__(self): - return '%s: %s' % (self.data.__class__.__name__, - super(ErrorString, self).__str__()) - - def __unicode__(self): - return u'%s: %s' % (self.data.__class__.__name__, - super(ErrorString, self).__unicode__()) - - -class ErrorOutput(object): - """ - Wrapper class for file-like error streams with - failsave de- and encoding of `str`, `bytes`, `unicode` and - `Exception` instances. - """ - - def __init__(self, stream=None, encoding=None, - encoding_errors='backslashreplace', - decoding_errors='replace'): - """ - :Parameters: - - `stream`: a file-like object, - a string (path to a file), - `None` (write to `sys.stderr`, default), or - evaluating to `False` (write() requests are ignored). - - `encoding`: `stream` text encoding. Guessed if None. - - `encoding_errors`: how to treat encoding errors. - """ - if stream is None: - stream = sys.stderr - elif not(stream): - stream = False - # if `stream` is a file name, open it - elif isinstance(stream, str): - stream = open(stream, 'w') - elif isinstance(stream, unicode): - stream = open(stream.encode(sys.getfilesystemencoding()), 'w') - - self.stream = stream - """Where warning output is sent.""" - - self.encoding = (encoding or getattr(stream, 'encoding', None) or - locale_encoding or 'ascii') - """The output character encoding.""" - - self.encoding_errors = encoding_errors - """Encoding error handler.""" - - self.decoding_errors = decoding_errors - """Decoding error handler.""" - - def write(self, data): - """ - Write `data` to self.stream. Ignore, if self.stream is False. - - `data` can be a `string`, `unicode`, or `Exception` instance. - """ - if self.stream is False: - return - if isinstance(data, Exception): - data = unicode(SafeString(data, self.encoding, - self.encoding_errors, self.decoding_errors)) - try: - self.stream.write(data) - except UnicodeEncodeError: - self.stream.write(data.encode(self.encoding, self.encoding_errors)) - except TypeError: # in Python 3, stderr expects unicode - if self.stream in (sys.stderr, sys.stdout): - self.stream.buffer.write(data) # write bytes to raw stream - else: - self.stream.write(unicode(data, self.encoding, - self.decoding_errors)) - - def close(self): - """ - Close the error-output stream. - - Ignored if the stream is` sys.stderr` or `sys.stdout` or has no - close() method. - """ - if self.stream in (sys.stdout, sys.stderr): - return - try: - self.stream.close() - except AttributeError: - pass diff --git a/docutils/examples.py b/docutils/examples.py deleted file mode 100644 index 395dbbf14..000000000 --- a/docutils/examples.py +++ /dev/null @@ -1,97 +0,0 @@ -# $Id: examples.py 7320 2012-01-19 22:33:02Z milde $ -# Author: David Goodger -# Copyright: This module has been placed in the public domain. - -""" -This module contains practical examples of Docutils client code. - -Importing this module from client code 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, io - - -def html_parts(input_string, source_path=None, destination_path=None, - input_encoding='unicode', doctitle=True, - 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 "

"). - """ - 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_body(input_string, source_path=None, destination_path=None, - input_encoding='unicode', output_encoding='unicode', - doctitle=True, initial_header_level=1): - """ - Given an input string, returns an HTML fragment as a string. - - The return value is the contents of the element. - - 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['html_body'] - if output_encoding != 'unicode': - fragment = fragment.encode(output_encoding) - return fragment - -def internals(input_string, source_path=None, destination_path=None, - input_encoding='unicode', settings_overrides=None): - """ - Return the document tree and publisher, for exploring Docutils internals. - - Parameters: see `html_parts()`. - """ - if settings_overrides: - overrides = settings_overrides.copy() - else: - overrides = {} - overrides['input_encoding'] = input_encoding - output, pub = core.publish_programmatically( - source_class=io.StringInput, source=input_string, - source_path=source_path, - destination_class=io.NullOutput, destination=None, - destination_path=destination_path, - reader=None, reader_name='standalone', - parser=None, parser_name='restructuredtext', - writer=None, writer_name='null', - settings=None, settings_spec=None, settings_overrides=overrides, - config_section=None, enable_exit_status=None) - return pub.writer.document, pub diff --git a/docutils/frontend.py b/docutils/frontend.py deleted file mode 100644 index 83f5fde59..000000000 --- a/docutils/frontend.py +++ /dev/null @@ -1,788 +0,0 @@ -# $Id: frontend.py 7339 2012-02-03 12:23:27Z milde $ -# Author: David Goodger -# Copyright: This module has been placed in the public domain. - -""" -Command-line and common processing for Docutils front-end tools. - -Exports the following classes: - -* `OptionParser`: Standard Docutils command-line processing. -* `Option`: Customized version of `optparse.Option`; validation support. -* `Values`: Runtime settings; objects are simple structs - (``object.attribute``). Supports cumulative list settings (attributes). -* `ConfigParser`: Standard Docutils config file processing. - -Also exports the following functions: - -* Option callbacks: `store_multiple`, `read_config_file`. -* Setting validators: `validate_encoding`, - `validate_encoding_error_handler`, - `validate_encoding_and_error_handler`, `validate_boolean`, - `validate_threshold`, `validate_colon_separated_string_list`, - `validate_dependency_file`. -* `make_paths_absolute`. -* SettingSpec manipulation: `filter_settings_spec`. -""" - -__docformat__ = 'reStructuredText' - -import os -import os.path -import sys -import warnings -import ConfigParser as CP -import codecs -import optparse -from optparse import SUPPRESS_HELP -import docutils -import docutils.utils -import docutils.nodes -from docutils.error_reporting import locale_encoding, ErrorOutput, ErrorString - - -def store_multiple(option, opt, value, parser, *args, **kwargs): - """ - Store multiple values in `parser.values`. (Option callback.) - - Store `None` for each attribute named in `args`, and store the value for - each key (attribute name) in `kwargs`. - """ - for attribute in args: - setattr(parser.values, attribute, None) - for key, value in kwargs.items(): - setattr(parser.values, key, value) - -def read_config_file(option, opt, value, parser): - """ - Read a configuration file during option processing. (Option callback.) - """ - try: - new_settings = parser.get_config_file_settings(value) - except ValueError, error: - parser.error(error) - parser.values.update(new_settings, parser) - -def validate_encoding(setting, value, option_parser, - config_parser=None, config_section=None): - try: - codecs.lookup(value) - except LookupError: - raise (LookupError('setting "%s": unknown encoding: "%s"' - % (setting, value)), - None, sys.exc_info()[2]) - return value - -def validate_encoding_error_handler(setting, value, option_parser, - config_parser=None, config_section=None): - try: - codecs.lookup_error(value) - except LookupError: - raise (LookupError( - 'unknown encoding error handler: "%s" (choices: ' - '"strict", "ignore", "replace", "backslashreplace", ' - '"xmlcharrefreplace", and possibly others; see documentation for ' - 'the Python ``codecs`` module)' % value), - None, sys.exc_info()[2]) - return value - -def validate_encoding_and_error_handler( - setting, value, option_parser, config_parser=None, config_section=None): - """ - Side-effect: if an error handler is included in the value, it is inserted - into the appropriate place as if it was a separate setting/option. - """ - if ':' in value: - encoding, handler = value.split(':') - validate_encoding_error_handler( - setting + '_error_handler', handler, option_parser, - config_parser, config_section) - if config_parser: - config_parser.set(config_section, setting + '_error_handler', - handler) - else: - setattr(option_parser.values, setting + '_error_handler', handler) - else: - encoding = value - validate_encoding(setting, encoding, option_parser, - config_parser, config_section) - return encoding - -def validate_boolean(setting, value, option_parser, - config_parser=None, config_section=None): - if isinstance(value, unicode): - try: - return option_parser.booleans[value.strip().lower()] - except KeyError: - raise (LookupError('unknown boolean value: "%s"' % value), - None, sys.exc_info()[2]) - return value - -def validate_nonnegative_int(setting, value, option_parser, - config_parser=None, config_section=None): - value = int(value) - if value < 0: - raise ValueError('negative value; must be positive or zero') - return value - -def validate_threshold(setting, value, option_parser, - config_parser=None, config_section=None): - try: - return int(value) - except ValueError: - try: - return option_parser.thresholds[value.lower()] - except (KeyError, AttributeError): - raise (LookupError('unknown threshold: %r.' % value), - None, sys.exc_info[2]) - -def validate_colon_separated_string_list( - setting, value, option_parser, config_parser=None, config_section=None): - if isinstance(value, unicode): - value = value.split(':') - else: - last = value.pop() - value.extend(last.split(':')) - return value - -def validate_url_trailing_slash( - setting, value, option_parser, config_parser=None, config_section=None): - if not value: - return './' - elif value.endswith('/'): - return value - else: - return value + '/' - -def validate_dependency_file(setting, value, option_parser, - config_parser=None, config_section=None): - try: - return docutils.utils.DependencyList(value) - except IOError: - return docutils.utils.DependencyList(None) - -def validate_strip_class(setting, value, option_parser, - config_parser=None, config_section=None): - # convert to list: - if isinstance(value, unicode): - value = [value] - class_values = filter(None, [v.strip() for v in value.pop().split(',')]) - # validate: - for class_value in class_values: - normalized = docutils.nodes.make_id(class_value) - if class_value != normalized: - raise ValueError('invalid class value %r (perhaps %r?)' - % (class_value, normalized)) - value.extend(class_values) - return value - -def make_paths_absolute(pathdict, keys, base_path=None): - """ - Interpret filesystem path settings relative to the `base_path` given. - - Paths are values in `pathdict` whose keys are in `keys`. Get `keys` from - `OptionParser.relative_path_settings`. - """ - if base_path is None: - base_path = os.getcwdu() # type(base_path) == unicode - # to allow combining non-ASCII cwd with unicode values in `pathdict` - for key in keys: - if key in pathdict: - value = pathdict[key] - if isinstance(value, list): - value = [make_one_path_absolute(base_path, path) - for path in value] - elif value: - value = make_one_path_absolute(base_path, value) - pathdict[key] = value - -def make_one_path_absolute(base_path, path): - return os.path.abspath(os.path.join(base_path, path)) - -def filter_settings_spec(settings_spec, *exclude, **replace): - """Return a copy of `settings_spec` excluding/replacing some settings. - - `settings_spec` is a tuple of configuration settings with a structure - described for docutils.SettingsSpec.settings_spec. - - Optional positional arguments are names of to-be-excluded settings. - Keyword arguments are option specification replacements. - (See the html4strict writer for an example.) - """ - settings = list(settings_spec) - # every third item is a sequence of option tuples - for i in range(2, len(settings), 3): - newopts = [] - for opt_spec in settings[i]: - # opt_spec is ("", [

\n') - self.in_document_title = len(self.body) - elif isinstance(node.parent, nodes.section): - tag = 'h%s' % (self.section_level + self.initial_header_level - 1) - self.body.append( - self.starttag(node, tag, '', CLASS='section-subtitle') + - self.starttag({}, 'span', '', CLASS='section-subtitle')) - self.context.append('\n' % tag) - - 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) - self.html_subtitle.extend(self.body) - del self.body[:] - - def visit_superscript(self, node): - self.body.append(self.starttag(node, 'sup', '')) - - def depart_superscript(self, node): - self.body.append('') - - def visit_system_message(self, node): - self.body.append(self.starttag(node, 'div', CLASS='system-message')) - self.body.append('

') - backref_text = '' - if len(node['backrefs']): - backrefs = node['backrefs'] - if len(backrefs) == 1: - backref_text = ('; backlink' - % backrefs[0]) - else: - i = 1 - backlinks = [] - for backref in backrefs: - backlinks.append('%s' % (backref, i)) - i += 1 - backref_text = ('; backlinks: %s' - % ', '.join(backlinks)) - if node.hasattr('line'): - line = ', line %s' % node['line'] - else: - line = '' - self.body.append('System Message: %s/%s ' - '(%s%s)%s

\n' - % (node['type'], node['level'], - self.encode(node['source']), line, backref_text)) - - def depart_system_message(self, node): - self.body.append('\n') - - def visit_table(self, node): - classes = ' '.join(['docutils', self.settings.table_style]).strip() - self.body.append( - self.starttag(node, 'table', CLASS=classes, border="1")) - - def depart_table(self, node): - self.body.append('\n') - - def visit_target(self, node): - if not ('refuri' in node or 'refid' in node - or 'refname' in node): - self.body.append(self.starttag(node, 'span', '', CLASS='target')) - self.context.append('') - else: - self.context.append('') - - def depart_target(self, node): - self.body.append(self.context.pop()) - - def visit_tbody(self, node): - self.write_colspecs() - self.body.append(self.context.pop()) # '\n' or '' - self.body.append(self.starttag(node, 'tbody', valign='top')) - - def depart_tbody(self, node): - self.body.append('\n') - - def visit_term(self, node): - self.body.append(self.starttag(node, 'dt', '')) - - def depart_term(self, node): - """ - Leave the end tag to `self.visit_definition()`, in case there's a - classifier. - """ - pass - - def visit_tgroup(self, node): - # Mozilla needs : - self.body.append(self.starttag(node, 'colgroup')) - # Appended by thead or tbody: - self.context.append('\n') - node.stubs = [] - - def depart_tgroup(self, node): - pass - - def visit_thead(self, node): - self.write_colspecs() - self.body.append(self.context.pop()) # '\n' - # There may or may not be a ; this is for to use: - self.context.append('') - self.body.append(self.starttag(node, 'thead', valign='bottom')) - - def depart_thead(self, node): - self.body.append('\n') - - def visit_title(self, node): - """Only 6 section levels are supported by HTML.""" - check_id = 0 # TODO: is this a bool (False) or a counter? - close_tag = '

\n' - if isinstance(node.parent, nodes.topic): - self.body.append( - self.starttag(node, 'p', '', CLASS='topic-title first')) - elif isinstance(node.parent, nodes.sidebar): - self.body.append( - self.starttag(node, 'p', '', CLASS='sidebar-title')) - elif isinstance(node.parent, nodes.Admonition): - self.body.append( - self.starttag(node, 'p', '', CLASS='admonition-title')) - elif isinstance(node.parent, nodes.table): - self.body.append( - self.starttag(node, 'caption', '')) - close_tag = '\n' - elif isinstance(node.parent, nodes.document): - self.body.append(self.starttag(node, 'h1', '', CLASS='title')) - close_tag = '\n' - self.in_document_title = len(self.body) - else: - assert isinstance(node.parent, nodes.section) - h_level = self.section_level + self.initial_header_level - 1 - atts = {} - if (len(node.parent) >= 2 and - isinstance(node.parent[1], nodes.subtitle)): - atts['CLASS'] = 'with-subtitle' - self.body.append( - self.starttag(node, 'h%s' % h_level, '', **atts)) - atts = {} - if node.hasattr('refid'): - atts['class'] = 'toc-backref' - atts['href'] = '#' + node['refid'] - if atts: - self.body.append(self.starttag({}, 'a', '', **atts)) - close_tag = '\n' % (h_level) - else: - close_tag = '\n' % (h_level) - 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) - self.html_title.extend(self.body) - del self.body[:] - - def visit_title_reference(self, node): - self.body.append(self.starttag(node, 'cite', '')) - - def depart_title_reference(self, node): - self.body.append('') - - def visit_topic(self, node): - self.body.append(self.starttag(node, 'div', CLASS='topic')) - self.topic_classes = node['classes'] - - def depart_topic(self, node): - self.body.append('\n') - self.topic_classes = [] - - def visit_transition(self, node): - self.body.append(self.emptytag(node, 'hr', CLASS='docutils')) - - def depart_transition(self, node): - pass - - def visit_version(self, node): - self.visit_docinfo_item(node, 'version', meta=False) - - def depart_version(self, node): - self.depart_docinfo_item() - - def unimplemented_visit(self, node): - raise NotImplementedError('visiting unimplemented node type: %s' - % node.__class__.__name__) - - -class SimpleListChecker(nodes.GenericNodeVisitor): - - """ - Raise `nodes.NodeFound` if non-simple list item is encountered. - - Here "simple" means a list item containing nothing other than a single - paragraph, a simple list, or a paragraph followed by a simple list. - """ - - def default_visit(self, node): - raise nodes.NodeFound - - def visit_bullet_list(self, node): - pass - - def visit_enumerated_list(self, node): - pass - - def visit_list_item(self, node): - children = [] - for child in node.children: - if not isinstance(child, nodes.Invisible): - children.append(child) - if (children and isinstance(children[0], nodes.paragraph) - and (isinstance(children[-1], nodes.bullet_list) - or isinstance(children[-1], nodes.enumerated_list))): - children.pop() - if len(children) <= 1: - return - else: - raise nodes.NodeFound - - def visit_paragraph(self, node): - raise nodes.SkipNode - - def invisible_visit(self, node): - """Invisible nodes should be ignored.""" - raise nodes.SkipNode - - visit_comment = invisible_visit - visit_substitution_definition = invisible_visit - visit_target = invisible_visit - visit_pending = invisible_visit diff --git a/docutils/writers/html4css1/html4css1.css b/docutils/writers/html4css1/html4css1.css deleted file mode 100644 index f5285ad09..000000000 --- a/docutils/writers/html4css1/html4css1.css +++ /dev/null @@ -1,311 +0,0 @@ -/* -:Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 7434 2012-05-11 21:06:27Z milde $ -:Copyright: This stylesheet has been placed in the public domain. - -Default cascading style sheet for the HTML output of Docutils. - -See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to -customize this style sheet. -*/ - -/* used to remove borders from tables and images */ -.borderless, table.borderless td, table.borderless th { - border: 0 } - -table.borderless td, table.borderless th { - /* Override padding for "table.docutils td" with "! important". - The right padding separates the table cells. */ - padding: 0 0.5em 0 0 ! important } - -.first { - /* Override more specific margin styles with "! important". */ - margin-top: 0 ! important } - -.last, .with-subtitle { - margin-bottom: 0 ! important } - -.hidden { - display: none } - -a.toc-backref { - text-decoration: none ; - color: black } - -blockquote.epigraph { - margin: 2em 5em ; } - -dl.docutils dd { - margin-bottom: 0.5em } - -object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] { - overflow: hidden; -} - -/* Uncomment (and remove this text!) to get bold-faced definition list terms -dl.docutils dt { - font-weight: bold } -*/ - -div.abstract { - margin: 2em 5em } - -div.abstract p.topic-title { - font-weight: bold ; - text-align: center } - -div.admonition, div.attention, div.caution, div.danger, div.error, -div.hint, div.important, div.note, div.tip, div.warning { - margin: 2em ; - border: medium outset ; - padding: 1em } - -div.admonition p.admonition-title, div.hint p.admonition-title, -div.important p.admonition-title, div.note p.admonition-title, -div.tip p.admonition-title { - font-weight: bold ; - font-family: sans-serif } - -div.attention p.admonition-title, div.caution p.admonition-title, -div.danger p.admonition-title, div.error p.admonition-title, -div.warning p.admonition-title { - color: red ; - font-weight: bold ; - font-family: sans-serif } - -/* Uncomment (and remove this text!) to get reduced vertical space in - compound paragraphs. -div.compound .compound-first, div.compound .compound-middle { - margin-bottom: 0.5em } - -div.compound .compound-last, div.compound .compound-middle { - margin-top: 0.5em } -*/ - -div.dedication { - margin: 2em 5em ; - text-align: center ; - font-style: italic } - -div.dedication p.topic-title { - font-weight: bold ; - font-style: normal } - -div.figure { - margin-left: 2em ; - margin-right: 2em } - -div.footer, div.header { - clear: both; - font-size: smaller } - -div.line-block { - display: block ; - margin-top: 1em ; - margin-bottom: 1em } - -div.line-block div.line-block { - margin-top: 0 ; - margin-bottom: 0 ; - margin-left: 1.5em } - -div.sidebar { - margin: 0 0 0.5em 1em ; - border: medium outset ; - padding: 1em ; - background-color: #ffffee ; - width: 40% ; - float: right ; - clear: right } - -div.sidebar p.rubric { - font-family: sans-serif ; - font-size: medium } - -div.system-messages { - margin: 5em } - -div.system-messages h1 { - color: red } - -div.system-message { - border: medium outset ; - padding: 1em } - -div.system-message p.system-message-title { - color: red ; - font-weight: bold } - -div.topic { - margin: 2em } - -h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, -h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { - margin-top: 0.4em } - -h1.title { - text-align: center } - -h2.subtitle { - text-align: center } - -hr.docutils { - width: 75% } - -img.align-left, .figure.align-left, object.align-left { - clear: left ; - float: left ; - margin-right: 1em } - -img.align-right, .figure.align-right, object.align-right { - clear: right ; - float: right ; - margin-left: 1em } - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left } - -.align-center { - clear: both ; - text-align: center } - -.align-right { - text-align: right } - -/* reset inner alignment in figures */ -div.align-right { - text-align: inherit } - -/* div.align-center * { */ -/* text-align: left } */ - -ol.simple, ul.simple { - margin-bottom: 1em } - -ol.arabic { - list-style: decimal } - -ol.loweralpha { - list-style: lower-alpha } - -ol.upperalpha { - list-style: upper-alpha } - -ol.lowerroman { - list-style: lower-roman } - -ol.upperroman { - list-style: upper-roman } - -p.attribution { - text-align: right ; - margin-left: 50% } - -p.caption { - font-style: italic } - -p.credits { - font-style: italic ; - font-size: smaller } - -p.label { - white-space: nowrap } - -p.rubric { - font-weight: bold ; - font-size: larger ; - color: maroon ; - text-align: center } - -p.sidebar-title { - font-family: sans-serif ; - font-weight: bold ; - font-size: larger } - -p.sidebar-subtitle { - font-family: sans-serif ; - font-weight: bold } - -p.topic-title { - font-weight: bold } - -pre.address { - margin-bottom: 0 ; - margin-top: 0 ; - font: inherit } - -pre.literal-block, pre.doctest-block, pre.math, pre.code { - margin-left: 2em ; - margin-right: 2em } - -pre.code .ln { /* line numbers */ - color: grey; -} - -.code { - background-color: #eeeeee -} - -span.classifier { - font-family: sans-serif ; - font-style: oblique } - -span.classifier-delimiter { - font-family: sans-serif ; - font-weight: bold } - -span.interpreted { - font-family: sans-serif } - -span.option { - white-space: nowrap } - -span.pre { - white-space: pre } - -span.problematic { - color: red } - -span.section-subtitle { - /* font-size relative to parent (h1..h6 element) */ - font-size: 80% } - -table.citation { - border-left: solid 1px gray; - margin-left: 1px } - -table.docinfo { - margin: 2em 4em } - -table.docutils { - margin-top: 0.5em ; - margin-bottom: 0.5em } - -table.footnote { - border-left: solid 1px black; - margin-left: 1px } - -table.docutils td, table.docutils th, -table.docinfo td, table.docinfo th { - padding-left: 0.5em ; - padding-right: 0.5em ; - vertical-align: top } - -table.docutils th.field-name, table.docinfo th.docinfo-name { - font-weight: bold ; - text-align: left ; - white-space: nowrap ; - padding-left: 0 } - -h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, -h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { - font-size: 100% } - -ul.auto-toc { - list-style-type: none } diff --git a/docutils/writers/html4css1/math.css b/docutils/writers/html4css1/math.css deleted file mode 100644 index 4f43b37e0..000000000 --- a/docutils/writers/html4css1/math.css +++ /dev/null @@ -1,274 +0,0 @@ -/* -* math2html: convert LaTeX equations to HTML output. -* -* Copyright (C) 2009,2010 Alex Fernández -* -* Released under the terms of the `2-Clause BSD license'_, in short: -* Copying and distribution of this file, with or without modification, -* are permitted in any medium without royalty provided the copyright -* notice and this notice are preserved. -* This file is offered as-is, without any warranty. -* -* .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause -* -* Based on eLyXer: convert LyX source files to HTML output. -* http://elyxer.nongnu.org/ -*/ -/* --end-- -* CSS file for LaTeX formulas. -*/ - -/* Formulas */ -.formula { - text-align: center; - font-family: "DejaVu Serif", serif; - margin: 1.2em 0; -} -span.formula { - white-space: nowrap; -} -div.formula { - padding: 0.5ex; - margin-left: auto; - margin-right: auto; -} - -/* Basic features */ -a.eqnumber { - display: inline-block; - float: right; - clear: right; - font-weight: bold; -} -span.unknown { - color: #800000; -} -span.ignored, span.arraydef { - display: none; -} -.formula i { - letter-spacing: 0.1ex; -} - -/* Alignment */ -.align-left, .align-l { - text-align: left; -} -.align-right, .align-r { - text-align: right; -} -.align-center, .align-c { - text-align: center; -} - -/* Structures */ -span.overline, span.bar { - text-decoration: overline; -} -.fraction, .fullfraction { - display: inline-block; - vertical-align: middle; - text-align: center; -} -.fraction .fraction { - font-size: 80%; - line-height: 100%; -} -span.numerator { - display: block; -} -span.denominator { - display: block; - padding: 0ex; - border-top: thin solid; -} -sup.numerator, sup.unit { - font-size: 70%; - vertical-align: 80%; -} -sub.denominator, sub.unit { - font-size: 70%; - vertical-align: -20%; -} -span.sqrt { - display: inline-block; - vertical-align: middle; - padding: 0.1ex; -} -sup.root { - font-size: 70%; - position: relative; - left: 1.4ex; -} -span.radical { - display: inline-block; - padding: 0ex; - font-size: 150%; - vertical-align: top; -} -span.root { - display: inline-block; - border-top: thin solid; - padding: 0ex; - vertical-align: middle; -} -span.symbol { - font-size: 125%; -} -span.bigsymbol { - font-size: 150%; -} -span.largesymbol { - font-size: 175%; -} -span.hugesymbol { - font-size: 200%; -} -span.scripts { - display: inline-table; - vertical-align: middle; -} -.script { - display: table-row; - text-align: left; - line-height: 150%; -} -span.limits { - display: inline-table; - vertical-align: middle; -} -.limit { - display: table-row; - line-height: 95%; -} -sup.limit, sub.limit { - line-height: 150%; -} -span.symbolover { - display: inline-block; - text-align: center; - position: relative; - float: right; - right: 100%; - bottom: 0.5em; - width: 0px; -} -span.withsymbol { - display: inline-block; -} -span.symbolunder { - display: inline-block; - text-align: center; - position: relative; - float: right; - right: 80%; - top: 0.3em; - width: 0px; -} - -/* Environments */ -span.array, span.bracketcases, span.binomial, span.environment { - display: inline-table; - text-align: center; - border-collapse: collapse; - margin: 0em; - vertical-align: middle; -} -span.arrayrow, span.binomrow { - display: table-row; - padding: 0ex; - border: 0ex; -} -span.arraycell, span.bracket, span.case, span.binomcell, span.environmentcell { - display: table-cell; - padding: 0ex 0.2ex; - line-height: 99%; - border: 0ex; -} -/* -* CSS file for LaTeX formulas, extra stuff: -* binomials, vertical braces, stackrel, fonts and colors. -*/ - -/* Inline binomials */ -span.binom { - display: inline-block; - vertical-align: middle; - text-align: center; - font-size: 80%; -} -span.binomstack { - display: block; - padding: 0em; -} - -/* Over- and underbraces */ -span.overbrace { - border-top: 2pt solid; -} -span.underbrace { - border-bottom: 2pt solid; -} - -/* Stackrel */ -span.stackrel { - display: inline-block; - text-align: center; -} -span.upstackrel { - display: block; - padding: 0em; - font-size: 80%; - line-height: 64%; - position: relative; - top: 0.15em; - -} -span.downstackrel { - display: block; - vertical-align: bottom; - padding: 0em; -} - -/* Fonts */ -span.mathsf, span.textsf { - font-style: normal; - font-family: sans-serif; -} -span.mathrm, span.textrm { - font-style: normal; - font-family: serif; -} -span.text, span.textnormal { - font-style: normal; -} -span.textipa { - color: #008080; -} -span.fraktur { - font-family: "Lucida Blackletter", eufm10, blackletter; -} -span.blackboard { - font-family: Blackboard, msbm10, serif; -} -span.scriptfont { - font-family: "Monotype Corsiva", "Apple Chancery", "URW Chancery L", cursive; - font-style: italic; -} - -/* Colors */ -span.colorbox { - display: inline-block; - padding: 5px; -} -span.fbox { - display: inline-block; - border: thin solid black; - padding: 2px; -} -span.boxed, span.framebox { - display: inline-block; - border: thin solid black; - padding: 5px; -} - diff --git a/docutils/writers/html4css1/template.txt b/docutils/writers/html4css1/template.txt deleted file mode 100644 index 2591bce35..000000000 --- a/docutils/writers/html4css1/template.txt +++ /dev/null @@ -1,8 +0,0 @@ -%(head_prefix)s -%(head)s -%(stylesheet)s -%(body_prefix)s -%(body_pre_docinfo)s -%(docinfo)s -%(body)s -%(body_suffix)s diff --git a/docutils/writers/latex2e/__init__.py b/docutils/writers/latex2e/__init__.py deleted file mode 100644 index cb71f0994..000000000 --- a/docutils/writers/latex2e/__init__.py +++ /dev/null @@ -1,3041 +0,0 @@ -# .. coding: utf8 -# $Id: __init__.py 7389 2012-03-30 11:58:21Z milde $ -# Author: Engelbert Gruber, Günter Milde -# Maintainer: docutils-develop@lists.sourceforge.net -# Copyright: This module has been placed in the public domain. - -"""LaTeX2e document tree Writer.""" - -__docformat__ = 'reStructuredText' - -# code contributions from several people included, thanks to all. -# some named: David Abrahams, Julien Letessier, Lele Gaifax, and others. -# -# convention deactivate code by two # i.e. ##. - -import sys -import os -import time -import re -import string -import urllib -try: - import roman -except ImportError: - import docutils.utils.roman as roman -from docutils import frontend, nodes, languages, writers, utils, io -from docutils.error_reporting import SafeString -from docutils.transforms import writer_aux -from docutils.math import pick_math_environment, unichar2tex - -# compatibility module for Python 2.3 -if not hasattr(string, 'Template'): - import docutils._string_template_compat - string.Template = docutils._string_template_compat.Template - -class Writer(writers.Writer): - - supported = ('latex','latex2e') - """Formats this writer supports.""" - - default_template = 'default.tex' - default_template_path = os.path.dirname(__file__) - - default_preamble = '\n'.join([r'% PDF Standard Fonts', - r'\usepackage{mathptmx} % Times', - r'\usepackage[scaled=.90]{helvet}', - r'\usepackage{courier}']) - settings_spec = ( - 'LaTeX-Specific Options', - None, - (('Specify documentclass. Default is "article".', - ['--documentclass'], - {'default': 'article', }), - ('Specify document options. Multiple options can be given, ' - 'separated by commas. Default is "a4paper".', - ['--documentoptions'], - {'default': 'a4paper', }), - ('Footnotes with numbers/symbols by Docutils. (default)', - ['--docutils-footnotes'], - {'default': True, 'action': 'store_true', - 'validator': frontend.validate_boolean}), - ('Alias for --docutils-footnotes (deprecated)', - ['--use-latex-footnotes'], - {'action': 'store_true', - 'validator': frontend.validate_boolean}), - ('Use figure floats for footnote text (deprecated)', - ['--figure-footnotes'], - {'action': 'store_true', - 'validator': frontend.validate_boolean}), - ('Format for footnote references: one of "superscript" or ' - '"brackets". Default is "superscript".', - ['--footnote-references'], - {'choices': ['superscript', 'brackets'], 'default': 'superscript', - 'metavar': '', - 'overrides': 'trim_footnote_reference_space'}), - ('Use \\cite command for citations. ', - ['--use-latex-citations'], - {'default': 0, 'action': 'store_true', - 'validator': frontend.validate_boolean}), - ('Use figure floats for citations ' - '(might get mixed with real figures). (default)', - ['--figure-citations'], - {'dest': 'use_latex_citations', 'action': 'store_false', - 'validator': frontend.validate_boolean}), - ('Format for block quote attributions: one of "dash" (em-dash ' - 'prefix), "parentheses"/"parens", or "none". Default is "dash".', - ['--attribution'], - {'choices': ['dash', 'parentheses', 'parens', 'none'], - 'default': 'dash', 'metavar': ''}), - ('Specify LaTeX packages/stylesheets. ' - ' A style is referenced with \\usepackage if extension is ' - '".sty" or omitted and with \\input else. ' - ' Overrides previous --stylesheet and --stylesheet-path settings.', - ['--stylesheet'], - {'default': '', 'metavar': '', - 'overrides': 'stylesheet_path'}), - ('Like --stylesheet, but the path is rewritten ' - 'relative to the output file. ', - ['--stylesheet-path'], - {'metavar': '', 'overrides': 'stylesheet'}), - ('Link to the stylesheet(s) in the output file. (default)', - ['--link-stylesheet'], - {'dest': 'embed_stylesheet', 'action': 'store_false'}), - ('Embed the stylesheet(s) in the output file. ' - 'Stylesheets must be accessible during processing. ', - ['--embed-stylesheet'], - {'default': 0, 'action': 'store_true', - 'validator': frontend.validate_boolean}), - ('Customization by LaTeX code in the preamble. ' - 'Default: select PDF standard fonts (Times, Helvetica, Courier).', - ['--latex-preamble'], - {'default': default_preamble}), - ('Specify the template file. Default: "%s".' % default_template, - ['--template'], - {'default': default_template, 'metavar': ''}), - ('Table of contents by LaTeX. (default) ', - ['--use-latex-toc'], - {'default': 1, 'action': 'store_true', - 'validator': frontend.validate_boolean}), - ('Table of contents by Docutils (without page numbers). ', - ['--use-docutils-toc'], - {'dest': 'use_latex_toc', 'action': 'store_false', - 'validator': frontend.validate_boolean}), - ('Add parts on top of the section hierarchy.', - ['--use-part-section'], - {'default': 0, 'action': 'store_true', - 'validator': frontend.validate_boolean}), - ('Attach author and date to the document info table. (default) ', - ['--use-docutils-docinfo'], - {'dest': 'use_latex_docinfo', 'action': 'store_false', - 'validator': frontend.validate_boolean}), - ('Attach author and date to the document title.', - ['--use-latex-docinfo'], - {'default': 0, 'action': 'store_true', - 'validator': frontend.validate_boolean}), - ("Typeset abstract as topic. (default)", - ['--topic-abstract'], - {'dest': 'use_latex_abstract', 'action': 'store_false', - 'validator': frontend.validate_boolean}), - ("Use LaTeX abstract environment for the document's abstract. ", - ['--use-latex-abstract'], - {'default': 0, 'action': 'store_true', - 'validator': frontend.validate_boolean}), - ('Color of any hyperlinks embedded in text ' - '(default: "blue", "false" to disable).', - ['--hyperlink-color'], {'default': 'blue'}), - ('Additional options to the "hyperref" package ' - '(default: "").', - ['--hyperref-options'], {'default': ''}), - ('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': ''}), - ('When possibile, use the specified environment for literal-blocks. ' - 'Default is quoting of whitespace and special chars.', - ['--literal-block-env'], - {'default': ''}), - ('When possibile, use verbatim for literal-blocks. ' - 'Compatibility alias for "--literal-block-env=verbatim".', - ['--use-verbatim-when-possible'], - {'default': 0, 'action': 'store_true', - 'validator': frontend.validate_boolean}), - ('Table style. "standard" with horizontal and vertical lines, ' - '"booktabs" (LaTeX booktabs style) only horizontal lines ' - 'above and below the table and below the header or "borderless". ' - 'Default: "standard"', - ['--table-style'], - {'choices': ['standard', 'booktabs','nolines', 'borderless'], - 'default': 'standard', - 'metavar': ''}), - ('LaTeX graphicx package option. ' - 'Possible values are "dvips", "pdftex". "auto" includes LaTeX code ' - 'to use "pdftex" if processing with pdf(la)tex and dvips otherwise. ' - 'Default is no option.', - ['--graphicx-option'], - {'default': ''}), - ('LaTeX font encoding. ' - 'Possible values are "", "T1" (default), "OT1", "LGR,T1" or ' - 'any other combination of options to the `fontenc` package. ', - ['--font-encoding'], - {'default': 'T1'}), - ('Per default the latex-writer puts the reference title into ' - 'hyperreferences. Specify "ref*" or "pageref*" to get the section ' - 'number or the page number.', - ['--reference-label'], - {'default': None, }), - ('Specify style and database for bibtex, for example ' - '"--use-bibtex=mystyle,mydb1,mydb2".', - ['--use-bibtex'], - {'default': None, }), - ),) - - settings_defaults = {'sectnum_depth': 0 # updated by SectNum transform - } - relative_path_settings = ('stylesheet_path',) - - config_section = 'latex2e writer' - config_section_dependencies = ('writers',) - - head_parts = ('head_prefix', 'requirements', 'latex_preamble', - 'stylesheet', 'fallbacks', 'pdfsetup', - 'title', 'subtitle', 'titledata') - visitor_attributes = head_parts + ('body_pre_docinfo', 'docinfo', - 'dedication', 'abstract', 'body') - - output = None - """Final translated form of `document`.""" - - def __init__(self): - writers.Writer.__init__(self) - self.translator_class = LaTeXTranslator - - # Override parent method to add latex-specific transforms - def get_transforms(self): - # call the parent class' method - transform_list = writers.Writer.get_transforms(self) - # print transform_list - # Convert specific admonitions to generic one - transform_list.append(writer_aux.Admonitions) - # TODO: footnote collection transform - # transform_list.append(footnotes.collect) - return transform_list - - def translate(self): - visitor = self.translator_class(self.document) - self.document.walkabout(visitor) - # copy parts - for part in self.visitor_attributes: - setattr(self, part, getattr(visitor, part)) - # get template string from file - try: - template_file = open(self.document.settings.template, 'rb') - except IOError: - template_file = open(os.path.join(self.default_template_path, - self.document.settings.template), 'rb') - template = string.Template(unicode(template_file.read(), 'utf-8')) - template_file.close() - # fill template - self.assemble_parts() # create dictionary of parts - self.output = template.substitute(self.parts) - - def assemble_parts(self): - """Assemble the `self.parts` dictionary of output fragments.""" - writers.Writer.assemble_parts(self) - for part in self.visitor_attributes: - lines = getattr(self, part) - if part in self.head_parts: - if lines: - lines.append('') # to get a trailing newline - self.parts[part] = '\n'.join(lines) - else: - # body contains inline elements, so join without newline - self.parts[part] = ''.join(lines) - - -class Babel(object): - """Language specifics for LaTeX.""" - - # TeX (babel) language names: - # ! not all of these are supported by Docutils! - # - # based on LyX' languages file with adaptions to `BCP 47`_ - # (http://www.rfc-editor.org/rfc/bcp/bcp47.txt) and - # http://www.tug.org/TUGboat/Articles/tb29-3/tb93miklavec.pdf - # * the key without subtags is the default - # * case is ignored - # cf. http://docutils.sourceforge.net/docs/howto/i18n.html - # http://www.w3.org/International/articles/language-tags/ - # and http://www.iana.org/assignments/language-subtag-registry - language_codes = { - # code TeX/Babel-name comment - 'af': 'afrikaans', - 'ar': 'arabic', - # 'be': 'belarusian', - 'bg': 'bulgarian', - 'br': 'breton', - 'ca': 'catalan', - # 'cop': 'coptic', - 'cs': 'czech', - 'cy': 'welsh', - 'da': 'danish', - 'de': 'ngerman', # new spelling (de_1996) - 'de_1901': 'german', # old spelling - 'de_at': 'naustrian', - 'de_at_1901': 'austrian', - 'dsb': 'lowersorbian', - 'el': 'greek', # monotonic (el-monoton) - 'el_polyton': 'polutonikogreek', - 'en': 'english', # TeX' default language - 'en_au': 'australian', - 'en_ca': 'canadian', - 'en_gb': 'british', - 'en_nz': 'newzealand', - 'en_us': 'american', - 'eo': 'esperanto', # '^' is active - 'es': 'spanish', - 'et': 'estonian', - 'eu': 'basque', - # 'fa': 'farsi', - 'fi': 'finnish', - 'fr': 'french', - 'fr_ca': 'canadien', - 'ga': 'irish', # Irish Gaelic - # 'grc': # Ancient Greek - 'grc_ibycus': 'ibycus', # Ibycus encoding - 'gl': 'galician', - 'he': 'hebrew', - 'hr': 'croatian', - 'hsb': 'uppersorbian', - 'hu': 'magyar', - 'ia': 'interlingua', - 'id': 'bahasai', # Bahasa (Indonesian) - 'is': 'icelandic', - 'it': 'italian', - 'ja': 'japanese', - 'kk': 'kazakh', - 'la': 'latin', - 'lt': 'lithuanian', - 'lv': 'latvian', - 'mn': 'mongolian', # Mongolian, Cyrillic script (mn-cyrl) - 'ms': 'bahasam', # Bahasa (Malay) - 'nb': 'norsk', # Norwegian Bokmal - 'nl': 'dutch', - 'nn': 'nynorsk', # Norwegian Nynorsk - 'no': 'norsk', # Norwegian Bokmal - 'pl': 'polish', - 'pt': 'portuges', - 'pt_br': 'brazil', - 'ro': 'romanian', - 'ru': 'russian', # '"' is active - 'se': 'samin', # North Sami - # sh-cyrl: Serbo-Croatian, Cyrillic script - 'sh-latn': 'serbian', # Serbo-Croatian, Latin script - 'sk': 'slovak', - 'sl': 'slovene', - 'sq': 'albanian', - # 'sr-cyrl': Serbian, Cyrillic script (sr-cyrl) - 'sr-latn': 'serbian', # Serbian, Latin script, " active. - 'sv': 'swedish', - # 'th': 'thai', - 'tr': 'turkish', - 'uk': 'ukrainian', - 'vi': 'vietnam', - # zh-latn: Chinese Pinyin - } - warn_msg = 'Language "%s" not supported by LaTeX (babel)' - - def __init__(self, language_code, reporter=None): - self.reporter = reporter - self.language = self.language_name(language_code) - self.otherlanguages = {} - self.quote_index = 0 - self.quotes = ('``', "''") - # language dependent configuration: - # double quotes are "active" in some languages (e.g. German). - self.literal_double_quote = u'"' - if self.language in ('ngerman', 'german', 'austrian', 'naustrian', - 'russian'): - self.quotes = (r'\glqq{}', r'\grqq{}') - self.literal_double_quote = ur'\dq{}' - if self.language == 'french': - self.quotes = (r'\og{}', r'\fg{}') - if self.language == 'italian': - self.literal_double_quote = ur'{\char`\"}' - - def __call__(self): - """Return the babel call with correct options and settings""" - languages = self.otherlanguages.keys() - languages.append(self.language or 'english') - self.setup = [r'\usepackage[%s]{babel}' % ','.join(languages)] - if 'spanish' in languages: - # reset active chars to the original meaning: - self.setup.append( - r'\addto\shorthandsspanish{\spanishdeactivate{."~<>}}') - # or prepend r'\def\spanishoptions{es-noshorthands}' - if (languages[-1] == 'english' and - 'french' in self.otherlanguages.keys()): - self.setup += ['% Prevent side-effects if French hyphenation ' - 'patterns are not loaded:', - r'\frenchbsetup{StandardLayout}', - r'\AtBeginDocument{\selectlanguage{%s}' - r'\noextrasfrench}' % self.language] - return '\n'.join(self.setup) - - def next_quote(self): - q = self.quotes[self.quote_index] - self.quote_index = (self.quote_index+1) % 2 - return q - - def quote_quotes(self,text): - t = None - for part in text.split('"'): - if t == None: - t = part - else: - t += self.next_quote() + part - return t - - def language_name(self, language_code): - """Return TeX language name for `language_code`""" - for tag in utils.normalize_language_tag(language_code): - try: - return self.language_codes[tag] - except KeyError: - pass - if self.reporter is not None: - self.reporter.warning(self.warn_msg % language_code) - return '' - - def get_language(self): - """Return `self.language` (for backwards compatibility with Sphinx). - """ - return self.language - - -# Building blocks for the latex preamble -# -------------------------------------- - -class SortableDict(dict): - """Dictionary with additional sorting methods - - Tip: use key starting with with '_' for sorting before small letters - and with '~' for sorting after small letters. - """ - def sortedkeys(self): - """Return sorted list of keys""" - keys = self.keys() - keys.sort() - return keys - - def sortedvalues(self): - """Return list of values sorted by keys""" - return [self[key] for key in self.sortedkeys()] - - -# PreambleCmds -# ````````````` -# A container for LaTeX code snippets that can be -# inserted into the preamble if required in the document. -# -# .. The package 'makecmds' would enable shorter definitions using the -# \providelength and \provideenvironment commands. -# However, it is pretty non-standard (texlive-latex-extra). - -class PreambleCmds(object): - """Building blocks for the latex preamble.""" - -PreambleCmds.abstract = r""" -% abstract title -\providecommand*{\DUtitleabstract}[1]{\centerline{\textbf{#1}}}""" - -PreambleCmds.admonition = r""" -% admonition (specially marked topic) -\providecommand{\DUadmonition}[2][class-arg]{% - % try \DUadmonition#1{#2}: - \ifcsname DUadmonition#1\endcsname% - \csname DUadmonition#1\endcsname{#2}% - \else - \begin{center} - \fbox{\parbox{0.9\textwidth}{#2}} - \end{center} - \fi -}""" - -PreambleCmds.align_center = r""" -\makeatletter -\@namedef{DUrolealign-center}{\centering} -\makeatother -""" - -## PreambleCmds.caption = r"""% configure caption layout -## \usepackage{caption} -## \captionsetup{singlelinecheck=false}% no exceptions for one-liners""" - -PreambleCmds.color = r"""\usepackage{color}""" - -PreambleCmds.docinfo = r""" -% docinfo (width of docinfo table) -\DUprovidelength{\DUdocinfowidth}{0.9\textwidth}""" -# PreambleCmds.docinfo._depends = 'providelength' - -PreambleCmds.dedication = r""" -% dedication topic -\providecommand{\DUtopicdedication}[1]{\begin{center}#1\end{center}}""" - -PreambleCmds.error = r""" -% error admonition title -\providecommand*{\DUtitleerror}[1]{\DUtitle{\color{red}#1}}""" -# PreambleCmds.errortitle._depends = 'color' - -PreambleCmds.fieldlist = r""" -% fieldlist environment -\ifthenelse{\isundefined{\DUfieldlist}}{ - \newenvironment{DUfieldlist}% - {\quote\description} - {\enddescription\endquote} -}{}""" - -PreambleCmds.float_settings = r"""\usepackage{float} % float configuration -\floatplacement{figure}{H} % place figures here definitely""" - -PreambleCmds.footnotes = r"""% numeric or symbol footnotes with hyperlinks -\providecommand*{\DUfootnotemark}[3]{% - \raisebox{1em}{\hypertarget{#1}{}}% - \hyperlink{#2}{\textsuperscript{#3}}% -} -\providecommand{\DUfootnotetext}[4]{% - \begingroup% - \renewcommand{\thefootnote}{% - \protect\raisebox{1em}{\protect\hypertarget{#1}{}}% - \protect\hyperlink{#2}{#3}}% - \footnotetext{#4}% - \endgroup% -}""" - -PreambleCmds.footnote_floats = r"""% settings for footnotes as floats: -\setlength{\floatsep}{0.5em} -\setlength{\textfloatsep}{\fill} -\addtolength{\textfloatsep}{3em} -\renewcommand{\textfraction}{0.5} -\renewcommand{\topfraction}{0.5} -\renewcommand{\bottomfraction}{0.5} -\setcounter{totalnumber}{50} -\setcounter{topnumber}{50} -\setcounter{bottomnumber}{50}""" - -PreambleCmds.graphicx_auto = r"""% Check output format -\ifx\pdftexversion\undefined - \usepackage{graphicx} -\else - \usepackage[pdftex]{graphicx} -\fi'))""" - -PreambleCmds.inline = r""" -% inline markup (custom roles) -% \DUrole{#1}{#2} tries \DUrole#1{#2} -\providecommand*{\DUrole}[2]{% - \ifcsname DUrole#1\endcsname% - \csname DUrole#1\endcsname{#2}% - \else% backwards compatibility: try \docutilsrole#1{#2} - \ifcsname docutilsrole#1\endcsname% - \csname docutilsrole#1\endcsname{#2}% - \else% - #2% - \fi% - \fi% -}""" - -PreambleCmds.legend = r""" -% legend environment -\ifthenelse{\isundefined{\DUlegend}}{ - \newenvironment{DUlegend}{\small}{} -}{}""" - -PreambleCmds.lineblock = r""" -% lineblock environment -\DUprovidelength{\DUlineblockindent}{2.5em} -\ifthenelse{\isundefined{\DUlineblock}}{ - \newenvironment{DUlineblock}[1]{% - \list{}{\setlength{\partopsep}{\parskip} - \addtolength{\partopsep}{\baselineskip} - \setlength{\topsep}{0pt} - \setlength{\itemsep}{0.15\baselineskip} - \setlength{\parsep}{0pt} - \setlength{\leftmargin}{#1}} - \raggedright - } - {\endlist} -}{}""" -# PreambleCmds.lineblock._depends = 'providelength' - -PreambleCmds.linking = r""" -%% hyperlinks: -\ifthenelse{\isundefined{\hypersetup}}{ - \usepackage[%s]{hyperref} - \urlstyle{same} %% normal text font (alternatives: tt, rm, sf) -}{}""" - -PreambleCmds.minitoc = r"""%% local table of contents -\usepackage{minitoc}""" - -PreambleCmds.optionlist = r""" -% optionlist environment -\providecommand*{\DUoptionlistlabel}[1]{\bf #1 \hfill} -\DUprovidelength{\DUoptionlistindent}{3cm} -\ifthenelse{\isundefined{\DUoptionlist}}{ - \newenvironment{DUoptionlist}{% - \list{}{\setlength{\labelwidth}{\DUoptionlistindent} - \setlength{\rightmargin}{1cm} - \setlength{\leftmargin}{\rightmargin} - \addtolength{\leftmargin}{\labelwidth} - \addtolength{\leftmargin}{\labelsep} - \renewcommand{\makelabel}{\DUoptionlistlabel}} - } - {\endlist} -}{}""" -# PreambleCmds.optionlist._depends = 'providelength' - -PreambleCmds.providelength = r""" -% providelength (provide a length variable and set default, if it is new) -\providecommand*{\DUprovidelength}[2]{ - \ifthenelse{\isundefined{#1}}{\newlength{#1}\setlength{#1}{#2}}{} -}""" - -PreambleCmds.rubric = r""" -% rubric (informal heading) -\providecommand*{\DUrubric}[2][class-arg]{% - \subsubsection*{\centering\textit{\textmd{#2}}}}""" - -PreambleCmds.sidebar = r""" -% sidebar (text outside the main text flow) -\providecommand{\DUsidebar}[2][class-arg]{% - \begin{center} - \colorbox[gray]{0.80}{\parbox{0.9\textwidth}{#2}} - \end{center} -}""" - -PreambleCmds.subtitle = r""" -% subtitle (for topic/sidebar) -\providecommand*{\DUsubtitle}[2][class-arg]{\par\emph{#2}\smallskip}""" - -PreambleCmds.table = r"""\usepackage{longtable,ltcaption,array} -\setlength{\extrarowheight}{2pt} -\newlength{\DUtablewidth} % internal use in tables""" - -# Options [force,almostfull] prevent spurious error messages, see -# de.comp.text.tex/2005-12/msg01855 -PreambleCmds.textcomp = """\ -\\usepackage{textcomp} % text symbol macros""" - -PreambleCmds.titlereference = r""" -% titlereference role -\providecommand*{\DUroletitlereference}[1]{\textsl{#1}}""" - -PreambleCmds.title = r""" -% title for topics, admonitions, unsupported section levels, and sidebar -\providecommand*{\DUtitle}[2][class-arg]{% - % call \DUtitle#1{#2} if it exists: - \ifcsname DUtitle#1\endcsname% - \csname DUtitle#1\endcsname{#2}% - \else - \smallskip\noindent\textbf{#2}\smallskip% - \fi -}""" - -PreambleCmds.topic = r""" -% topic (quote with heading) -\providecommand{\DUtopic}[2][class-arg]{% - \ifcsname DUtopic#1\endcsname% - \csname DUtopic#1\endcsname{#2}% - \else - \begin{quote}#2\end{quote} - \fi -}""" - -PreambleCmds.transition = r""" -% transition (break, fancybreak, anonymous section) -\providecommand*{\DUtransition}[1][class-arg]{% - \hspace*{\fill}\hrulefill\hspace*{\fill} - \vskip 0.5\baselineskip -}""" - - -# LaTeX encoding maps -# ------------------- -# :: - -class CharMaps(object): - """LaTeX representations for active and Unicode characters.""" - - # characters that always need escaping: - special = { - ord('#'): ur'\#', - ord('$'): ur'\$', - ord('%'): ur'\%', - ord('&'): ur'\&', - ord('~'): ur'\textasciitilde{}', - ord('_'): ur'\_', - ord('^'): ur'\textasciicircum{}', - ord('\\'): ur'\textbackslash{}', - ord('{'): ur'\{', - ord('}'): ur'\}', - # Square brackets are ordinary chars and cannot be escaped with '\', - # so we put them in a group '{[}'. (Alternative: ensure that all - # macros with optional arguments are terminated with {} and text - # inside any optional argument is put in a group ``[{text}]``). - # Commands with optional args inside an optional arg must be put in a - # group, e.g. ``\item[{\hyperref[label]{text}}]``. - ord('['): ur'{[}', - ord(']'): ur'{]}', - # the soft hyphen is unknown in 8-bit text and not properly handled by XeTeX - 0x00AD: ur'\-', # SOFT HYPHEN - } - # Unicode chars that are not recognized by LaTeX's utf8 encoding - unsupported_unicode = { - 0x00A0: ur'~', # NO-BREAK SPACE - # TODO: ensure white space also at the beginning of a line? - # 0x00A0: ur'\leavevmode\nobreak\vadjust{}~' - 0x2008: ur'\,', # PUNCTUATION SPACE    - 0x2011: ur'\hbox{-}', # NON-BREAKING HYPHEN - 0x202F: ur'\,', # NARROW NO-BREAK SPACE - 0x21d4: ur'$\Leftrightarrow$', - # Docutils footnote symbols: - 0x2660: ur'$\spadesuit$', - 0x2663: ur'$\clubsuit$', - } - # Unicode chars that are recognized by LaTeX's utf8 encoding - utf8_supported_unicode = { - 0x200C: ur'\textcompwordmark', # ZERO WIDTH NON-JOINER - 0x2013: ur'\textendash{}', - 0x2014: ur'\textemdash{}', - 0x2018: ur'\textquoteleft{}', - 0x2019: ur'\textquoteright{}', - 0x201A: ur'\quotesinglbase{}', # SINGLE LOW-9 QUOTATION MARK - 0x201C: ur'\textquotedblleft{}', - 0x201D: ur'\textquotedblright{}', - 0x201E: ur'\quotedblbase{}', # DOUBLE LOW-9 QUOTATION MARK - 0x2030: ur'\textperthousand{}', # PER MILLE SIGN - 0x2031: ur'\textpertenthousand{}', # PER TEN THOUSAND SIGN - 0x2039: ur'\guilsinglleft{}', - 0x203A: ur'\guilsinglright{}', - 0x2423: ur'\textvisiblespace{}', # OPEN BOX - 0x2020: ur'\dag{}', - 0x2021: ur'\ddag{}', - 0x2026: ur'\dots{}', - 0x2122: ur'\texttrademark{}', - } - # recognized with 'utf8', if textcomp is loaded - textcomp = { - # Latin-1 Supplement - 0x00a2: ur'\textcent{}', # ¢ CENT SIGN - 0x00a4: ur'\textcurrency{}', # ¤ CURRENCY SYMBOL - 0x00a5: ur'\textyen{}', # ¥ YEN SIGN - 0x00a6: ur'\textbrokenbar{}', # ¦ BROKEN BAR - 0x00a7: ur'\textsection{}', # § SECTION SIGN - 0x00a8: ur'\textasciidieresis{}', # ¨ DIAERESIS - 0x00a9: ur'\textcopyright{}', # © COPYRIGHT SIGN - 0x00aa: ur'\textordfeminine{}', # ª FEMININE ORDINAL INDICATOR - 0x00ac: ur'\textlnot{}', # ¬ NOT SIGN - 0x00ae: ur'\textregistered{}', # ® REGISTERED SIGN - 0x00af: ur'\textasciimacron{}', # ¯ MACRON - 0x00b0: ur'\textdegree{}', # ° DEGREE SIGN - 0x00b1: ur'\textpm{}', # ± PLUS-MINUS SIGN - 0x00b2: ur'\texttwosuperior{}', # ² SUPERSCRIPT TWO - 0x00b3: ur'\textthreesuperior{}', # ³ SUPERSCRIPT THREE - 0x00b4: ur'\textasciiacute{}', # ´ ACUTE ACCENT - 0x00b5: ur'\textmu{}', # µ MICRO SIGN - 0x00b6: ur'\textparagraph{}', # ¶ PILCROW SIGN # not equal to \textpilcrow - 0x00b9: ur'\textonesuperior{}', # ¹ SUPERSCRIPT ONE - 0x00ba: ur'\textordmasculine{}', # º MASCULINE ORDINAL INDICATOR - 0x00bc: ur'\textonequarter{}', # 1/4 FRACTION - 0x00bd: ur'\textonehalf{}', # 1/2 FRACTION - 0x00be: ur'\textthreequarters{}', # 3/4 FRACTION - 0x00d7: ur'\texttimes{}', # × MULTIPLICATION SIGN - 0x00f7: ur'\textdiv{}', # ÷ DIVISION SIGN - # - 0x0192: ur'\textflorin{}', # LATIN SMALL LETTER F WITH HOOK - 0x02b9: ur'\textasciiacute{}', # MODIFIER LETTER PRIME - 0x02ba: ur'\textacutedbl{}', # MODIFIER LETTER DOUBLE PRIME - 0x2016: ur'\textbardbl{}', # DOUBLE VERTICAL LINE - 0x2022: ur'\textbullet{}', # BULLET - 0x2032: ur'\textasciiacute{}', # PRIME - 0x2033: ur'\textacutedbl{}', # DOUBLE PRIME - 0x2035: ur'\textasciigrave{}', # REVERSED PRIME - 0x2036: ur'\textgravedbl{}', # REVERSED DOUBLE PRIME - 0x203b: ur'\textreferencemark{}', # REFERENCE MARK - 0x203d: ur'\textinterrobang{}', # INTERROBANG - 0x2044: ur'\textfractionsolidus{}', # FRACTION SLASH - 0x2045: ur'\textlquill{}', # LEFT SQUARE BRACKET WITH QUILL - 0x2046: ur'\textrquill{}', # RIGHT SQUARE BRACKET WITH QUILL - 0x2052: ur'\textdiscount{}', # COMMERCIAL MINUS SIGN - 0x20a1: ur'\textcolonmonetary{}', # COLON SIGN - 0x20a3: ur'\textfrenchfranc{}', # FRENCH FRANC SIGN - 0x20a4: ur'\textlira{}', # LIRA SIGN - 0x20a6: ur'\textnaira{}', # NAIRA SIGN - 0x20a9: ur'\textwon{}', # WON SIGN - 0x20ab: ur'\textdong{}', # DONG SIGN - 0x20ac: ur'\texteuro{}', # EURO SIGN - 0x20b1: ur'\textpeso{}', # PESO SIGN - 0x20b2: ur'\textguarani{}', # GUARANI SIGN - 0x2103: ur'\textcelsius{}', # DEGREE CELSIUS - 0x2116: ur'\textnumero{}', # NUMERO SIGN - 0x2117: ur'\textcircledP{}', # SOUND RECORDING COYRIGHT - 0x211e: ur'\textrecipe{}', # PRESCRIPTION TAKE - 0x2120: ur'\textservicemark{}', # SERVICE MARK - 0x2122: ur'\texttrademark{}', # TRADE MARK SIGN - 0x2126: ur'\textohm{}', # OHM SIGN - 0x2127: ur'\textmho{}', # INVERTED OHM SIGN - 0x212e: ur'\textestimated{}', # ESTIMATED SYMBOL - 0x2190: ur'\textleftarrow{}', # LEFTWARDS ARROW - 0x2191: ur'\textuparrow{}', # UPWARDS ARROW - 0x2192: ur'\textrightarrow{}', # RIGHTWARDS ARROW - 0x2193: ur'\textdownarrow{}', # DOWNWARDS ARROW - 0x2212: ur'\textminus{}', # MINUS SIGN - 0x2217: ur'\textasteriskcentered{}', # ASTERISK OPERATOR - 0x221a: ur'\textsurd{}', # SQUARE ROOT - 0x2422: ur'\textblank{}', # BLANK SYMBOL - 0x25e6: ur'\textopenbullet{}', # WHITE BULLET - 0x25ef: ur'\textbigcircle{}', # LARGE CIRCLE - 0x266a: ur'\textmusicalnote{}', # EIGHTH NOTE - 0x26ad: ur'\textmarried{}', # MARRIAGE SYMBOL - 0x26ae: ur'\textdivorced{}', # DIVORCE SYMBOL - 0x27e8: ur'\textlangle{}', # MATHEMATICAL LEFT ANGLE BRACKET - 0x27e9: ur'\textrangle{}', # MATHEMATICAL RIGHT ANGLE BRACKET - } - # Unicode chars that require a feature/package to render - pifont = { - 0x2665: ur'\ding{170}', # black heartsuit - 0x2666: ur'\ding{169}', # black diamondsuit - 0x2713: ur'\ding{51}', # check mark - 0x2717: ur'\ding{55}', # check mark - } - # TODO: greek alphabet ... ? - # see also LaTeX codec - # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252124 - # and unimap.py from TeXML - - -class DocumentClass(object): - """Details of a LaTeX document class.""" - - def __init__(self, document_class, with_part=False): - self.document_class = document_class - self._with_part = with_part - self.sections = ['section', 'subsection', 'subsubsection', - 'paragraph', 'subparagraph'] - if self.document_class in ('book', 'memoir', 'report', - 'scrbook', 'scrreprt'): - self.sections.insert(0, 'chapter') - if self._with_part: - self.sections.insert(0, 'part') - - def section(self, level): - """Return the LaTeX section name for section `level`. - - The name depends on the specific document class. - Level is 1,2,3..., as level 0 is the title. - """ - if level <= len(self.sections): - return self.sections[level-1] - else: # unsupported levels - return 'DUtitle[section%s]' % roman.toRoman(level) - -class Table(object): - """Manage a table while traversing. - - Maybe change to a mixin defining the visit/departs, but then - class Table internal variables are in the Translator. - - Table style might be - - :standard: horizontal and vertical lines - :booktabs: only horizontal lines (requires "booktabs" LaTeX package) - :borderless: no borders around table cells - :nolines: alias for borderless - """ - def __init__(self,translator,latex_type,table_style): - self._translator = translator - self._latex_type = latex_type - self._table_style = table_style - self._open = False - # miscellaneous attributes - self._attrs = {} - self._col_width = [] - self._rowspan = [] - self.stubs = [] - self._in_thead = 0 - - def open(self): - self._open = True - self._col_specs = [] - self.caption = [] - self._attrs = {} - self._in_head = False # maybe context with search - def close(self): - self._open = False - self._col_specs = None - self.caption = [] - self._attrs = {} - self.stubs = [] - def is_open(self): - return self._open - - def set_table_style(self, table_style): - if not table_style in ('standard','booktabs','borderless','nolines'): - return - self._table_style = table_style - - def get_latex_type(self): - if self._latex_type == 'longtable' and not self.caption: - # do not advance the "table" counter (requires "ltcaption" package) - return('longtable*') - return self._latex_type - - def set(self,attr,value): - self._attrs[attr] = value - def get(self,attr): - if attr in self._attrs: - return self._attrs[attr] - return None - - def get_vertical_bar(self): - if self._table_style == 'standard': - return '|' - return '' - - # horizontal lines are drawn below a row, - def get_opening(self): - return '\n'.join([r'\setlength{\DUtablewidth}{\linewidth}', - r'\begin{%s}[c]' % self.get_latex_type()]) - - def get_closing(self): - closing = [] - if self._table_style == 'booktabs': - closing.append(r'\bottomrule') - # elif self._table_style == 'standard': - # closing.append(r'\hline') - closing.append(r'\end{%s}' % self.get_latex_type()) - return '\n'.join(closing) - - def visit_colspec(self, node): - self._col_specs.append(node) - # "stubs" list is an attribute of the tgroup element: - self.stubs.append(node.attributes.get('stub')) - - def get_colspecs(self): - """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._col_specs: - colwidth = float(node['colwidth']+1) / width - total_width += colwidth - self._col_width = [] - self._rowspan = [] - # donot make it full linewidth - factor = 0.93 - if total_width > 1.0: - factor /= total_width - bar = self.get_vertical_bar() - latex_table_spec = '' - for node in self._col_specs: - colwidth = factor * float(node['colwidth']+1) / width - self._col_width.append(colwidth+0.005) - self._rowspan.append(0) - latex_table_spec += '%sp{%.3f\\DUtablewidth}' % (bar, colwidth+0.005) - return latex_table_spec+bar - - def get_column_width(self): - """Return columnwidth for current cell (not multicell).""" - return '%.2f\\DUtablewidth' % self._col_width[self._cell_in_row-1] - - def get_multicolumn_width(self, start, len_): - """Return sum of columnwidths for multicell.""" - mc_width = sum([width - for width in ([self._col_width[start + co - 1] - for co in range (len_)])]) - return '%.2f\\DUtablewidth' % mc_width - - def get_caption(self): - if not self.caption: - return '' - caption = ''.join(self.caption) - if 1 == self._translator.thead_depth(): - return r'\caption{%s}\\' '\n' % caption - return r'\caption[]{%s (... continued)}\\' '\n' % caption - - def need_recurse(self): - if self._latex_type == 'longtable': - return 1 == self._translator.thead_depth() - return 0 - - def visit_thead(self): - self._in_thead += 1 - if self._table_style == 'standard': - return ['\\hline\n'] - elif self._table_style == 'booktabs': - return ['\\toprule\n'] - return [] - - def depart_thead(self): - a = [] - #if self._table_style == 'standard': - # a.append('\\hline\n') - if self._table_style == 'booktabs': - a.append('\\midrule\n') - if self._latex_type == 'longtable': - if 1 == self._translator.thead_depth(): - a.append('\\endfirsthead\n') - else: - a.append('\\endhead\n') - a.append(r'\multicolumn{%d}{c}' % len(self._col_specs) + - r'{\hfill ... continued on next page} \\') - a.append('\n\\endfoot\n\\endlastfoot\n') - # for longtable one could add firsthead, foot and lastfoot - self._in_thead -= 1 - return a - def visit_row(self): - self._cell_in_row = 0 - def depart_row(self): - res = [' \\\\\n'] - self._cell_in_row = None # remove cell counter - for i in range(len(self._rowspan)): - if (self._rowspan[i]>0): - self._rowspan[i] -= 1 - - if self._table_style == 'standard': - rowspans = [i+1 for i in range(len(self._rowspan)) - if (self._rowspan[i]<=0)] - if len(rowspans)==len(self._rowspan): - res.append('\\hline\n') - else: - cline = '' - rowspans.reverse() - # TODO merge clines - while True: - try: - c_start = rowspans.pop() - except: - break - cline += '\\cline{%d-%d}\n' % (c_start,c_start) - res.append(cline) - return res - - def set_rowspan(self,cell,value): - try: - self._rowspan[cell] = value - except: - pass - def get_rowspan(self,cell): - try: - return self._rowspan[cell] - except: - return 0 - def get_entry_number(self): - return self._cell_in_row - def visit_entry(self): - self._cell_in_row += 1 - def is_stub_column(self): - if len(self.stubs) >= self._cell_in_row: - return self.stubs[self._cell_in_row-1] - return False - - -class LaTeXTranslator(nodes.NodeVisitor): - - # When options are given to the documentclass, latex will pass them - # to other packages, as done with babel. - # Dummy settings might be taken from document settings - - # Write code for typesetting with 8-bit tex/pdftex (vs. xetex/luatex) engine - # overwritten by the XeTeX writer - is_xetex = False - - # Config setting defaults - # ----------------------- - - # TODO: use mixins for different implementations. - # list environment for docinfo. else tabularx - ## use_optionlist_for_docinfo = False # TODO: NOT YET IN USE - - # Use compound enumerations (1.A.1.) - compound_enumerators = False - - # If using compound enumerations, include section information. - section_prefix_for_enumerators = False - - # This is the character that separates the section ("." subsection ...) - # prefix from the regular list enumerator. - section_enumerator_separator = '-' - - # Auxiliary variables - # ------------------- - - has_latex_toc = False # is there a toc in the doc? (needed by minitoc) - is_toc_list = False # is the current bullet_list a ToC? - section_level = 0 - - # Flags to encode(): - # inside citation reference labels underscores dont need to be escaped - inside_citation_reference_label = False - verbatim = False # do not encode - insert_non_breaking_blanks = False # replace blanks by "~" - insert_newline = False # add latex newline commands - literal = False # literal text (block or inline) - - - def __init__(self, document, babel_class=Babel): - nodes.NodeVisitor.__init__(self, document) - # Reporter - # ~~~~~~~~ - self.warn = self.document.reporter.warning - self.error = self.document.reporter.error - - # Settings - # ~~~~~~~~ - self.settings = settings = document.settings - self.latex_encoding = self.to_latex_encoding(settings.output_encoding) - self.use_latex_toc = settings.use_latex_toc - self.use_latex_docinfo = settings.use_latex_docinfo - self._use_latex_citations = settings.use_latex_citations - self._reference_label = settings.reference_label - self.hyperlink_color = settings.hyperlink_color - self.compound_enumerators = settings.compound_enumerators - self.font_encoding = getattr(settings, 'font_encoding', '') - self.section_prefix_for_enumerators = ( - settings.section_prefix_for_enumerators) - self.section_enumerator_separator = ( - settings.section_enumerator_separator.replace('_', r'\_')) - # literal blocks: - self.literal_block_env = '' - self.literal_block_options = '' - if settings.literal_block_env != '': - (none, - self.literal_block_env, - self.literal_block_options, - none ) = re.split('(\w+)(.*)', settings.literal_block_env) - elif settings.use_verbatim_when_possible: - self.literal_block_env = 'verbatim' - # - if self.settings.use_bibtex: - self.bibtex = self.settings.use_bibtex.split(',',1) - # TODO avoid errors on not declared citations. - else: - self.bibtex = None - # language module for Docutils-generated text - # (labels, bibliographic_fields, and author_separators) - self.language_module = languages.get_language(settings.language_code, - document.reporter) - self.babel = babel_class(settings.language_code, document.reporter) - self.author_separator = self.language_module.author_separators[0] - d_options = [self.settings.documentoptions] - if self.babel.language not in ('english', ''): - d_options.append(self.babel.language) - self.documentoptions = ','.join(filter(None, d_options)) - self.d_class = DocumentClass(settings.documentclass, - settings.use_part_section) - # graphic package options: - if self.settings.graphicx_option == '': - self.graphicx_package = r'\usepackage{graphicx}' - elif self.settings.graphicx_option.lower() == 'auto': - self.graphicx_package = PreambleCmds.graphicx_auto - else: - self.graphicx_package = (r'\usepackage[%s]{graphicx}' % - self.settings.graphicx_option) - # footnotes: - self.docutils_footnotes = settings.docutils_footnotes - if settings.use_latex_footnotes: - self.docutils_footnotes = True - self.warn('`use_latex_footnotes` is deprecated. ' - 'The setting has been renamed to `docutils_footnotes` ' - 'and the alias will be removed in a future version.') - self.figure_footnotes = settings.figure_footnotes - if self.figure_footnotes: - self.docutils_footnotes = True - self.warn('The "figure footnotes" workaround/setting is strongly ' - 'deprecated and will be removed in a future version.') - - # Output collection stacks - # ~~~~~~~~~~~~~~~~~~~~~~~~ - - # Document parts - self.head_prefix = [r'\documentclass[%s]{%s}' % - (self.documentoptions, self.settings.documentclass)] - self.requirements = SortableDict() # made a list in depart_document() - self.requirements['__static'] = r'\usepackage{ifthen}' - self.latex_preamble = [settings.latex_preamble] - self.fallbacks = SortableDict() # made a list in depart_document() - self.pdfsetup = [] # PDF properties (hyperref package) - self.title = [] - self.subtitle = [] - self.titledata = [] # \title, \author, \date - ## self.body_prefix = ['\\begin{document}\n'] - self.body_pre_docinfo = [] # \maketitle - self.docinfo = [] - self.dedication = [] - self.abstract = [] - self.body = [] - ## self.body_suffix = ['\\end{document}\n'] - - # A heterogenous stack used in conjunction with the tree traversal. - # Make sure that the pops correspond to the pushes: - self.context = [] - - # Title metadata: - self.title_labels = [] - self.subtitle_labels = [] - # (if use_latex_docinfo: collects lists of - # author/organization/contact/address lines) - self.author_stack = [] - self.date = [] - - # PDF properties: pdftitle, pdfauthor - # TODO?: pdfcreator, pdfproducer, pdfsubject, pdfkeywords - self.pdfinfo = [] - self.pdfauthor = [] - - # 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 = [] - # The maximum number of enumeration counters we've used. - # If we go beyond this number, we need to create a new - # counter; otherwise, just reuse an old one. - self._max_enumeration_counters = 0 - - self._bibitems = [] - - # object for a table while proccessing. - self.table_stack = [] - self.active_table = Table(self, 'longtable', settings.table_style) - - # Where to collect the output of visitor methods (default: body) - self.out = self.body - self.out_stack = [] # stack of output collectors - - # Process settings - # ~~~~~~~~~~~~~~~~ - # Encodings: - # Docutils' output-encoding => TeX input encoding - if self.latex_encoding != 'ascii': - self.requirements['_inputenc'] = (r'\usepackage[%s]{inputenc}' - % self.latex_encoding) - # TeX font encoding - if self.font_encoding and not self.is_xetex: - self.requirements['_fontenc'] = (r'\usepackage[%s]{fontenc}' % - self.font_encoding) - # page layout with typearea (if there are relevant document options) - if (settings.documentclass.find('scr') == -1 and - (self.documentoptions.find('DIV') != -1 or - self.documentoptions.find('BCOR') != -1)): - self.requirements['typearea'] = r'\usepackage{typearea}' - - # Stylesheets - # (the name `self.stylesheet` is singular because only one - # stylesheet was supported before Docutils 0.6). - self.stylesheet = [self.stylesheet_call(path) - for path in utils.get_stylesheet_list(settings)] - - # PDF setup - if self.hyperlink_color in ('0', 'false', 'False', ''): - self.hyperref_options = '' - else: - self.hyperref_options = 'colorlinks=true,linkcolor=%s,urlcolor=%s' % ( - self.hyperlink_color, self.hyperlink_color) - if settings.hyperref_options: - self.hyperref_options += ',' + settings.hyperref_options - - # LaTeX Toc - # include all supported sections in toc and PDF bookmarks - # (or use documentclass-default (as currently))? - ## if self.use_latex_toc: - ## self.requirements['tocdepth'] = (r'\setcounter{tocdepth}{%d}' % - ## len(self.d_class.sections)) - - # Section numbering - if not self.settings.sectnum_xform: # section numbering by Docutils - PreambleCmds.secnumdepth = r'\setcounter{secnumdepth}{0}' - else: # section numbering by LaTeX: - secnumdepth = settings.sectnum_depth - # Possible values of settings.sectnum_depth: - # None "sectnum" directive without depth arg -> LaTeX default - # 0 no "sectnum" directive -> no section numbers - # >0 value of "depth" argument -> translate to LaTeX levels: - # -1 part (0 with "article" document class) - # 0 chapter (missing in "article" document class) - # 1 section - # 2 subsection - # 3 subsubsection - # 4 paragraph - # 5 subparagraph - if secnumdepth is not None: - # limit to supported levels - secnumdepth = min(secnumdepth, len(self.d_class.sections)) - # adjust to document class and use_part_section settings - if 'chapter' in self.d_class.sections: - secnumdepth -= 1 - if self.d_class.sections[0] == 'part': - secnumdepth -= 1 - PreambleCmds.secnumdepth = \ - r'\setcounter{secnumdepth}{%d}' % secnumdepth - - # start with specified number: - if (hasattr(settings, 'sectnum_start') and - settings.sectnum_start != 1): - self.requirements['sectnum_start'] = ( - r'\setcounter{%s}{%d}' % (self.d_class.sections[0], - settings.sectnum_start-1)) - # TODO: currently ignored (configure in a stylesheet): - ## settings.sectnum_prefix - ## settings.sectnum_suffix - - # Auxiliary Methods - # ----------------- - - def stylesheet_call(self, path): - """Return code to reference or embed stylesheet file `path`""" - # is it a package (no extension or *.sty) or "normal" tex code: - (base, ext) = os.path.splitext(path) - is_package = ext in ['.sty', ''] - # Embed content of style file: - if self.settings.embed_stylesheet: - if is_package: - path = base + '.sty' # ensure extension - try: - content = io.FileInput(source_path=path, - encoding='utf-8', - handle_io_errors=False).read() - self.settings.record_dependencies.add(path) - except IOError, err: - msg = u"Cannot embed stylesheet '%s':\n %s." % ( - path, SafeString(err.strerror)) - self.document.reporter.error(msg) - return '% ' + msg.replace('\n', '\n% ') - if is_package: - content = '\n'.join([r'\makeatletter', - content, - r'\makeatother']) - return '%% embedded stylesheet: %s\n%s' % (path, content) - # Link to style file: - if is_package: - path = base # drop extension - cmd = r'\usepackage{%s}' - else: - cmd = r'\input{%s}' - if self.settings.stylesheet_path: - # adapt path relative to output (cf. config.html#stylesheet-path) - path = utils.relative_path(self.settings._destination, path) - return cmd % path - - def to_latex_encoding(self,docutils_encoding): - """Translate docutils encoding name into LaTeX's. - - Default method is remove "-" and "_" chars from docutils_encoding. - """ - tr = { 'iso-8859-1': 'latin1', # west european - 'iso-8859-2': 'latin2', # east european - 'iso-8859-3': 'latin3', # esperanto, maltese - 'iso-8859-4': 'latin4', # north european, scandinavian, baltic - 'iso-8859-5': 'iso88595', # cyrillic (ISO) - 'iso-8859-9': 'latin5', # turkish - 'iso-8859-15': 'latin9', # latin9, update to latin1. - 'mac_cyrillic': 'maccyr', # cyrillic (on Mac) - 'windows-1251': 'cp1251', # cyrillic (on Windows) - 'koi8-r': 'koi8-r', # cyrillic (Russian) - 'koi8-u': 'koi8-u', # cyrillic (Ukrainian) - 'windows-1250': 'cp1250', # - 'windows-1252': 'cp1252', # - 'us-ascii': 'ascii', # ASCII (US) - # unmatched encodings - #'': 'applemac', - #'': 'ansinew', # windows 3.1 ansi - #'': 'ascii', # ASCII encoding for the range 32--127. - #'': 'cp437', # dos latin us - #'': 'cp850', # dos latin 1 - #'': 'cp852', # dos latin 2 - #'': 'decmulti', - #'': 'latin10', - #'iso-8859-6': '' # arabic - #'iso-8859-7': '' # greek - #'iso-8859-8': '' # hebrew - #'iso-8859-10': '' # latin6, more complete iso-8859-4 - } - encoding = docutils_encoding.lower() - if encoding in tr: - return tr[encoding] - # drop hyphen or low-line from "latin-1", "latin_1", "utf-8" and similar - encoding = encoding.replace('_', '').replace('-', '') - # strip the error handler - return encoding.split(':')[0] - - def language_label(self, docutil_label): - return self.language_module.labels[docutil_label] - - def encode(self, text): - """Return text with 'problematic' characters escaped. - - * Escape the ten special printing characters ``# $ % & ~ _ ^ \ { }``, - square brackets ``[ ]``, double quotes and (in OT1) ``< | >``. - * Translate non-supported Unicode characters. - * Separate ``-`` (and more in literal text) to prevent input ligatures. - """ - if self.verbatim: - return text - - # Set up the translation table: - table = CharMaps.special.copy() - # keep the underscore in citation references - if self.inside_citation_reference_label: - del(table[ord('_')]) - # Workarounds for OT1 font-encoding - if self.font_encoding in ['OT1', ''] and not self.is_xetex: - # * out-of-order characters in cmtt - if self.literal: - # replace underscore by underlined blank, - # because this has correct width. - table[ord('_')] = u'\\underline{~}' - # the backslash doesn't work, so we use a mirrored slash. - # \reflectbox is provided by graphicx: - self.requirements['graphicx'] = self.graphicx_package - table[ord('\\')] = ur'\reflectbox{/}' - # * ``< | >`` come out as different chars (except for cmtt): - else: - table[ord('|')] = ur'\textbar{}' - table[ord('<')] = ur'\textless{}' - table[ord('>')] = ur'\textgreater{}' - if self.insert_non_breaking_blanks: - table[ord(' ')] = ur'~' - if self.literal: - # double quotes are 'active' in some languages - # TODO: use \textquotedbl if font encoding starts with T? - table[ord('"')] = self.babel.literal_double_quote - # Unicode replacements for 8-bit tex engines (not required with XeTeX/LuaTeX): - if not self.is_xetex: - table.update(CharMaps.unsupported_unicode) - if not self.latex_encoding.startswith('utf8'): - table.update(CharMaps.utf8_supported_unicode) - table.update(CharMaps.textcomp) - table.update(CharMaps.pifont) - # Characters that require a feature/package to render - if [True for ch in text if ord(ch) in CharMaps.textcomp]: - self.requirements['textcomp'] = PreambleCmds.textcomp - if [True for ch in text if ord(ch) in CharMaps.pifont]: - self.requirements['pifont'] = '\\usepackage{pifont}' - - text = text.translate(table) - - # Break up input ligatures e.g. '--' to '-{}-'. - if not self.is_xetex: # Not required with xetex/luatex - separate_chars = '-' - # In monospace-font, we also separate ',,', '``' and "''" and some - # other characters which can't occur in non-literal text. - if self.literal: - separate_chars += ',`\'"<>' - for char in separate_chars * 2: - # Do it twice ("* 2") because otherwise we would replace - # '---' by '-{}--'. - text = text.replace(char + char, char + '{}' + char) - - # Literal line breaks (in address or literal blocks): - if self.insert_newline: - lines = text.split('\n') - # Add a protected space to blank lines (except the last) - # to avoid ``! LaTeX Error: There's no line here to end.`` - for i, line in enumerate(lines[:-1]): - if not line.lstrip(): - lines[i] += '~' - text = (r'\\' + '\n').join(lines) - if not self.literal: - text = self.babel.quote_quotes(text) - if self.literal and not self.insert_non_breaking_blanks: - # preserve runs of spaces but allow wrapping - text = text.replace(' ', ' ~') - return text - - def attval(self, text, - whitespace=re.compile('[\n\r\t\v\f]')): - """Cleanse, encode, and return attribute value text.""" - return self.encode(whitespace.sub(' ', text)) - - # TODO: is this used anywhere? -> update (use template) or delete - ## def astext(self): - ## """Assemble document parts and return as string.""" - ## head = '\n'.join(self.head_prefix + self.stylesheet + self.head) - ## body = ''.join(self.body_prefix + self.body + self.body_suffix) - ## return head + '\n' + body - - def is_inline(self, node): - """Check whether a node represents an inline element""" - return isinstance(node.parent, nodes.TextElement) - - def append_hypertargets(self, node): - """Append hypertargets for all ids of `node`""" - # hypertarget places the anchor at the target's baseline, - # so we raise it explicitely - self.out.append('%\n'.join(['\\raisebox{1em}{\\hypertarget{%s}{}}' % - id for id in node['ids']])) - - def ids_to_labels(self, node, set_anchor=True): - """Return list of label definitions for all ids of `node` - - If `set_anchor` is True, an anchor is set with \phantomsection. - """ - labels = ['\\label{%s}' % id for id in node.get('ids', [])] - if set_anchor and labels: - labels.insert(0, '\\phantomsection') - return labels - - def push_output_collector(self, new_out): - self.out_stack.append(self.out) - self.out = new_out - - def pop_output_collector(self): - self.out = self.out_stack.pop() - - # Visitor methods - # --------------- - - def visit_Text(self, node): - self.out.append(self.encode(node.astext())) - - def depart_Text(self, node): - pass - - def visit_abbreviation(self, node): - node['classes'].insert(0, 'abbreviation') - self.visit_inline(node) - - def depart_abbreviation(self, node): - self.depart_inline(node) - - def visit_acronym(self, node): - node['classes'].insert(0, 'acronym') - self.visit_inline(node) - - def depart_acronym(self, node): - self.depart_inline(node) - - def visit_address(self, node): - self.visit_docinfo_item(node, 'address') - - def depart_address(self, node): - self.depart_docinfo_item(node) - - def visit_admonition(self, node): - self.fallbacks['admonition'] = PreambleCmds.admonition - if 'error' in node['classes']: - self.fallbacks['error'] = PreambleCmds.error - # strip the generic 'admonition' from the list of classes - node['classes'] = [cls for cls in node['classes'] - if cls != 'admonition'] - self.out.append('\n\\DUadmonition[%s]{\n' % ','.join(node['classes'])) - - def depart_admonition(self, node=None): - self.out.append('}\n') - - def visit_author(self, node): - self.visit_docinfo_item(node, 'author') - - def depart_author(self, node): - self.depart_docinfo_item(node) - - def visit_authors(self, node): - # not used: visit_author is called anyway for each author. - pass - - def depart_authors(self, node): - pass - - def visit_block_quote(self, node): - self.out.append( '%\n\\begin{quote}\n') - if node['classes']: - self.visit_inline(node) - - def depart_block_quote(self, node): - if node['classes']: - self.depart_inline(node) - self.out.append( '\n\\end{quote}\n') - - def visit_bullet_list(self, node): - if self.is_toc_list: - self.out.append( '%\n\\begin{list}{}{}\n' ) - else: - self.out.append( '%\n\\begin{itemize}\n' ) - - def depart_bullet_list(self, node): - if self.is_toc_list: - self.out.append( '\n\\end{list}\n' ) - else: - self.out.append( '\n\\end{itemize}\n' ) - - def visit_superscript(self, node): - self.out.append(r'\textsuperscript{') - if node['classes']: - self.visit_inline(node) - - def depart_superscript(self, node): - if node['classes']: - self.depart_inline(node) - self.out.append('}') - - def visit_subscript(self, node): - self.out.append(r'\textsubscript{') # requires `fixltx2e` - if node['classes']: - self.visit_inline(node) - - def depart_subscript(self, node): - if node['classes']: - self.depart_inline(node) - self.out.append('}') - - def visit_caption(self, node): - self.out.append( '\\caption{' ) - - def depart_caption(self, node): - self.out.append('}\n') - - def visit_title_reference(self, node): - self.fallbacks['titlereference'] = PreambleCmds.titlereference - self.out.append(r'\DUroletitlereference{') - if node['classes']: - self.visit_inline(node) - - def depart_title_reference(self, node): - if node['classes']: - self.depart_inline(node) - self.out.append( '}' ) - - def visit_citation(self, node): - # TODO maybe use cite bibitems - if self._use_latex_citations: - self.push_output_collector([]) - else: - # TODO: do we need these? - ## self.requirements['~fnt_floats'] = PreambleCmds.footnote_floats - self.out.append(r'\begin{figure}[b]') - self.append_hypertargets(node) - - def depart_citation(self, node): - if self._use_latex_citations: - label = self.out[0] - text = ''.join(self.out[1:]) - self._bibitems.append([label, text]) - self.pop_output_collector() - else: - self.out.append('\\end{figure}\n') - - def visit_citation_reference(self, node): - if self._use_latex_citations: - if not self.inside_citation_reference_label: - self.out.append(r'\cite{') - self.inside_citation_reference_label = 1 - else: - assert self.body[-1] in (' ', '\n'),\ - 'unexpected non-whitespace while in reference label' - del self.body[-1] - else: - href = '' - if 'refid' in node: - href = node['refid'] - elif 'refname' in node: - href = self.document.nameids[node['refname']] - self.out.append('\\hyperlink{%s}{[' % href) - - def depart_citation_reference(self, node): - if self._use_latex_citations: - followup_citation = False - # check for a following citation separated by a space or newline - next_siblings = node.traverse(descend=False, siblings=True, - include_self=False) - if len(next_siblings) > 1: - next = next_siblings[0] - if (isinstance(next, nodes.Text) and - next.astext() in (' ', '\n')): - if next_siblings[1].__class__ == node.__class__: - followup_citation = True - if followup_citation: - self.out.append(',') - else: - self.out.append('}') - self.inside_citation_reference_label = False - else: - self.out.append(']}') - - def visit_classifier(self, node): - self.out.append( '(\\textbf{' ) - - def depart_classifier(self, node): - self.out.append( '})\n' ) - - def visit_colspec(self, node): - self.active_table.visit_colspec(node) - - def depart_colspec(self, node): - pass - - def visit_comment(self, node): - # Precede every line with a comment sign, wrap in newlines - self.out.append('\n%% %s\n' % node.astext().replace('\n', '\n% ')) - raise nodes.SkipNode - - def depart_comment(self, node): - pass - - def visit_compound(self, node): - pass - - def depart_compound(self, node): - pass - - def visit_contact(self, node): - self.visit_docinfo_item(node, 'contact') - - def depart_contact(self, node): - self.depart_docinfo_item(node) - - def visit_container(self, node): - pass - - def depart_container(self, node): - pass - - def visit_copyright(self, node): - self.visit_docinfo_item(node, 'copyright') - - def depart_copyright(self, node): - self.depart_docinfo_item(node) - - def visit_date(self, node): - self.visit_docinfo_item(node, 'date') - - def depart_date(self, node): - self.depart_docinfo_item(node) - - def visit_decoration(self, node): - # header and footer - pass - - def depart_decoration(self, node): - pass - - def visit_definition(self, node): - pass - - def depart_definition(self, node): - self.out.append('\n') - - def visit_definition_list(self, node): - self.out.append( '%\n\\begin{description}\n' ) - - def depart_definition_list(self, node): - self.out.append( '\\end{description}\n' ) - - def visit_definition_list_item(self, node): - pass - - def depart_definition_list_item(self, node): - pass - - def visit_description(self, node): - self.out.append(' ') - - def depart_description(self, node): - pass - - def visit_docinfo(self, node): - self.push_output_collector(self.docinfo) - - def depart_docinfo(self, node): - self.pop_output_collector() - # Some itmes (e.g. author) end up at other places - if self.docinfo: - # tabularx: automatic width of columns, no page breaks allowed. - self.requirements['tabularx'] = r'\usepackage{tabularx}' - self.fallbacks['_providelength'] = PreambleCmds.providelength - self.fallbacks['docinfo'] = PreambleCmds.docinfo - # - self.docinfo.insert(0, '\n% Docinfo\n' - '\\begin{center}\n' - '\\begin{tabularx}{\\DUdocinfowidth}{lX}\n') - self.docinfo.append('\\end{tabularx}\n' - '\\end{center}\n') - - def visit_docinfo_item(self, node, name): - if name == 'author': - self.pdfauthor.append(self.attval(node.astext())) - if self.use_latex_docinfo: - if name in ('author', 'organization', 'contact', 'address'): - # We attach these to the last author. If any of them precedes - # the first author, put them in a separate "author" group - # (in lack of better semantics). - if name == 'author' or not self.author_stack: - self.author_stack.append([]) - if name == 'address': # newlines are meaningful - self.insert_newline = True - text = self.encode(node.astext()) - self.insert_newline = False - else: - text = self.attval(node.astext()) - self.author_stack[-1].append(text) - raise nodes.SkipNode - elif name == 'date': - self.date.append(self.attval(node.astext())) - raise nodes.SkipNode - self.out.append('\\textbf{%s}: &\n\t' % self.language_label(name)) - if name == 'address': - self.insert_newline = 1 - self.out.append('{\\raggedright\n') - self.context.append(' } \\\\\n') - else: - self.context.append(' \\\\\n') - - def depart_docinfo_item(self, node): - self.out.append(self.context.pop()) - # for address we did set insert_newline - self.insert_newline = False - - def visit_doctest_block(self, node): - self.visit_literal_block(node) - - def depart_doctest_block(self, node): - self.depart_literal_block(node) - - def visit_document(self, node): - # titled document? - if (self.use_latex_docinfo or len(node) and - isinstance(node[0], nodes.title)): - self.title_labels += self.ids_to_labels(node, set_anchor=False) - - def depart_document(self, node): - # Complete header with information gained from walkabout - # * language setup - if (self.babel.otherlanguages or - self.babel.language not in ('', 'english')): - self.requirements['babel'] = self.babel() - # * conditional requirements (before style sheet) - self.requirements = self.requirements.sortedvalues() - # * coditional fallback definitions (after style sheet) - self.fallbacks = self.fallbacks.sortedvalues() - # * PDF properties - self.pdfsetup.append(PreambleCmds.linking % self.hyperref_options) - if self.pdfauthor: - authors = self.author_separator.join(self.pdfauthor) - self.pdfinfo.append(' pdfauthor={%s}' % authors) - if self.pdfinfo: - self.pdfsetup += [r'\hypersetup{'] + self.pdfinfo + ['}'] - # Complete body - # * document title (with "use_latex_docinfo" also - # 'author', 'organization', 'contact', 'address' and 'date') - if self.title or ( - self.use_latex_docinfo and (self.author_stack or self.date)): - # with the default template, titledata is written to the preamble - self.titledata.append('%%% Title Data') - # \title (empty \title prevents error with \maketitle) - if self.title: - self.title.insert(0, '\phantomsection%\n ') - title = [''.join(self.title)] + self.title_labels - if self.subtitle: - title += [r'\\ % subtitle', - r'\large{%s}' % ''.join(self.subtitle) - ] + self.subtitle_labels - self.titledata.append(r'\title{%s}' % '%\n '.join(title)) - # \author (empty \author prevents warning with \maketitle) - authors = ['\\\\\n'.join(author_entry) - for author_entry in self.author_stack] - self.titledata.append(r'\author{%s}' % - ' \\and\n'.join(authors)) - # \date (empty \date prevents defaulting to \today) - self.titledata.append(r'\date{%s}' % ', '.join(self.date)) - # \maketitle in the body formats title with LaTeX - self.body_pre_docinfo.append('\\maketitle\n') - - # * bibliography - # TODO insertion point of bibliography should be configurable. - if self._use_latex_citations and len(self._bibitems)>0: - if not self.bibtex: - widest_label = '' - for bi in self._bibitems: - if len(widest_label) self._max_enumeration_counters: - self._max_enumeration_counters = len(self._enumeration_counters) - self.out.append('\\newcounter{%s}\n' % counter_name) - else: - self.out.append('\\setcounter{%s}{0}\n' % counter_name) - - self.out.append('\\begin{list}{%s\\%s{%s}%s}\n' % - (enum_prefix,enum_type,counter_name,enum_suffix)) - self.out.append('{\n') - self.out.append('\\usecounter{%s}\n' % counter_name) - # set start after usecounter, because it initializes to zero. - if 'start' in node: - self.out.append('\\addtocounter{%s}{%d}\n' % - (counter_name,node['start']-1)) - ## set rightmargin equal to leftmargin - self.out.append('\\setlength{\\rightmargin}{\\leftmargin}\n') - self.out.append('}\n') - - def depart_enumerated_list(self, node): - self.out.append('\\end{list}\n') - self._enumeration_counters.pop() - - def visit_field(self, node): - # real output is done in siblings: _argument, _body, _name - pass - - def depart_field(self, node): - self.out.append('\n') - ##self.out.append('%[depart_field]\n') - - def visit_field_argument(self, node): - self.out.append('%[visit_field_argument]\n') - - def depart_field_argument(self, node): - self.out.append('%[depart_field_argument]\n') - - def visit_field_body(self, node): - pass - - def depart_field_body(self, node): - if self.out is self.docinfo: - self.out.append(r'\\') - - def visit_field_list(self, node): - if self.out is not self.docinfo: - self.fallbacks['fieldlist'] = PreambleCmds.fieldlist - self.out.append('%\n\\begin{DUfieldlist}\n') - - def depart_field_list(self, node): - if self.out is not self.docinfo: - self.out.append('\\end{DUfieldlist}\n') - - def visit_field_name(self, node): - if self.out is self.docinfo: - self.out.append('\\textbf{') - else: - # Commands with optional args inside an optional arg must be put - # in a group, e.g. ``\item[{\hyperref[label]{text}}]``. - self.out.append('\\item[{') - - def depart_field_name(self, node): - if self.out is self.docinfo: - self.out.append('}: &') - else: - self.out.append(':}]') - - def visit_figure(self, node): - self.requirements['float_settings'] = PreambleCmds.float_settings - # ! the 'align' attribute should set "outer alignment" ! - # For "inner alignment" use LaTeX default alignment (similar to HTML) - ## if ('align' not in node.attributes or - ## node.attributes['align'] == 'center'): - ## align = '\n\\centering' - ## align_end = '' - ## else: - ## # TODO non vertical space for other alignments. - ## align = '\\begin{flush%s}' % node.attributes['align'] - ## align_end = '\\end{flush%s}' % node.attributes['align'] - ## self.out.append( '\\begin{figure}%s\n' % align ) - ## self.context.append( '%s\\end{figure}\n' % align_end ) - self.out.append('\\begin{figure}') - if node.get('ids'): - self.out += ['\n'] + self.ids_to_labels(node) - - def depart_figure(self, node): - self.out.append('\\end{figure}\n') - - def visit_footer(self, node): - self.push_output_collector([]) - self.out.append(r'\newcommand{\DUfooter}{') - - def depart_footer(self, node): - self.out.append('}') - self.requirements['~footer'] = ''.join(self.out) - self.pop_output_collector() - - def visit_footnote(self, node): - try: - backref = node['backrefs'][0] - except IndexError: - backref = node['ids'][0] # no backref, use self-ref instead - if self.settings.figure_footnotes: - self.requirements['~fnt_floats'] = PreambleCmds.footnote_floats - self.out.append('\\begin{figure}[b]') - self.append_hypertargets(node) - if node.get('id') == node.get('name'): # explicite label - self.out += self.ids_to_labels(node) - elif self.docutils_footnotes: - self.fallbacks['footnotes'] = PreambleCmds.footnotes - num,text = node.astext().split(None,1) - if self.settings.footnote_references == 'brackets': - num = '[%s]' % num - self.out.append('%%\n\\DUfootnotetext{%s}{%s}{%s}{' % - (node['ids'][0], backref, self.encode(num))) - if node['ids'] == node['names']: - self.out += self.ids_to_labels(node) - # mask newline to prevent spurious whitespace: - self.out.append('%') - ## else: # TODO: "real" LaTeX \footnote{}s - - def depart_footnote(self, node): - if self.figure_footnotes: - self.out.append('\\end{figure}\n') - else: - self.out.append('}\n') - - def visit_footnote_reference(self, node): - href = '' - if 'refid' in node: - href = node['refid'] - elif 'refname' in node: - href = self.document.nameids[node['refname']] - # if not self.docutils_footnotes: - # TODO: insert footnote content at (or near) this place - # print "footnote-ref to", node['refid'] - # footnotes = (self.document.footnotes + - # self.document.autofootnotes + - # self.document.symbol_footnotes) - # for footnote in footnotes: - # # print footnote['ids'] - # if node.get('refid', '') in footnote['ids']: - # print 'matches', footnote['ids'] - format = self.settings.footnote_references - if format == 'brackets': - self.append_hypertargets(node) - self.out.append('\\hyperlink{%s}{[' % href) - self.context.append(']}') - else: - self.fallbacks['footnotes'] = PreambleCmds.footnotes - self.out.append(r'\DUfootnotemark{%s}{%s}{' % - (node['ids'][0], href)) - self.context.append('}') - - def depart_footnote_reference(self, node): - self.out.append(self.context.pop()) - - # footnote/citation label - def label_delim(self, node, bracket, superscript): - if isinstance(node.parent, nodes.footnote): - if not self.figure_footnotes: - raise nodes.SkipNode - if self.settings.footnote_references == 'brackets': - self.out.append(bracket) - else: - self.out.append(superscript) - else: - assert isinstance(node.parent, nodes.citation) - if not self._use_latex_citations: - self.out.append(bracket) - - def visit_label(self, node): - """footnote or citation label: in brackets or as superscript""" - self.label_delim(node, '[', '\\textsuperscript{') - - def depart_label(self, node): - self.label_delim(node, ']', '}') - - # elements generated by the framework e.g. section numbers. - def visit_generated(self, node): - pass - - def depart_generated(self, node): - pass - - def visit_header(self, node): - self.push_output_collector([]) - self.out.append(r'\newcommand{\DUheader}{') - - def depart_header(self, node): - self.out.append('}') - self.requirements['~header'] = ''.join(self.out) - self.pop_output_collector() - - def to_latex_length(self, length_str, pxunit=None): - """Convert `length_str` with rst lenght to LaTeX length - """ - if pxunit is not None: - sys.stderr.write('deprecation warning: LaTeXTranslator.to_latex_length()' - ' option `pxunit` will be removed.') - match = re.match('(\d*\.?\d*)\s*(\S*)', length_str) - if not match: - return length_str - value, unit = match.groups()[:2] - # no unit or "DTP" points (called 'bp' in TeX): - if unit in ('', 'pt'): - length_str = '%sbp' % value - # percentage: relate to current line width - elif unit == '%': - length_str = '%.3f\\linewidth' % (float(value)/100.0) - elif self.is_xetex and unit == 'px': - # XeTeX does not know the length unit px. - # Use \pdfpxdimen, the macro to set the value of 1 px in pdftex. - # This way, configuring works the same for pdftex and xetex. - self.fallbacks['_providelength'] = PreambleCmds.providelength - self.fallbacks['px'] = '\n\\DUprovidelength{\\pdfpxdimen}{1bp}\n' - length_str = r'%s\pdfpxdimen' % value - return length_str - - def visit_image(self, node): - self.requirements['graphicx'] = self.graphicx_package - attrs = node.attributes - # Convert image URI to a local file path - imagepath = urllib.url2pathname(attrs['uri']).replace('\\', '/') - # alignment defaults: - if not 'align' in attrs: - # Set default align of image in a figure to 'center' - if isinstance(node.parent, nodes.figure): - attrs['align'] = 'center' - # query 'align-*' class argument - for cls in node['classes']: - if cls.startswith('align-'): - attrs['align'] = cls.split('-')[1] - # pre- and postfix (prefix inserted in reverse order) - pre = [] - post = [] - include_graphics_options = [] - display_style = ('block-', 'inline-')[self.is_inline(node)] - align_codes = { - # inline images: by default latex aligns the bottom. - 'bottom': ('', ''), - 'middle': (r'\raisebox{-0.5\height}{', '}'), - 'top': (r'\raisebox{-\height}{', '}'), - # block level images: - 'center': (r'\noindent\makebox[\textwidth][c]{', '}'), - 'left': (r'\noindent{', r'\hfill}'), - 'right': (r'\noindent{\hfill', '}'),} - if 'align' in attrs: - try: - align_code = align_codes[attrs['align']] - pre.append(align_code[0]) - post.append(align_code[1]) - except KeyError: - pass # TODO: warn? - if 'height' in attrs: - include_graphics_options.append('height=%s' % - self.to_latex_length(attrs['height'])) - if 'scale' in attrs: - include_graphics_options.append('scale=%f' % - (attrs['scale'] / 100.0)) - if 'width' in attrs: - include_graphics_options.append('width=%s' % - self.to_latex_length(attrs['width'])) - if not self.is_inline(node): - pre.append('\n') - post.append('\n') - pre.reverse() - self.out.extend(pre) - options = '' - if include_graphics_options: - options = '[%s]' % (','.join(include_graphics_options)) - self.out.append('\\includegraphics%s{%s}' % (options, imagepath)) - self.out.extend(post) - - def depart_image(self, node): - if node.get('ids'): - self.out += self.ids_to_labels(node) + ['\n'] - - def visit_inline(self, node): # , i.e. custom roles - # Make a copy to keep ``node['classes']`` True if a - # language argument is popped (used in conditional calls of - # depart_inline()): - classes = node['classes'][:] - self.context.append('}' * len(classes)) - # handle language specification: - language_tags = [cls for cls in classes - if cls.startswith('language-')] - if language_tags: - language = self.babel.language_name(language_tags[0][9:]) - if language: - self.babel.otherlanguages[language] = True - self.out.append(r'\otherlanguage{%s}{' % language) - classes.pop(classes.index(language_tags[0])) - if not classes: - return - # mark up for styling with custom macros - if 'align-center' in classes: - self.fallbacks['align-center'] = PreambleCmds.align_center - self.fallbacks['inline'] = PreambleCmds.inline - self.out += [r'\DUrole{%s}{' % cls for cls in classes] - - def depart_inline(self, node): - self.out.append(self.context.pop()) - - def visit_interpreted(self, node): - # @@@ Incomplete, pending a proper implementation on the - # Parser/Reader end. - self.visit_literal(node) - - def depart_interpreted(self, node): - self.depart_literal(node) - - def visit_legend(self, node): - self.fallbacks['legend'] = PreambleCmds.legend - self.out.append('\\begin{DUlegend}') - - def depart_legend(self, node): - self.out.append('\\end{DUlegend}\n') - - def visit_line(self, node): - self.out.append('\item[] ') - - def depart_line(self, node): - self.out.append('\n') - - def visit_line_block(self, node): - self.fallbacks['_providelength'] = PreambleCmds.providelength - self.fallbacks['lineblock'] = PreambleCmds.lineblock - if isinstance(node.parent, nodes.line_block): - self.out.append('\\item[]\n' - '\\begin{DUlineblock}{\\DUlineblockindent}\n') - else: - self.out.append('\n\\begin{DUlineblock}{0em}\n') - if node['classes']: - self.visit_inline(node) - self.out.append('\n') - - def depart_line_block(self, node): - if node['classes']: - self.depart_inline(node) - self.out.append('\n') - self.out.append('\\end{DUlineblock}\n') - - def visit_list_item(self, node): - self.out.append('\n\\item ') - - def depart_list_item(self, node): - pass - - def visit_literal(self, node): - self.literal = True - self.out.append('\\texttt{') - if node['classes']: - self.visit_inline(node) - - def depart_literal(self, node): - self.literal = False - if node['classes']: - self.depart_inline(node) - self.out.append('}') - - # 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. - # - # 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 or \alltt. - # - # We can distinguish between the two kinds by the number of - # siblings that compose this node: if it is composed by a - # single element, it's either - # * a real one, - # * a parsed-literal that does not contain any markup, or - # * a parsed-literal containing just one markup construct. - def is_plaintext(self, node): - """Check whether a node can be typeset verbatim""" - return (len(node) == 1) and isinstance(node[0], nodes.Text) - - def visit_literal_block(self, node): - """Render a literal block.""" - # environments and packages to typeset literal blocks - packages = {'listing': r'\usepackage{moreverb}', - 'lstlisting': r'\usepackage{listings}', - 'Verbatim': r'\usepackage{fancyvrb}', - # 'verbatim': '', - 'verbatimtab': r'\usepackage{moreverb}'} - - if not self.active_table.is_open(): - # no quote inside tables, to avoid vertical space between - # table border and literal block. - # BUG: fails if normal text preceeds the literal block. - self.out.append('%\n\\begin{quote}') - self.context.append('\n\\end{quote}\n') - else: - self.out.append('\n') - self.context.append('\n') - if self.literal_block_env != '' and self.is_plaintext(node): - self.requirements['literal_block'] = packages.get( - self.literal_block_env, '') - self.verbatim = True - self.out.append('\\begin{%s}%s\n' % (self.literal_block_env, - self.literal_block_options)) - else: - self.literal = True - self.insert_newline = True - self.insert_non_breaking_blanks = True - self.out.append('{\\ttfamily \\raggedright \\noindent\n') - - def depart_literal_block(self, node): - if self.verbatim: - self.out.append('\n\\end{%s}\n' % self.literal_block_env) - self.verbatim = False - else: - self.out.append('\n}') - self.insert_non_breaking_blanks = False - self.insert_newline = False - self.literal = False - self.out.append(self.context.pop()) - - ## def visit_meta(self, node): - ## self.out.append('[visit_meta]\n') - # TODO: set keywords for pdf? - # But: - # The reStructuredText "meta" directive creates a "pending" node, - # which contains knowledge that the embedded "meta" node can only - # be handled by HTML-compatible writers. The "pending" node is - # resolved by the docutils.transforms.components.Filter transform, - # which checks that the calling writer supports HTML; if it doesn't, - # the "pending" node (and enclosed "meta" node) is removed from the - # document. - # --- docutils/docs/peps/pep-0258.html#transformer - - ## def depart_meta(self, node): - ## self.out.append('[depart_meta]\n') - - def visit_math(self, node, math_env='$'): - """math role""" - if node['classes']: - self.visit_inline(node) - self.requirements['amsmath'] = r'\usepackage{amsmath}' - math_code = node.astext().translate(unichar2tex.uni2tex_table) - if node.get('ids'): - math_code = '\n'.join([math_code] + self.ids_to_labels(node)) - if math_env == '$': - wrapper = u'$%s$' - else: - wrapper = u'\n'.join(['%%', - r'\begin{%s}' % math_env, - '%s', - r'\end{%s}' % math_env]) - # print repr(wrapper), repr(math_code) - self.out.append(wrapper % math_code) - if node['classes']: - self.depart_inline(node) - # Content already processed: - raise nodes.SkipNode - - def depart_math(self, node): - pass # never reached - - def visit_math_block(self, node): - math_env = pick_math_environment(node.astext()) - self.visit_math(node, math_env=math_env) - - def depart_math_block(self, node): - pass # never reached - - def visit_option(self, node): - if self.context[-1]: - # this is not the first option - self.out.append(', ') - - def depart_option(self, node): - # flag that the first option is done. - self.context[-1] += 1 - - def visit_option_argument(self, node): - """Append the delimiter betweeen an option and its argument to body.""" - self.out.append(node.get('delimiter', ' ')) - - def depart_option_argument(self, node): - pass - - def visit_option_group(self, node): - self.out.append('\n\\item[') - # flag for first option - self.context.append(0) - - def depart_option_group(self, node): - self.context.pop() # the flag - self.out.append('] ') - - def visit_option_list(self, node): - self.fallbacks['_providelength'] = PreambleCmds.providelength - self.fallbacks['optionlist'] = PreambleCmds.optionlist - self.out.append('%\n\\begin{DUoptionlist}\n') - - def depart_option_list(self, node): - self.out.append('\n\\end{DUoptionlist}\n') - - def visit_option_list_item(self, node): - pass - - def depart_option_list_item(self, node): - pass - - def visit_option_string(self, node): - ##self.out.append(self.starttag(node, 'span', '', CLASS='option')) - pass - - def depart_option_string(self, node): - ##self.out.append('') - pass - - def visit_organization(self, node): - self.visit_docinfo_item(node, 'organization') - - def depart_organization(self, node): - self.depart_docinfo_item(node) - - def visit_paragraph(self, node): - # insert blank line, if the paragraph is not first in a list item - # nor follows a non-paragraph node in a compound - index = node.parent.index(node) - if (index == 0 and (isinstance(node.parent, nodes.list_item) or - isinstance(node.parent, nodes.description))): - pass - elif (index > 0 and isinstance(node.parent, nodes.compound) and - not isinstance(node.parent[index - 1], nodes.paragraph) and - not isinstance(node.parent[index - 1], nodes.compound)): - pass - else: - self.out.append('\n') - if node.get('ids'): - self.out += self.ids_to_labels(node) + ['\n'] - if node['classes']: - self.visit_inline(node) - - def depart_paragraph(self, node): - if node['classes']: - self.depart_inline(node) - self.out.append('\n') - - def visit_problematic(self, node): - self.requirements['color'] = PreambleCmds.color - self.out.append('%\n') - self.append_hypertargets(node) - self.out.append(r'\hyperlink{%s}{\textbf{\color{red}' % node['refid']) - - def depart_problematic(self, node): - self.out.append('}}') - - def visit_raw(self, node): - if not 'latex' in node.get('format', '').split(): - raise nodes.SkipNode - if not self.is_inline(node): - self.out.append('\n') - if node['classes']: - self.visit_inline(node) - # append "as-is" skipping any LaTeX-encoding - self.verbatim = True - - def depart_raw(self, node): - self.verbatim = False - if node['classes']: - self.depart_inline(node) - if not self.is_inline(node): - self.out.append('\n') - - def has_unbalanced_braces(self, string): - """Test whether there are unmatched '{' or '}' characters.""" - level = 0 - for ch in string: - if ch == '{': - level += 1 - if ch == '}': - level -= 1 - if level < 0: - return True - return level != 0 - - def visit_reference(self, node): - # We need to escape #, \, and % if we use the URL in a command. - special_chars = {ord('#'): ur'\#', - ord('%'): ur'\%', - ord('\\'): ur'\\', - } - # external reference (URL) - if 'refuri' in node: - href = unicode(node['refuri']).translate(special_chars) - # problematic chars double caret and unbalanced braces: - if href.find('^^') != -1 or self.has_unbalanced_braces(href): - self.error( - 'External link "%s" not supported by LaTeX.\n' - ' (Must not contain "^^" or unbalanced braces.)' % href) - if node['refuri'] == node.astext(): - self.out.append(r'\url{%s}' % href) - raise nodes.SkipNode - self.out.append(r'\href{%s}{' % href) - return - # internal reference - if 'refid' in node: - href = node['refid'] - elif 'refname' in node: - href = self.document.nameids[node['refname']] - else: - raise AssertionError('Unknown reference.') - if not self.is_inline(node): - self.out.append('\n') - self.out.append('\\hyperref[%s]{' % href) - if self._reference_label: - self.out.append('\\%s{%s}}' % - (self._reference_label, href.replace('#', ''))) - raise nodes.SkipNode - - def depart_reference(self, node): - self.out.append('}') - if not self.is_inline(node): - self.out.append('\n') - - def visit_revision(self, node): - self.visit_docinfo_item(node, 'revision') - - def depart_revision(self, node): - self.depart_docinfo_item(node) - - 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): - self.requirements['color'] = PreambleCmds.color - self.fallbacks['sidebar'] = PreambleCmds.sidebar - self.out.append('\n\\DUsidebar{\n') - - def depart_sidebar(self, node): - self.out.append('}\n') - - attribution_formats = {'dash': (u'—', ''), # EM DASH - 'parentheses': ('(', ')'), - 'parens': ('(', ')'), - 'none': ('', '')} - - def visit_attribution(self, node): - prefix, suffix = self.attribution_formats[self.settings.attribution] - self.out.append('\\nopagebreak\n\n\\raggedleft ') - self.out.append(prefix) - self.context.append(suffix) - - def depart_attribution(self, node): - self.out.append(self.context.pop() + '\n') - - def visit_status(self, node): - self.visit_docinfo_item(node, 'status') - - def depart_status(self, node): - self.depart_docinfo_item(node) - - def visit_strong(self, node): - self.out.append('\\textbf{') - if node['classes']: - self.visit_inline(node) - - def depart_strong(self, node): - if node['classes']: - self.depart_inline(node) - self.out.append('}') - - def visit_substitution_definition(self, node): - raise nodes.SkipNode - - def visit_substitution_reference(self, node): - self.unimplemented_visit(node) - - def visit_subtitle(self, node): - if isinstance(node.parent, nodes.document): - self.push_output_collector(self.subtitle) - self.subtitle_labels += self.ids_to_labels(node, set_anchor=False) - # section subtitle: "starred" (no number, not in ToC) - elif isinstance(node.parent, nodes.section): - self.out.append(r'\%s*{' % - self.d_class.section(self.section_level + 1)) - else: - self.fallbacks['subtitle'] = PreambleCmds.subtitle - self.out.append('\n\\DUsubtitle[%s]{' % node.parent.tagname) - - def depart_subtitle(self, node): - if isinstance(node.parent, nodes.document): - self.pop_output_collector() - else: - self.out.append('}\n') - - def visit_system_message(self, node): - self.requirements['color'] = PreambleCmds.color - self.fallbacks['title'] = PreambleCmds.title - node['classes'] = ['system-message'] - self.visit_admonition(node) - self.out.append('\\DUtitle[system-message]{system-message}\n') - self.append_hypertargets(node) - try: - line = ', line~%s' % node['line'] - except KeyError: - line = '' - self.out.append('\n\n{\color{red}%s/%s} in \\texttt{%s}%s\n' % - (node['type'], node['level'], - self.encode(node['source']), line)) - if len(node['backrefs']) == 1: - self.out.append('\n\\hyperlink{%s}{' % node['backrefs'][0]) - self.context.append('}') - else: - backrefs = ['\\hyperlink{%s}{%d}' % (href, i+1) - for (i, href) in enumerate(node['backrefs'])] - self.context.append('backrefs: ' + ' '.join(backrefs)) - - def depart_system_message(self, node): - self.out.append(self.context.pop()) - self.depart_admonition() - - def visit_table(self, node): - self.requirements['table'] = PreambleCmds.table - if self.active_table.is_open(): - self.table_stack.append(self.active_table) - # nesting longtable does not work (e.g. 2007-04-18) - self.active_table = Table(self,'tabular',self.settings.table_style) - # A longtable moves before \paragraph and \subparagraph - # section titles if it immediately follows them: - if (self.active_table._latex_type == 'longtable' and - isinstance(node.parent, nodes.section) and - node.parent.index(node) == 1 and - self.d_class.section(self.section_level).find('paragraph') != -1): - self.out.append('\\leavevmode') - self.active_table.open() - for cls in node['classes']: - self.active_table.set_table_style(cls) - if self.active_table._table_style == 'booktabs': - self.requirements['booktabs'] = r'\usepackage{booktabs}' - self.push_output_collector([]) - - def depart_table(self, node): - # wrap content in the right environment: - content = self.out - self.pop_output_collector() - self.out.append('\n' + self.active_table.get_opening()) - self.out += content - self.out.append(self.active_table.get_closing() + '\n') - self.active_table.close() - if len(self.table_stack)>0: - self.active_table = self.table_stack.pop() - else: - self.active_table.set_table_style(self.settings.table_style) - # Insert hyperlabel after (long)table, as - # other places (beginning, caption) result in LaTeX errors. - if node.get('ids'): - self.out += self.ids_to_labels(node, set_anchor=False) + ['\n'] - - def visit_target(self, node): - # Skip indirect targets: - if ('refuri' in node # external hyperlink - or 'refid' in node # resolved internal link - or 'refname' in node): # unresolved internal link - ## self.out.append('%% %s\n' % node) # for debugging - return - self.out.append('%\n') - # do we need an anchor (\phantomsection)? - set_anchor = not(isinstance(node.parent, nodes.caption) or - isinstance(node.parent, nodes.title)) - # TODO: where else can/must we omit the \phantomsection? - self.out += self.ids_to_labels(node, set_anchor) - - def depart_target(self, node): - pass - - def visit_tbody(self, node): - # BUG write preamble if not yet done (colspecs not []) - # for tables without heads. - if not self.active_table.get('preamble written'): - self.visit_thead(None) - self.depart_thead(None) - - def depart_tbody(self, node): - pass - - def visit_term(self, node): - """definition list term""" - # Commands with optional args inside an optional arg must be put - # in a group, e.g. ``\item[{\hyperref[label]{text}}]``. - self.out.append('\\item[{') - - def depart_term(self, node): - # \leavevmode results in a line break if the - # term is followed by an item list. - self.out.append('}] \leavevmode ') - - def visit_tgroup(self, node): - #self.out.append(self.starttag(node, 'colgroup')) - #self.context.append('\n') - pass - - def depart_tgroup(self, node): - pass - - _thead_depth = 0 - def thead_depth (self): - return self._thead_depth - - def visit_thead(self, node): - self._thead_depth += 1 - if 1 == self.thead_depth(): - self.out.append('{%s}\n' % self.active_table.get_colspecs()) - self.active_table.set('preamble written',1) - self.out.append(self.active_table.get_caption()) - self.out.extend(self.active_table.visit_thead()) - - def depart_thead(self, node): - if node is not None: - self.out.extend(self.active_table.depart_thead()) - if self.active_table.need_recurse(): - node.walkabout(self) - self._thead_depth -= 1 - - def visit_title(self, node): - """Append section and other titles.""" - # Document title - if node.parent.tagname == 'document': - self.push_output_collector(self.title) - self.context.append('') - self.pdfinfo.append(' pdftitle={%s},' % - self.encode(node.astext())) - # Topic titles (topic, admonition, sidebar) - elif (isinstance(node.parent, nodes.topic) or - isinstance(node.parent, nodes.admonition) or - isinstance(node.parent, nodes.sidebar)): - self.fallbacks['title'] = PreambleCmds.title - classes = ','.join(node.parent['classes']) - if not classes: - classes = node.tagname - self.out.append('\\DUtitle[%s]{' % classes) - self.context.append('}\n') - # Table caption - elif isinstance(node.parent, nodes.table): - self.push_output_collector(self.active_table.caption) - self.context.append('') - # Section title - else: - self.requirements['secnumdepth'] = PreambleCmds.secnumdepth - section_name = self.d_class.section(self.section_level) - self.out.append('\n\n') - # System messages heading in red: - if ('system-messages' in node.parent['classes']): - self.requirements['color'] = PreambleCmds.color - section_title = self.encode(node.astext()) - self.out.append(r'\%s[%s]{\color{red}' % ( - section_name,section_title)) - else: - self.out.append(r'\%s{' % section_name) - if self.section_level > len(self.d_class.sections): - # section level not supported by LaTeX - self.fallbacks['title'] = PreambleCmds.title - # self.out.append('\\phantomsection%\n ') - # label and ToC entry: - bookmark = [''] - # add sections with unsupported level to toc and pdfbookmarks? - ## if self.section_level > len(self.d_class.sections): - ## section_title = self.encode(node.astext()) - ## bookmark.append(r'\addcontentsline{toc}{%s}{%s}' % - ## (section_name, section_title)) - bookmark += self.ids_to_labels(node.parent, set_anchor=False) - self.context.append('%\n '.join(bookmark) + '%\n}\n') - - # MAYBE postfix paragraph and subparagraph with \leavemode to - # ensure floats stay in the section and text starts on a new line. - - def depart_title(self, node): - self.out.append(self.context.pop()) - if (isinstance(node.parent, nodes.table) or - node.parent.tagname == 'document'): - self.pop_output_collector() - - def minitoc(self, node, title, depth): - """Generate a local table of contents with LaTeX package minitoc""" - section_name = self.d_class.section(self.section_level) - # name-prefix for current section level - minitoc_names = {'part': 'part', 'chapter': 'mini'} - if 'chapter' not in self.d_class.sections: - minitoc_names['section'] = 'sect' - try: - minitoc_name = minitoc_names[section_name] - except KeyError: # minitoc only supports part- and toplevel - self.warn('Skipping local ToC at %s level.\n' % section_name + - ' Feature not supported with option "use-latex-toc"', - base_node=node) - return - # Requirements/Setup - self.requirements['minitoc'] = PreambleCmds.minitoc - self.requirements['minitoc-'+minitoc_name] = (r'\do%stoc' % - minitoc_name) - # depth: (Docutils defaults to unlimited depth) - maxdepth = len(self.d_class.sections) - self.requirements['minitoc-%s-depth' % minitoc_name] = ( - r'\mtcsetdepth{%stoc}{%d}' % (minitoc_name, maxdepth)) - # Process 'depth' argument (!Docutils stores a relative depth while - # minitoc expects an absolute depth!): - offset = {'sect': 1, 'mini': 0, 'part': 0} - if 'chapter' in self.d_class.sections: - offset['part'] = -1 - if depth: - self.out.append('\\setcounter{%stocdepth}{%d}' % - (minitoc_name, depth + offset[minitoc_name])) - # title: - self.out.append('\\mtcsettitle{%stoc}{%s}\n' % (minitoc_name, title)) - # the toc-generating command: - self.out.append('\\%stoc\n' % minitoc_name) - - def visit_topic(self, node): - # Topic nodes can be generic topic, abstract, dedication, or ToC. - # table of contents: - if 'contents' in node['classes']: - self.out.append('\n') - self.out += self.ids_to_labels(node) - # add contents to PDF bookmarks sidebar - if isinstance(node.next_node(), nodes.title): - self.out.append('\n\\pdfbookmark[%d]{%s}{%s}\n' % - (self.section_level+1, - node.next_node().astext(), - node.get('ids', ['contents'])[0] - )) - if self.use_latex_toc: - title = '' - if isinstance(node.next_node(), nodes.title): - title = self.encode(node.pop(0).astext()) - depth = node.get('depth', 0) - if 'local' in node['classes']: - self.minitoc(node, title, depth) - self.context.append('') - return - if depth: - self.out.append('\\setcounter{tocdepth}{%d}\n' % depth) - if title != 'Contents': - self.out.append('\\renewcommand{\\contentsname}{%s}\n' % - title) - self.out.append('\\tableofcontents\n\n') - self.has_latex_toc = True - else: # Docutils generated contents list - # set flag for visit_bullet_list() and visit_title() - self.is_toc_list = True - self.context.append('') - elif ('abstract' in node['classes'] and - self.settings.use_latex_abstract): - self.push_output_collector(self.abstract) - self.out.append('\\begin{abstract}') - self.context.append('\\end{abstract}\n') - if isinstance(node.next_node(), nodes.title): - node.pop(0) # LaTeX provides its own title - else: - self.fallbacks['topic'] = PreambleCmds.topic - # special topics: - if 'abstract' in node['classes']: - self.fallbacks['abstract'] = PreambleCmds.abstract - self.push_output_collector(self.abstract) - if 'dedication' in node['classes']: - self.fallbacks['dedication'] = PreambleCmds.dedication - self.push_output_collector(self.dedication) - self.out.append('\n\\DUtopic[%s]{\n' % ','.join(node['classes'])) - self.context.append('}\n') - - def depart_topic(self, node): - self.out.append(self.context.pop()) - self.is_toc_list = False - if ('abstract' in node['classes'] or - 'dedication' in node['classes']): - self.pop_output_collector() - - def visit_rubric(self, node): - self.fallbacks['rubric'] = PreambleCmds.rubric - self.out.append('\n\\DUrubric{') - self.context.append('}\n') - - def depart_rubric(self, node): - self.out.append(self.context.pop()) - - def visit_transition(self, node): - self.fallbacks['transition'] = PreambleCmds.transition - self.out.append('\n\n') - self.out.append('%' + '_' * 75 + '\n') - self.out.append(r'\DUtransition') - self.out.append('\n\n') - - def depart_transition(self, node): - pass - - def visit_version(self, node): - self.visit_docinfo_item(node, 'version') - - def depart_version(self, node): - self.depart_docinfo_item(node) - - def unimplemented_visit(self, node): - raise NotImplementedError('visiting unimplemented node type: %s' % - node.__class__.__name__) - -# def unknown_visit(self, node): -# def default_visit(self, node): - -# vim: set ts=4 et ai : diff --git a/docutils/writers/latex2e/default.tex b/docutils/writers/latex2e/default.tex deleted file mode 100644 index 69e99fd7b..000000000 --- a/docutils/writers/latex2e/default.tex +++ /dev/null @@ -1,15 +0,0 @@ -$head_prefix% generated by Docutils -\usepackage{fixltx2e} % LaTeX patches, \textsubscript -\usepackage{cmap} % fix search and cut-and-paste in Acrobat -$requirements -%%% Custom LaTeX preamble -$latex_preamble -%%% User specified packages and stylesheets -$stylesheet -%%% Fallback definitions for Docutils-specific commands -$fallbacks$pdfsetup -$titledata -%%% Body -\begin{document} -$body_pre_docinfo$docinfo$dedication$abstract$body -\end{document} diff --git a/docutils/writers/latex2e/docutils-05-compat.sty b/docutils/writers/latex2e/docutils-05-compat.sty deleted file mode 100644 index cc6b6a8aa..000000000 --- a/docutils/writers/latex2e/docutils-05-compat.sty +++ /dev/null @@ -1,738 +0,0 @@ -% ================================================================== -% Changes to the Docutils latex2e writer since version 0.5 -% ================================================================== -% -% A backwards compatibility style sheet -% ************************************* -% -% :Author: Guenter Milde -% :Contact: milde@users.sourceforge.net -% :Revision: $Revision: 6156 $ -% :Date: $Date: 2009-02-24 $ -% :Copyright: © 2009 Günter Milde, -% :License: Released under the terms of the `2-Clause BSD license`_, in short: -% -% Copying and distribution of this file, with or without modification, -% are permitted in any medium without royalty provided the copyright -% notice and this notice are preserved. -% This file is offered as-is, without any warranty. -% -% :Abstract: This file documents changes and provides a style for best -% possible compatibility to the behaviour of the `latex2e` -% writer of Doctutils release 0.5. -% -% .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause -% -% :: - -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{docutils-05-compat} -[2009/03/26 v0.1 compatibility with rst2latex from Docutils 0.5] - -% .. contents:: -% :depth: 3 -% -% Usage -% ===== -% -% * To get an (almost) identic look for your old documents, -% place ``docutils-05-compat.sty`` in the TEXINPUT path (e.g. -% the current work directory) and pass the -% ``--stylesheet=docutils-05-compat`` option to ``rst2latex.py``. -% -% * To use your custom stylesheets without change, add them to the -% compatibility style, e.g. -% ``--stylesheet="docutils-05-compat,mystyle.tex``. -% -% .. tip:: As the changes include bug fixes that are partly reverted by this -% style, it is recommended to adapt the stylesheets to the new version or -% copy just the relevant parts of this style into them. -% -% Changes since 0.5 -% ================= -% -% Bugfixes -% -------- -% -% * Newlines around comments, targets and references prevent run-together -% paragraphs. -% -% + An image directive with hyperlink reference or target did not start a -% new paragraph (e.g. the first two image examples in -% standalone_rst_latex.tex). -% -% + Paragraphs were not separated if there was a (hyper) target definition -% inbetween. -% -% + Paragraphs did run together, if separated by a comment-paragraph in the -% rst source. -% -% * Fixed missing and spurious internal links/targets. -% Internal links now take you to the correct place. -% -% * Verbose and linked system messages. -% -% * `Figure and image alignment`_ now conforms to the rst definition. -% -% * Put `header and footer directive`__ content in \DUheader respective -% \DUfooter macros (ignored by the default style/template). -% -% (They were put inside hard-coded markup at the top/bottom of the document -% without an option to get them on every page.) -% -% __ ../ref/rst/directives.html#document-header-footer -% -% * Render doctest blocks as literal blocks (fixes bug [1586058] doctest block -% nested in admonition). I.e. -% -% + indent doctest blocks by nesting in a quote environment. This is also -% the rendering by the HTML writer (html4css2.css). -% + apply the ``--literal-block-env`` setting also to doctest blocks. -% -% .. warning:: -% (``--literal-block-env=verbatim`` and -% ``--literal-block-env=lstlistings`` fail with literal or doctest -% blocks nested in an admonition. -% -% * Two-way hyperlinked footnotes and support for symbol footnotes and -% ``--footnote-references=brackets`` with ``--use-latex-footnotes``. -% -% * The packages `fixltx2e` (providing LaTeX patches and the \textsubscript -% command) and `cmap` (including character maps in the generated PDF for -% better search and copy-and-paste operations) are now always loaded -% (configurable with custom templates_). -% -% Backwards compatibility: -% "Bug for bug compatibility" is not provided. -% -% -% New configuration setting defaults -% ---------------------------------- -% -% - font-encoding: "T1" (formerly implicitely set by 'ae'). -% - use-latex-toc: true (ToC with page numbers). -% - use-latex-footnotes: true (no mixup with figures). -% -% Backwards compatibility: -% Reset to the former defaults with: -% -% | font-encoding: '' -% | use-latex-toc: False -% | use-latex-footnotes: False -% -% (in the config file) or the command line options: -% -% ``--figure-footnotes --use-docutils-toc --font-encoding=''`` -% -% -% Cleaner LaTeX source -% -------------------- -% -% New features: -% * Remove redundant "double protection" from the encoding of the "special -% printing characters" and square brackets, e.g. ``\%`` instead of -% ``{\%}``. -% * Remove some spurious whitespace, e.g. ``\item [what:] -> \item[what:]``. -% * Use conventional style for "named" macros, e.g. ``\dots{}`` instead of -% ``{\dots}`` -% -% Backwards compatibility: -% Changes do not affect the output. -% -% -% LaTeX style sheets -% ------------------ -% -% New Feature: -% LaTeX packages can be used as ``--stylesheet`` argument without -% restriction. -% -% Implementation: -% Use ``\usepackage`` if style sheet ends with ``.sty`` or has no -% extension and ``\input`` else. -% -% Rationale: -% while ``\input`` works with extension as well as without extension, -% ``\usepackage`` expects the package name without extension. (The latex2e -% writer will strip a ``.sty`` extension.) -% -% -% Backwards compatibility: -% Up to Docutils 0.5, if no filename extension is given in the -% ``stylesheet`` argument, ``.tex`` is assumed (by latex). -% -% Since Docutils 0.6, a stylesheet without filename extension is assumed to -% be a LaTeX package (``*.sty``) and referenced with the ``\usepackage`` -% command. -% -% .. important:: -% Always specify the extension if you want the style sheet to be -% ``\input`` by LaTeX. -% -% -% Templates -% --------- -% -% New Feature: -% Advanced configuration via custom templates. -% -% Implementation: -% A ``--template`` option and config setting allows specification of a -% template file. -% -% See the `LaTeX writer documentation`__ for details. -% -% __ latex.html#templates -% -% -% Custom roles -% ------------ -% -% New Feature: failsave implementation -% As with classes to HTML objects, class arguments are silently ignored if -% there is no styling rule for this class in a custom style sheet. -% -% New Feature: custom roles based on standard roles -% As class support needs to be handled by the LaTeX writer, this feature was -% not present "automatically" (as in HTML). Modified visit/depart_*() -% methods for the standard roles now call visit/depart_inline() if there are -% class arguments to the node. -% -% Backwards compatibility: -% The implementation is fully backwards compatible. (SVN versions 5742 to -% 5861 contained an implementation that did not work with commands expecting -% an argument.) -% -% Length units -% ------------ -% -% New Features: -% 1. Add default unit if none given. -% A poll on docutils-users favoured ``bp`` (Big Point: 1 bp = 1/72 in). -% -% 2. Do not change ``px`` to ``pt``. -% -% 3. Lengths specified in the document with unit "pt" will be written with -% unit "bp" to the LaTeX source. -% -% Rationale: -% 1. prevent LaTeX error "missing unit". -% -% 2. ``px`` is a valid unit in pdftex since version 1.3.0 released on -% 2005-02-04: -% -% 1px defaults to 1bp (or 72dpi), but can be changed with the -% ``\pdfpxdimen`` primitive.:: - - \pdfpxdimen=1in % 1 dpi - \divide\pdfpxdimen by 96 % 96 dpi - -% -- http://www.tug.org/applications/pdftex/NEWS -% -% Modern TeX distributions use pdftex also for dvi generation (i.e. -% ``latex`` actually calls ``pdftex`` with some options). -% -% 3. In Docutils (as well as CSS) the unit symbol "pt" denotes the -% `Postscript point` or `DTP point` while LaTeX uses "pt" for the `LaTeX -% point`, which is unknown to Docutils and 0.3 % smaller. -% -% The `DTP point` is available in LaTeX as "bp" (big point): -% -% 1 pt = 1/72.25 in < 1 bp = 1/72 in -% -% -% Backwards compatibility: -% Images with width specification in ``px`` come out slightly (0.3 %) larger: -% -% 1 px = 1 bp = 1/72 in > 1 pt = 1/72.25 in -% -% This can be reset with :: - - \pdfpxdimen=1pt - -% .. caution:: It is impossible to revert the change of lengths specified with -% "pt" or without unit in a style sheet, however the 0.3 % change will be -% imperceptible in most cases. -% -% .. admonition:: Error ``illegal unit px`` -% -% The unit ``px`` is not defined in "pure" LaTeX, but introduced by the -% `pdfTeX` converter on 2005-02-04. `pdfTeX` is used in all modern LaTeX -% distributions (since ca. 2006) also for conversion into DVI. -% -% If you convert the LaTeX source with a legacy program, you might get the -% error ``illegal unit px``. -% -% If updating LaTeX is not an option, just remove the ``px`` from the length -% specification. HTML/CSS will default to ``px`` while the `latexe2` writer -% will add the fallback unit ``bp``. -% -% -% Font encoding -% ------------- -% -% New feature: -% Do not mix font-encoding and font settings: do not load the obsolete -% `ae` and `aeguill` packages unless explicitely required via the -% ``--stylesheet`` option. -% -% :font-encoding = "": do not load `ae` and `aeguill`, i.e. -% -% * do not change font settings, -% * do not use the fontenc package -% (implicitely loaded via `ae`), -% * use LaTeX default font encoding (OT1) -% -% :font-encoding = "OT1": load `fontenc` with ``\usepackage[OT1]{fontenc}`` -% -% Example: -% ``--font-encoding=LGR,T1`` becomes ``\usepackage[LGR,T1]{fontenc}`` -% (Latin, Latin-1 Supplement, and Greek) -% -% -% Backwards compatibility: -% Load the ae and aeguill packages if fontenc is not used. -% -% .. tip:: Using `ae` is not recommended. A similar look (but better -% implementation) can be achieved with the packages `lmodern`, `cmsuper`, -% or `cmlgr` all providing Computer Modern look-alikes in vector format and -% T1 encoding, e.g. ``--font-encoding=T1 --stylesheet=lmodern``. -% -% Sub- and superscript as text -% ---------------------------- -% -% New feature: -% Set sub- and superscript role argument in text mode not as math. -% -% Pass the role content to ``\textsubscript`` or ``\textsuperscript``. -% -% Backwards compatibility: -% The old implementation set the role content in Math mode, where -% -% * whitespace is ignored, -% * a different command set and font setting scheme is active, -% * Latin letters are typeset italic but numbers upright. -% -% Although it is possible to redefine ``\textsubscript`` and -% ``\textsuperscript`` to typeset the content in math-mode, this can lead to -% errors with certain input and is therefore not done in this style sheet. -% -% .. tip:: To get italic subscripts, define and use in your document -% `custom roles`_ like ``.. role:: sub(subscript)`` and -% ``.. role:: super(superscript)`` and define the "role commands":: - - \newcommand{\DUrolesub}{\itshape} - \newcommand{\DUrolesuper}{\itshape} - -% Alternatively, if you want all sub- and superscripts in italic, redefine -% the macros:: - - %% \let\DUsup\textsubscript - %% \let\DUsuper\textsuperscript - %% \renewcommand*{\textsubscript}{\DUsub\itshape} - %% \renewcommand*{\textsuperscript}{\DUsuper\itshape} - -% This is not fully backwards compatible, as it will also set numbers in -% italic shape and not ignore whitespace. -% -% Page layout -% ----------- -% -% New features: -% * Margins are configurable via the ``DIV=...`` document option. -% -% * The ``\raggedbottom`` setting is no longer inserted into the document. It -% is the default for article and report classes. If requested in combination -% with a book class, it can be given in a custom style sheet. -% -% Backwards compatibility: -% Up to version 0.5, use of `typearea` and a DIV setting of 12 were -% hard-coded into the latex2e writer :: - - \usepackage{typearea} - \typearea{12} - -% and the vertical alignment of lower boundary of the text area in book -% classes disabled via :: - - \raggedbottom - - -% ToC and section numbers -% ----------------------- -% -% Better conformance to Docutils specifications. -% -% New feature: -% * The "depth" argument of the "contents" and "sectnum" directives is -% respected. -% -% * section numbering independent of 'use-latex-toc': -% -% + sections are only numbered if there is a "sectnum" directive in the -% document -% -% + section numbering by LaTeX if the "sectnum_xforms" config setting is -% False. -% -% Backwards compatibility: -% -% The previous behaviour was to always number sections if 'use-latex-toc' is -% true, using the document class defaults. It cannot be restored -% universally, the following code sets the default values of the "article" -% document class:: - - \setcounter{secnumdepth}{3} - \setcounter{tocdepth}{3} - -% .. TODO or not to do? (Back-compatibility problems) -% * The default "depth" of the LaTeX-created ToC and the LaTeX section -% numbering is increased to the number of supported section levels. -% -% New feature: -% If 'use-latex-toc' is set, local tables of content are typeset using the -% 'minitoc' package (instead of being ignored). -% -% Backwards compatibility: -% Disable the creation of local ToCs (ignoring all special commands) by -% replacing ``\usepackage{minitoc} with ``\usepackage{mtcoff}``. -% -% -% Default font in admonitions and sidebar -% --------------------------------------- -% -% New feature: -% Use default font in admonitions and sidebar. -% -% Backward compatibility: -% See the fallback definitions for admonitions_, `topic title`_ and -% `sidebar`_. -% -% -% Figure placement -% ---------------- -% -% New feature: -% Use ``\floatplacement`` from the `float` package instead of -% "hard-coded" optional argument for the global setting. -% -% Default to ``\floatplacement{figure}{H}`` (here definitely). This -% corresponds most closely to the source and HTML placement (principle of -% least surprise). -% -% Backwards compatibility: -% Set the global default back to the previous used value:: - - \usepackage{float} - \floatplacement{figure}{htbp} % here, top, bottom, extra-page - - -% Figure and image alignment -% -------------------------- -% -% New features: -% -% a) Fix behaviour of 'align' argument to a figure (do not align figure -% contents). -% -% As the 'figwidth' argument is still ignored and the "natural width" of a -% figure in LaTeX is 100% \textwidth, setting the 'align' argument of a -% figure has currently no effect on the LaTeX output. -% -% b) Set default align of image in a figure to 'center'. -% -% c) Also center images that are wider than textwidth. -% -% d) Align images with class "align-[right|center|left]" (allows setting the -% alignment of an image in a figure). -% -% Backwards compatibility: -% There is no "automatic" way to reverse these changes via a style sheet. -% -% a) The alignment of the image can be set with the "align-left", -% "align-center" and "align-right" class arguments. -% -% As previously, the caption of a figure is aligned according to the -% document class -- configurable with a style sheet using the "caption" -% package. -% -% b) See a) -% -% c) Set the alignment of "oversized" images to "left" to get back the -% old placement. -% -% Shorter preamble -% ---------------- -% -% New feature: -% The document preamble is pruned to contain only relevant commands and -% settings. -% -% Packages that are no longer required -% ```````````````````````````````````` -% -% The following packages where required in pre-0.5 versions and still loaded -% with version 0.5:: - -\usepackage{shortvrb} -\usepackage{amsmath} - - -% Packages that are conditionally loaded -% `````````````````````````````````````` -% -% Additional to the `typearea` for `page layout`_, the following packages are -% only loaded if actually required by doctree elements: -% -% Tables -% ^^^^^^ -% -% Standard package for tables across several pages:: - -\usepackage{longtable} - -% Extra space between text in tables and the line above them -% ('array' is implicitely loaded by 'tabularx', see below):: - -\usepackage{array} -\setlength{\extrarowheight}{2pt} - -% Table cells spanning multiple rows:: - -\usepackage{multirow} - -% Docinfo -% ^^^^^^^ -% -% One-page tables with auto-width columns:: - -\usepackage{tabularx} - -% Images -% ^^^^^^ -% Include graphic files:: - -\usepackage{graphicx} - -% Problematic, Sidebar -% ^^^^^^^^^^^^^^^^^^^^ -% Set text and/or background colour, coloured boxes with ``\colorbox``:: - -\usepackage{color} - -% Floats for footnotes settings -% ````````````````````````````` -% -% Settings for the use of floats for footnotes are only included if -% -% * the option "use-latex-footnotes" is False, and -% * there is at least one footnote in the document. -% -% :: - -% begin: floats for footnotes tweaking. -\setlength{\floatsep}{0.5em} -\setlength{\textfloatsep}{\fill} -\addtolength{\textfloatsep}{3em} -\renewcommand{\textfraction}{0.5} -\renewcommand{\topfraction}{0.5} -\renewcommand{\bottomfraction}{0.5} -\setcounter{totalnumber}{50} -\setcounter{topnumber}{50} -\setcounter{bottomnumber}{50} -% end floats for footnotes - - -% Special lengths, commands, and environments -% ------------------------------------------- -% -% Removed definitions -% ``````````````````` -% -% admonition width -% ^^^^^^^^^^^^^^^^ -% The ``admonitionwith`` lenght is replaced by the more powerful -% ``\DUadmonition`` command (see admonitions_). -% -% Backwards compatibility: -% The default value (90 % of the textwidth) is unchanged. -% -% To configure the admonition width, you must redefine the ``DUadmonition`` -% command instead of changing the ``admonitionwith`` length value. -% -% -% Renamed definitions (now conditional) -% ````````````````````````````````````` -% -% The names for special doctree elements are now prefixed with ``DU``. -% -% Up to version 0.5, all definitions were included in the preamble (before the -% style sheet) of every document -- even if not used in the body. Since -% version 0.6, fallback definitions are included after the style sheet and -% only if required. -% -% Customization is done by an alternative definition in a style sheet with -% ``\newcommand`` instead of the former ``\renewcommand``. -% -% The following code provides the old definitions and maps them (or their -% custom variants) to the new interface. -% -% docinfo width -% ^^^^^^^^^^^^^ -% :: - -\newlength{\docinfowidth} -\setlength{\docinfowidth}{0.9\textwidth} - -\newlength{\DUdocinfowidth} -\AtBeginDocument{\setlength{\DUdocinfowidth}{\docinfowidth}} - -% line block -% ^^^^^^^^^^ -% :: - -\newlength{\lineblockindentation} -\setlength{\lineblockindentation}{2.5em} -\newenvironment{lineblock}[1] -{\begin{list}{} - {\setlength{\partopsep}{\parskip} - \addtolength{\partopsep}{\baselineskip} - \topsep0pt\itemsep0.15\baselineskip\parsep0pt - \leftmargin#1} - \raggedright} -{\end{list}} - -\newlength{\DUlineblockindent} -\AtBeginDocument{\setlength{\DUlineblockindent}{\lineblockindentation}} -\newenvironment{DUlineblock}[1] - {\begin{lineblock}{#1}} - {\end{lineblock}} - -% local line width -% ^^^^^^^^^^^^^^^^ -% -% The ``\locallinewidth`` length for internal use in tables is replaced -% by ``\DUtablewidth``. It was never intended for customization:: - -\newlength{\locallinewidth} - -% option lists -% ^^^^^^^^^^^^ -% :: - -\newcommand{\optionlistlabel}[1]{\bf #1 \hfill} -\newenvironment{optionlist}[1] -{\begin{list}{} - {\setlength{\labelwidth}{#1} - \setlength{\rightmargin}{1cm} - \setlength{\leftmargin}{\rightmargin} - \addtolength{\leftmargin}{\labelwidth} - \addtolength{\leftmargin}{\labelsep} - \renewcommand{\makelabel}{\optionlistlabel}} -}{\end{list}} - -\newcommand{\DUoptionlistlabel}{\optionlistlabel} -\newenvironment{DUoptionlist} - {\begin{optionlist}{3cm}} - {\end{optionlist}} - -% rubric -% ^^^^^^ -% Now less prominent (not bold, normal size) restore with:: - -\newcommand{\rubric}[1]{\subsection*{~\hfill {\it #1} \hfill ~}} -\newcommand{\DUrubric}[2][class-arg]{\rubric{#2}} - -% title reference role -% ^^^^^^^^^^^^^^^^^^^^ -% :: - -\newcommand{\titlereference}[1]{\textsl{#1}} -\newcommand{\DUroletitlereference}[1]{\titlereference{#1}} - - -% New definitions -% ``````````````` -% -% New Feature: -% Enable customization of some more Docutils elements with special commands -% -% :admonition: ``DUadmonition`` command (replacing ``\admonitionwidth``), -% :field list: ``DUfieldlist`` environment, -% :legend: ``DUlegend`` environment, -% :sidebar: ``\DUsidebar``, ``\DUtitle``, and -% ``DUsubtitle`` commands, -% :topic: ``\DUtopic`` and ``\DUtitle`` commands, -% :transition: ``\DUtransition`` command. -% :footnotes: ``\DUfootnotemark`` and ``\DUfootnotetext`` commands with -% hyperlink support using the Docutils-provided footnote label. -% -% Backwards compatibility: -% In most cases, the default definition corresponds to the previously used -% construct. The following definitions restore the old behaviour in case of -% changes. -% -% admonitions -% ^^^^^^^^^^^ -% Use sans-serif fonts:: - -\newcommand{\DUadmonition}[2][class-arg]{% - \begin{center} - \fbox{\parbox{0.9\textwidth}{\sffamily #2}} - \end{center} -} - -% dedication -% ^^^^^^^^^^ -% Do not center:: - -\newcommand{\DUtopicdedication}[1]{#1} - -% But center the title:: - -\newcommand*{\DUtitlededication}[1]{\centerline{\textbf{#1}}} - -% sidebar -% ^^^^^^^ -% Use sans-serif fonts, a frame, and a darker shade of grey:: - -\providecommand{\DUsidebar}[2][class-arg]{% - \begin{center} - \sffamily - \fbox{\colorbox[gray]{0.80}{\parbox{0.9\textwidth}{#2}}} - \end{center} -} - -% sidebar sub-title -% ^^^^^^^^^^^^^^^^^ -% Bold instead of emphasized:: - -\providecommand*{\DUsubtitlesidebar}[1]{\hspace*{\fill}\\ - \textbf{#1}\smallskip} - -% topic -% ^^^^^ -% No quote but normal text:: - -\newcommand{\DUtopic}[2][class-arg]{% - \ifcsname DUtopic#1\endcsname% - \csname DUtopic#1\endcsname{#2}% - \else - #2 - \fi -} - -% topic title -% ^^^^^^^^^^^ -% Title for "topics" (admonitions, sidebar). -% -% Larger font size:: - -\providecommand*{\DUtitletopic}[1]{\textbf{\large #1}\smallskip} - -% transition -% ^^^^^^^^^^ -% Do not add vertical space after the transition. :: - -\providecommand*{\DUtransition}[1][class-arg]{% - \hspace*{\fill}\hrulefill\hspace*{\fill}} diff --git a/docutils/writers/latex2e/titlepage.tex b/docutils/writers/latex2e/titlepage.tex deleted file mode 100644 index d57deca3d..000000000 --- a/docutils/writers/latex2e/titlepage.tex +++ /dev/null @@ -1,20 +0,0 @@ -% generated by Docutils -$head_prefix -\usepackage{fixltx2e} % LaTeX patches, \textsubscript -\usepackage{cmap} % fix search and cut-and-paste in Acrobat -$requirements -%%% Custom LaTeX preamble -$latex_preamble -%%% User specified packages and stylesheets -$stylesheet -%%% Fallback definitions for Docutils-specific commands -$fallbacks$pdfsetup -$titledata -%%% Body -\begin{document} -\begin{titlepage} -$body_pre_docinfo$docinfo$dedication$abstract -\thispagestyle{empty} -\end{titlepage} -$body -\end{document} diff --git a/docutils/writers/latex2e/xelatex.tex b/docutils/writers/latex2e/xelatex.tex deleted file mode 100644 index 09110278d..000000000 --- a/docutils/writers/latex2e/xelatex.tex +++ /dev/null @@ -1,16 +0,0 @@ -$head_prefix% generated by Docutils -% rubber: set program xelatex -\usepackage[no-sscript]{xltxtra} % loads fixltx2e, metalogo, xunicode, fontspec -\defaultfontfeatures{Scale=MatchLowercase} -$requirements -%%% Custom LaTeX preamble -$latex_preamble -%%% User specified packages and stylesheets -$stylesheet -%%% Fallback definitions for Docutils-specific commands -$fallbacks$pdfsetup -$titledata -%%% Body -\begin{document} -$body_pre_docinfo$docinfo$dedication$abstract$body -\end{document} diff --git a/docutils/writers/manpage.py b/docutils/writers/manpage.py deleted file mode 100644 index 2d4735866..000000000 --- a/docutils/writers/manpage.py +++ /dev/null @@ -1,1135 +0,0 @@ -# -*- coding: utf-8 -*- -# $Id: manpage.py 7321 2012-01-20 06:50:44Z grubert $ -# Author: Engelbert Gruber -# Copyright: This module is put into the public domain. - -""" -Simple man page writer for reStructuredText. - -Man pages (short for "manual pages") contain system documentation on unix-like -systems. The pages are grouped in numbered sections: - - 1 executable programs and shell commands - 2 system calls - 3 library functions - 4 special files - 5 file formats - 6 games - 7 miscellaneous - 8 system administration - -Man pages are written *troff*, a text file formatting system. - -See http://www.tldp.org/HOWTO/Man-Page for a start. - -Man pages have no subsection only parts. -Standard parts - - NAME , - SYNOPSIS , - DESCRIPTION , - OPTIONS , - FILES , - SEE ALSO , - BUGS , - -and - - AUTHOR . - -A unix-like system keeps an index of the DESCRIPTIONs, which is accesable -by the command whatis or apropos. - -""" - -__docformat__ = 'reStructuredText' - -import re - -import docutils -from docutils import nodes, writers, languages -try: - import roman -except ImportError: - import docutils.utils.roman as roman - -FIELD_LIST_INDENT = 7 -DEFINITION_LIST_INDENT = 7 -OPTION_LIST_INDENT = 7 -BLOCKQOUTE_INDENT = 3.5 - -# Define two macros so man/roff can calculate the -# indent/unindent margins by itself -MACRO_DEF = (r""". -.nr rst2man-indent-level 0 -. -.de1 rstReportMargin -\\$1 \\n[an-margin] -level \\n[rst2man-indent-level] -level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] -- -\\n[rst2man-indent0] -\\n[rst2man-indent1] -\\n[rst2man-indent2] -.. -.de1 INDENT -.\" .rstReportMargin pre: -. RS \\$1 -. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] -. nr rst2man-indent-level +1 -.\" .rstReportMargin post: -.. -.de UNINDENT -. RE -.\" indent \\n[an-margin] -.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] -.nr rst2man-indent-level -1 -.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] -.in \\n[rst2man-indent\\n[rst2man-indent-level]]u -.. -""") - -class Writer(writers.Writer): - - supported = ('manpage',) - """Formats this writer supports.""" - - output = None - """Final translated form of `document`.""" - - def __init__(self): - writers.Writer.__init__(self) - self.translator_class = Translator - - def translate(self): - visitor = self.translator_class(self.document) - self.document.walkabout(visitor) - self.output = visitor.astext() - - -class Table: - def __init__(self): - self._rows = [] - self._options = ['center'] - self._tab_char = '\t' - self._coldefs = [] - def new_row(self): - self._rows.append([]) - def append_separator(self, separator): - """Append the separator for table head.""" - self._rows.append([separator]) - def append_cell(self, cell_lines): - """cell_lines is an array of lines""" - start = 0 - if len(cell_lines) > 0 and cell_lines[0] == '.sp\n': - start = 1 - self._rows[-1].append(cell_lines[start:]) - if len(self._coldefs) < len(self._rows[-1]): - self._coldefs.append('l') - def _minimize_cell(self, cell_lines): - """Remove leading and trailing blank and ``.sp`` lines""" - while (cell_lines and cell_lines[0] in ('\n', '.sp\n')): - del cell_lines[0] - while (cell_lines and cell_lines[-1] in ('\n', '.sp\n')): - del cell_lines[-1] - def as_list(self): - text = ['.TS\n'] - text.append(' '.join(self._options) + ';\n') - text.append('|%s|.\n' % ('|'.join(self._coldefs))) - for row in self._rows: - # row = array of cells. cell = array of lines. - text.append('_\n') # line above - text.append('T{\n') - for i in range(len(row)): - cell = row[i] - self._minimize_cell(cell) - text.extend(cell) - if not text[-1].endswith('\n'): - text[-1] += '\n' - if i < len(row)-1: - text.append('T}'+self._tab_char+'T{\n') - else: - text.append('T}\n') - text.append('_\n') - text.append('.TE\n') - return text - -class Translator(nodes.NodeVisitor): - """""" - - words_and_spaces = re.compile(r'\S+| +|\n') - possibly_a_roff_command = re.compile(r'\.\w') - document_start = """Man page generated from reStructuredText.""" - - def __init__(self, document): - nodes.NodeVisitor.__init__(self, document) - self.settings = settings = document.settings - lcode = settings.language_code - self.language = languages.get_language(lcode, document.reporter) - self.head = [] - self.body = [] - self.foot = [] - self.section_level = 0 - self.context = [] - self.topic_class = '' - self.colspecs = [] - self.compact_p = 1 - self.compact_simple = None - # the list style "*" bullet or "#" numbered - self._list_char = [] - # writing the header .TH and .SH NAME is postboned after - # docinfo. - self._docinfo = { - "title" : "", "title_upper": "", - "subtitle" : "", - "manual_section" : "", "manual_group" : "", - "author" : [], - "date" : "", - "copyright" : "", - "version" : "", - } - self._docinfo_keys = [] # a list to keep the sequence as in source. - self._docinfo_names = {} # to get name from text not normalized. - self._in_docinfo = None - self._active_table = None - self._in_literal = False - self.header_written = 0 - self._line_block = 0 - self.authors = [] - self.section_level = 0 - self._indent = [0] - # central definition of simple processing rules - # what to output on : visit, depart - # Do not use paragraph requests ``.PP`` because these set indentation. - # use ``.sp``. Remove superfluous ``.sp`` in ``astext``. - # - # Fonts are put on a stack, the top one is used. - # ``.ft P`` or ``\\fP`` pop from stack. - # ``B`` bold, ``I`` italic, ``R`` roman should be available. - # Hopefully ``C`` courier too. - self.defs = { - 'indent' : ('.INDENT %.1f\n', '.UNINDENT\n'), - 'definition_list_item' : ('.TP', ''), - 'field_name' : ('.TP\n.B ', '\n'), - 'literal' : ('\\fB', '\\fP'), - 'literal_block' : ('.sp\n.nf\n.ft C\n', '\n.ft P\n.fi\n'), - - 'option_list_item' : ('.TP\n', ''), - - 'reference' : (r'\fI\%', r'\fP'), - 'emphasis': ('\\fI', '\\fP'), - 'strong' : ('\\fB', '\\fP'), - 'term' : ('\n.B ', '\n'), - 'title_reference' : ('\\fI', '\\fP'), - - 'topic-title' : ('.SS ',), - 'sidebar-title' : ('.SS ',), - - 'problematic' : ('\n.nf\n', '\n.fi\n'), - } - # NOTE do not specify the newline before a dot-command, but ensure - # it is there. - - def comment_begin(self, text): - """Return commented version of the passed text WITHOUT end of - line/comment.""" - prefix = '.\\" ' - out_text = ''.join( - [(prefix + in_line + '\n') - for in_line in text.split('\n')]) - return out_text - - def comment(self, text): - """Return commented version of the passed text.""" - return self.comment_begin(text)+'.\n' - - def ensure_eol(self): - """Ensure the last line in body is terminated by new line.""" - if self.body[-1][-1] != '\n': - self.body.append('\n') - - def astext(self): - """Return the final formatted document as a string.""" - if not self.header_written: - # ensure we get a ".TH" as viewers require it. - self.head.append(self.header()) - # filter body - for i in xrange(len(self.body)-1, 0, -1): - # remove superfluous vertical gaps. - if self.body[i] == '.sp\n': - if self.body[i - 1][:4] in ('.BI ','.IP '): - self.body[i] = '.\n' - elif (self.body[i - 1][:3] == '.B ' and - self.body[i - 2][:4] == '.TP\n'): - self.body[i] = '.\n' - elif (self.body[i - 1] == '\n' and - not self.possibly_a_roff_command.match(self.body[i - 2]) and - (self.body[i - 3][:7] == '.TP\n.B ' - or self.body[i - 3][:4] == '\n.B ') - ): - self.body[i] = '.\n' - return ''.join(self.head + self.body + self.foot) - - def deunicode(self, text): - text = text.replace(u'\xa0', '\\ ') - text = text.replace(u'\u2020', '\\(dg') - return text - - def visit_Text(self, node): - text = node.astext() - text = text.replace('\\','\\e') - replace_pairs = [ - (u'-', ur'\-'), - (u'\'', ur'\(aq'), - (u'´', ur'\''), - (u'`', ur'\(ga'), - ] - for (in_char, out_markup) in replace_pairs: - text = text.replace(in_char, out_markup) - # unicode - text = self.deunicode(text) - if self._in_literal: - # prevent interpretation of "." at line start - if text[0] == '.': - text = '\\&' + text - text = text.replace('\n.', '\n\\&.') - self.body.append(text) - - def depart_Text(self, node): - pass - - def list_start(self, node): - class enum_char: - enum_style = { - 'bullet' : '\\(bu', - 'emdash' : '\\(em', - } - - def __init__(self, style): - self._style = style - if node.has_key('start'): - self._cnt = node['start'] - 1 - else: - self._cnt = 0 - self._indent = 2 - if style == 'arabic': - # indentation depends on number of childrens - # and start value. - self._indent = len(str(len(node.children))) - self._indent += len(str(self._cnt)) + 1 - elif style == 'loweralpha': - self._cnt += ord('a') - 1 - self._indent = 3 - elif style == 'upperalpha': - self._cnt += ord('A') - 1 - self._indent = 3 - elif style.endswith('roman'): - self._indent = 5 - - def next(self): - if self._style == 'bullet': - return self.enum_style[self._style] - elif self._style == 'emdash': - return self.enum_style[self._style] - self._cnt += 1 - # TODO add prefix postfix - if self._style == 'arabic': - return "%d." % self._cnt - elif self._style in ('loweralpha', 'upperalpha'): - return "%c." % self._cnt - elif self._style.endswith('roman'): - res = roman.toRoman(self._cnt) + '.' - if self._style.startswith('upper'): - return res.upper() - return res.lower() - else: - return "%d." % self._cnt - def get_width(self): - return self._indent - def __repr__(self): - return 'enum_style-%s' % list(self._style) - - if node.has_key('enumtype'): - self._list_char.append(enum_char(node['enumtype'])) - else: - self._list_char.append(enum_char('bullet')) - if len(self._list_char) > 1: - # indent nested lists - self.indent(self._list_char[-2].get_width()) - else: - self.indent(self._list_char[-1].get_width()) - - def list_end(self): - self.dedent() - self._list_char.pop() - - def header(self): - tmpl = (".TH %(title_upper)s %(manual_section)s" - " \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n" - ".SH NAME\n" - "%(title)s \- %(subtitle)s\n") - return tmpl % self._docinfo - - def append_header(self): - """append header with .TH and .SH NAME""" - # NOTE before everything - # .TH title_upper section date source manual - if self.header_written: - return - self.body.append(self.header()) - self.body.append(MACRO_DEF) - self.header_written = 1 - - def visit_address(self, node): - self.visit_docinfo_item(node, 'address') - - def depart_address(self, node): - pass - - def visit_admonition(self, node, name=None): - if name: - self.body.append('.IP %s\n' % - self.language.labels.get(name, name)) - - def depart_admonition(self, node): - self.body.append('.RE\n') - - def visit_attention(self, node): - self.visit_admonition(node, 'attention') - - depart_attention = depart_admonition - - def visit_docinfo_item(self, node, name): - if name == 'author': - self._docinfo[name].append(node.astext()) - else: - self._docinfo[name] = node.astext() - self._docinfo_keys.append(name) - raise nodes.SkipNode - - def depart_docinfo_item(self, node): - pass - - def visit_author(self, node): - self.visit_docinfo_item(node, 'author') - - depart_author = depart_docinfo_item - - def visit_authors(self, node): - # _author is called anyway. - pass - - def depart_authors(self, node): - pass - - def visit_block_quote(self, node): - # BUG/HACK: indent alway uses the _last_ indention, - # thus we need two of them. - self.indent(BLOCKQOUTE_INDENT) - self.indent(0) - - def depart_block_quote(self, node): - self.dedent() - self.dedent() - - def visit_bullet_list(self, node): - self.list_start(node) - - def depart_bullet_list(self, node): - self.list_end() - - def visit_caption(self, node): - pass - - def depart_caption(self, node): - pass - - def visit_caution(self, node): - self.visit_admonition(node, 'caution') - - depart_caution = depart_admonition - - def visit_citation(self, node): - num, text = node.astext().split(None, 1) - num = num.strip() - self.body.append('.IP [%s] 5\n' % num) - - def depart_citation(self, node): - pass - - def visit_citation_reference(self, node): - self.body.append('['+node.astext()+']') - raise nodes.SkipNode - - def visit_classifier(self, node): - pass - - def depart_classifier(self, node): - pass - - def visit_colspec(self, node): - self.colspecs.append(node) - - def depart_colspec(self, node): - pass - - def write_colspecs(self): - self.body.append("%s.\n" % ('L '*len(self.colspecs))) - - def visit_comment(self, node, - sub=re.compile('-(?=-)').sub): - self.body.append(self.comment(node.astext())) - raise nodes.SkipNode - - def visit_contact(self, node): - self.visit_docinfo_item(node, 'contact') - - depart_contact = depart_docinfo_item - - def visit_container(self, node): - pass - - def depart_container(self, node): - pass - - def visit_compound(self, node): - pass - - def depart_compound(self, node): - pass - - def visit_copyright(self, node): - self.visit_docinfo_item(node, 'copyright') - - def visit_danger(self, node): - self.visit_admonition(node, 'danger') - - depart_danger = depart_admonition - - def visit_date(self, node): - self.visit_docinfo_item(node, 'date') - - def visit_decoration(self, node): - pass - - def depart_decoration(self, node): - pass - - def visit_definition(self, node): - pass - - def depart_definition(self, node): - pass - - def visit_definition_list(self, node): - self.indent(DEFINITION_LIST_INDENT) - - def depart_definition_list(self, node): - self.dedent() - - def visit_definition_list_item(self, node): - self.body.append(self.defs['definition_list_item'][0]) - - def depart_definition_list_item(self, node): - self.body.append(self.defs['definition_list_item'][1]) - - def visit_description(self, node): - pass - - def depart_description(self, node): - pass - - def visit_docinfo(self, node): - self._in_docinfo = 1 - - def depart_docinfo(self, node): - self._in_docinfo = None - # NOTE nothing should be written before this - self.append_header() - - def visit_doctest_block(self, node): - self.body.append(self.defs['literal_block'][0]) - self._in_literal = True - - def depart_doctest_block(self, node): - self._in_literal = False - self.body.append(self.defs['literal_block'][1]) - - def visit_document(self, node): - # no blank line between comment and header. - self.body.append(self.comment(self.document_start).rstrip()+'\n') - # writing header is postboned - self.header_written = 0 - - def depart_document(self, node): - if self._docinfo['author']: - self.body.append('.SH AUTHOR\n%s\n' - % ', '.join(self._docinfo['author'])) - skip = ('author', 'copyright', 'date', - 'manual_group', 'manual_section', - 'subtitle', - 'title', 'title_upper', 'version') - for name in self._docinfo_keys: - if name == 'address': - self.body.append("\n%s:\n%s%s.nf\n%s\n.fi\n%s%s" % ( - self.language.labels.get(name, name), - self.defs['indent'][0] % 0, - self.defs['indent'][0] % BLOCKQOUTE_INDENT, - self._docinfo[name], - self.defs['indent'][1], - self.defs['indent'][1])) - elif not name in skip: - if name in self._docinfo_names: - label = self._docinfo_names[name] - else: - label = self.language.labels.get(name, name) - self.body.append("\n%s: %s\n" % (label, self._docinfo[name])) - if self._docinfo['copyright']: - self.body.append('.SH COPYRIGHT\n%s\n' - % self._docinfo['copyright']) - self.body.append(self.comment( - 'Generated by docutils manpage writer.')) - - def visit_emphasis(self, node): - self.body.append(self.defs['emphasis'][0]) - - def depart_emphasis(self, node): - self.body.append(self.defs['emphasis'][1]) - - def visit_entry(self, node): - # a cell in a table row - if 'morerows' in node: - self.document.reporter.warning('"table row spanning" not supported', - base_node=node) - if 'morecols' in node: - self.document.reporter.warning( - '"table cell spanning" not supported', base_node=node) - self.context.append(len(self.body)) - - def depart_entry(self, node): - start = self.context.pop() - self._active_table.append_cell(self.body[start:]) - del self.body[start:] - - def visit_enumerated_list(self, node): - self.list_start(node) - - def depart_enumerated_list(self, node): - self.list_end() - - def visit_error(self, node): - self.visit_admonition(node, 'error') - - depart_error = depart_admonition - - def visit_field(self, node): - pass - - def depart_field(self, node): - pass - - def visit_field_body(self, node): - if self._in_docinfo: - name_normalized = self._field_name.lower().replace(" ","_") - self._docinfo_names[name_normalized] = self._field_name - self.visit_docinfo_item(node, name_normalized) - raise nodes.SkipNode - - def depart_field_body(self, node): - pass - - def visit_field_list(self, node): - self.indent(FIELD_LIST_INDENT) - - def depart_field_list(self, node): - self.dedent() - - def visit_field_name(self, node): - if self._in_docinfo: - self._field_name = node.astext() - raise nodes.SkipNode - else: - self.body.append(self.defs['field_name'][0]) - - def depart_field_name(self, node): - self.body.append(self.defs['field_name'][1]) - - def visit_figure(self, node): - self.indent(2.5) - self.indent(0) - - def depart_figure(self, node): - self.dedent() - self.dedent() - - def visit_footer(self, node): - self.document.reporter.warning('"footer" not supported', - base_node=node) - - def depart_footer(self, node): - pass - - def visit_footnote(self, node): - num, text = node.astext().split(None, 1) - num = num.strip() - self.body.append('.IP [%s] 5\n' % self.deunicode(num)) - - def depart_footnote(self, node): - pass - - def footnote_backrefs(self, node): - self.document.reporter.warning('"footnote_backrefs" not supported', - base_node=node) - - def visit_footnote_reference(self, node): - self.body.append('['+self.deunicode(node.astext())+']') - raise nodes.SkipNode - - def depart_footnote_reference(self, node): - pass - - def visit_generated(self, node): - pass - - def depart_generated(self, node): - pass - - def visit_header(self, node): - raise NotImplementedError, node.astext() - - def depart_header(self, node): - pass - - def visit_hint(self, node): - self.visit_admonition(node, 'hint') - - depart_hint = depart_admonition - - def visit_subscript(self, node): - self.body.append('\\s-2\\d') - - def depart_subscript(self, node): - self.body.append('\\u\\s0') - - def visit_superscript(self, node): - self.body.append('\\s-2\\u') - - def depart_superscript(self, node): - self.body.append('\\d\\s0') - - def visit_attribution(self, node): - self.body.append('\\(em ') - - def depart_attribution(self, node): - self.body.append('\n') - - def visit_image(self, node): - self.document.reporter.warning('"image" not supported', - base_node=node) - text = [] - if 'alt' in node.attributes: - text.append(node.attributes['alt']) - if 'uri' in node.attributes: - text.append(node.attributes['uri']) - self.body.append('[image: %s]\n' % ('/'.join(text))) - raise nodes.SkipNode - - def visit_important(self, node): - self.visit_admonition(node, 'important') - - depart_important = depart_admonition - - def visit_label(self, node): - # footnote and citation - if (isinstance(node.parent, nodes.footnote) - or isinstance(node.parent, nodes.citation)): - raise nodes.SkipNode - self.document.reporter.warning('"unsupported "label"', - base_node=node) - self.body.append('[') - - def depart_label(self, node): - self.body.append(']\n') - - def visit_legend(self, node): - pass - - def depart_legend(self, node): - pass - - # WHAT should we use .INDENT, .UNINDENT ? - def visit_line_block(self, node): - self._line_block += 1 - if self._line_block == 1: - # TODO: separate inline blocks from previous paragraphs - # see http://hg.intevation.org/mercurial/crew/rev/9c142ed9c405 - # self.body.append('.sp\n') - # but it does not work for me. - self.body.append('.nf\n') - else: - self.body.append('.in +2\n') - - def depart_line_block(self, node): - self._line_block -= 1 - if self._line_block == 0: - self.body.append('.fi\n') - self.body.append('.sp\n') - else: - self.body.append('.in -2\n') - - def visit_line(self, node): - pass - - def depart_line(self, node): - self.body.append('\n') - - def visit_list_item(self, node): - # man 7 man argues to use ".IP" instead of ".TP" - self.body.append('.IP %s %d\n' % ( - self._list_char[-1].next(), - self._list_char[-1].get_width(),)) - - def depart_list_item(self, node): - pass - - def visit_literal(self, node): - self.body.append(self.defs['literal'][0]) - - def depart_literal(self, node): - self.body.append(self.defs['literal'][1]) - - def visit_literal_block(self, node): - self.body.append(self.defs['literal_block'][0]) - self._in_literal = True - - def depart_literal_block(self, node): - self._in_literal = False - self.body.append(self.defs['literal_block'][1]) - - def visit_math(self, node): - self.document.reporter.warning('"math" role not supported', - base_node=node) - self.visit_literal(node) - - def depart_math(self, node): - self.depart_literal(node) - - def visit_math_block(self, node): - self.document.reporter.warning('"math" directive not supported', - base_node=node) - self.visit_literal_block(node) - - def depart_math_block(self, node): - self.depart_literal_block(node) - - def visit_meta(self, node): - raise NotImplementedError, node.astext() - - def depart_meta(self, node): - pass - - def visit_note(self, node): - self.visit_admonition(node, 'note') - - depart_note = depart_admonition - - def indent(self, by=0.5): - # if we are in a section ".SH" there already is a .RS - step = self._indent[-1] - self._indent.append(by) - self.body.append(self.defs['indent'][0] % step) - - def dedent(self): - self._indent.pop() - self.body.append(self.defs['indent'][1]) - - def visit_option_list(self, node): - self.indent(OPTION_LIST_INDENT) - - def depart_option_list(self, node): - self.dedent() - - def visit_option_list_item(self, node): - # one item of the list - self.body.append(self.defs['option_list_item'][0]) - - def depart_option_list_item(self, node): - self.body.append(self.defs['option_list_item'][1]) - - def visit_option_group(self, node): - # as one option could have several forms it is a group - # options without parameter bold only, .B, -v - # options with parameter bold italic, .BI, -f file - # - # we do not know if .B or .BI - self.context.append('.B') # blind guess - self.context.append(len(self.body)) # to be able to insert later - self.context.append(0) # option counter - - def depart_option_group(self, node): - self.context.pop() # the counter - start_position = self.context.pop() - text = self.body[start_position:] - del self.body[start_position:] - self.body.append('%s%s\n' % (self.context.pop(), ''.join(text))) - - def visit_option(self, node): - # each form of the option will be presented separately - if self.context[-1] > 0: - self.body.append(', ') - if self.context[-3] == '.BI': - self.body.append('\\') - self.body.append(' ') - - def depart_option(self, node): - self.context[-1] += 1 - - def visit_option_string(self, node): - # do not know if .B or .BI - pass - - def depart_option_string(self, node): - pass - - def visit_option_argument(self, node): - self.context[-3] = '.BI' # bold/italic alternate - if node['delimiter'] != ' ': - self.body.append('\\fB%s ' % node['delimiter']) - elif self.body[len(self.body)-1].endswith('='): - # a blank only means no blank in output, just changing font - self.body.append(' ') - else: - # blank backslash blank, switch font then a blank - self.body.append(' \\ ') - - def depart_option_argument(self, node): - pass - - def visit_organization(self, node): - self.visit_docinfo_item(node, 'organization') - - def depart_organization(self, node): - pass - - def first_child(self, node): - first = isinstance(node.parent[0], nodes.label) # skip label - for child in node.parent.children[first:]: - if isinstance(child, nodes.Invisible): - continue - if child is node: - return 1 - break - return 0 - - def visit_paragraph(self, node): - # ``.PP`` : Start standard indented paragraph. - # ``.LP`` : Start block paragraph, all except the first. - # ``.P [type]`` : Start paragraph type. - # NOTE dont use paragraph starts because they reset indentation. - # ``.sp`` is only vertical space - self.ensure_eol() - if not self.first_child(node): - self.body.append('.sp\n') - - def depart_paragraph(self, node): - self.body.append('\n') - - def visit_problematic(self, node): - self.body.append(self.defs['problematic'][0]) - - def depart_problematic(self, node): - self.body.append(self.defs['problematic'][1]) - - def visit_raw(self, node): - if node.get('format') == 'manpage': - self.body.append(node.astext() + "\n") - # Keep non-manpage raw text out of output: - raise nodes.SkipNode - - def visit_reference(self, node): - """E.g. link or email address.""" - self.body.append(self.defs['reference'][0]) - - def depart_reference(self, node): - self.body.append(self.defs['reference'][1]) - - def visit_revision(self, node): - self.visit_docinfo_item(node, 'revision') - - depart_revision = depart_docinfo_item - - def visit_row(self, node): - self._active_table.new_row() - - def depart_row(self, node): - pass - - def visit_section(self, node): - self.section_level += 1 - - def depart_section(self, node): - self.section_level -= 1 - - def visit_status(self, node): - self.visit_docinfo_item(node, 'status') - - depart_status = depart_docinfo_item - - def visit_strong(self, node): - self.body.append(self.defs['strong'][0]) - - def depart_strong(self, node): - self.body.append(self.defs['strong'][1]) - - def visit_substitution_definition(self, node): - """Internal only.""" - raise nodes.SkipNode - - def visit_substitution_reference(self, node): - self.document.reporter.warning('"substitution_reference" not supported', - base_node=node) - - def visit_subtitle(self, node): - if isinstance(node.parent, nodes.sidebar): - self.body.append(self.defs['strong'][0]) - elif isinstance(node.parent, nodes.document): - self.visit_docinfo_item(node, 'subtitle') - elif isinstance(node.parent, nodes.section): - self.body.append(self.defs['strong'][0]) - - def depart_subtitle(self, node): - # document subtitle calls SkipNode - self.body.append(self.defs['strong'][1]+'\n.PP\n') - - def visit_system_message(self, node): - # TODO add report_level - #if node['level'] < self.document.reporter['writer'].report_level: - # Level is too low to display: - # raise nodes.SkipNode - attr = {} - backref_text = '' - if node.hasattr('id'): - attr['name'] = node['id'] - if node.hasattr('line'): - line = ', line %s' % node['line'] - else: - line = '' - self.body.append('.IP "System Message: %s/%s (%s:%s)"\n' - % (node['type'], node['level'], node['source'], line)) - - def depart_system_message(self, node): - pass - - def visit_table(self, node): - self._active_table = Table() - - def depart_table(self, node): - self.ensure_eol() - self.body.extend(self._active_table.as_list()) - self._active_table = None - - def visit_target(self, node): - # targets are in-document hyper targets, without any use for man-pages. - raise nodes.SkipNode - - def visit_tbody(self, node): - pass - - def depart_tbody(self, node): - pass - - def visit_term(self, node): - self.body.append(self.defs['term'][0]) - - def depart_term(self, node): - self.body.append(self.defs['term'][1]) - - def visit_tgroup(self, node): - pass - - def depart_tgroup(self, node): - pass - - def visit_thead(self, node): - # MAYBE double line '=' - pass - - def depart_thead(self, node): - # MAYBE double line '=' - pass - - def visit_tip(self, node): - self.visit_admonition(node, 'tip') - - depart_tip = depart_admonition - - def visit_title(self, node): - if isinstance(node.parent, nodes.topic): - self.body.append(self.defs['topic-title'][0]) - elif isinstance(node.parent, nodes.sidebar): - self.body.append(self.defs['sidebar-title'][0]) - elif isinstance(node.parent, nodes.admonition): - self.body.append('.IP "') - elif self.section_level == 0: - self._docinfo['title'] = node.astext() - # document title for .TH - self._docinfo['title_upper'] = node.astext().upper() - raise nodes.SkipNode - elif self.section_level == 1: - self.body.append('.SH %s\n' % self.deunicode(node.astext().upper())) - raise nodes.SkipNode - else: - self.body.append('.SS ') - - def depart_title(self, node): - if isinstance(node.parent, nodes.admonition): - self.body.append('"') - self.body.append('\n') - - def visit_title_reference(self, node): - """inline citation reference""" - self.body.append(self.defs['title_reference'][0]) - - def depart_title_reference(self, node): - self.body.append(self.defs['title_reference'][1]) - - def visit_topic(self, node): - pass - - def depart_topic(self, node): - pass - - def visit_sidebar(self, node): - pass - - def depart_sidebar(self, node): - pass - - def visit_rubric(self, node): - pass - - def depart_rubric(self, node): - pass - - def visit_transition(self, node): - # .PP Begin a new paragraph and reset prevailing indent. - # .sp N leaves N lines of blank space. - # .ce centers the next line - self.body.append('\n.sp\n.ce\n----\n') - - def depart_transition(self, node): - self.body.append('\n.ce 0\n.sp\n') - - def visit_version(self, node): - self.visit_docinfo_item(node, 'version') - - def visit_warning(self, node): - self.visit_admonition(node, 'warning') - - depart_warning = depart_admonition - - def unimplemented_visit(self, node): - raise NotImplementedError('visiting unimplemented node type: %s' - % node.__class__.__name__) - -# vim: set fileencoding=utf-8 et ts=4 ai : diff --git a/docutils/writers/null.py b/docutils/writers/null.py deleted file mode 100644 index b870788a4..000000000 --- a/docutils/writers/null.py +++ /dev/null @@ -1,21 +0,0 @@ -# $Id: null.py 4564 2006-05-21 20:44:42Z wiemann $ -# Author: David Goodger -# Copyright: This module has been placed in the public domain. - -""" -A do-nothing Writer. -""" - -from docutils import writers - - -class Writer(writers.UnfilteredWriter): - - supported = ('null',) - """Formats this writer supports.""" - - config_section = 'null writer' - config_section_dependencies = ('writers',) - - def translate(self): - pass diff --git a/docutils/writers/odf_odt/__init__.py b/docutils/writers/odf_odt/__init__.py deleted file mode 100644 index 3a9f6fa7b..000000000 --- a/docutils/writers/odf_odt/__init__.py +++ /dev/null @@ -1,3266 +0,0 @@ -# $Id: __init__.py 7422 2012-05-03 10:55:30Z milde $ -# Author: Dave Kuhlman -# Copyright: This module has been placed in the public domain. - -""" -Open Document Format (ODF) Writer. - -""" - -VERSION = '1.0a' - -__docformat__ = 'reStructuredText' - - -import sys -import os -import os.path -import tempfile -import zipfile -from xml.dom import minidom -import time -import re -import StringIO -import inspect -import imp -import copy -import urllib2 -import docutils -from docutils import frontend, nodes, utils, writers, languages -from docutils.parsers import rst -from docutils.readers import standalone -from docutils.transforms import references - - -WhichElementTree = '' -try: - # 1. Try to use lxml. - #from lxml import etree - #WhichElementTree = 'lxml' - raise ImportError('Ignoring lxml') -except ImportError, e: - try: - # 2. Try to use ElementTree from the Python standard library. - from xml.etree import ElementTree as etree - WhichElementTree = 'elementtree' - except ImportError, e: - try: - # 3. Try to use a version of ElementTree installed as a separate - # product. - from elementtree import ElementTree as etree - WhichElementTree = 'elementtree' - except ImportError, e: - s1 = 'Must install either a version of Python containing ' \ - 'ElementTree (Python version >=2.5) or install ElementTree.' - raise ImportError(s1) - -# -# Import pygments and odtwriter pygments formatters if possible. -try: - import pygments - import pygments.lexers - from pygmentsformatter import OdtPygmentsProgFormatter, \ - OdtPygmentsLaTeXFormatter -except ImportError, exp: - pygments = None - -try: # check for the Python Imaging Library - import PIL -except ImportError: - try: # sometimes PIL modules are put in PYTHONPATH's root - import Image - class PIL(object): pass # dummy wrapper - PIL.Image = Image - except ImportError: - PIL = None - -## import warnings -## warnings.warn('importing IPShellEmbed', UserWarning) -## from IPython.Shell import IPShellEmbed -## args = ['-pdb', '-pi1', 'In <\\#>: ', '-pi2', ' .\\D.: ', -## '-po', 'Out<\\#>: ', '-nosep'] -## ipshell = IPShellEmbed(args, -## banner = 'Entering IPython. Press Ctrl-D to exit.', -## exit_msg = 'Leaving Interpreter, back to program.') - - -# -# ElementTree does not support getparent method (lxml does). -# This wrapper class and the following support functions provide -# that support for the ability to get the parent of an element. -# -if WhichElementTree == 'elementtree': - class _ElementInterfaceWrapper(etree._ElementInterface): - def __init__(self, tag, attrib=None): - etree._ElementInterface.__init__(self, tag, attrib) - if attrib is None: - attrib = {} - self.parent = None - def setparent(self, parent): - self.parent = parent - def getparent(self): - return self.parent - - -# -# Constants and globals - -SPACES_PATTERN = re.compile(r'( +)') -TABS_PATTERN = re.compile(r'(\t+)') -FILL_PAT1 = re.compile(r'^ +') -FILL_PAT2 = re.compile(r' {2,}') - -TABLESTYLEPREFIX = 'rststyle-table-' -TABLENAMEDEFAULT = '%s0' % TABLESTYLEPREFIX -TABLEPROPERTYNAMES = ('border', 'border-top', 'border-left', - 'border-right', 'border-bottom', ) - -GENERATOR_DESC = 'Docutils.org/odf_odt' - -NAME_SPACE_1 = 'urn:oasis:names:tc:opendocument:xmlns:office:1.0' - -CONTENT_NAMESPACE_DICT = CNSD = { -# 'office:version': '1.0', - 'chart': 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0', - 'dc': 'http://purl.org/dc/elements/1.1/', - 'dom': 'http://www.w3.org/2001/xml-events', - 'dr3d': 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0', - 'draw': 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0', - 'fo': 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0', - 'form': 'urn:oasis:names:tc:opendocument:xmlns:form:1.0', - 'math': 'http://www.w3.org/1998/Math/MathML', - 'meta': 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0', - 'number': 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0', - 'office': NAME_SPACE_1, - 'ooo': 'http://openoffice.org/2004/office', - 'oooc': 'http://openoffice.org/2004/calc', - 'ooow': 'http://openoffice.org/2004/writer', - 'presentation': 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0', - - 'script': 'urn:oasis:names:tc:opendocument:xmlns:script:1.0', - 'style': 'urn:oasis:names:tc:opendocument:xmlns:style:1.0', - 'svg': 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0', - 'table': 'urn:oasis:names:tc:opendocument:xmlns:table:1.0', - 'text': 'urn:oasis:names:tc:opendocument:xmlns:text:1.0', - 'xforms': 'http://www.w3.org/2002/xforms', - 'xlink': 'http://www.w3.org/1999/xlink', - 'xsd': 'http://www.w3.org/2001/XMLSchema', - 'xsi': 'http://www.w3.org/2001/XMLSchema-instance', - } - -STYLES_NAMESPACE_DICT = SNSD = { -# 'office:version': '1.0', - 'chart': 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0', - 'dc': 'http://purl.org/dc/elements/1.1/', - 'dom': 'http://www.w3.org/2001/xml-events', - 'dr3d': 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0', - 'draw': 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0', - 'fo': 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0', - 'form': 'urn:oasis:names:tc:opendocument:xmlns:form:1.0', - 'math': 'http://www.w3.org/1998/Math/MathML', - 'meta': 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0', - 'number': 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0', - 'office': NAME_SPACE_1, - 'presentation': 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0', - 'ooo': 'http://openoffice.org/2004/office', - 'oooc': 'http://openoffice.org/2004/calc', - 'ooow': 'http://openoffice.org/2004/writer', - 'script': 'urn:oasis:names:tc:opendocument:xmlns:script:1.0', - 'style': 'urn:oasis:names:tc:opendocument:xmlns:style:1.0', - 'svg': 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0', - 'table': 'urn:oasis:names:tc:opendocument:xmlns:table:1.0', - 'text': 'urn:oasis:names:tc:opendocument:xmlns:text:1.0', - 'xlink': 'http://www.w3.org/1999/xlink', - } - -MANIFEST_NAMESPACE_DICT = MANNSD = { - 'manifest': 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0', -} - -META_NAMESPACE_DICT = METNSD = { -# 'office:version': '1.0', - 'dc': 'http://purl.org/dc/elements/1.1/', - 'meta': 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0', - 'office': NAME_SPACE_1, - 'ooo': 'http://openoffice.org/2004/office', - 'xlink': 'http://www.w3.org/1999/xlink', -} - -# -# Attribute dictionaries for use with ElementTree (not lxml), which -# does not support use of nsmap parameter on Element() and SubElement(). - -CONTENT_NAMESPACE_ATTRIB = { - #'office:version': '1.0', - 'xmlns:chart': 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0', - 'xmlns:dc': 'http://purl.org/dc/elements/1.1/', - 'xmlns:dom': 'http://www.w3.org/2001/xml-events', - 'xmlns:dr3d': 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0', - 'xmlns:draw': 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0', - 'xmlns:fo': 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0', - 'xmlns:form': 'urn:oasis:names:tc:opendocument:xmlns:form:1.0', - 'xmlns:math': 'http://www.w3.org/1998/Math/MathML', - 'xmlns:meta': 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0', - 'xmlns:number': 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0', - 'xmlns:office': NAME_SPACE_1, - 'xmlns:presentation': 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0', - 'xmlns:ooo': 'http://openoffice.org/2004/office', - 'xmlns:oooc': 'http://openoffice.org/2004/calc', - 'xmlns:ooow': 'http://openoffice.org/2004/writer', - 'xmlns:script': 'urn:oasis:names:tc:opendocument:xmlns:script:1.0', - 'xmlns:style': 'urn:oasis:names:tc:opendocument:xmlns:style:1.0', - 'xmlns:svg': 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0', - 'xmlns:table': 'urn:oasis:names:tc:opendocument:xmlns:table:1.0', - 'xmlns:text': 'urn:oasis:names:tc:opendocument:xmlns:text:1.0', - 'xmlns:xforms': 'http://www.w3.org/2002/xforms', - 'xmlns:xlink': 'http://www.w3.org/1999/xlink', - 'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema', - 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', - } - -STYLES_NAMESPACE_ATTRIB = { - #'office:version': '1.0', - 'xmlns:chart': 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0', - 'xmlns:dc': 'http://purl.org/dc/elements/1.1/', - 'xmlns:dom': 'http://www.w3.org/2001/xml-events', - 'xmlns:dr3d': 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0', - 'xmlns:draw': 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0', - 'xmlns:fo': 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0', - 'xmlns:form': 'urn:oasis:names:tc:opendocument:xmlns:form:1.0', - 'xmlns:math': 'http://www.w3.org/1998/Math/MathML', - 'xmlns:meta': 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0', - 'xmlns:number': 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0', - 'xmlns:office': NAME_SPACE_1, - 'xmlns:presentation': 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0', - 'xmlns:ooo': 'http://openoffice.org/2004/office', - 'xmlns:oooc': 'http://openoffice.org/2004/calc', - 'xmlns:ooow': 'http://openoffice.org/2004/writer', - 'xmlns:script': 'urn:oasis:names:tc:opendocument:xmlns:script:1.0', - 'xmlns:style': 'urn:oasis:names:tc:opendocument:xmlns:style:1.0', - 'xmlns:svg': 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0', - 'xmlns:table': 'urn:oasis:names:tc:opendocument:xmlns:table:1.0', - 'xmlns:text': 'urn:oasis:names:tc:opendocument:xmlns:text:1.0', - 'xmlns:xlink': 'http://www.w3.org/1999/xlink', - } - -MANIFEST_NAMESPACE_ATTRIB = { - 'xmlns:manifest': 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0', -} - -META_NAMESPACE_ATTRIB = { - #'office:version': '1.0', - 'xmlns:dc': 'http://purl.org/dc/elements/1.1/', - 'xmlns:meta': 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0', - 'xmlns:office': NAME_SPACE_1, - 'xmlns:ooo': 'http://openoffice.org/2004/office', - 'xmlns:xlink': 'http://www.w3.org/1999/xlink', -} - - -# -# Functions -# - -# -# ElementTree support functions. -# In order to be able to get the parent of elements, must use these -# instead of the functions with same name provided by ElementTree. -# -def Element(tag, attrib=None, nsmap=None, nsdict=CNSD): - if attrib is None: - attrib = {} - tag, attrib = fix_ns(tag, attrib, nsdict) - if WhichElementTree == 'lxml': - el = etree.Element(tag, attrib, nsmap=nsmap) - else: - el = _ElementInterfaceWrapper(tag, attrib) - return el - -def SubElement(parent, tag, attrib=None, nsmap=None, nsdict=CNSD): - if attrib is None: - attrib = {} - tag, attrib = fix_ns(tag, attrib, nsdict) - if WhichElementTree == 'lxml': - el = etree.SubElement(parent, tag, attrib, nsmap=nsmap) - else: - el = _ElementInterfaceWrapper(tag, attrib) - parent.append(el) - el.setparent(parent) - return el - -def fix_ns(tag, attrib, nsdict): - nstag = add_ns(tag, nsdict) - nsattrib = {} - for key, val in attrib.iteritems(): - nskey = add_ns(key, nsdict) - nsattrib[nskey] = val - return nstag, nsattrib - -def add_ns(tag, nsdict=CNSD): - if WhichElementTree == 'lxml': - nstag, name = tag.split(':') - ns = nsdict.get(nstag) - if ns is None: - raise RuntimeError, 'Invalid namespace prefix: %s' % nstag - tag = '{%s}%s' % (ns, name,) - return tag - -def ToString(et): - outstream = StringIO.StringIO() - if sys.version_info >= (3, 2): - et.write(outstream, encoding="unicode") - else: - et.write(outstream) - s1 = outstream.getvalue() - outstream.close() - return s1 - - -def escape_cdata(text): - text = text.replace("&", "&") - text = text.replace("<", "<") - text = text.replace(">", ">") - ascii = '' - for char in text: - if ord(char) >= ord("\x7f"): - ascii += "&#x%X;" % ( ord(char), ) - else: - ascii += char - return ascii - - - -WORD_SPLIT_PAT1 = re.compile(r'\b(\w*)\b\W*') - -def split_words(line): - # We need whitespace at the end of the string for our regexpr. - line += ' ' - words = [] - pos1 = 0 - mo = WORD_SPLIT_PAT1.search(line, pos1) - while mo is not None: - word = mo.groups()[0] - words.append(word) - pos1 = mo.end() - mo = WORD_SPLIT_PAT1.search(line, pos1) - return words - - -# -# Classes -# - - -class TableStyle(object): - def __init__(self, border=None, backgroundcolor=None): - self.border = border - self.backgroundcolor = backgroundcolor - def get_border_(self): - return self.border_ - def set_border_(self, border): - self.border_ = border - border = property(get_border_, set_border_) - def get_backgroundcolor_(self): - return self.backgroundcolor_ - def set_backgroundcolor_(self, backgroundcolor): - self.backgroundcolor_ = backgroundcolor - backgroundcolor = property(get_backgroundcolor_, set_backgroundcolor_) - -BUILTIN_DEFAULT_TABLE_STYLE = TableStyle( - border = '0.0007in solid #000000') - -# -# Information about the indentation level for lists nested inside -# other contexts, e.g. dictionary lists. -class ListLevel(object): - def __init__(self, level, sibling_level=True, nested_level=True): - self.level = level - self.sibling_level = sibling_level - self.nested_level = nested_level - def set_sibling(self, sibling_level): self.sibling_level = sibling_level - def get_sibling(self): return self.sibling_level - def set_nested(self, nested_level): self.nested_level = nested_level - def get_nested(self): return self.nested_level - def set_level(self, level): self.level = level - def get_level(self): return self.level - - -class Writer(writers.Writer): - - MIME_TYPE = 'application/vnd.oasis.opendocument.text' - EXTENSION = '.odt' - - supported = ('odt', ) - """Formats this writer supports.""" - - default_stylesheet = 'styles' + EXTENSION - - default_stylesheet_path = utils.relative_path( - os.path.join(os.getcwd(), 'dummy'), - os.path.join(os.path.dirname(__file__), default_stylesheet)) - - default_template = 'template.txt' - - default_template_path = utils.relative_path( - os.path.join(os.getcwd(), 'dummy'), - os.path.join(os.path.dirname(__file__), default_template)) - - settings_spec = ( - 'ODF-Specific Options', - None, - ( - ('Specify a stylesheet. ' - 'Default: "%s"' % default_stylesheet_path, - ['--stylesheet'], - { - 'default': default_stylesheet_path, - 'dest': 'stylesheet' - }), - ('Specify a configuration/mapping file relative to the ' - 'current working ' - 'directory for additional ODF options. ' - 'In particular, this file may contain a section named ' - '"Formats" that maps default style names to ' - 'names to be used in the resulting output file allowing for ' - 'adhering to external standards. ' - 'For more info and the format of the configuration/mapping file, ' - 'see the odtwriter doc.', - ['--odf-config-file'], - {'metavar': ''}), - ('Obfuscate email addresses to confuse harvesters while still ' - 'keeping email links usable with standards-compliant browsers.', - ['--cloak-email-addresses'], - {'default': False, - 'action': 'store_true', - 'dest': 'cloak_email_addresses', - 'validator': frontend.validate_boolean}), - ('Do not obfuscate email addresses.', - ['--no-cloak-email-addresses'], - {'default': False, - 'action': 'store_false', - 'dest': 'cloak_email_addresses', - 'validator': frontend.validate_boolean}), - ('Specify the thickness of table borders in thousands of a cm. ' - 'Default is 35.', - ['--table-border-thickness'], - {'default': None, - 'validator': frontend.validate_nonnegative_int}), - ('Add syntax highlighting in literal code blocks.', - ['--add-syntax-highlighting'], - {'default': False, - 'action': 'store_true', - 'dest': 'add_syntax_highlighting', - 'validator': frontend.validate_boolean}), - ('Do not add syntax highlighting in literal code blocks. (default)', - ['--no-syntax-highlighting'], - {'default': False, - 'action': 'store_false', - 'dest': 'add_syntax_highlighting', - 'validator': frontend.validate_boolean}), - ('Create sections for headers. (default)', - ['--create-sections'], - {'default': True, - 'action': 'store_true', - 'dest': 'create_sections', - 'validator': frontend.validate_boolean}), - ('Do not create sections for headers.', - ['--no-sections'], - {'default': True, - 'action': 'store_false', - 'dest': 'create_sections', - 'validator': frontend.validate_boolean}), - ('Create links.', - ['--create-links'], - {'default': False, - 'action': 'store_true', - 'dest': 'create_links', - 'validator': frontend.validate_boolean}), - ('Do not create links. (default)', - ['--no-links'], - {'default': False, - 'action': 'store_false', - 'dest': 'create_links', - 'validator': frontend.validate_boolean}), - ('Generate endnotes at end of document, not footnotes ' - 'at bottom of page.', - ['--endnotes-end-doc'], - {'default': False, - 'action': 'store_true', - 'dest': 'endnotes_end_doc', - 'validator': frontend.validate_boolean}), - ('Generate footnotes at bottom of page, not endnotes ' - 'at end of document. (default)', - ['--no-endnotes-end-doc'], - {'default': False, - 'action': 'store_false', - 'dest': 'endnotes_end_doc', - 'validator': frontend.validate_boolean}), - ('Generate a bullet list table of contents, not ' - 'an ODF/oowriter table of contents.', - ['--generate-list-toc'], - {'default': True, - 'action': 'store_false', - 'dest': 'generate_oowriter_toc', - 'validator': frontend.validate_boolean}), - ('Generate an ODF/oowriter table of contents, not ' - 'a bullet list. (default)', - ['--generate-oowriter-toc'], - {'default': True, - 'action': 'store_true', - 'dest': 'generate_oowriter_toc', - 'validator': frontend.validate_boolean}), - ('Specify the contents of an custom header line. ' - 'See odf_odt writer documentation for details ' - 'about special field character sequences.', - ['--custom-odt-header'], - { 'default': '', - 'dest': 'custom_header', - }), - ('Specify the contents of an custom footer line. ' - 'See odf_odt writer documentation for details ' - 'about special field character sequences.', - ['--custom-odt-footer'], - { 'default': '', - 'dest': 'custom_footer', - }), - ) - ) - - settings_defaults = { - 'output_encoding_error_handler': 'xmlcharrefreplace', - } - - relative_path_settings = ( - 'stylesheet_path', - ) - - config_section = 'opendocument odf writer' - config_section_dependencies = ( - 'writers', - ) - - def __init__(self): - writers.Writer.__init__(self) - self.translator_class = ODFTranslator - - def translate(self): - self.settings = self.document.settings - self.visitor = self.translator_class(self.document) - self.visitor.retrieve_styles(self.EXTENSION) - self.document.walkabout(self.visitor) - self.visitor.add_doc_title() - self.assemble_my_parts() - self.output = self.parts['whole'] - - def assemble_my_parts(self): - """Assemble the `self.parts` dictionary. Extend in subclasses. - """ - writers.Writer.assemble_parts(self) - f = tempfile.NamedTemporaryFile() - zfile = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) - self.write_zip_str(zfile, 'mimetype', self.MIME_TYPE, - compress_type=zipfile.ZIP_STORED) - content = self.visitor.content_astext() - self.write_zip_str(zfile, 'content.xml', content) - s1 = self.create_manifest() - self.write_zip_str(zfile, 'META-INF/manifest.xml', s1) - s1 = self.create_meta() - self.write_zip_str(zfile, 'meta.xml', s1) - s1 = self.get_stylesheet() - self.write_zip_str(zfile, 'styles.xml', s1) - self.store_embedded_files(zfile) - self.copy_from_stylesheet(zfile) - zfile.close() - f.seek(0) - whole = f.read() - f.close() - self.parts['whole'] = whole - self.parts['encoding'] = self.document.settings.output_encoding - self.parts['version'] = docutils.__version__ - - def write_zip_str(self, zfile, name, bytes, compress_type=zipfile.ZIP_DEFLATED): - localtime = time.localtime(time.time()) - zinfo = zipfile.ZipInfo(name, localtime) - # Add some standard UNIX file access permissions (-rw-r--r--). - zinfo.external_attr = (0x81a4 & 0xFFFF) << 16L - zinfo.compress_type = compress_type - zfile.writestr(zinfo, bytes) - - def store_embedded_files(self, zfile): - embedded_files = self.visitor.get_embedded_file_list() - for source, destination in embedded_files: - if source is None: - continue - try: - # encode/decode - destination1 = destination.decode('latin-1').encode('utf-8') - zfile.write(source, destination1) - except OSError, e: - self.document.reporter.warning( - "Can't open file %s." % (source, )) - - def get_settings(self): - """ - modeled after get_stylesheet - """ - stylespath = self.settings.stylesheet - zfile = zipfile.ZipFile(stylespath, 'r') - s1 = zfile.read('settings.xml') - zfile.close() - return s1 - - def get_stylesheet(self): - """Get the stylesheet from the visitor. - Ask the visitor to setup the page. - """ - s1 = self.visitor.setup_page() - return s1 - - def copy_from_stylesheet(self, outzipfile): - """Copy images, settings, etc from the stylesheet doc into target doc. - """ - stylespath = self.settings.stylesheet - inzipfile = zipfile.ZipFile(stylespath, 'r') - # Copy the styles. - s1 = inzipfile.read('settings.xml') - self.write_zip_str(outzipfile, 'settings.xml', s1) - # Copy the images. - namelist = inzipfile.namelist() - for name in namelist: - if name.startswith('Pictures/'): - imageobj = inzipfile.read(name) - outzipfile.writestr(name, imageobj) - inzipfile.close() - - def assemble_parts(self): - pass - - def create_manifest(self): - if WhichElementTree == 'lxml': - root = Element('manifest:manifest', - nsmap=MANIFEST_NAMESPACE_DICT, - nsdict=MANIFEST_NAMESPACE_DICT, - ) - else: - root = Element('manifest:manifest', - attrib=MANIFEST_NAMESPACE_ATTRIB, - nsdict=MANIFEST_NAMESPACE_DICT, - ) - doc = etree.ElementTree(root) - SubElement(root, 'manifest:file-entry', attrib={ - 'manifest:media-type': self.MIME_TYPE, - 'manifest:full-path': '/', - }, nsdict=MANNSD) - SubElement(root, 'manifest:file-entry', attrib={ - 'manifest:media-type': 'text/xml', - 'manifest:full-path': 'content.xml', - }, nsdict=MANNSD) - SubElement(root, 'manifest:file-entry', attrib={ - 'manifest:media-type': 'text/xml', - 'manifest:full-path': 'styles.xml', - }, nsdict=MANNSD) - SubElement(root, 'manifest:file-entry', attrib={ - 'manifest:media-type': 'text/xml', - 'manifest:full-path': 'settings.xml', - }, nsdict=MANNSD) - SubElement(root, 'manifest:file-entry', attrib={ - 'manifest:media-type': 'text/xml', - 'manifest:full-path': 'meta.xml', - }, nsdict=MANNSD) - s1 = ToString(doc) - doc = minidom.parseString(s1) - s1 = doc.toprettyxml(' ') - return s1 - - def create_meta(self): - if WhichElementTree == 'lxml': - root = Element('office:document-meta', - nsmap=META_NAMESPACE_DICT, - nsdict=META_NAMESPACE_DICT, - ) - else: - root = Element('office:document-meta', - attrib=META_NAMESPACE_ATTRIB, - nsdict=META_NAMESPACE_DICT, - ) - doc = etree.ElementTree(root) - root = SubElement(root, 'office:meta', nsdict=METNSD) - el1 = SubElement(root, 'meta:generator', nsdict=METNSD) - el1.text = 'Docutils/rst2odf.py/%s' % (VERSION, ) - s1 = os.environ.get('USER', '') - el1 = SubElement(root, 'meta:initial-creator', nsdict=METNSD) - el1.text = s1 - s2 = time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime()) - el1 = SubElement(root, 'meta:creation-date', nsdict=METNSD) - el1.text = s2 - el1 = SubElement(root, 'dc:creator', nsdict=METNSD) - el1.text = s1 - el1 = SubElement(root, 'dc:date', nsdict=METNSD) - el1.text = s2 - el1 = SubElement(root, 'dc:language', nsdict=METNSD) - el1.text = 'en-US' - el1 = SubElement(root, 'meta:editing-cycles', nsdict=METNSD) - el1.text = '1' - el1 = SubElement(root, 'meta:editing-duration', nsdict=METNSD) - el1.text = 'PT00M01S' - title = self.visitor.get_title() - el1 = SubElement(root, 'dc:title', nsdict=METNSD) - if title: - el1.text = title - else: - el1.text = '[no title]' - meta_dict = self.visitor.get_meta_dict() - keywordstr = meta_dict.get('keywords') - if keywordstr is not None: - keywords = split_words(keywordstr) - for keyword in keywords: - el1 = SubElement(root, 'meta:keyword', nsdict=METNSD) - el1.text = keyword - description = meta_dict.get('description') - if description is not None: - el1 = SubElement(root, 'dc:description', nsdict=METNSD) - el1.text = description - s1 = ToString(doc) - #doc = minidom.parseString(s1) - #s1 = doc.toprettyxml(' ') - return s1 - -# class ODFTranslator(nodes.SparseNodeVisitor): - -class ODFTranslator(nodes.GenericNodeVisitor): - - used_styles = ( - 'attribution', 'blockindent', 'blockquote', 'blockquote-bulletitem', - 'blockquote-bulletlist', 'blockquote-enumitem', 'blockquote-enumlist', - 'bulletitem', 'bulletlist', - 'caption', 'legend', - 'centeredtextbody', 'codeblock', 'codeblock-indented', - 'codeblock-classname', 'codeblock-comment', 'codeblock-functionname', - 'codeblock-keyword', 'codeblock-name', 'codeblock-number', - 'codeblock-operator', 'codeblock-string', 'emphasis', 'enumitem', - 'enumlist', 'epigraph', 'epigraph-bulletitem', 'epigraph-bulletlist', - 'epigraph-enumitem', 'epigraph-enumlist', 'footer', - 'footnote', 'citation', - 'header', 'highlights', 'highlights-bulletitem', - 'highlights-bulletlist', 'highlights-enumitem', 'highlights-enumlist', - 'horizontalline', 'inlineliteral', 'quotation', 'rubric', - 'strong', 'table-title', 'textbody', 'tocbulletlist', 'tocenumlist', - 'title', - 'subtitle', - 'heading1', - 'heading2', - 'heading3', - 'heading4', - 'heading5', - 'heading6', - 'heading7', - 'admon-attention-hdr', - 'admon-attention-body', - 'admon-caution-hdr', - 'admon-caution-body', - 'admon-danger-hdr', - 'admon-danger-body', - 'admon-error-hdr', - 'admon-error-body', - 'admon-generic-hdr', - 'admon-generic-body', - 'admon-hint-hdr', - 'admon-hint-body', - 'admon-important-hdr', - 'admon-important-body', - 'admon-note-hdr', - 'admon-note-body', - 'admon-tip-hdr', - 'admon-tip-body', - 'admon-warning-hdr', - 'admon-warning-body', - 'tableoption', - 'tableoption.%c', 'tableoption.%c%d', 'Table%d', 'Table%d.%c', - 'Table%d.%c%d', - 'lineblock1', - 'lineblock2', - 'lineblock3', - 'lineblock4', - 'lineblock5', - 'lineblock6', - 'image', 'figureframe', - ) - - def __init__(self, document): - #nodes.SparseNodeVisitor.__init__(self, document) - nodes.GenericNodeVisitor.__init__(self, document) - self.settings = document.settings - lcode = self.settings.language_code - self.language = languages.get_language(lcode, document.reporter) - self.format_map = { } - if self.settings.odf_config_file: - from ConfigParser import ConfigParser - - parser = ConfigParser() - parser.read(self.settings.odf_config_file) - for rststyle, format in parser.items("Formats"): - if rststyle not in self.used_styles: - self.document.reporter.warning( - 'Style "%s" is not a style used by odtwriter.' % ( - rststyle, )) - self.format_map[rststyle] = format.decode('utf-8') - self.section_level = 0 - self.section_count = 0 - # Create ElementTree content and styles documents. - if WhichElementTree == 'lxml': - root = Element( - 'office:document-content', - nsmap=CONTENT_NAMESPACE_DICT, - ) - else: - root = Element( - 'office:document-content', - attrib=CONTENT_NAMESPACE_ATTRIB, - ) - self.content_tree = etree.ElementTree(element=root) - self.current_element = root - SubElement(root, 'office:scripts') - SubElement(root, 'office:font-face-decls') - el = SubElement(root, 'office:automatic-styles') - self.automatic_styles = el - el = SubElement(root, 'office:body') - el = self.generate_content_element(el) - self.current_element = el - self.body_text_element = el - self.paragraph_style_stack = [self.rststyle('textbody'), ] - self.list_style_stack = [] - self.table_count = 0 - self.column_count = ord('A') - 1 - self.trace_level = -1 - self.optiontablestyles_generated = False - self.field_name = None - self.field_element = None - self.title = None - self.image_count = 0 - self.image_style_count = 0 - self.image_dict = {} - self.embedded_file_list = [] - self.syntaxhighlighting = 1 - self.syntaxhighlight_lexer = 'python' - self.header_content = [] - self.footer_content = [] - self.in_header = False - self.in_footer = False - self.blockstyle = '' - self.in_table_of_contents = False - self.table_of_content_index_body = None - self.list_level = 0 - self.def_list_level = 0 - self.footnote_ref_dict = {} - self.footnote_list = [] - self.footnote_chars_idx = 0 - self.footnote_level = 0 - self.pending_ids = [ ] - self.in_paragraph = False - self.found_doc_title = False - self.bumped_list_level_stack = [] - self.meta_dict = {} - self.line_block_level = 0 - self.line_indent_level = 0 - self.citation_id = None - self.style_index = 0 # use to form unique style names - self.str_stylesheet = '' - self.str_stylesheetcontent = '' - self.dom_stylesheet = None - self.table_styles = None - self.in_citation = False - - - def get_str_stylesheet(self): - return self.str_stylesheet - - def retrieve_styles(self, extension): - """Retrieve the stylesheet from either a .xml file or from - a .odt (zip) file. Return the content as a string. - """ - s2 = None - stylespath = self.settings.stylesheet - ext = os.path.splitext(stylespath)[1] - if ext == '.xml': - stylesfile = open(stylespath, 'r') - s1 = stylesfile.read() - stylesfile.close() - elif ext == extension: - zfile = zipfile.ZipFile(stylespath, 'r') - s1 = zfile.read('styles.xml') - s2 = zfile.read('content.xml') - zfile.close() - else: - raise RuntimeError, 'stylesheet path (%s) must be %s or .xml file' %(stylespath, extension) - self.str_stylesheet = s1 - self.str_stylesheetcontent = s2 - self.dom_stylesheet = etree.fromstring(self.str_stylesheet) - self.dom_stylesheetcontent = etree.fromstring(self.str_stylesheetcontent) - self.table_styles = self.extract_table_styles(s2) - - def extract_table_styles(self, styles_str): - root = etree.fromstring(styles_str) - table_styles = {} - auto_styles = root.find( - '{%s}automatic-styles' % (CNSD['office'], )) - for stylenode in auto_styles: - name = stylenode.get('{%s}name' % (CNSD['style'], )) - tablename = name.split('.')[0] - family = stylenode.get('{%s}family' % (CNSD['style'], )) - if name.startswith(TABLESTYLEPREFIX): - tablestyle = table_styles.get(tablename) - if tablestyle is None: - tablestyle = TableStyle() - table_styles[tablename] = tablestyle - if family == 'table': - properties = stylenode.find( - '{%s}table-properties' % (CNSD['style'], )) - property = properties.get('{%s}%s' % (CNSD['fo'], - 'background-color', )) - if property is not None and property != 'none': - tablestyle.backgroundcolor = property - elif family == 'table-cell': - properties = stylenode.find( - '{%s}table-cell-properties' % (CNSD['style'], )) - if properties is not None: - border = self.get_property(properties) - if border is not None: - tablestyle.border = border - return table_styles - - def get_property(self, stylenode): - border = None - for propertyname in TABLEPROPERTYNAMES: - border = stylenode.get('{%s}%s' % (CNSD['fo'], propertyname, )) - if border is not None and border != 'none': - return border - return border - - def add_doc_title(self): - text = self.settings.title - if text: - self.title = text - if not self.found_doc_title: - el = Element('text:p', attrib = { - 'text:style-name': self.rststyle('title'), - }) - el.text = text - self.body_text_element.insert(0, el) - - def rststyle(self, name, parameters=( )): - """ - Returns the style name to use for the given style. - - If `parameters` is given `name` must contain a matching number of ``%`` and - is used as a format expression with `parameters` as the value. - """ - name1 = name % parameters - stylename = self.format_map.get(name1, 'rststyle-%s' % name1) - return stylename - - def generate_content_element(self, root): - return SubElement(root, 'office:text') - - def setup_page(self): - self.setup_paper(self.dom_stylesheet) - if (len(self.header_content) > 0 or len(self.footer_content) > 0 or - self.settings.custom_header or self.settings.custom_footer): - self.add_header_footer(self.dom_stylesheet) - new_content = etree.tostring(self.dom_stylesheet) - return new_content - - def setup_paper(self, root_el): - try: - fin = os.popen("paperconf -s 2> /dev/null") - w, h = map(float, fin.read().split()) - fin.close() - except: - w, h = 612, 792 # default to Letter - def walk(el): - if el.tag == "{%s}page-layout-properties" % SNSD["style"] and \ - not el.attrib.has_key("{%s}page-width" % SNSD["fo"]): - el.attrib["{%s}page-width" % SNSD["fo"]] = "%.3fpt" % w - el.attrib["{%s}page-height" % SNSD["fo"]] = "%.3fpt" % h - el.attrib["{%s}margin-left" % SNSD["fo"]] = \ - el.attrib["{%s}margin-right" % SNSD["fo"]] = \ - "%.3fpt" % (.1 * w) - el.attrib["{%s}margin-top" % SNSD["fo"]] = \ - el.attrib["{%s}margin-bottom" % SNSD["fo"]] = \ - "%.3fpt" % (.1 * h) - else: - for subel in el.getchildren(): walk(subel) - walk(root_el) - - def add_header_footer(self, root_el): - automatic_styles = root_el.find( - '{%s}automatic-styles' % SNSD['office']) - path = '{%s}master-styles' % (NAME_SPACE_1, ) - master_el = root_el.find(path) - if master_el is None: - return - path = '{%s}master-page' % (SNSD['style'], ) - master_el = master_el.find(path) - if master_el is None: - return - el1 = master_el - if self.header_content or self.settings.custom_header: - if WhichElementTree == 'lxml': - el2 = SubElement(el1, 'style:header', nsdict=SNSD) - else: - el2 = SubElement(el1, 'style:header', - attrib=STYLES_NAMESPACE_ATTRIB, - nsdict=STYLES_NAMESPACE_DICT, - ) - for el in self.header_content: - attrkey = add_ns('text:style-name', nsdict=SNSD) - el.attrib[attrkey] = self.rststyle('header') - el2.append(el) - if self.settings.custom_header: - elcustom = self.create_custom_headfoot(el2, - self.settings.custom_header, 'header', automatic_styles) - if self.footer_content or self.settings.custom_footer: - if WhichElementTree == 'lxml': - el2 = SubElement(el1, 'style:footer', nsdict=SNSD) - else: - el2 = SubElement(el1, 'style:footer', - attrib=STYLES_NAMESPACE_ATTRIB, - nsdict=STYLES_NAMESPACE_DICT, - ) - for el in self.footer_content: - attrkey = add_ns('text:style-name', nsdict=SNSD) - el.attrib[attrkey] = self.rststyle('footer') - el2.append(el) - if self.settings.custom_footer: - elcustom = self.create_custom_headfoot(el2, - self.settings.custom_footer, 'footer', automatic_styles) - - code_none, code_field, code_text = range(3) - field_pat = re.compile(r'%(..?)%') - - def create_custom_headfoot(self, parent, text, style_name, automatic_styles): - parent = SubElement(parent, 'text:p', attrib={ - 'text:style-name': self.rststyle(style_name), - }) - current_element = None - field_iter = self.split_field_specifiers_iter(text) - for item in field_iter: - if item[0] == ODFTranslator.code_field: - if item[1] not in ('p', 'P', - 't1', 't2', 't3', 't4', - 'd1', 'd2', 'd3', 'd4', 'd5', - 's', 't', 'a'): - msg = 'bad field spec: %%%s%%' % (item[1], ) - raise RuntimeError, msg - el1 = self.make_field_element(parent, - item[1], style_name, automatic_styles) - if el1 is None: - msg = 'bad field spec: %%%s%%' % (item[1], ) - raise RuntimeError, msg - else: - current_element = el1 - else: - if current_element is None: - parent.text = item[1] - else: - current_element.tail = item[1] - - def make_field_element(self, parent, text, style_name, automatic_styles): - if text == 'p': - el1 = SubElement(parent, 'text:page-number', attrib={ - #'text:style-name': self.rststyle(style_name), - 'text:select-page': 'current', - }) - elif text == 'P': - el1 = SubElement(parent, 'text:page-count', attrib={ - #'text:style-name': self.rststyle(style_name), - }) - elif text == 't1': - self.style_index += 1 - el1 = SubElement(parent, 'text:time', attrib={ - 'text:style-name': self.rststyle(style_name), - 'text:fixed': 'true', - 'style:data-style-name': 'rst-time-style-%d' % self.style_index, - }) - el2 = SubElement(automatic_styles, 'number:time-style', attrib={ - 'style:name': 'rst-time-style-%d' % self.style_index, - 'xmlns:number': SNSD['number'], - 'xmlns:style': SNSD['style'], - }) - el3 = SubElement(el2, 'number:hours', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = ':' - el3 = SubElement(el2, 'number:minutes', attrib={ - 'number:style': 'long', - }) - elif text == 't2': - self.style_index += 1 - el1 = SubElement(parent, 'text:time', attrib={ - 'text:style-name': self.rststyle(style_name), - 'text:fixed': 'true', - 'style:data-style-name': 'rst-time-style-%d' % self.style_index, - }) - el2 = SubElement(automatic_styles, 'number:time-style', attrib={ - 'style:name': 'rst-time-style-%d' % self.style_index, - 'xmlns:number': SNSD['number'], - 'xmlns:style': SNSD['style'], - }) - el3 = SubElement(el2, 'number:hours', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = ':' - el3 = SubElement(el2, 'number:minutes', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = ':' - el3 = SubElement(el2, 'number:seconds', attrib={ - 'number:style': 'long', - }) - elif text == 't3': - self.style_index += 1 - el1 = SubElement(parent, 'text:time', attrib={ - 'text:style-name': self.rststyle(style_name), - 'text:fixed': 'true', - 'style:data-style-name': 'rst-time-style-%d' % self.style_index, - }) - el2 = SubElement(automatic_styles, 'number:time-style', attrib={ - 'style:name': 'rst-time-style-%d' % self.style_index, - 'xmlns:number': SNSD['number'], - 'xmlns:style': SNSD['style'], - }) - el3 = SubElement(el2, 'number:hours', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = ':' - el3 = SubElement(el2, 'number:minutes', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = ' ' - el3 = SubElement(el2, 'number:am-pm') - elif text == 't4': - self.style_index += 1 - el1 = SubElement(parent, 'text:time', attrib={ - 'text:style-name': self.rststyle(style_name), - 'text:fixed': 'true', - 'style:data-style-name': 'rst-time-style-%d' % self.style_index, - }) - el2 = SubElement(automatic_styles, 'number:time-style', attrib={ - 'style:name': 'rst-time-style-%d' % self.style_index, - 'xmlns:number': SNSD['number'], - 'xmlns:style': SNSD['style'], - }) - el3 = SubElement(el2, 'number:hours', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = ':' - el3 = SubElement(el2, 'number:minutes', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = ':' - el3 = SubElement(el2, 'number:seconds', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = ' ' - el3 = SubElement(el2, 'number:am-pm') - elif text == 'd1': - self.style_index += 1 - el1 = SubElement(parent, 'text:date', attrib={ - 'text:style-name': self.rststyle(style_name), - 'style:data-style-name': 'rst-date-style-%d' % self.style_index, - }) - el2 = SubElement(automatic_styles, 'number:date-style', attrib={ - 'style:name': 'rst-date-style-%d' % self.style_index, - 'number:automatic-order': 'true', - 'xmlns:number': SNSD['number'], - 'xmlns:style': SNSD['style'], - }) - el3 = SubElement(el2, 'number:month', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = '/' - el3 = SubElement(el2, 'number:day', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = '/' - el3 = SubElement(el2, 'number:year') - elif text == 'd2': - self.style_index += 1 - el1 = SubElement(parent, 'text:date', attrib={ - 'text:style-name': self.rststyle(style_name), - 'style:data-style-name': 'rst-date-style-%d' % self.style_index, - }) - el2 = SubElement(automatic_styles, 'number:date-style', attrib={ - 'style:name': 'rst-date-style-%d' % self.style_index, - 'number:automatic-order': 'true', - 'xmlns:number': SNSD['number'], - 'xmlns:style': SNSD['style'], - }) - el3 = SubElement(el2, 'number:month', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = '/' - el3 = SubElement(el2, 'number:day', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = '/' - el3 = SubElement(el2, 'number:year', attrib={ - 'number:style': 'long', - }) - elif text == 'd3': - self.style_index += 1 - el1 = SubElement(parent, 'text:date', attrib={ - 'text:style-name': self.rststyle(style_name), - 'style:data-style-name': 'rst-date-style-%d' % self.style_index, - }) - el2 = SubElement(automatic_styles, 'number:date-style', attrib={ - 'style:name': 'rst-date-style-%d' % self.style_index, - 'number:automatic-order': 'true', - 'xmlns:number': SNSD['number'], - 'xmlns:style': SNSD['style'], - }) - el3 = SubElement(el2, 'number:month', attrib={ - 'number:textual': 'true', - }) - el3 = SubElement(el2, 'number:text') - el3.text = ' ' - el3 = SubElement(el2, 'number:day', attrib={ - }) - el3 = SubElement(el2, 'number:text') - el3.text = ', ' - el3 = SubElement(el2, 'number:year', attrib={ - 'number:style': 'long', - }) - elif text == 'd4': - self.style_index += 1 - el1 = SubElement(parent, 'text:date', attrib={ - 'text:style-name': self.rststyle(style_name), - 'style:data-style-name': 'rst-date-style-%d' % self.style_index, - }) - el2 = SubElement(automatic_styles, 'number:date-style', attrib={ - 'style:name': 'rst-date-style-%d' % self.style_index, - 'number:automatic-order': 'true', - 'xmlns:number': SNSD['number'], - 'xmlns:style': SNSD['style'], - }) - el3 = SubElement(el2, 'number:month', attrib={ - 'number:textual': 'true', - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = ' ' - el3 = SubElement(el2, 'number:day', attrib={ - }) - el3 = SubElement(el2, 'number:text') - el3.text = ', ' - el3 = SubElement(el2, 'number:year', attrib={ - 'number:style': 'long', - }) - elif text == 'd5': - self.style_index += 1 - el1 = SubElement(parent, 'text:date', attrib={ - 'text:style-name': self.rststyle(style_name), - 'style:data-style-name': 'rst-date-style-%d' % self.style_index, - }) - el2 = SubElement(automatic_styles, 'number:date-style', attrib={ - 'style:name': 'rst-date-style-%d' % self.style_index, - 'xmlns:number': SNSD['number'], - 'xmlns:style': SNSD['style'], - }) - el3 = SubElement(el2, 'number:year', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = '-' - el3 = SubElement(el2, 'number:month', attrib={ - 'number:style': 'long', - }) - el3 = SubElement(el2, 'number:text') - el3.text = '-' - el3 = SubElement(el2, 'number:day', attrib={ - 'number:style': 'long', - }) - elif text == 's': - el1 = SubElement(parent, 'text:subject', attrib={ - 'text:style-name': self.rststyle(style_name), - }) - elif text == 't': - el1 = SubElement(parent, 'text:title', attrib={ - 'text:style-name': self.rststyle(style_name), - }) - elif text == 'a': - el1 = SubElement(parent, 'text:author-name', attrib={ - 'text:fixed': 'false', - }) - else: - el1 = None - return el1 - - def split_field_specifiers_iter(self, text): - pos1 = 0 - pos_end = len(text) - while True: - mo = ODFTranslator.field_pat.search(text, pos1) - if mo: - pos2 = mo.start() - if pos2 > pos1: - yield (ODFTranslator.code_text, text[pos1:pos2]) - yield (ODFTranslator.code_field, mo.group(1)) - pos1 = mo.end() - else: - break - trailing = text[pos1:] - if trailing: - yield (ODFTranslator.code_text, trailing) - - - def astext(self): - root = self.content_tree.getroot() - et = etree.ElementTree(root) - s1 = ToString(et) - return s1 - - def content_astext(self): - return self.astext() - - def set_title(self, title): self.title = title - def get_title(self): return self.title - def set_embedded_file_list(self, embedded_file_list): - self.embedded_file_list = embedded_file_list - def get_embedded_file_list(self): return self.embedded_file_list - def get_meta_dict(self): return self.meta_dict - - def process_footnotes(self): - for node, el1 in self.footnote_list: - backrefs = node.attributes.get('backrefs', []) - first = True - for ref in backrefs: - el2 = self.footnote_ref_dict.get(ref) - if el2 is not None: - if first: - first = False - el3 = copy.deepcopy(el1) - el2.append(el3) - else: - children = el2.getchildren() - if len(children) > 0: # and 'id' in el2.attrib: - child = children[0] - ref1 = child.text - attribkey = add_ns('text:id', nsdict=SNSD) - id1 = el2.get(attribkey, 'footnote-error') - if id1 is None: - id1 = '' - tag = add_ns('text:note-ref', nsdict=SNSD) - el2.tag = tag - if self.settings.endnotes_end_doc: - note_class = 'endnote' - else: - note_class = 'footnote' - el2.attrib.clear() - attribkey = add_ns('text:note-class', nsdict=SNSD) - el2.attrib[attribkey] = note_class - attribkey = add_ns('text:ref-name', nsdict=SNSD) - el2.attrib[attribkey] = id1 - attribkey = add_ns('text:reference-format', nsdict=SNSD) - el2.attrib[attribkey] = 'page' - el2.text = ref1 - - # - # Utility methods - - def append_child(self, tag, attrib=None, parent=None): - if parent is None: - parent = self.current_element - if attrib is None: - el = SubElement(parent, tag) - else: - el = SubElement(parent, tag, attrib) - return el - - def append_p(self, style, text=None): - result = self.append_child('text:p', attrib={ - 'text:style-name': self.rststyle(style)}) - self.append_pending_ids(result) - if text is not None: - result.text = text - return result - - def append_pending_ids(self, el): - if self.settings.create_links: - for id in self.pending_ids: - SubElement(el, 'text:reference-mark', attrib={ - 'text:name': id}) - self.pending_ids = [ ] - - def set_current_element(self, el): - self.current_element = el - - def set_to_parent(self): - self.current_element = self.current_element.getparent() - - def generate_labeled_block(self, node, label): - label = '%s:' % (self.language.labels[label], ) - el = self.append_p('textbody') - el1 = SubElement(el, 'text:span', - attrib={'text:style-name': self.rststyle('strong')}) - el1.text = label - el = self.append_p('blockindent') - return el - - def generate_labeled_line(self, node, label): - label = '%s:' % (self.language.labels[label], ) - el = self.append_p('textbody') - el1 = SubElement(el, 'text:span', - attrib={'text:style-name': self.rststyle('strong')}) - el1.text = label - el1.tail = node.astext() - return el - - def encode(self, text): - text = text.replace(u'\u00a0', " ") - return text - - # - # Visitor functions - # - # In alphabetic order, more or less. - # See docutils.docutils.nodes.node_class_names. - # - - def dispatch_visit(self, node): - """Override to catch basic attributes which many nodes have.""" - self.handle_basic_atts(node) - nodes.GenericNodeVisitor.dispatch_visit(self, node) - - def handle_basic_atts(self, node): - if isinstance(node, nodes.Element) and node['ids']: - self.pending_ids += node['ids'] - - def default_visit(self, node): - self.document.reporter.warning('missing visit_%s' % (node.tagname, )) - - def default_departure(self, node): - self.document.reporter.warning('missing depart_%s' % (node.tagname, )) - -## def add_text_to_element(self, text): -## # Are we in a citation. If so, add text to current element, not -## # to children. -## # Are we in mixed content? If so, add the text to the -## # etree tail of the previous sibling element. -## if not self.in_citation and len(self.current_element.getchildren()) > 0: -## if self.current_element.getchildren()[-1].tail: -## self.current_element.getchildren()[-1].tail += text -## else: -## self.current_element.getchildren()[-1].tail = text -## else: -## if self.current_element.text: -## self.current_element.text += text -## else: -## self.current_element.text = text -## -## def visit_Text(self, node): -## # Skip nodes whose text has been processed in parent nodes. -## if isinstance(node.parent, docutils.nodes.literal_block): -## return -## text = node.astext() -## self.add_text_to_element(text) - - def visit_Text(self, node): - # Skip nodes whose text has been processed in parent nodes. - if isinstance(node.parent, docutils.nodes.literal_block): - return - text = node.astext() - # Are we in mixed content? If so, add the text to the - # etree tail of the previous sibling element. - if len(self.current_element.getchildren()) > 0: - if self.current_element.getchildren()[-1].tail: - self.current_element.getchildren()[-1].tail += text - else: - self.current_element.getchildren()[-1].tail = text - else: - if self.current_element.text: - self.current_element.text += text - else: - self.current_element.text = text - - def depart_Text(self, node): - pass - - # - # Pre-defined fields - # - - def visit_address(self, node): - el = self.generate_labeled_block(node, 'address') - self.set_current_element(el) - - def depart_address(self, node): - self.set_to_parent() - - def visit_author(self, node): - if isinstance(node.parent, nodes.authors): - el = self.append_p('blockindent') - else: - el = self.generate_labeled_block(node, 'author') - self.set_current_element(el) - - def depart_author(self, node): - self.set_to_parent() - - def visit_authors(self, node): - label = '%s:' % (self.language.labels['authors'], ) - el = self.append_p('textbody') - el1 = SubElement(el, 'text:span', - attrib={'text:style-name': self.rststyle('strong')}) - el1.text = label - - def depart_authors(self, node): - pass - - def visit_contact(self, node): - el = self.generate_labeled_block(node, 'contact') - self.set_current_element(el) - - def depart_contact(self, node): - self.set_to_parent() - - def visit_copyright(self, node): - el = self.generate_labeled_block(node, 'copyright') - self.set_current_element(el) - - def depart_copyright(self, node): - self.set_to_parent() - - def visit_date(self, node): - self.generate_labeled_line(node, 'date') - - def depart_date(self, node): - pass - - def visit_organization(self, node): - el = self.generate_labeled_block(node, 'organization') - self.set_current_element(el) - - def depart_organization(self, node): - self.set_to_parent() - - def visit_status(self, node): - el = self.generate_labeled_block(node, 'status') - self.set_current_element(el) - - def depart_status(self, node): - self.set_to_parent() - - def visit_revision(self, node): - el = self.generate_labeled_line(node, 'revision') - - def depart_revision(self, node): - pass - - def visit_version(self, node): - el = self.generate_labeled_line(node, 'version') - #self.set_current_element(el) - - def depart_version(self, node): - #self.set_to_parent() - pass - - def visit_attribution(self, node): - el = self.append_p('attribution', node.astext()) - - def depart_attribution(self, node): - pass - - def visit_block_quote(self, node): - if 'epigraph' in node.attributes['classes']: - self.paragraph_style_stack.append(self.rststyle('epigraph')) - self.blockstyle = self.rststyle('epigraph') - elif 'highlights' in node.attributes['classes']: - self.paragraph_style_stack.append(self.rststyle('highlights')) - self.blockstyle = self.rststyle('highlights') - else: - self.paragraph_style_stack.append(self.rststyle('blockquote')) - self.blockstyle = self.rststyle('blockquote') - self.line_indent_level += 1 - - def depart_block_quote(self, node): - self.paragraph_style_stack.pop() - self.blockstyle = '' - self.line_indent_level -= 1 - - def visit_bullet_list(self, node): - self.list_level +=1 - if self.in_table_of_contents: - if self.settings.generate_oowriter_toc: - pass - else: - if node.has_key('classes') and \ - 'auto-toc' in node.attributes['classes']: - el = SubElement(self.current_element, 'text:list', attrib={ - 'text:style-name': self.rststyle('tocenumlist'), - }) - self.list_style_stack.append(self.rststyle('enumitem')) - else: - el = SubElement(self.current_element, 'text:list', attrib={ - 'text:style-name': self.rststyle('tocbulletlist'), - }) - self.list_style_stack.append(self.rststyle('bulletitem')) - self.set_current_element(el) - else: - if self.blockstyle == self.rststyle('blockquote'): - el = SubElement(self.current_element, 'text:list', attrib={ - 'text:style-name': self.rststyle('blockquote-bulletlist'), - }) - self.list_style_stack.append( - self.rststyle('blockquote-bulletitem')) - elif self.blockstyle == self.rststyle('highlights'): - el = SubElement(self.current_element, 'text:list', attrib={ - 'text:style-name': self.rststyle('highlights-bulletlist'), - }) - self.list_style_stack.append( - self.rststyle('highlights-bulletitem')) - elif self.blockstyle == self.rststyle('epigraph'): - el = SubElement(self.current_element, 'text:list', attrib={ - 'text:style-name': self.rststyle('epigraph-bulletlist'), - }) - self.list_style_stack.append( - self.rststyle('epigraph-bulletitem')) - else: - el = SubElement(self.current_element, 'text:list', attrib={ - 'text:style-name': self.rststyle('bulletlist'), - }) - self.list_style_stack.append(self.rststyle('bulletitem')) - self.set_current_element(el) - - def depart_bullet_list(self, node): - if self.in_table_of_contents: - if self.settings.generate_oowriter_toc: - pass - else: - self.set_to_parent() - self.list_style_stack.pop() - else: - self.set_to_parent() - self.list_style_stack.pop() - self.list_level -=1 - - def visit_caption(self, node): - raise nodes.SkipChildren() - pass - - def depart_caption(self, node): - pass - - def visit_comment(self, node): - el = self.append_p('textbody') - el1 = SubElement(el, 'office:annotation', attrib={}) - el2 = SubElement(el1, 'dc:creator', attrib={}) - s1 = os.environ.get('USER', '') - el2.text = s1 - el2 = SubElement(el1, 'text:p', attrib={}) - el2.text = node.astext() - - def depart_comment(self, node): - pass - - def visit_compound(self, node): - # The compound directive currently receives no special treatment. - pass - - def depart_compound(self, node): - pass - - def visit_container(self, node): - styles = node.attributes.get('classes', ()) - if len(styles) > 0: - self.paragraph_style_stack.append(self.rststyle(styles[0])) - - def depart_container(self, node): - styles = node.attributes.get('classes', ()) - if len(styles) > 0: - self.paragraph_style_stack.pop() - - def visit_decoration(self, node): - pass - - def depart_decoration(self, node): - pass - - def visit_definition_list(self, node): - self.def_list_level +=1 - if self.list_level > 5: - raise RuntimeError( - 'max definition list nesting level exceeded') - - def depart_definition_list(self, node): - self.def_list_level -=1 - - def visit_definition_list_item(self, node): - pass - - def depart_definition_list_item(self, node): - pass - - def visit_term(self, node): - el = self.append_p('deflist-term-%d' % self.def_list_level) - el.text = node.astext() - self.set_current_element(el) - raise nodes.SkipChildren() - - def depart_term(self, node): - self.set_to_parent() - - def visit_definition(self, node): - self.paragraph_style_stack.append( - self.rststyle('deflist-def-%d' % self.def_list_level)) - self.bumped_list_level_stack.append(ListLevel(1)) - - def depart_definition(self, node): - self.paragraph_style_stack.pop() - self.bumped_list_level_stack.pop() - - def visit_classifier(self, node): - els = self.current_element.getchildren() - if len(els) > 0: - el = els[-1] - el1 = SubElement(el, 'text:span', - attrib={'text:style-name': self.rststyle('emphasis') - }) - el1.text = ' (%s)' % (node.astext(), ) - - def depart_classifier(self, node): - pass - - def visit_document(self, node): - pass - - def depart_document(self, node): - self.process_footnotes() - - def visit_docinfo(self, node): - self.section_level += 1 - self.section_count += 1 - if self.settings.create_sections: - el = self.append_child('text:section', attrib={ - 'text:name': 'Section%d' % self.section_count, - 'text:style-name': 'Sect%d' % self.section_level, - }) - self.set_current_element(el) - - def depart_docinfo(self, node): - self.section_level -= 1 - if self.settings.create_sections: - self.set_to_parent() - - def visit_emphasis(self, node): - el = SubElement(self.current_element, 'text:span', - attrib={'text:style-name': self.rststyle('emphasis')}) - self.set_current_element(el) - - def depart_emphasis(self, node): - self.set_to_parent() - - def visit_enumerated_list(self, node): - el1 = self.current_element - if self.blockstyle == self.rststyle('blockquote'): - el2 = SubElement(el1, 'text:list', attrib={ - 'text:style-name': self.rststyle('blockquote-enumlist'), - }) - self.list_style_stack.append(self.rststyle('blockquote-enumitem')) - elif self.blockstyle == self.rststyle('highlights'): - el2 = SubElement(el1, 'text:list', attrib={ - 'text:style-name': self.rststyle('highlights-enumlist'), - }) - self.list_style_stack.append(self.rststyle('highlights-enumitem')) - elif self.blockstyle == self.rststyle('epigraph'): - el2 = SubElement(el1, 'text:list', attrib={ - 'text:style-name': self.rststyle('epigraph-enumlist'), - }) - self.list_style_stack.append(self.rststyle('epigraph-enumitem')) - else: - liststylename = 'enumlist-%s' % (node.get('enumtype', 'arabic'), ) - el2 = SubElement(el1, 'text:list', attrib={ - 'text:style-name': self.rststyle(liststylename), - }) - self.list_style_stack.append(self.rststyle('enumitem')) - self.set_current_element(el2) - - def depart_enumerated_list(self, node): - self.set_to_parent() - self.list_style_stack.pop() - - def visit_list_item(self, node): - # If we are in a "bumped" list level, then wrap this - # list in an outer lists in order to increase the - # indentation level. - if self.in_table_of_contents: - if self.settings.generate_oowriter_toc: - self.paragraph_style_stack.append( - self.rststyle('contents-%d' % (self.list_level, ))) - else: - el1 = self.append_child('text:list-item') - self.set_current_element(el1) - else: - el1 = self.append_child('text:list-item') - el3 = el1 - if len(self.bumped_list_level_stack) > 0: - level_obj = self.bumped_list_level_stack[-1] - if level_obj.get_sibling(): - level_obj.set_nested(False) - for level_obj1 in self.bumped_list_level_stack: - for idx in range(level_obj1.get_level()): - el2 = self.append_child('text:list', parent=el3) - el3 = self.append_child( - 'text:list-item', parent=el2) - self.paragraph_style_stack.append(self.list_style_stack[-1]) - self.set_current_element(el3) - - def depart_list_item(self, node): - if self.in_table_of_contents: - if self.settings.generate_oowriter_toc: - self.paragraph_style_stack.pop() - else: - self.set_to_parent() - else: - if len(self.bumped_list_level_stack) > 0: - level_obj = self.bumped_list_level_stack[-1] - if level_obj.get_sibling(): - level_obj.set_nested(True) - for level_obj1 in self.bumped_list_level_stack: - for idx in range(level_obj1.get_level()): - self.set_to_parent() - self.set_to_parent() - self.paragraph_style_stack.pop() - self.set_to_parent() - - def visit_header(self, node): - self.in_header = True - - def depart_header(self, node): - self.in_header = False - - def visit_footer(self, node): - self.in_footer = True - - def depart_footer(self, node): - self.in_footer = False - - def visit_field(self, node): - pass - - def depart_field(self, node): - pass - - def visit_field_list(self, node): - pass - - def depart_field_list(self, node): - pass - - def visit_field_name(self, node): - el = self.append_p('textbody') - el1 = SubElement(el, 'text:span', - attrib={'text:style-name': self.rststyle('strong')}) - el1.text = node.astext() - - def depart_field_name(self, node): - pass - - def visit_field_body(self, node): - self.paragraph_style_stack.append(self.rststyle('blockindent')) - - def depart_field_body(self, node): - self.paragraph_style_stack.pop() - - def visit_figure(self, node): - pass - - def depart_figure(self, node): - pass - - def visit_footnote(self, node): - self.footnote_level += 1 - self.save_footnote_current = self.current_element - el1 = Element('text:note-body') - self.current_element = el1 - self.footnote_list.append((node, el1)) - if isinstance(node, docutils.nodes.citation): - self.paragraph_style_stack.append(self.rststyle('citation')) - else: - self.paragraph_style_stack.append(self.rststyle('footnote')) - - def depart_footnote(self, node): - self.paragraph_style_stack.pop() - self.current_element = self.save_footnote_current - self.footnote_level -= 1 - - footnote_chars = [ - '*', '**', '***', - '++', '+++', - '##', '###', - '@@', '@@@', - ] - - def visit_footnote_reference(self, node): - if self.footnote_level <= 0: - id = node.attributes['ids'][0] - refid = node.attributes.get('refid') - if refid is None: - refid = '' - if self.settings.endnotes_end_doc: - note_class = 'endnote' - else: - note_class = 'footnote' - el1 = self.append_child('text:note', attrib={ - 'text:id': '%s' % (refid, ), - 'text:note-class': note_class, - }) - note_auto = str(node.attributes.get('auto', 1)) - if isinstance(node, docutils.nodes.citation_reference): - citation = '[%s]' % node.astext() - el2 = SubElement(el1, 'text:note-citation', attrib={ - 'text:label': citation, - }) - el2.text = citation - elif note_auto == '1': - el2 = SubElement(el1, 'text:note-citation', attrib={ - 'text:label': node.astext(), - }) - el2.text = node.astext() - elif note_auto == '*': - if self.footnote_chars_idx >= len( - ODFTranslator.footnote_chars): - self.footnote_chars_idx = 0 - footnote_char = ODFTranslator.footnote_chars[ - self.footnote_chars_idx] - self.footnote_chars_idx += 1 - el2 = SubElement(el1, 'text:note-citation', attrib={ - 'text:label': footnote_char, - }) - el2.text = footnote_char - self.footnote_ref_dict[id] = el1 - raise nodes.SkipChildren() - - def depart_footnote_reference(self, node): - pass - - def visit_citation(self, node): - self.in_citation = True - for id in node.attributes['ids']: - self.citation_id = id - break - self.paragraph_style_stack.append(self.rststyle('blockindent')) - self.bumped_list_level_stack.append(ListLevel(1)) - - def depart_citation(self, node): - self.citation_id = None - self.paragraph_style_stack.pop() - self.bumped_list_level_stack.pop() - self.in_citation = False - - def visit_citation_reference(self, node): - if self.settings.create_links: - id = node.attributes['refid'] - el = self.append_child('text:reference-ref', attrib={ - 'text:ref-name': '%s' % (id, ), - 'text:reference-format': 'text', - }) - el.text = '[' - self.set_current_element(el) - elif self.current_element.text is None: - self.current_element.text = '[' - else: - self.current_element.text += '[' - - def depart_citation_reference(self, node): - self.current_element.text += ']' - if self.settings.create_links: - self.set_to_parent() - - def visit_label(self, node): - if isinstance(node.parent, docutils.nodes.footnote): - raise nodes.SkipChildren() - elif self.citation_id is not None: - el = self.append_p('textbody') - self.set_current_element(el) - el.text = '[' - if self.settings.create_links: - el1 = self.append_child('text:reference-mark-start', attrib={ - 'text:name': '%s' % (self.citation_id, ), - }) - - def depart_label(self, node): - if isinstance(node.parent, docutils.nodes.footnote): - pass - elif self.citation_id is not None: - self.current_element.text += ']' - if self.settings.create_links: - el = self.append_child('text:reference-mark-end', attrib={ - 'text:name': '%s' % (self.citation_id, ), - }) - self.set_to_parent() - - def visit_generated(self, node): - pass - - def depart_generated(self, node): - pass - - def check_file_exists(self, path): - if os.path.exists(path): - return 1 - else: - return 0 - - def visit_image(self, node): - # Capture the image file. - if 'uri' in node.attributes: - source = node.attributes['uri'] - if not source.startswith('http:'): - if not source.startswith(os.sep): - docsource, line = utils.get_source_line(node) - if docsource: - dirname = os.path.dirname(docsource) - if dirname: - source = '%s%s%s' % (dirname, os.sep, source, ) - if not self.check_file_exists(source): - self.document.reporter.warning( - 'Cannot find image file %s.' % (source, )) - return - else: - return - if source in self.image_dict: - filename, destination = self.image_dict[source] - else: - self.image_count += 1 - filename = os.path.split(source)[1] - destination = 'Pictures/1%08x%s' % (self.image_count, filename, ) - if source.startswith('http:'): - try: - imgfile = urllib2.urlopen(source) - content = imgfile.read() - imgfile.close() - imgfile2 = tempfile.NamedTemporaryFile('wb', delete=False) - imgfile2.write(content) - imgfile2.close() - imgfilename = imgfile2.name - source = imgfilename - except urllib2.HTTPError, e: - self.document.reporter.warning( - "Can't open image url %s." % (source, )) - spec = (source, destination,) - else: - spec = (os.path.abspath(source), destination,) - self.embedded_file_list.append(spec) - self.image_dict[source] = (source, destination,) - # Is this a figure (containing an image) or just a plain image? - if self.in_paragraph: - el1 = self.current_element - else: - el1 = SubElement(self.current_element, 'text:p', - attrib={'text:style-name': self.rststyle('textbody')}) - el2 = el1 - if isinstance(node.parent, docutils.nodes.figure): - el3, el4, el5, caption = self.generate_figure(node, source, - destination, el2) - attrib = {} - el6, width = self.generate_image(node, source, destination, - el5, attrib) - if caption is not None: - el6.tail = caption - else: #if isinstance(node.parent, docutils.nodes.image): - el3 = self.generate_image(node, source, destination, el2) - - def depart_image(self, node): - pass - - def get_image_width_height(self, node, attr): - size = None - if attr in node.attributes: - size = node.attributes[attr] - unit = size[-2:] - if unit.isalpha(): - size = size[:-2] - else: - unit = 'px' - try: - size = float(size) - except ValueError, e: - self.document.reporter.warning( - 'Invalid %s for image: "%s"' % ( - attr, node.attributes[attr])) - size = [size, unit] - return size - - def get_image_scale(self, node): - if 'scale' in node.attributes: - try: - scale = int(node.attributes['scale']) - if scale < 1: # or scale > 100: - self.document.reporter.warning( - 'scale out of range (%s), using 1.' % (scale, )) - scale = 1 - scale = scale * 0.01 - except ValueError, e: - self.document.reporter.warning( - 'Invalid scale for image: "%s"' % ( - node.attributes['scale'], )) - else: - scale = 1.0 - return scale - - def get_image_scaled_width_height(self, node, source): - scale = self.get_image_scale(node) - width = self.get_image_width_height(node, 'width') - height = self.get_image_width_height(node, 'height') - - dpi = (72, 72) - if PIL is not None and source in self.image_dict: - filename, destination = self.image_dict[source] - imageobj = PIL.Image.open(filename, 'r') - dpi = imageobj.info.get('dpi', dpi) - # dpi information can be (xdpi, ydpi) or xydpi - try: iter(dpi) - except: dpi = (dpi, dpi) - else: - imageobj = None - - if width is None or height is None: - if imageobj is None: - raise RuntimeError( - 'image size not fully specified and PIL not installed') - if width is None: width = [imageobj.size[0], 'px'] - if height is None: height = [imageobj.size[1], 'px'] - - width[0] *= scale - height[0] *= scale - if width[1] == 'px': width = [width[0] / dpi[0], 'in'] - if height[1] == 'px': height = [height[0] / dpi[1], 'in'] - - width[0] = str(width[0]) - height[0] = str(height[0]) - return ''.join(width), ''.join(height) - - def generate_figure(self, node, source, destination, current_element): - caption = None - width, height = self.get_image_scaled_width_height(node, source) - for node1 in node.parent.children: - if node1.tagname == 'caption': - caption = node1.astext() - self.image_style_count += 1 - # - # Add the style for the caption. - if caption is not None: - attrib = { - 'style:class': 'extra', - 'style:family': 'paragraph', - 'style:name': 'Caption', - 'style:parent-style-name': 'Standard', - } - el1 = SubElement(self.automatic_styles, 'style:style', - attrib=attrib, nsdict=SNSD) - attrib = { - 'fo:margin-bottom': '0.0835in', - 'fo:margin-top': '0.0835in', - 'text:line-number': '0', - 'text:number-lines': 'false', - } - el2 = SubElement(el1, 'style:paragraph-properties', - attrib=attrib, nsdict=SNSD) - attrib = { - 'fo:font-size': '12pt', - 'fo:font-style': 'italic', - 'style:font-name': 'Times', - 'style:font-name-complex': 'Lucidasans1', - 'style:font-size-asian': '12pt', - 'style:font-size-complex': '12pt', - 'style:font-style-asian': 'italic', - 'style:font-style-complex': 'italic', - } - el2 = SubElement(el1, 'style:text-properties', - attrib=attrib, nsdict=SNSD) - style_name = 'rstframestyle%d' % self.image_style_count - # Add the styles - attrib = { - 'style:name': style_name, - 'style:family': 'graphic', - 'style:parent-style-name': self.rststyle('figureframe'), - } - el1 = SubElement(self.automatic_styles, - 'style:style', attrib=attrib, nsdict=SNSD) - halign = 'center' - valign = 'top' - if 'align' in node.attributes: - align = node.attributes['align'].split() - for val in align: - if val in ('left', 'center', 'right'): - halign = val - elif val in ('top', 'middle', 'bottom'): - valign = val - attrib = {} - wrap = False - classes = node.parent.attributes.get('classes') - if classes and 'wrap' in classes: - wrap = True - if wrap: - attrib['style:wrap'] = 'dynamic' - else: - attrib['style:wrap'] = 'none' - el2 = SubElement(el1, - 'style:graphic-properties', attrib=attrib, nsdict=SNSD) - attrib = { - 'draw:style-name': style_name, - 'draw:name': 'Frame1', - 'text:anchor-type': 'paragraph', - 'draw:z-index': '0', - } - attrib['svg:width'] = width - # dbg - #attrib['svg:height'] = height - el3 = SubElement(current_element, 'draw:frame', attrib=attrib) - attrib = {} - el4 = SubElement(el3, 'draw:text-box', attrib=attrib) - attrib = { - 'text:style-name': self.rststyle('caption'), - } - el5 = SubElement(el4, 'text:p', attrib=attrib) - return el3, el4, el5, caption - - def generate_image(self, node, source, destination, current_element, - frame_attrs=None): - width, height = self.get_image_scaled_width_height(node, source) - self.image_style_count += 1 - style_name = 'rstframestyle%d' % self.image_style_count - # Add the style. - attrib = { - 'style:name': style_name, - 'style:family': 'graphic', - 'style:parent-style-name': self.rststyle('image'), - } - el1 = SubElement(self.automatic_styles, - 'style:style', attrib=attrib, nsdict=SNSD) - halign = None - valign = None - if 'align' in node.attributes: - align = node.attributes['align'].split() - for val in align: - if val in ('left', 'center', 'right'): - halign = val - elif val in ('top', 'middle', 'bottom'): - valign = val - if frame_attrs is None: - attrib = { - 'style:vertical-pos': 'top', - 'style:vertical-rel': 'paragraph', - 'style:horizontal-rel': 'paragraph', - 'style:mirror': 'none', - 'fo:clip': 'rect(0cm 0cm 0cm 0cm)', - 'draw:luminance': '0%', - 'draw:contrast': '0%', - 'draw:red': '0%', - 'draw:green': '0%', - 'draw:blue': '0%', - 'draw:gamma': '100%', - 'draw:color-inversion': 'false', - 'draw:image-opacity': '100%', - 'draw:color-mode': 'standard', - } - else: - attrib = frame_attrs - if halign is not None: - attrib['style:horizontal-pos'] = halign - if valign is not None: - attrib['style:vertical-pos'] = valign - # If there is a classes/wrap directive or we are - # inside a table, add a no-wrap style. - wrap = False - classes = node.attributes.get('classes') - if classes and 'wrap' in classes: - wrap = True - if wrap: - attrib['style:wrap'] = 'dynamic' - else: - attrib['style:wrap'] = 'none' - # If we are inside a table, add a no-wrap style. - if self.is_in_table(node): - attrib['style:wrap'] = 'none' - el2 = SubElement(el1, - 'style:graphic-properties', attrib=attrib, nsdict=SNSD) - # Add the content. - #el = SubElement(current_element, 'text:p', - # attrib={'text:style-name': self.rststyle('textbody')}) - attrib={ - 'draw:style-name': style_name, - 'draw:name': 'graphics2', - 'draw:z-index': '1', - } - if isinstance(node.parent, nodes.TextElement): - attrib['text:anchor-type'] = 'as-char' #vds - else: - attrib['text:anchor-type'] = 'paragraph' - attrib['svg:width'] = width - attrib['svg:height'] = height - el1 = SubElement(current_element, 'draw:frame', attrib=attrib) - el2 = SubElement(el1, 'draw:image', attrib={ - 'xlink:href': '%s' % (destination, ), - 'xlink:type': 'simple', - 'xlink:show': 'embed', - 'xlink:actuate': 'onLoad', - }) - return el1, width - - def is_in_table(self, node): - node1 = node.parent - while node1: - if isinstance(node1, docutils.nodes.entry): - return True - node1 = node1.parent - return False - - def visit_legend(self, node): - if isinstance(node.parent, docutils.nodes.figure): - el1 = self.current_element[-1] - el1 = el1[0][0] - self.current_element = el1 - self.paragraph_style_stack.append(self.rststyle('legend')) - - def depart_legend(self, node): - if isinstance(node.parent, docutils.nodes.figure): - self.paragraph_style_stack.pop() - self.set_to_parent() - self.set_to_parent() - self.set_to_parent() - - def visit_line_block(self, node): - self.line_indent_level += 1 - self.line_block_level += 1 - - def depart_line_block(self, node): - self.line_indent_level -= 1 - self.line_block_level -= 1 - - def visit_line(self, node): - style = 'lineblock%d' % self.line_indent_level - el1 = SubElement(self.current_element, 'text:p', attrib={ - 'text:style-name': self.rststyle(style), - }) - self.current_element = el1 - - def depart_line(self, node): - self.set_to_parent() - - def visit_literal(self, node): - el = SubElement(self.current_element, 'text:span', - attrib={'text:style-name': self.rststyle('inlineliteral')}) - self.set_current_element(el) - - def depart_literal(self, node): - self.set_to_parent() - - def visit_inline(self, node): - styles = node.attributes.get('classes', ()) - if len(styles) > 0: - inline_style = styles[0] - el = SubElement(self.current_element, 'text:span', - attrib={'text:style-name': self.rststyle(inline_style)}) - self.set_current_element(el) - - def depart_inline(self, node): - self.set_to_parent() - - def _calculate_code_block_padding(self, line): - count = 0 - matchobj = SPACES_PATTERN.match(line) - if matchobj: - pad = matchobj.group() - count = len(pad) - else: - matchobj = TABS_PATTERN.match(line) - if matchobj: - pad = matchobj.group() - count = len(pad) * 8 - return count - - def _add_syntax_highlighting(self, insource, language): - lexer = pygments.lexers.get_lexer_by_name(language, stripall=True) - if language in ('latex', 'tex'): - fmtr = OdtPygmentsLaTeXFormatter(lambda name, parameters=(): - self.rststyle(name, parameters), - escape_function=escape_cdata) - else: - fmtr = OdtPygmentsProgFormatter(lambda name, parameters=(): - self.rststyle(name, parameters), - escape_function=escape_cdata) - outsource = pygments.highlight(insource, lexer, fmtr) - return outsource - - def fill_line(self, line): - line = FILL_PAT1.sub(self.fill_func1, line) - line = FILL_PAT2.sub(self.fill_func2, line) - return line - - def fill_func1(self, matchobj): - spaces = matchobj.group(0) - repl = '' % (len(spaces), ) - return repl - - def fill_func2(self, matchobj): - spaces = matchobj.group(0) - repl = ' ' % (len(spaces) - 1, ) - return repl - - def visit_literal_block(self, node): - if len(self.paragraph_style_stack) > 1: - wrapper1 = '%%s' % ( - self.rststyle('codeblock-indented'), ) - else: - wrapper1 = '%%s' % ( - self.rststyle('codeblock'), ) - source = node.astext() - if (pygments and - self.settings.add_syntax_highlighting - #and - #node.get('hilight', False) - ): - language = node.get('language', 'python') - source = self._add_syntax_highlighting(source, language) - else: - source = escape_cdata(source) - lines = source.split('\n') - # If there is an empty last line, remove it. - if lines[-1] == '': - del lines[-1] - lines1 = [''] - - my_lines = [] - for my_line in lines: - my_line = self.fill_line(my_line) - my_line = my_line.replace(" ", "\n") - my_lines.append(my_line) - my_lines_str = ''.join(my_lines) - my_lines_str2 = wrapper1 % (my_lines_str, ) - lines1.append(my_lines_str2) - lines1.append('') - s1 = ''.join(lines1) - if WhichElementTree != "lxml": - s1 = s1.encode("utf-8") - el1 = etree.fromstring(s1) - children = el1.getchildren() - for child in children: - self.current_element.append(child) - - def depart_literal_block(self, node): - pass - - visit_doctest_block = visit_literal_block - depart_doctest_block = depart_literal_block - - # placeholder for math (see docs/dev/todo.txt) - def visit_math(self, node): - self.document.reporter.warning('"math" role not supported', - base_node=node) - self.visit_literal(node) - - def depart_math(self, node): - self.depart_literal(node) - - def visit_math_block(self, node): - self.document.reporter.warning('"math" directive not supported', - base_node=node) - self.visit_literal_block(node) - - def depart_math_block(self, node): - self.depart_literal_block(node) - - def visit_meta(self, node): - name = node.attributes.get('name') - content = node.attributes.get('content') - if name is not None and content is not None: - self.meta_dict[name] = content - - def depart_meta(self, node): - pass - - def visit_option_list(self, node): - table_name = 'tableoption' - # - # Generate automatic styles - if not self.optiontablestyles_generated: - self.optiontablestyles_generated = True - el = SubElement(self.automatic_styles, 'style:style', attrib={ - 'style:name': self.rststyle(table_name), - 'style:family': 'table'}, nsdict=SNSD) - el1 = SubElement(el, 'style:table-properties', attrib={ - 'style:width': '17.59cm', - 'table:align': 'left', - 'style:shadow': 'none'}, nsdict=SNSD) - el = SubElement(self.automatic_styles, 'style:style', attrib={ - 'style:name': self.rststyle('%s.%%c' % table_name, ( 'A', )), - 'style:family': 'table-column'}, nsdict=SNSD) - el1 = SubElement(el, 'style:table-column-properties', attrib={ - 'style:column-width': '4.999cm'}, nsdict=SNSD) - el = SubElement(self.automatic_styles, 'style:style', attrib={ - 'style:name': self.rststyle('%s.%%c' % table_name, ( 'B', )), - 'style:family': 'table-column'}, nsdict=SNSD) - el1 = SubElement(el, 'style:table-column-properties', attrib={ - 'style:column-width': '12.587cm'}, nsdict=SNSD) - el = SubElement(self.automatic_styles, 'style:style', attrib={ - 'style:name': self.rststyle( - '%s.%%c%%d' % table_name, ( 'A', 1, )), - 'style:family': 'table-cell'}, nsdict=SNSD) - el1 = SubElement(el, 'style:table-cell-properties', attrib={ - 'fo:background-color': 'transparent', - 'fo:padding': '0.097cm', - 'fo:border-left': '0.035cm solid #000000', - 'fo:border-right': 'none', - 'fo:border-top': '0.035cm solid #000000', - 'fo:border-bottom': '0.035cm solid #000000'}, nsdict=SNSD) - el2 = SubElement(el1, 'style:background-image', nsdict=SNSD) - el = SubElement(self.automatic_styles, 'style:style', attrib={ - 'style:name': self.rststyle( - '%s.%%c%%d' % table_name, ( 'B', 1, )), - 'style:family': 'table-cell'}, nsdict=SNSD) - el1 = SubElement(el, 'style:table-cell-properties', attrib={ - 'fo:padding': '0.097cm', - 'fo:border': '0.035cm solid #000000'}, nsdict=SNSD) - el = SubElement(self.automatic_styles, 'style:style', attrib={ - 'style:name': self.rststyle( - '%s.%%c%%d' % table_name, ( 'A', 2, )), - 'style:family': 'table-cell'}, nsdict=SNSD) - el1 = SubElement(el, 'style:table-cell-properties', attrib={ - 'fo:padding': '0.097cm', - 'fo:border-left': '0.035cm solid #000000', - 'fo:border-right': 'none', - 'fo:border-top': 'none', - 'fo:border-bottom': '0.035cm solid #000000'}, nsdict=SNSD) - el = SubElement(self.automatic_styles, 'style:style', attrib={ - 'style:name': self.rststyle( - '%s.%%c%%d' % table_name, ( 'B', 2, )), - 'style:family': 'table-cell'}, nsdict=SNSD) - el1 = SubElement(el, 'style:table-cell-properties', attrib={ - 'fo:padding': '0.097cm', - 'fo:border-left': '0.035cm solid #000000', - 'fo:border-right': '0.035cm solid #000000', - 'fo:border-top': 'none', - 'fo:border-bottom': '0.035cm solid #000000'}, nsdict=SNSD) - # - # Generate table data - el = self.append_child('table:table', attrib={ - 'table:name': self.rststyle(table_name), - 'table:style-name': self.rststyle(table_name), - }) - el1 = SubElement(el, 'table:table-column', attrib={ - 'table:style-name': self.rststyle( - '%s.%%c' % table_name, ( 'A', ))}) - el1 = SubElement(el, 'table:table-column', attrib={ - 'table:style-name': self.rststyle( - '%s.%%c' % table_name, ( 'B', ))}) - el1 = SubElement(el, 'table:table-header-rows') - el2 = SubElement(el1, 'table:table-row') - el3 = SubElement(el2, 'table:table-cell', attrib={ - 'table:style-name': self.rststyle( - '%s.%%c%%d' % table_name, ( 'A', 1, )), - 'office:value-type': 'string'}) - el4 = SubElement(el3, 'text:p', attrib={ - 'text:style-name': 'Table_20_Heading'}) - el4.text= 'Option' - el3 = SubElement(el2, 'table:table-cell', attrib={ - 'table:style-name': self.rststyle( - '%s.%%c%%d' % table_name, ( 'B', 1, )), - 'office:value-type': 'string'}) - el4 = SubElement(el3, 'text:p', attrib={ - 'text:style-name': 'Table_20_Heading'}) - el4.text= 'Description' - self.set_current_element(el) - - def depart_option_list(self, node): - self.set_to_parent() - - def visit_option_list_item(self, node): - el = self.append_child('table:table-row') - self.set_current_element(el) - - def depart_option_list_item(self, node): - self.set_to_parent() - - def visit_option_group(self, node): - el = self.append_child('table:table-cell', attrib={ - 'table:style-name': 'Table%d.A2' % self.table_count, - 'office:value-type': 'string', - }) - self.set_current_element(el) - - def depart_option_group(self, node): - self.set_to_parent() - - def visit_option(self, node): - el = self.append_child('text:p', attrib={ - 'text:style-name': 'Table_20_Contents'}) - el.text = node.astext() - - def depart_option(self, node): - pass - - def visit_option_string(self, node): - pass - - def depart_option_string(self, node): - pass - - def visit_option_argument(self, node): - pass - - def depart_option_argument(self, node): - pass - - def visit_description(self, node): - el = self.append_child('table:table-cell', attrib={ - 'table:style-name': 'Table%d.B2' % self.table_count, - 'office:value-type': 'string', - }) - el1 = SubElement(el, 'text:p', attrib={ - 'text:style-name': 'Table_20_Contents'}) - el1.text = node.astext() - raise nodes.SkipChildren() - - def depart_description(self, node): - pass - - def visit_paragraph(self, node): - self.in_paragraph = True - if self.in_header: - el = self.append_p('header') - elif self.in_footer: - el = self.append_p('footer') - else: - style_name = self.paragraph_style_stack[-1] - el = self.append_child('text:p', - attrib={'text:style-name': style_name}) - self.append_pending_ids(el) - self.set_current_element(el) - - def depart_paragraph(self, node): - self.in_paragraph = False - self.set_to_parent() - if self.in_header: - self.header_content.append( - self.current_element.getchildren()[-1]) - self.current_element.remove( - self.current_element.getchildren()[-1]) - elif self.in_footer: - self.footer_content.append( - self.current_element.getchildren()[-1]) - self.current_element.remove( - self.current_element.getchildren()[-1]) - - def visit_problematic(self, node): - pass - - def depart_problematic(self, node): - pass - - def visit_raw(self, node): - if 'format' in node.attributes: - formats = node.attributes['format'] - formatlist = formats.split() - if 'odt' in formatlist: - rawstr = node.astext() - attrstr = ' '.join(['%s="%s"' % (k, v, ) - for k,v in CONTENT_NAMESPACE_ATTRIB.items()]) - contentstr = '%s' % (attrstr, rawstr, ) - if WhichElementTree != "lxml": - contentstr = contentstr.encode("utf-8") - content = etree.fromstring(contentstr) - elements = content.getchildren() - if len(elements) > 0: - el1 = elements[0] - if self.in_header: - pass - elif self.in_footer: - pass - else: - self.current_element.append(el1) - raise nodes.SkipChildren() - - def depart_raw(self, node): - if self.in_header: - pass - elif self.in_footer: - pass - else: - pass - - def visit_reference(self, node): - text = node.astext() - if self.settings.create_links: - if node.has_key('refuri'): - href = node['refuri'] - if ( self.settings.cloak_email_addresses - and href.startswith('mailto:')): - href = self.cloak_mailto(href) - el = self.append_child('text:a', attrib={ - 'xlink:href': '%s' % href, - 'xlink:type': 'simple', - }) - self.set_current_element(el) - elif node.has_key('refid'): - if self.settings.create_links: - href = node['refid'] - el = self.append_child('text:reference-ref', attrib={ - 'text:ref-name': '%s' % href, - 'text:reference-format': 'text', - }) - else: - self.document.reporter.warning( - 'References must have "refuri" or "refid" attribute.') - if (self.in_table_of_contents and - len(node.children) >= 1 and - isinstance(node.children[0], docutils.nodes.generated)): - node.remove(node.children[0]) - - def depart_reference(self, node): - if self.settings.create_links: - if node.has_key('refuri'): - self.set_to_parent() - - def visit_rubric(self, node): - style_name = self.rststyle('rubric') - classes = node.get('classes') - if classes: - class1 = classes[0] - if class1: - style_name = class1 - el = SubElement(self.current_element, 'text:h', attrib = { - #'text:outline-level': '%d' % section_level, - #'text:style-name': 'Heading_20_%d' % section_level, - 'text:style-name': style_name, - }) - text = node.astext() - el.text = self.encode(text) - - def depart_rubric(self, node): - pass - - def visit_section(self, node, move_ids=1): - self.section_level += 1 - self.section_count += 1 - if self.settings.create_sections: - el = self.append_child('text:section', attrib={ - 'text:name': 'Section%d' % self.section_count, - 'text:style-name': 'Sect%d' % self.section_level, - }) - self.set_current_element(el) - - def depart_section(self, node): - self.section_level -= 1 - if self.settings.create_sections: - self.set_to_parent() - - def visit_strong(self, node): - el = SubElement(self.current_element, 'text:span', - attrib={'text:style-name': self.rststyle('strong')}) - self.set_current_element(el) - - def depart_strong(self, node): - self.set_to_parent() - - def visit_substitution_definition(self, node): - raise nodes.SkipChildren() - - def depart_substitution_definition(self, node): - pass - - def visit_system_message(self, node): - pass - - def depart_system_message(self, node): - pass - - def get_table_style(self, node): - table_style = None - table_name = None - use_predefined_table_style = False - str_classes = node.get('classes') - if str_classes is not None: - for str_class in str_classes: - if str_class.startswith(TABLESTYLEPREFIX): - table_name = str_class - use_predefined_table_style = True - break - if table_name is not None: - table_style = self.table_styles.get(table_name) - if table_style is None: - # If we can't find the table style, issue warning - # and use the default table style. - self.document.reporter.warning( - 'Can\'t find table style "%s". Using default.' % ( - table_name, )) - table_name = TABLENAMEDEFAULT - table_style = self.table_styles.get(table_name) - if table_style is None: - # If we can't find the default table style, issue a warning - # and use a built-in default style. - self.document.reporter.warning( - 'Can\'t find default table style "%s". Using built-in default.' % ( - table_name, )) - table_style = BUILTIN_DEFAULT_TABLE_STYLE - else: - table_name = TABLENAMEDEFAULT - table_style = self.table_styles.get(table_name) - if table_style is None: - # If we can't find the default table style, issue a warning - # and use a built-in default style. - self.document.reporter.warning( - 'Can\'t find default table style "%s". Using built-in default.' % ( - table_name, )) - table_style = BUILTIN_DEFAULT_TABLE_STYLE - return table_style - - def visit_table(self, node): - self.table_count += 1 - table_style = self.get_table_style(node) - table_name = '%s%%d' % TABLESTYLEPREFIX - el1 = SubElement(self.automatic_styles, 'style:style', attrib={ - 'style:name': self.rststyle( - '%s' % table_name, ( self.table_count, )), - 'style:family': 'table', - }, nsdict=SNSD) - if table_style.backgroundcolor is None: - el1_1 = SubElement(el1, 'style:table-properties', attrib={ - #'style:width': '17.59cm', - #'table:align': 'margins', - 'table:align': 'left', - 'fo:margin-top': '0in', - 'fo:margin-bottom': '0.10in', - }, nsdict=SNSD) - else: - el1_1 = SubElement(el1, 'style:table-properties', attrib={ - #'style:width': '17.59cm', - 'table:align': 'margins', - 'fo:margin-top': '0in', - 'fo:margin-bottom': '0.10in', - 'fo:background-color': table_style.backgroundcolor, - }, nsdict=SNSD) - # We use a single cell style for all cells in this table. - # That's probably not correct, but seems to work. - el2 = SubElement(self.automatic_styles, 'style:style', attrib={ - 'style:name': self.rststyle( - '%s.%%c%%d' % table_name, ( self.table_count, 'A', 1, )), - 'style:family': 'table-cell', - }, nsdict=SNSD) - thickness = self.settings.table_border_thickness - if thickness is None: - line_style1 = table_style.border - else: - line_style1 = '0.%03dcm solid #000000' % (thickness, ) - el2_1 = SubElement(el2, 'style:table-cell-properties', attrib={ - 'fo:padding': '0.049cm', - 'fo:border-left': line_style1, - 'fo:border-right': line_style1, - 'fo:border-top': line_style1, - 'fo:border-bottom': line_style1, - }, nsdict=SNSD) - title = None - for child in node.children: - if child.tagname == 'title': - title = child.astext() - break - if title is not None: - el3 = self.append_p('table-title', title) - else: - pass - el4 = SubElement(self.current_element, 'table:table', attrib={ - 'table:name': self.rststyle( - '%s' % table_name, ( self.table_count, )), - 'table:style-name': self.rststyle( - '%s' % table_name, ( self.table_count, )), - }) - self.set_current_element(el4) - self.current_table_style = el1 - self.table_width = 0.0 - - def depart_table(self, node): - attribkey = add_ns('style:width', nsdict=SNSD) - attribval = '%.4fin' % (self.table_width, ) - el1 = self.current_table_style - el2 = el1[0] - el2.attrib[attribkey] = attribval - self.set_to_parent() - - def visit_tgroup(self, node): - self.column_count = ord('A') - 1 - - def depart_tgroup(self, node): - pass - - def visit_colspec(self, node): - self.column_count += 1 - colspec_name = self.rststyle( - '%s%%d.%%s' % TABLESTYLEPREFIX, - (self.table_count, chr(self.column_count), ) - ) - colwidth = node['colwidth'] / 12.0 - el1 = SubElement(self.automatic_styles, 'style:style', attrib={ - 'style:name': colspec_name, - 'style:family': 'table-column', - }, nsdict=SNSD) - el1_1 = SubElement(el1, 'style:table-column-properties', attrib={ - 'style:column-width': '%.4fin' % colwidth - }, - nsdict=SNSD) - el2 = self.append_child('table:table-column', attrib={ - 'table:style-name': colspec_name, - }) - self.table_width += colwidth - - def depart_colspec(self, node): - pass - - def visit_thead(self, node): - el = self.append_child('table:table-header-rows') - self.set_current_element(el) - self.in_thead = True - self.paragraph_style_stack.append('Table_20_Heading') - - def depart_thead(self, node): - self.set_to_parent() - self.in_thead = False - self.paragraph_style_stack.pop() - - def visit_row(self, node): - self.column_count = ord('A') - 1 - el = self.append_child('table:table-row') - self.set_current_element(el) - - def depart_row(self, node): - self.set_to_parent() - - def visit_entry(self, node): - self.column_count += 1 - cellspec_name = self.rststyle( - '%s%%d.%%c%%d' % TABLESTYLEPREFIX, - (self.table_count, 'A', 1, ) - ) - attrib={ - 'table:style-name': cellspec_name, - 'office:value-type': 'string', - } - morecols = node.get('morecols', 0) - if morecols > 0: - attrib['table:number-columns-spanned'] = '%d' % (morecols + 1,) - self.column_count += morecols - morerows = node.get('morerows', 0) - if morerows > 0: - attrib['table:number-rows-spanned'] = '%d' % (morerows + 1,) - el1 = self.append_child('table:table-cell', attrib=attrib) - self.set_current_element(el1) - - def depart_entry(self, node): - self.set_to_parent() - - def visit_tbody(self, node): - pass - - def depart_tbody(self, node): - pass - - def visit_target(self, node): - # - # I don't know how to implement targets in ODF. - # How do we create a target in oowriter? A cross-reference? - if not (node.has_key('refuri') or node.has_key('refid') - or node.has_key('refname')): - pass - else: - pass - - def depart_target(self, node): - pass - - def visit_title(self, node, move_ids=1, title_type='title'): - if isinstance(node.parent, docutils.nodes.section): - section_level = self.section_level - if section_level > 7: - self.document.reporter.warning( - 'Heading/section levels greater than 7 not supported.') - self.document.reporter.warning( - ' Reducing to heading level 7 for heading: "%s"' % ( - node.astext(), )) - section_level = 7 - el1 = self.append_child('text:h', attrib = { - 'text:outline-level': '%d' % section_level, - #'text:style-name': 'Heading_20_%d' % section_level, - 'text:style-name': self.rststyle( - 'heading%d', (section_level, )), - }) - self.append_pending_ids(el1) - self.set_current_element(el1) - elif isinstance(node.parent, docutils.nodes.document): - # text = self.settings.title - #else: - # text = node.astext() - el1 = SubElement(self.current_element, 'text:p', attrib = { - 'text:style-name': self.rststyle(title_type), - }) - self.append_pending_ids(el1) - text = node.astext() - self.title = text - self.found_doc_title = True - self.set_current_element(el1) - - def depart_title(self, node): - if (isinstance(node.parent, docutils.nodes.section) or - isinstance(node.parent, docutils.nodes.document)): - self.set_to_parent() - - def visit_subtitle(self, node, move_ids=1): - self.visit_title(node, move_ids, title_type='subtitle') - - def depart_subtitle(self, node): - self.depart_title(node) - - def visit_title_reference(self, node): - el = self.append_child('text:span', attrib={ - 'text:style-name': self.rststyle('quotation')}) - el.text = self.encode(node.astext()) - raise nodes.SkipChildren() - - def depart_title_reference(self, node): - pass - - def generate_table_of_content_entry_template(self, el1): - for idx in range(1, 11): - el2 = SubElement(el1, - 'text:table-of-content-entry-template', - attrib={ - 'text:outline-level': "%d" % (idx, ), - 'text:style-name': self.rststyle('contents-%d' % (idx, )), - }) - el3 = SubElement(el2, 'text:index-entry-chapter') - el3 = SubElement(el2, 'text:index-entry-text') - el3 = SubElement(el2, 'text:index-entry-tab-stop', attrib={ - 'style:leader-char': ".", - 'style:type': "right", - }) - el3 = SubElement(el2, 'text:index-entry-page-number') - - def find_title_label(self, node, class_type, label_key): - label = '' - title_node = None - for child in node.children: - if isinstance(child, class_type): - title_node = child - break - if title_node is not None: - label = title_node.astext() - else: - label = self.language.labels[label_key] - return label - - def visit_topic(self, node): - if 'classes' in node.attributes: - if 'contents' in node.attributes['classes']: - label = self.find_title_label(node, docutils.nodes.title, - 'contents') - if self.settings.generate_oowriter_toc: - el1 = self.append_child('text:table-of-content', attrib={ - 'text:name': 'Table of Contents1', - 'text:protected': 'true', - 'text:style-name': 'Sect1', - }) - el2 = SubElement(el1, - 'text:table-of-content-source', - attrib={ - 'text:outline-level': '10', - }) - el3 =SubElement(el2, 'text:index-title-template', attrib={ - 'text:style-name': 'Contents_20_Heading', - }) - el3.text = label - self.generate_table_of_content_entry_template(el2) - el4 = SubElement(el1, 'text:index-body') - el5 = SubElement(el4, 'text:index-title') - el6 = SubElement(el5, 'text:p', attrib={ - 'text:style-name': self.rststyle('contents-heading'), - }) - el6.text = label - self.save_current_element = self.current_element - self.table_of_content_index_body = el4 - self.set_current_element(el4) - else: - el = self.append_p('horizontalline') - el = self.append_p('centeredtextbody') - el1 = SubElement(el, 'text:span', - attrib={'text:style-name': self.rststyle('strong')}) - el1.text = label - self.in_table_of_contents = True - elif 'abstract' in node.attributes['classes']: - el = self.append_p('horizontalline') - el = self.append_p('centeredtextbody') - el1 = SubElement(el, 'text:span', - attrib={'text:style-name': self.rststyle('strong')}) - label = self.find_title_label(node, docutils.nodes.title, - 'abstract') - el1.text = label - elif 'dedication' in node.attributes['classes']: - el = self.append_p('horizontalline') - el = self.append_p('centeredtextbody') - el1 = SubElement(el, 'text:span', - attrib={'text:style-name': self.rststyle('strong')}) - label = self.find_title_label(node, docutils.nodes.title, - 'dedication') - el1.text = label - - def depart_topic(self, node): - if 'classes' in node.attributes: - if 'contents' in node.attributes['classes']: - if self.settings.generate_oowriter_toc: - self.update_toc_page_numbers( - self.table_of_content_index_body) - self.set_current_element(self.save_current_element) - else: - el = self.append_p('horizontalline') - self.in_table_of_contents = False - - def update_toc_page_numbers(self, el): - collection = [] - self.update_toc_collect(el, 0, collection) - self.update_toc_add_numbers(collection) - - def update_toc_collect(self, el, level, collection): - collection.append((level, el)) - level += 1 - for child_el in el.getchildren(): - if child_el.tag != 'text:index-body': - self.update_toc_collect(child_el, level, collection) - - def update_toc_add_numbers(self, collection): - for level, el1 in collection: - if (el1.tag == 'text:p' and - el1.text != 'Table of Contents'): - el2 = SubElement(el1, 'text:tab') - el2.tail = '9999' - - - def visit_transition(self, node): - el = self.append_p('horizontalline') - - def depart_transition(self, node): - pass - - # - # Admonitions - # - def visit_warning(self, node): - self.generate_admonition(node, 'warning') - - def depart_warning(self, node): - self.paragraph_style_stack.pop() - - def visit_attention(self, node): - self.generate_admonition(node, 'attention') - - depart_attention = depart_warning - - def visit_caution(self, node): - self.generate_admonition(node, 'caution') - - depart_caution = depart_warning - - def visit_danger(self, node): - self.generate_admonition(node, 'danger') - - depart_danger = depart_warning - - def visit_error(self, node): - self.generate_admonition(node, 'error') - - depart_error = depart_warning - - def visit_hint(self, node): - self.generate_admonition(node, 'hint') - - depart_hint = depart_warning - - def visit_important(self, node): - self.generate_admonition(node, 'important') - - depart_important = depart_warning - - def visit_note(self, node): - self.generate_admonition(node, 'note') - - depart_note = depart_warning - - def visit_tip(self, node): - self.generate_admonition(node, 'tip') - - depart_tip = depart_warning - - def visit_admonition(self, node): - title = None - for child in node.children: - if child.tagname == 'title': - title = child.astext() - if title is None: - classes1 = node.get('classes') - if classes1: - title = classes1[0] - self.generate_admonition(node, 'generic', title) - - depart_admonition = depart_warning - - def generate_admonition(self, node, label, title=None): - el1 = SubElement(self.current_element, 'text:p', attrib = { - 'text:style-name': self.rststyle('admon-%s-hdr', ( label, )), - }) - if title: - el1.text = title - else: - el1.text = '%s!' % (label.capitalize(), ) - s1 = self.rststyle('admon-%s-body', ( label, )) - self.paragraph_style_stack.append(s1) - - # - # Roles (e.g. subscript, superscript, strong, ... - # - def visit_subscript(self, node): - el = self.append_child('text:span', attrib={ - 'text:style-name': 'rststyle-subscript', - }) - self.set_current_element(el) - - def depart_subscript(self, node): - self.set_to_parent() - - def visit_superscript(self, node): - el = self.append_child('text:span', attrib={ - 'text:style-name': 'rststyle-superscript', - }) - self.set_current_element(el) - - def depart_superscript(self, node): - self.set_to_parent() - - -# Use an own reader to modify transformations done. -class Reader(standalone.Reader): - - def get_transforms(self): - default = standalone.Reader.get_transforms(self) - if self.settings.create_links: - return default - return [ i - for i in default - if i is not references.DanglingReferences ] diff --git a/docutils/writers/odf_odt/pygmentsformatter.py b/docutils/writers/odf_odt/pygmentsformatter.py deleted file mode 100644 index e8ce8279e..000000000 --- a/docutils/writers/odf_odt/pygmentsformatter.py +++ /dev/null @@ -1,109 +0,0 @@ -# $Id: pygmentsformatter.py 5853 2009-01-19 21:02:02Z dkuhlman $ -# Author: Dave Kuhlman -# Copyright: This module has been placed in the public domain. - -""" - -Additional support for Pygments formatter. - -""" - - -import pygments -import pygments.formatter - - -class OdtPygmentsFormatter(pygments.formatter.Formatter): - def __init__(self, rststyle_function, escape_function): - pygments.formatter.Formatter.__init__(self) - self.rststyle_function = rststyle_function - self.escape_function = escape_function - - def rststyle(self, name, parameters=( )): - return self.rststyle_function(name, parameters) - - -class OdtPygmentsProgFormatter(OdtPygmentsFormatter): - def format(self, tokensource, outfile): - tokenclass = pygments.token.Token - for ttype, value in tokensource: - value = self.escape_function(value) - if ttype == tokenclass.Keyword: - s2 = self.rststyle('codeblock-keyword') - s1 = '%s' % \ - (s2, value, ) - elif ttype == tokenclass.Literal.String: - s2 = self.rststyle('codeblock-string') - s1 = '%s' % \ - (s2, value, ) - elif ttype in ( - tokenclass.Literal.Number.Integer, - tokenclass.Literal.Number.Integer.Long, - tokenclass.Literal.Number.Float, - tokenclass.Literal.Number.Hex, - tokenclass.Literal.Number.Oct, - tokenclass.Literal.Number, - ): - s2 = self.rststyle('codeblock-number') - s1 = '%s' % \ - (s2, value, ) - elif ttype == tokenclass.Operator: - s2 = self.rststyle('codeblock-operator') - s1 = '%s' % \ - (s2, value, ) - elif ttype == tokenclass.Comment: - s2 = self.rststyle('codeblock-comment') - s1 = '%s' % \ - (s2, value, ) - elif ttype == tokenclass.Name.Class: - s2 = self.rststyle('codeblock-classname') - s1 = '%s' % \ - (s2, value, ) - elif ttype == tokenclass.Name.Function: - s2 = self.rststyle('codeblock-functionname') - s1 = '%s' % \ - (s2, value, ) - elif ttype == tokenclass.Name: - s2 = self.rststyle('codeblock-name') - s1 = '%s' % \ - (s2, value, ) - else: - s1 = value - outfile.write(s1) - - -class OdtPygmentsLaTeXFormatter(OdtPygmentsFormatter): - def format(self, tokensource, outfile): - tokenclass = pygments.token.Token - for ttype, value in tokensource: - value = self.escape_function(value) - if ttype == tokenclass.Keyword: - s2 = self.rststyle('codeblock-keyword') - s1 = '%s' % \ - (s2, value, ) - elif ttype in (tokenclass.Literal.String, - tokenclass.Literal.String.Backtick, - ): - s2 = self.rststyle('codeblock-string') - s1 = '%s' % \ - (s2, value, ) - elif ttype == tokenclass.Name.Attribute: - s2 = self.rststyle('codeblock-operator') - s1 = '%s' % \ - (s2, value, ) - elif ttype == tokenclass.Comment: - if value[-1] == '\n': - s2 = self.rststyle('codeblock-comment') - s1 = '%s\n' % \ - (s2, value[:-1], ) - else: - s2 = self.rststyle('codeblock-comment') - s1 = '%s' % \ - (s2, value, ) - elif ttype == tokenclass.Name.Builtin: - s2 = self.rststyle('codeblock-name') - s1 = '%s' % \ - (s2, value, ) - else: - s1 = value - outfile.write(s1) diff --git a/docutils/writers/odf_odt/styles.odt b/docutils/writers/odf_odt/styles.odt deleted file mode 100644 index e17b00721..000000000 Binary files a/docutils/writers/odf_odt/styles.odt and /dev/null differ diff --git a/docutils/writers/pep_html/__init__.py b/docutils/writers/pep_html/__init__.py deleted file mode 100644 index 503fa17bf..000000000 --- a/docutils/writers/pep_html/__init__.py +++ /dev/null @@ -1,105 +0,0 @@ -# $Id: __init__.py 6328 2010-05-23 21:20:29Z gbrandl $ -# Author: David Goodger -# Copyright: This module has been placed in the public domain. - -""" -PEP HTML Writer. -""" - -__docformat__ = 'reStructuredText' - - -import sys -import os -import os.path -import codecs -import docutils -from docutils import frontend, nodes, utils, writers -from docutils.writers import html4css1 - - -class Writer(html4css1.Writer): - - default_stylesheet = 'pep.css' - - default_stylesheet_path = utils.relative_path( - os.path.join(os.getcwd(), 'dummy'), - os.path.join(os.path.dirname(__file__), default_stylesheet)) - - default_template = 'template.txt' - - default_template_path = utils.relative_path( - os.path.join(os.getcwd(), 'dummy'), - os.path.join(os.path.dirname(__file__), default_template)) - - settings_spec = html4css1.Writer.settings_spec + ( - 'PEP/HTML-Specific Options', - 'For the PEP/HTML writer, the default value for the --stylesheet-path ' - 'option is "%s", and the default value for --template is "%s". ' - 'See HTML-Specific Options above.' - % (default_stylesheet_path, default_template_path), - (('Python\'s home URL. Default is "http://www.python.org".', - ['--python-home'], - {'default': 'http://www.python.org', 'metavar': ''}), - ('Home URL prefix for PEPs. Default is "." (current directory).', - ['--pep-home'], - {'default': '.', 'metavar': ''}), - # For testing. - (frontend.SUPPRESS_HELP, - ['--no-random'], - {'action': 'store_true', 'validator': frontend.validate_boolean}),)) - - settings_default_overrides = {'stylesheet_path': default_stylesheet_path, - 'template': default_template_path,} - - relative_path_settings = (html4css1.Writer.relative_path_settings - + ('template',)) - - config_section = 'pep_html writer' - config_section_dependencies = ('writers', 'html4css1 writer') - - def __init__(self): - html4css1.Writer.__init__(self) - self.translator_class = HTMLTranslator - - def interpolation_dict(self): - subs = html4css1.Writer.interpolation_dict(self) - settings = self.document.settings - pyhome = settings.python_home - subs['pyhome'] = pyhome - subs['pephome'] = settings.pep_home - if pyhome == '..': - subs['pepindex'] = '.' - else: - subs['pepindex'] = pyhome + '/dev/peps' - index = self.document.first_child_matching_class(nodes.field_list) - header = self.document[index] - self.pepnum = header[0][1].astext() - subs['pep'] = self.pepnum - if settings.no_random: - subs['banner'] = 0 - else: - import random - subs['banner'] = random.randrange(64) - try: - subs['pepnum'] = '%04i' % int(self.pepnum) - except ValueError: - subs['pepnum'] = self.pepnum - self.title = header[1][1].astext() - subs['title'] = self.title - subs['body'] = ''.join( - self.body_pre_docinfo + self.docinfo + self.body) - return subs - - def assemble_parts(self): - html4css1.Writer.assemble_parts(self) - self.parts['title'] = [self.title] - self.parts['pepnum'] = self.pepnum - - -class HTMLTranslator(html4css1.HTMLTranslator): - - def depart_field_list(self, node): - html4css1.HTMLTranslator.depart_field_list(self, node) - if 'rfc2822' in node['classes']: - self.body.append('
\n') diff --git a/docutils/writers/pep_html/pep.css b/docutils/writers/pep_html/pep.css deleted file mode 100644 index 620740978..000000000 --- a/docutils/writers/pep_html/pep.css +++ /dev/null @@ -1,344 +0,0 @@ -/* -:Author: David Goodger -:Contact: goodger@python.org -:date: $Date: 2006-05-21 22:44:42 +0200 (Son, 21 Mai 2006) $ -:version: $Revision: 4564 $ -:copyright: This stylesheet has been placed in the public domain. - -Default cascading style sheet for the PEP HTML output of Docutils. -*/ - -/* "! important" is used here to override other ``margin-top`` and - ``margin-bottom`` styles that are later in the stylesheet or - more specific. See http://www.w3.org/TR/CSS1#the-cascade */ -.first { - margin-top: 0 ! important } - -.last, .with-subtitle { - margin-bottom: 0 ! important } - -.hidden { - display: none } - -.navigation { - width: 100% ; - background: #99ccff ; - margin-top: 0px ; - margin-bottom: 0px } - -.navigation .navicon { - width: 150px ; - height: 35px } - -.navigation .textlinks { - padding-left: 1em ; - text-align: left } - -.navigation td, .navigation th { - padding-left: 0em ; - padding-right: 0em ; - vertical-align: middle } - -.rfc2822 { - margin-top: 0.5em ; - margin-left: 0.5em ; - margin-right: 0.5em ; - margin-bottom: 0em } - -.rfc2822 td { - text-align: left } - -.rfc2822 th.field-name { - text-align: right ; - font-family: sans-serif ; - padding-right: 0.5em ; - font-weight: bold ; - margin-bottom: 0em } - -a.toc-backref { - text-decoration: none ; - color: black } - -blockquote.epigraph { - margin: 2em 5em ; } - -body { - margin: 0px ; - margin-bottom: 1em ; - padding: 0px } - -dl.docutils dd { - margin-bottom: 0.5em } - -div.section { - margin-left: 1em ; - margin-right: 1em ; - margin-bottom: 1.5em } - -div.section div.section { - margin-left: 0em ; - margin-right: 0em ; - margin-top: 1.5em } - -div.abstract { - margin: 2em 5em } - -div.abstract p.topic-title { - font-weight: bold ; - text-align: center } - -div.admonition, div.attention, div.caution, div.danger, div.error, -div.hint, div.important, div.note, div.tip, div.warning { - margin: 2em ; - border: medium outset ; - padding: 1em } - -div.admonition p.admonition-title, div.hint p.admonition-title, -div.important p.admonition-title, div.note p.admonition-title, -div.tip p.admonition-title { - font-weight: bold ; - font-family: sans-serif } - -div.attention p.admonition-title, div.caution p.admonition-title, -div.danger p.admonition-title, div.error p.admonition-title, -div.warning p.admonition-title { - color: red ; - font-weight: bold ; - font-family: sans-serif } - -/* Uncomment (and remove this text!) to get reduced vertical space in - compound paragraphs. -div.compound .compound-first, div.compound .compound-middle { - margin-bottom: 0.5em } - -div.compound .compound-last, div.compound .compound-middle { - margin-top: 0.5em } -*/ - -div.dedication { - margin: 2em 5em ; - text-align: center ; - font-style: italic } - -div.dedication p.topic-title { - font-weight: bold ; - font-style: normal } - -div.figure { - margin-left: 2em ; - margin-right: 2em } - -div.footer, div.header { - clear: both; - font-size: smaller } - -div.footer { - margin-left: 1em ; - margin-right: 1em } - -div.line-block { - display: block ; - margin-top: 1em ; - margin-bottom: 1em } - -div.line-block div.line-block { - margin-top: 0 ; - margin-bottom: 0 ; - margin-left: 1.5em } - -div.sidebar { - margin-left: 1em ; - border: medium outset ; - padding: 1em ; - background-color: #ffffee ; - width: 40% ; - float: right ; - clear: right } - -div.sidebar p.rubric { - font-family: sans-serif ; - font-size: medium } - -div.system-messages { - margin: 5em } - -div.system-messages h1 { - color: red } - -div.system-message { - border: medium outset ; - padding: 1em } - -div.system-message p.system-message-title { - color: red ; - font-weight: bold } - -div.topic { - margin: 2em } - -h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, -h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { - margin-top: 0.4em } - -h1 { - font-family: sans-serif ; - font-size: large } - -h2 { - font-family: sans-serif ; - font-size: medium } - -h3 { - font-family: sans-serif ; - font-size: small } - -h4 { - font-family: sans-serif ; - font-style: italic ; - font-size: small } - -h5 { - font-family: sans-serif; - font-size: x-small } - -h6 { - font-family: sans-serif; - font-style: italic ; - font-size: x-small } - -hr.docutils { - width: 75% } - -img.align-left { - clear: left } - -img.align-right { - clear: right } - -img.borderless { - border: 0 } - -ol.simple, ul.simple { - margin-bottom: 1em } - -ol.arabic { - list-style: decimal } - -ol.loweralpha { - list-style: lower-alpha } - -ol.upperalpha { - list-style: upper-alpha } - -ol.lowerroman { - list-style: lower-roman } - -ol.upperroman { - list-style: upper-roman } - -p.attribution { - text-align: right ; - margin-left: 50% } - -p.caption { - font-style: italic } - -p.credits { - font-style: italic ; - font-size: smaller } - -p.label { - white-space: nowrap } - -p.rubric { - font-weight: bold ; - font-size: larger ; - color: maroon ; - text-align: center } - -p.sidebar-title { - font-family: sans-serif ; - font-weight: bold ; - font-size: larger } - -p.sidebar-subtitle { - font-family: sans-serif ; - font-weight: bold } - -p.topic-title { - font-family: sans-serif ; - font-weight: bold } - -pre.address { - margin-bottom: 0 ; - margin-top: 0 ; - font-family: serif ; - font-size: 100% } - -pre.literal-block, pre.doctest-block { - margin-left: 2em ; - margin-right: 2em } - -span.classifier { - font-family: sans-serif ; - font-style: oblique } - -span.classifier-delimiter { - font-family: sans-serif ; - font-weight: bold } - -span.interpreted { - font-family: sans-serif } - -span.option { - white-space: nowrap } - -span.option-argument { - font-style: italic } - -span.pre { - white-space: pre } - -span.problematic { - color: red } - -span.section-subtitle { - /* font-size relative to parent (h1..h6 element) */ - font-size: 80% } - -table.citation { - border-left: solid 1px gray; - margin-left: 1px } - -table.docinfo { - margin: 2em 4em } - -table.docutils { - margin-top: 0.5em ; - margin-bottom: 0.5em } - -table.footnote { - border-left: solid 1px black; - margin-left: 1px } - -table.docutils td, table.docutils th, -table.docinfo td, table.docinfo th { - padding-left: 0.5em ; - padding-right: 0.5em ; - vertical-align: top } - -td.num { - text-align: right } - -th.field-name { - font-weight: bold ; - text-align: left ; - white-space: nowrap ; - padding-left: 0 } - -h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, -h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { - font-size: 100% } - -ul.auto-toc { - list-style-type: none } diff --git a/docutils/writers/pep_html/template.txt b/docutils/writers/pep_html/template.txt deleted file mode 100644 index 62c07a87f..000000000 --- a/docutils/writers/pep_html/template.txt +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - PEP %(pep)s -- %(title)s - %(stylesheet)s - - - - - -
-%(body)s -%(body_suffix)s diff --git a/docutils/writers/pseudoxml.py b/docutils/writers/pseudoxml.py deleted file mode 100644 index bb833d668..000000000 --- a/docutils/writers/pseudoxml.py +++ /dev/null @@ -1,31 +0,0 @@ -# $Id: pseudoxml.py 7320 2012-01-19 22:33:02Z milde $ -# Author: David Goodger -# Copyright: This module has been placed in the public domain. - -""" -Simple internal document tree Writer, writes indented pseudo-XML. -""" - -__docformat__ = 'reStructuredText' - - -from docutils import writers - - -class Writer(writers.Writer): - - supported = ('pprint', 'pformat', 'pseudoxml') - """Formats this writer supports.""" - - config_section = 'pseudoxml writer' - config_section_dependencies = ('writers',) - - output = None - """Final translated form of `document`.""" - - def translate(self): - self.output = self.document.pformat() - - def supports(self, format): - """This writer supports all format-specific elements.""" - return True diff --git a/docutils/writers/s5_html/__init__.py b/docutils/writers/s5_html/__init__.py deleted file mode 100644 index 44d32201c..000000000 --- a/docutils/writers/s5_html/__init__.py +++ /dev/null @@ -1,347 +0,0 @@ -# $Id: __init__.py 7320 2012-01-19 22:33:02Z milde $ -# Authors: Chris Liechti ; -# David Goodger -# Copyright: This module has been placed in the public domain. - -""" -S5/HTML Slideshow Writer. -""" - -__docformat__ = 'reStructuredText' - - -import sys -import os -import re -import docutils -from docutils import frontend, nodes, utils -from docutils.writers import html4css1 -from docutils.parsers.rst import directives -from docutils._compat import b - -themes_dir_path = utils.relative_path( - os.path.join(os.getcwd(), 'dummy'), - os.path.join(os.path.dirname(__file__), 'themes')) - -def find_theme(name): - # Where else to look for a theme? - # Check working dir? Destination dir? Config dir? Plugins dir? - path = os.path.join(themes_dir_path, name) - if not os.path.isdir(path): - raise docutils.ApplicationError( - 'Theme directory not found: %r (path: %r)' % (name, path)) - return path - - -class Writer(html4css1.Writer): - - settings_spec = html4css1.Writer.settings_spec + ( - 'S5 Slideshow Specific Options', - 'For the S5/HTML writer, the --no-toc-backlinks option ' - '(defined in General Docutils Options above) is the default, ' - 'and should not be changed.', - (('Specify an installed S5 theme by name. Overrides --theme-url. ' - 'The default theme name is "default". The theme files will be ' - 'copied into a "ui/" directory, in the same directory as the ' - 'destination file (output HTML). Note that existing theme files ' - 'will not be overwritten (unless --overwrite-theme-files is used).', - ['--theme'], - {'default': 'default', 'metavar': '', - 'overrides': 'theme_url'}), - ('Specify an S5 theme URL. The destination file (output HTML) will ' - 'link to this theme; nothing will be copied. Overrides --theme.', - ['--theme-url'], - {'metavar': '', 'overrides': 'theme'}), - ('Allow existing theme files in the ``ui/`` directory to be ' - 'overwritten. The default is not to overwrite theme files.', - ['--overwrite-theme-files'], - {'action': 'store_true', 'validator': frontend.validate_boolean}), - ('Keep existing theme files in the ``ui/`` directory; do not ' - 'overwrite any. This is the default.', - ['--keep-theme-files'], - {'dest': 'overwrite_theme_files', 'action': 'store_false'}), - ('Set the initial view mode to "slideshow" [default] or "outline".', - ['--view-mode'], - {'choices': ['slideshow', 'outline'], 'default': 'slideshow', - 'metavar': ''}), - ('Normally hide the presentation controls in slideshow mode. ' - 'This is the default.', - ['--hidden-controls'], - {'action': 'store_true', 'default': True, - 'validator': frontend.validate_boolean}), - ('Always show the presentation controls in slideshow mode. ' - 'The default is to hide the controls.', - ['--visible-controls'], - {'dest': 'hidden_controls', 'action': 'store_false'}), - ('Enable the current slide indicator ("1 / 15"). ' - 'The default is to disable it.', - ['--current-slide'], - {'action': 'store_true', 'validator': frontend.validate_boolean}), - ('Disable the current slide indicator. This is the default.', - ['--no-current-slide'], - {'dest': 'current_slide', 'action': 'store_false'}),)) - - settings_default_overrides = {'toc_backlinks': 0} - - config_section = 's5_html writer' - config_section_dependencies = ('writers', 'html4css1 writer') - - def __init__(self): - html4css1.Writer.__init__(self) - self.translator_class = S5HTMLTranslator - - -class S5HTMLTranslator(html4css1.HTMLTranslator): - - s5_stylesheet_template = """\ - - - - - - - - -\n""" - # The script element must go in front of the link elements to - # avoid a flash of unstyled content (FOUC), reproducible with - # Firefox. - - disable_current_slide = """ -\n""" - - layout_template = """\ -
-
-
- - -
\n""" -#
-#
-#
-#
- - default_theme = 'default' - """Name of the default theme.""" - - base_theme_file = '__base__' - """Name of the file containing the name of the base theme.""" - - direct_theme_files = ( - 'slides.css', 'outline.css', 'print.css', 'opera.css', 'slides.js') - """Names of theme files directly linked to in the output HTML""" - - indirect_theme_files = ( - 's5-core.css', 'framing.css', 'pretty.css', 'blank.gif', 'iepngfix.htc') - """Names of files used indirectly; imported or used by files in - `direct_theme_files`.""" - - required_theme_files = indirect_theme_files + direct_theme_files - """Names of mandatory theme files.""" - - def __init__(self, *args): - html4css1.HTMLTranslator.__init__(self, *args) - #insert S5-specific stylesheet and script stuff: - self.theme_file_path = None - self.setup_theme() - view_mode = self.document.settings.view_mode - control_visibility = ('visible', 'hidden')[self.document.settings - .hidden_controls] - self.stylesheet.append(self.s5_stylesheet_template - % {'path': self.theme_file_path, - 'view_mode': view_mode, - 'control_visibility': control_visibility}) - if not self.document.settings.current_slide: - self.stylesheet.append(self.disable_current_slide) - self.add_meta('\n') - self.s5_footer = [] - self.s5_header = [] - self.section_count = 0 - self.theme_files_copied = None - - def setup_theme(self): - if self.document.settings.theme: - self.copy_theme() - elif self.document.settings.theme_url: - self.theme_file_path = self.document.settings.theme_url - else: - raise docutils.ApplicationError( - 'No theme specified for S5/HTML writer.') - - def copy_theme(self): - """ - Locate & copy theme files. - - A theme may be explicitly based on another theme via a '__base__' - file. The default base theme is 'default'. Files are accumulated - from the specified theme, any base themes, and 'default'. - """ - settings = self.document.settings - path = find_theme(settings.theme) - theme_paths = [path] - self.theme_files_copied = {} - required_files_copied = {} - # This is a link (URL) in HTML, so we use "/", not os.sep: - self.theme_file_path = '%s/%s' % ('ui', settings.theme) - if settings._destination: - dest = os.path.join( - os.path.dirname(settings._destination), 'ui', settings.theme) - if not os.path.isdir(dest): - os.makedirs(dest) - else: - # no destination, so we can't copy the theme - return - default = False - while path: - for f in os.listdir(path): # copy all files from each theme - if f == self.base_theme_file: - continue # ... except the "__base__" file - if ( self.copy_file(f, path, dest) - and f in self.required_theme_files): - required_files_copied[f] = 1 - if default: - break # "default" theme has no base theme - # Find the "__base__" file in theme directory: - base_theme_file = os.path.join(path, self.base_theme_file) - # If it exists, read it and record the theme path: - if os.path.isfile(base_theme_file): - lines = open(base_theme_file).readlines() - for line in lines: - line = line.strip() - if line and not line.startswith('#'): - path = find_theme(line) - if path in theme_paths: # check for duplicates (cycles) - path = None # if found, use default base - else: - theme_paths.append(path) - break - else: # no theme name found - path = None # use default base - else: # no base theme file found - path = None # use default base - if not path: - path = find_theme(self.default_theme) - theme_paths.append(path) - default = True - if len(required_files_copied) != len(self.required_theme_files): - # Some required files weren't found & couldn't be copied. - required = list(self.required_theme_files) - for f in required_files_copied.keys(): - required.remove(f) - raise docutils.ApplicationError( - 'Theme files not found: %s' - % ', '.join(['%r' % f for f in required])) - - files_to_skip_pattern = re.compile(r'~$|\.bak$|#$|\.cvsignore$') - - def copy_file(self, name, source_dir, dest_dir): - """ - Copy file `name` from `source_dir` to `dest_dir`. - Return 1 if the file exists in either `source_dir` or `dest_dir`. - """ - source = os.path.join(source_dir, name) - dest = os.path.join(dest_dir, name) - if dest in self.theme_files_copied: - return 1 - else: - self.theme_files_copied[dest] = 1 - if os.path.isfile(source): - if self.files_to_skip_pattern.search(source): - return None - settings = self.document.settings - if os.path.exists(dest) and not settings.overwrite_theme_files: - settings.record_dependencies.add(dest) - else: - src_file = open(source, 'rb') - src_data = src_file.read() - src_file.close() - dest_file = open(dest, 'wb') - dest_dir = dest_dir.replace(os.sep, '/') - dest_file.write(src_data.replace( - b('ui/default'), - dest_dir[dest_dir.rfind('ui/'):].encode( - sys.getfilesystemencoding()))) - dest_file.close() - settings.record_dependencies.add(source) - return 1 - if os.path.isfile(dest): - return 1 - - def depart_document(self, node): - self.head_prefix.extend([self.doctype, - self.head_prefix_template % - {'lang': self.settings.language_code}]) - self.html_prolog.append(self.doctype) - self.meta.insert(0, self.content_type % self.settings.output_encoding) - self.head.insert(0, self.content_type % self.settings.output_encoding) - - header = ''.join(self.s5_header) - footer = ''.join(self.s5_footer) - title = ''.join(self.html_title).replace('

', '

') - layout = self.layout_template % {'header': header, - 'title': title, - 'footer': footer} - self.fragment.extend(self.body) - self.body_prefix.extend(layout) - self.body_prefix.append('
\n') - self.body_prefix.append( - self.starttag({'classes': ['slide'], 'ids': ['slide0']}, 'div')) - if not self.section_count: - self.body.append('
\n') - self.body_suffix.insert(0, '

\n') - # skip content-type meta tag with interpolated charset value: - self.html_head.extend(self.head[1:]) - self.html_body.extend(self.body_prefix[1:] + self.body_pre_docinfo - + self.docinfo + self.body - + self.body_suffix[:-1]) - - def depart_footer(self, node): - start = self.context.pop() - self.s5_footer.append('

') - self.s5_footer.extend(self.body[start:]) - self.s5_footer.append('

') - del self.body[start:] - - def depart_header(self, node): - start = self.context.pop() - header = ['\n') - del self.body[start:] - self.s5_header.extend(header) - - def visit_section(self, node): - if not self.section_count: - self.body.append('\n\n') - self.section_count += 1 - self.section_level += 1 - if self.section_level > 1: - # dummy for matching div's - self.body.append(self.starttag(node, 'div', CLASS='section')) - else: - self.body.append(self.starttag(node, 'div', CLASS='slide')) - - def visit_subtitle(self, node): - if isinstance(node.parent, nodes.section): - level = self.section_level + self.initial_header_level - 1 - if level == 1: - level = 2 - tag = 'h%s' % level - self.body.append(self.starttag(node, tag, '')) - self.context.append('\n' % tag) - else: - html4css1.HTMLTranslator.visit_subtitle(self, node) - - def visit_title(self, node): - html4css1.HTMLTranslator.visit_title(self, node) diff --git a/docutils/writers/s5_html/themes/README.txt b/docutils/writers/s5_html/themes/README.txt deleted file mode 100644 index 2e01b51ee..000000000 --- a/docutils/writers/s5_html/themes/README.txt +++ /dev/null @@ -1,6 +0,0 @@ -Except where otherwise noted (default/iepngfix.htc), all files in this -directory have been released into the Public Domain. - -These files are based on files from S5 1.1, released into the Public -Domain by Eric Meyer. For further details, please see -http://www.meyerweb.com/eric/tools/s5/credits.html. diff --git a/docutils/writers/s5_html/themes/big-black/__base__ b/docutils/writers/s5_html/themes/big-black/__base__ deleted file mode 100644 index f08be9ad5..000000000 --- a/docutils/writers/s5_html/themes/big-black/__base__ +++ /dev/null @@ -1,2 +0,0 @@ -# base theme of this theme: -big-white diff --git a/docutils/writers/s5_html/themes/big-black/framing.css b/docutils/writers/s5_html/themes/big-black/framing.css deleted file mode 100644 index 5a31113fb..000000000 --- a/docutils/writers/s5_html/themes/big-black/framing.css +++ /dev/null @@ -1,25 +0,0 @@ -/* The following styles size, place, and layer the slide components. - Edit these if you want to change the overall slide layout. - The commented lines can be uncommented (and modified, if necessary) - to help you with the rearrangement process. */ - -/* target = 1024x768 */ - -div#header, div#footer, .slide {width: 100%; top: 0; left: 0;} -div#header {top: 0; z-index: 1;} -div#footer {display:none;} -.slide {top: 0; width: 92%; padding: 0.1em 4% 4%; z-index: 2;} -/* list-style: none;} */ -div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;} -div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; - margin: 0;} -#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em; - z-index: 10;} -html>body #currentSlide {position: fixed;} - -/* -div#header {background: #FCC;} -div#footer {background: #CCF;} -div#controls {background: #BBD;} -div#currentSlide {background: #FFC;} -*/ diff --git a/docutils/writers/s5_html/themes/big-black/pretty.css b/docutils/writers/s5_html/themes/big-black/pretty.css deleted file mode 100644 index 82bcc9dc4..000000000 --- a/docutils/writers/s5_html/themes/big-black/pretty.css +++ /dev/null @@ -1,109 +0,0 @@ -/* This file has been placed in the public domain. */ -/* Following are the presentation styles -- edit away! */ - -html, body {margin: 0; padding: 0;} -body {background: black; color: white;} -:link, :visited {text-decoration: none; color: cyan;} -#controls :active {color: #888 !important;} -#controls :focus {outline: 1px dotted #CCC;} - -blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;} -blockquote p {margin: 0;} - -kbd {font-weight: bold; font-size: 1em;} -sup {font-size: smaller; line-height: 1px;} - -.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;} -.slide ul ul li {list-style: square;} -.slide img.leader {display: block; margin: 0 auto;} -.slide tt {font-size: 90%;} - -.slide {font-size: 3em; font-family: sans-serif; font-weight: bold;} -.slide h1 {padding-top: 0; z-index: 1; margin: 0; font-size: 120%;} -.slide h2 {font-size: 110%;} -.slide h3 {font-size: 105%;} -h1 abbr {font-variant: small-caps;} - -div#controls {position: absolute; left: 50%; bottom: 0; - width: 50%; text-align: right; font: bold 0.9em sans-serif;} -html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;} -div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; - margin: 0; padding: 0;} -#controls #navLinks a {padding: 0; margin: 0 0.5em; - border: none; color: #888; cursor: pointer;} -#controls #navList {height: 1em;} -#controls #navList #jumplist {position: absolute; bottom: 0; right: 0; - background: black; color: #CCC;} - -#currentSlide {text-align: center; font-size: 0.5em; color: #AAA; - font-family: sans-serif; font-weight: bold;} - -#slide0 h1 {position: static; margin: 0 0 0.5em; padding-top: 0.3em; top: 0; - font-size: 150%; white-space: normal; background: transparent;} -#slide0 h2 {font: 110%; font-style: italic; color: gray;} -#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;} -#slide0 h4 {margin-top: 0; font-size: 1em;} - -ul.urls {list-style: none; display: inline; margin: 0;} -.urls li {display: inline; margin: 0;} -.external {border-bottom: 1px dotted gray;} -html>body .external {border-bottom: none;} -.external:after {content: " \274F"; font-size: smaller; color: #FCC;} - -.incremental, .incremental *, .incremental *:after { - color: black; visibility: visible; border: 0;} -img.incremental {visibility: hidden;} -.slide .current {color: lime;} - -.slide-display {display: inline ! important;} - -.huge {font-size: 150%;} -.big {font-size: 120%;} -.small {font-size: 75%;} -.tiny {font-size: 50%;} -.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;} -.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;} - -.maroon {color: maroon;} -.red {color: red;} -.magenta {color: magenta;} -.fuchsia {color: fuchsia;} -.pink {color: #FAA;} -.orange {color: orange;} -.yellow {color: yellow;} -.lime {color: lime;} -.green {color: green;} -.olive {color: olive;} -.teal {color: teal;} -.cyan {color: cyan;} -.aqua {color: aqua;} -.blue {color: blue;} -.navy {color: navy;} -.purple {color: purple;} -.black {color: black;} -.gray {color: gray;} -.silver {color: silver;} -.white {color: white;} - -.left {text-align: left ! important;} -.center {text-align: center ! important;} -.right {text-align: right ! important;} - -.animation {position: relative; margin: 1em 0; padding: 0;} -.animation img {position: absolute;} - -/* Docutils-specific overrides */ - -.slide table.docinfo {margin: 0.5em 0 0.5em 1em;} - -div.sidebar {background-color: black;} - -pre.literal-block, pre.doctest-block {background-color: black;} - -tt.docutils {background-color: black;} - -/* diagnostics */ -/* -li:after {content: " [" attr(class) "]"; color: #F88;} -div:before {content: "[" attr(class) "]"; color: #F88;} -*/ diff --git a/docutils/writers/s5_html/themes/big-white/framing.css b/docutils/writers/s5_html/themes/big-white/framing.css deleted file mode 100644 index cd343432b..000000000 --- a/docutils/writers/s5_html/themes/big-white/framing.css +++ /dev/null @@ -1,24 +0,0 @@ -/* This file has been placed in the public domain. */ -/* The following styles size, place, and layer the slide components. - Edit these if you want to change the overall slide layout. - The commented lines can be uncommented (and modified, if necessary) - to help you with the rearrangement process. */ - -/* target = 1024x768 */ - -div#header, div#footer, .slide {width: 100%; top: 0; left: 0;} -div#footer {display:none;} -.slide {top: 0; width: 92%; padding: 0.25em 4% 4%; z-index: 2;} -div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;} -div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; - margin: 0;} -#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em; - z-index: 10;} -html>body #currentSlide {position: fixed;} - -/* -div#header {background: #FCC;} -div#footer {background: #CCF;} -div#controls {background: #BBD;} -div#currentSlide {background: #FFC;} -*/ diff --git a/docutils/writers/s5_html/themes/big-white/pretty.css b/docutils/writers/s5_html/themes/big-white/pretty.css deleted file mode 100644 index c5e2fcf97..000000000 --- a/docutils/writers/s5_html/themes/big-white/pretty.css +++ /dev/null @@ -1,107 +0,0 @@ -/* This file has been placed in the public domain. */ -/* Following are the presentation styles -- edit away! */ - -html, body {margin: 0; padding: 0;} -body {background: white; color: black;} -:link, :visited {text-decoration: none; color: #00C;} -#controls :active {color: #88A !important;} -#controls :focus {outline: 1px dotted #227;} - -blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;} -blockquote p {margin: 0;} - -kbd {font-weight: bold; font-size: 1em;} -sup {font-size: smaller; line-height: 1px;} - -.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;} -.slide ul ul li {list-style: square;} -.slide img.leader {display: block; margin: 0 auto;} -.slide tt {font-size: 90%;} - -.slide {font-size: 3em; font-family: sans-serif; font-weight: bold;} -.slide h1 {padding-top: 0; z-index: 1; margin: 0; font-size: 120%;} -.slide h2 {font-size: 110%;} -.slide h3 {font-size: 105%;} -h1 abbr {font-variant: small-caps;} - -div#controls {position: absolute; left: 50%; bottom: 0; - width: 50%; text-align: right; font: bold 0.9em sans-serif;} -html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;} -div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; - margin: 0; padding: 0;} -#controls #navLinks a {padding: 0; margin: 0 0.5em; - border: none; color: #005; cursor: pointer;} -#controls #navList {height: 1em;} -#controls #navList #jumplist {position: absolute; bottom: 0; right: 0; - background: #DDD; color: #227;} - -#currentSlide {text-align: center; font-size: 0.5em; color: #444; - font-family: sans-serif; font-weight: bold;} - -#slide0 h1 {position: static; margin: 0 0 0.5em; padding-top: 0.3em; top: 0; - font-size: 150%; white-space: normal; background: transparent;} -#slide0 h2 {font: 110%; font-style: italic; color: gray;} -#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;} -#slide0 h4 {margin-top: 0; font-size: 1em;} - -ul.urls {list-style: none; display: inline; margin: 0;} -.urls li {display: inline; margin: 0;} -.external {border-bottom: 1px dotted gray;} -html>body .external {border-bottom: none;} -.external:after {content: " \274F"; font-size: smaller; color: #77B;} - -.incremental, .incremental *, .incremental *:after { - color: white; visibility: visible; border: 0;} -img.incremental {visibility: hidden;} -.slide .current {color: green;} - -.slide-display {display: inline ! important;} - -.huge {font-size: 150%;} -.big {font-size: 120%;} -.small {font-size: 75%;} -.tiny {font-size: 50%;} -.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;} -.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;} - -.maroon {color: maroon;} -.red {color: red;} -.magenta {color: magenta;} -.fuchsia {color: fuchsia;} -.pink {color: #FAA;} -.orange {color: orange;} -.yellow {color: yellow;} -.lime {color: lime;} -.green {color: green;} -.olive {color: olive;} -.teal {color: teal;} -.cyan {color: cyan;} -.aqua {color: aqua;} -.blue {color: blue;} -.navy {color: navy;} -.purple {color: purple;} -.black {color: black;} -.gray {color: gray;} -.silver {color: silver;} -.white {color: white;} - -.left {text-align: left ! important;} -.center {text-align: center ! important;} -.right {text-align: right ! important;} - -.animation {position: relative; margin: 1em 0; padding: 0;} -.animation img {position: absolute;} - -/* Docutils-specific overrides */ - -.slide table.docinfo {margin: 0.5em 0 0.5em 1em;} - -pre.literal-block, pre.doctest-block {background-color: white;} - -tt.docutils {background-color: white;} - -/* diagnostics */ -/* -li:after {content: " [" attr(class) "]"; color: #F88;} -div:before {content: "[" attr(class) "]"; color: #F88;} -*/ diff --git a/docutils/writers/s5_html/themes/default/blank.gif b/docutils/writers/s5_html/themes/default/blank.gif deleted file mode 100644 index 75b945d25..000000000 Binary files a/docutils/writers/s5_html/themes/default/blank.gif and /dev/null differ diff --git a/docutils/writers/s5_html/themes/default/framing.css b/docutils/writers/s5_html/themes/default/framing.css deleted file mode 100644 index c4727f303..000000000 --- a/docutils/writers/s5_html/themes/default/framing.css +++ /dev/null @@ -1,25 +0,0 @@ -/* This file has been placed in the public domain. */ -/* The following styles size, place, and layer the slide components. - Edit these if you want to change the overall slide layout. - The commented lines can be uncommented (and modified, if necessary) - to help you with the rearrangement process. */ - -/* target = 1024x768 */ - -div#header, div#footer, .slide {width: 100%; top: 0; left: 0;} -div#header {position: fixed; top: 0; height: 3em; z-index: 1;} -div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;} -.slide {top: 0; width: 92%; padding: 2.5em 4% 4%; z-index: 2;} -div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;} -div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; - margin: 0;} -#currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em; - z-index: 10;} -html>body #currentSlide {position: fixed;} - -/* -div#header {background: #FCC;} -div#footer {background: #CCF;} -div#controls {background: #BBD;} -div#currentSlide {background: #FFC;} -*/ diff --git a/docutils/writers/s5_html/themes/default/iepngfix.htc b/docutils/writers/s5_html/themes/default/iepngfix.htc deleted file mode 100644 index 9f3d628b5..000000000 --- a/docutils/writers/s5_html/themes/default/iepngfix.htc +++ /dev/null @@ -1,42 +0,0 @@ - - - - - \ No newline at end of file diff --git a/docutils/writers/s5_html/themes/default/opera.css b/docutils/writers/s5_html/themes/default/opera.css deleted file mode 100644 index c9d1148be..000000000 --- a/docutils/writers/s5_html/themes/default/opera.css +++ /dev/null @@ -1,8 +0,0 @@ -/* This file has been placed in the public domain. */ -/* DO NOT CHANGE THESE unless you really want to break Opera Show */ -.slide { - visibility: visible !important; - position: static !important; - page-break-before: always; -} -#slide0 {page-break-before: avoid;} diff --git a/docutils/writers/s5_html/themes/default/outline.css b/docutils/writers/s5_html/themes/default/outline.css deleted file mode 100644 index fa767e227..000000000 --- a/docutils/writers/s5_html/themes/default/outline.css +++ /dev/null @@ -1,16 +0,0 @@ -/* This file has been placed in the public domain. */ -/* Don't change this unless you want the layout stuff to show up in the - outline view! */ - -.layout div, #footer *, #controlForm * {display: none;} -#footer, #controls, #controlForm, #navLinks, #toggle { - display: block; visibility: visible; margin: 0; padding: 0;} -#toggle {float: right; padding: 0.5em;} -html>body #toggle {position: fixed; top: 0; right: 0;} - -/* making the outline look pretty-ish */ - -#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;} -#toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;} - -.outline {display: inline ! important;} diff --git a/docutils/writers/s5_html/themes/default/pretty.css b/docutils/writers/s5_html/themes/default/pretty.css deleted file mode 100644 index 1cede72d4..000000000 --- a/docutils/writers/s5_html/themes/default/pretty.css +++ /dev/null @@ -1,120 +0,0 @@ -/* This file has been placed in the public domain. */ -/* Following are the presentation styles -- edit away! */ - -html, body {margin: 0; padding: 0;} -body {background: white; color: black;} -/* Replace the background style above with the style below (and again for - div#header) for a graphic: */ -/* background: white url(bodybg.gif) -16px 0 no-repeat; */ -:link, :visited {text-decoration: none; color: #00C;} -#controls :active {color: #88A !important;} -#controls :focus {outline: 1px dotted #227;} -h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;} - -blockquote {padding: 0 2em 0.5em; margin: 0 1.5em 0.5em;} -blockquote p {margin: 0;} - -kbd {font-weight: bold; font-size: 1em;} -sup {font-size: smaller; line-height: 1px;} - -.slide pre {padding: 0; margin-left: 0; margin-right: 0; font-size: 90%;} -.slide ul ul li {list-style: square;} -.slide img.leader {display: block; margin: 0 auto;} -.slide tt {font-size: 90%;} - -div#header, div#footer {background: #005; color: #AAB; font-family: sans-serif;} -/* background: #005 url(bodybg.gif) -16px 0 no-repeat; */ -div#footer {font-size: 0.5em; font-weight: bold; padding: 1em 0;} -#footer h1 {display: block; padding: 0 1em;} -#footer h2 {display: block; padding: 0.8em 1em 0;} - -.slide {font-size: 1.2em;} -.slide h1 {position: absolute; top: 0.45em; z-index: 1; - margin: 0; padding-left: 0.7em; white-space: nowrap; - font: bold 150% sans-serif; color: #DDE; background: #005;} -.slide h2 {font: bold 120%/1em sans-serif; padding-top: 0.5em;} -.slide h3 {font: bold 100% sans-serif; padding-top: 0.5em;} -h1 abbr {font-variant: small-caps;} - -div#controls {position: absolute; left: 50%; bottom: 0; - width: 50%; text-align: right; font: bold 0.9em sans-serif;} -html>body div#controls {position: fixed; padding: 0 0 1em 0; top: auto;} -div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; - margin: 0; padding: 0;} -#controls #navLinks a {padding: 0; margin: 0 0.5em; - background: #005; border: none; color: #779; cursor: pointer;} -#controls #navList {height: 1em;} -#controls #navList #jumplist {position: absolute; bottom: 0; right: 0; - background: #DDD; color: #227;} - -#currentSlide {text-align: center; font-size: 0.5em; color: #449; - font-family: sans-serif; font-weight: bold;} - -#slide0 {padding-top: 1.5em} -#slide0 h1 {position: static; margin: 1em 0 0; padding: 0; color: #000; - font: bold 2em sans-serif; white-space: normal; background: transparent;} -#slide0 h2 {font: bold italic 1em sans-serif; margin: 0.25em;} -#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;} -#slide0 h4 {margin-top: 0; font-size: 1em;} - -ul.urls {list-style: none; display: inline; margin: 0;} -.urls li {display: inline; margin: 0;} -.external {border-bottom: 1px dotted gray;} -html>body .external {border-bottom: none;} -.external:after {content: " \274F"; font-size: smaller; color: #77B;} - -.incremental, .incremental *, .incremental *:after {visibility: visible; - color: white; border: 0;} -img.incremental {visibility: hidden;} -.slide .current {color: green;} - -.slide-display {display: inline ! important;} - -.huge {font-family: sans-serif; font-weight: bold; font-size: 150%;} -.big {font-family: sans-serif; font-weight: bold; font-size: 120%;} -.small {font-size: 75%;} -.tiny {font-size: 50%;} -.huge tt, .big tt, .small tt, .tiny tt {font-size: 115%;} -.huge pre, .big pre, .small pre, .tiny pre {font-size: 115%;} - -.maroon {color: maroon;} -.red {color: red;} -.magenta {color: magenta;} -.fuchsia {color: fuchsia;} -.pink {color: #FAA;} -.orange {color: orange;} -.yellow {color: yellow;} -.lime {color: lime;} -.green {color: green;} -.olive {color: olive;} -.teal {color: teal;} -.cyan {color: cyan;} -.aqua {color: aqua;} -.blue {color: blue;} -.navy {color: navy;} -.purple {color: purple;} -.black {color: black;} -.gray {color: gray;} -.silver {color: silver;} -.white {color: white;} - -.left {text-align: left ! important;} -.center {text-align: center ! important;} -.right {text-align: right ! important;} - -.animation {position: relative; margin: 1em 0; padding: 0;} -.animation img {position: absolute;} - -/* Docutils-specific overrides */ - -.slide table.docinfo {margin: 1em 0 0.5em 2em;} - -pre.literal-block, pre.doctest-block {background-color: white;} - -tt.docutils {background-color: white;} - -/* diagnostics */ -/* -li:after {content: " [" attr(class) "]"; color: #F88;} -div:before {content: "[" attr(class) "]"; color: #F88;} -*/ diff --git a/docutils/writers/s5_html/themes/default/print.css b/docutils/writers/s5_html/themes/default/print.css deleted file mode 100644 index 9d057cc8c..000000000 --- a/docutils/writers/s5_html/themes/default/print.css +++ /dev/null @@ -1,24 +0,0 @@ -/* This file has been placed in the public domain. */ -/* The following rule is necessary to have all slides appear in print! - DO NOT REMOVE IT! */ -.slide, ul {page-break-inside: avoid; visibility: visible !important;} -h1 {page-break-after: avoid;} - -body {font-size: 12pt; background: white;} -* {color: black;} - -#slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;} -#slide0 h3 {margin: 0; padding: 0;} -#slide0 h4 {margin: 0 0 0.5em; padding: 0;} -#slide0 {margin-bottom: 3em;} - -#header {display: none;} -#footer h1 {margin: 0; border-bottom: 1px solid; color: gray; - font-style: italic;} -#footer h2, #controls {display: none;} - -.print {display: inline ! important;} - -/* The following rule keeps the layout stuff out of print. - Remove at your own risk! */ -.layout, .layout * {display: none !important;} diff --git a/docutils/writers/s5_html/themes/default/s5-core.css b/docutils/writers/s5_html/themes/default/s5-core.css deleted file mode 100644 index 6965f5e8f..000000000 --- a/docutils/writers/s5_html/themes/default/s5-core.css +++ /dev/null @@ -1,11 +0,0 @@ -/* This file has been placed in the public domain. */ -/* Do not edit or override these styles! - The system will likely break if you do. */ - -div#header, div#footer, div#controls, .slide {position: absolute;} -html>body div#header, html>body div#footer, - html>body div#controls, html>body .slide {position: fixed;} -.handout {display: none;} -.layout {display: block;} -.slide, .hideme, .incremental {visibility: hidden;} -#slide0 {visibility: visible;} diff --git a/docutils/writers/s5_html/themes/default/slides.css b/docutils/writers/s5_html/themes/default/slides.css deleted file mode 100644 index 82bdc0ee0..000000000 --- a/docutils/writers/s5_html/themes/default/slides.css +++ /dev/null @@ -1,10 +0,0 @@ -/* This file has been placed in the public domain. */ - -/* required to make the slide show run at all */ -@import url(s5-core.css); - -/* sets basic placement and size of slide components */ -@import url(framing.css); - -/* styles that make the slides look good */ -@import url(pretty.css); diff --git a/docutils/writers/s5_html/themes/default/slides.js b/docutils/writers/s5_html/themes/default/slides.js deleted file mode 100644 index 81e04e5d4..000000000 --- a/docutils/writers/s5_html/themes/default/slides.js +++ /dev/null @@ -1,558 +0,0 @@ -// S5 v1.1 slides.js -- released into the Public Domain -// Modified for Docutils (http://docutils.sf.net) by David Goodger -// -// Please see http://www.meyerweb.com/eric/tools/s5/credits.html for -// information about all the wonderful and talented contributors to this code! - -var undef; -var slideCSS = ''; -var snum = 0; -var smax = 1; -var slideIDs = new Array(); -var incpos = 0; -var number = undef; -var s5mode = true; -var defaultView = 'slideshow'; -var controlVis = 'visible'; - -var isIE = navigator.appName == 'Microsoft Internet Explorer' ? 1 : 0; -var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0; -var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0; - -function hasClass(object, className) { - if (!object.className) return false; - return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1); -} - -function hasValue(object, value) { - if (!object) return false; - return (object.search('(^|\\s)' + value + '(\\s|$)') != -1); -} - -function removeClass(object,className) { - if (!object) return; - object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2); -} - -function addClass(object,className) { - if (!object || hasClass(object, className)) return; - if (object.className) { - object.className += ' '+className; - } else { - object.className = className; - } -} - -function GetElementsWithClassName(elementName,className) { - var allElements = document.getElementsByTagName(elementName); - var elemColl = new Array(); - for (var i = 0; i< allElements.length; i++) { - if (hasClass(allElements[i], className)) { - elemColl[elemColl.length] = allElements[i]; - } - } - return elemColl; -} - -function isParentOrSelf(element, id) { - if (element == null || element.nodeName=='BODY') return false; - else if (element.id == id) return true; - else return isParentOrSelf(element.parentNode, id); -} - -function nodeValue(node) { - var result = ""; - if (node.nodeType == 1) { - var children = node.childNodes; - for (var i = 0; i < children.length; ++i) { - result += nodeValue(children[i]); - } - } - else if (node.nodeType == 3) { - result = node.nodeValue; - } - return(result); -} - -function slideLabel() { - var slideColl = GetElementsWithClassName('*','slide'); - var list = document.getElementById('jumplist'); - smax = slideColl.length; - for (var n = 0; n < smax; n++) { - var obj = slideColl[n]; - - var did = 'slide' + n.toString(); - if (obj.getAttribute('id')) { - slideIDs[n] = obj.getAttribute('id'); - } - else { - obj.setAttribute('id',did); - slideIDs[n] = did; - } - if (isOp) continue; - - var otext = ''; - var menu = obj.firstChild; - if (!menu) continue; // to cope with empty slides - while (menu && menu.nodeType == 3) { - menu = menu.nextSibling; - } - if (!menu) continue; // to cope with slides with only text nodes - - var menunodes = menu.childNodes; - for (var o = 0; o < menunodes.length; o++) { - otext += nodeValue(menunodes[o]); - } - list.options[list.length] = new Option(n + ' : ' + otext, n); - } -} - -function currentSlide() { - var cs; - var footer_nodes; - var vis = 'visible'; - if (document.getElementById) { - cs = document.getElementById('currentSlide'); - footer_nodes = document.getElementById('footer').childNodes; - } else { - cs = document.currentSlide; - footer = document.footer.childNodes; - } - cs.innerHTML = '' + snum + '<\/span> ' + - '\/<\/span> ' + - '' + (smax-1) + '<\/span>'; - if (snum == 0) { - vis = 'hidden'; - } - cs.style.visibility = vis; - for (var i = 0; i < footer_nodes.length; i++) { - if (footer_nodes[i].nodeType == 1) { - footer_nodes[i].style.visibility = vis; - } - } -} - -function go(step) { - if (document.getElementById('slideProj').disabled || step == 0) return; - var jl = document.getElementById('jumplist'); - var cid = slideIDs[snum]; - var ce = document.getElementById(cid); - if (incrementals[snum].length > 0) { - for (var i = 0; i < incrementals[snum].length; i++) { - removeClass(incrementals[snum][i], 'current'); - removeClass(incrementals[snum][i], 'incremental'); - } - } - if (step != 'j') { - snum += step; - lmax = smax - 1; - if (snum > lmax) snum = lmax; - if (snum < 0) snum = 0; - } else - snum = parseInt(jl.value); - var nid = slideIDs[snum]; - var ne = document.getElementById(nid); - if (!ne) { - ne = document.getElementById(slideIDs[0]); - snum = 0; - } - if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;} - if (incrementals[snum].length > 0 && incpos == 0) { - for (var i = 0; i < incrementals[snum].length; i++) { - if (hasClass(incrementals[snum][i], 'current')) - incpos = i + 1; - else - addClass(incrementals[snum][i], 'incremental'); - } - } - if (incrementals[snum].length > 0 && incpos > 0) - addClass(incrementals[snum][incpos - 1], 'current'); - ce.style.visibility = 'hidden'; - ne.style.visibility = 'visible'; - jl.selectedIndex = snum; - currentSlide(); - number = 0; -} - -function goTo(target) { - if (target >= smax || target == snum) return; - go(target - snum); -} - -function subgo(step) { - if (step > 0) { - removeClass(incrementals[snum][incpos - 1],'current'); - removeClass(incrementals[snum][incpos], 'incremental'); - addClass(incrementals[snum][incpos],'current'); - incpos++; - } else { - incpos--; - removeClass(incrementals[snum][incpos],'current'); - addClass(incrementals[snum][incpos], 'incremental'); - addClass(incrementals[snum][incpos - 1],'current'); - } -} - -function toggle() { - var slideColl = GetElementsWithClassName('*','slide'); - var slides = document.getElementById('slideProj'); - var outline = document.getElementById('outlineStyle'); - if (!slides.disabled) { - slides.disabled = true; - outline.disabled = false; - s5mode = false; - fontSize('1em'); - for (var n = 0; n < smax; n++) { - var slide = slideColl[n]; - slide.style.visibility = 'visible'; - } - } else { - slides.disabled = false; - outline.disabled = true; - s5mode = true; - fontScale(); - for (var n = 0; n < smax; n++) { - var slide = slideColl[n]; - slide.style.visibility = 'hidden'; - } - slideColl[snum].style.visibility = 'visible'; - } -} - -function showHide(action) { - var obj = GetElementsWithClassName('*','hideme')[0]; - switch (action) { - case 's': obj.style.visibility = 'visible'; break; - case 'h': obj.style.visibility = 'hidden'; break; - case 'k': - if (obj.style.visibility != 'visible') { - obj.style.visibility = 'visible'; - } else { - obj.style.visibility = 'hidden'; - } - break; - } -} - -// 'keys' code adapted from MozPoint (http://mozpoint.mozdev.org/) -function keys(key) { - if (!key) { - key = event; - key.which = key.keyCode; - } - if (key.which == 84) { - toggle(); - return; - } - if (s5mode) { - switch (key.which) { - case 10: // return - case 13: // enter - if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return; - if (key.target && isParentOrSelf(key.target, 'controls')) return; - if(number != undef) { - goTo(number); - break; - } - case 32: // spacebar - case 34: // page down - case 39: // rightkey - case 40: // downkey - if(number != undef) { - go(number); - } else if (!incrementals[snum] || incpos >= incrementals[snum].length) { - go(1); - } else { - subgo(1); - } - break; - case 33: // page up - case 37: // leftkey - case 38: // upkey - if(number != undef) { - go(-1 * number); - } else if (!incrementals[snum] || incpos <= 0) { - go(-1); - } else { - subgo(-1); - } - break; - case 36: // home - goTo(0); - break; - case 35: // end - goTo(smax-1); - break; - case 67: // c - showHide('k'); - break; - } - if (key.which < 48 || key.which > 57) { - number = undef; - } else { - if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return; - if (key.target && isParentOrSelf(key.target, 'controls')) return; - number = (((number != undef) ? number : 0) * 10) + (key.which - 48); - } - } - return false; -} - -function clicker(e) { - number = undef; - var target; - if (window.event) { - target = window.event.srcElement; - e = window.event; - } else target = e.target; - if (target.href != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target, 'object')) return true; - if (!e.which || e.which == 1) { - if (!incrementals[snum] || incpos >= incrementals[snum].length) { - go(1); - } else { - subgo(1); - } - } -} - -function findSlide(hash) { - var target = document.getElementById(hash); - if (target) { - for (var i = 0; i < slideIDs.length; i++) { - if (target.id == slideIDs[i]) return i; - } - } - return null; -} - -function slideJump() { - if (window.location.hash == null || window.location.hash == '') { - currentSlide(); - return; - } - if (window.location.hash == null) return; - var dest = null; - dest = findSlide(window.location.hash.slice(1)); - if (dest == null) { - dest = 0; - } - go(dest - snum); -} - -function fixLinks() { - var thisUri = window.location.href; - thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length); - var aelements = document.getElementsByTagName('A'); - for (var i = 0; i < aelements.length; i++) { - var a = aelements[i].href; - var slideID = a.match('\#.+'); - if ((slideID) && (slideID[0].slice(0,1) == '#')) { - var dest = findSlide(slideID[0].slice(1)); - if (dest != null) { - if (aelements[i].addEventListener) { - aelements[i].addEventListener("click", new Function("e", - "if (document.getElementById('slideProj').disabled) return;" + - "go("+dest+" - snum); " + - "if (e.preventDefault) e.preventDefault();"), true); - } else if (aelements[i].attachEvent) { - aelements[i].attachEvent("onclick", new Function("", - "if (document.getElementById('slideProj').disabled) return;" + - "go("+dest+" - snum); " + - "event.returnValue = false;")); - } - } - } - } -} - -function externalLinks() { - if (!document.getElementsByTagName) return; - var anchors = document.getElementsByTagName('a'); - for (var i=0; i' + - '