Got module working with FreeCAD 0.17 running Python 3+

This commit is contained in:
Jeremy Mack Wright 2018-06-12 11:44:45 -04:00
parent ceb37b47c0
commit 05289f504d
57 changed files with 5924 additions and 2534 deletions

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
"""Adds all of the commands that are used for the menus of the CadQuery module"""
# (c) 2014-2016 Jeremy Wright Apache 2.0 License
# (c) 2014-2018 Jeremy Wright Apache 2.0 License
import imp, os, sys, tempfile
import FreeCAD, FreeCADGui
from PySide import QtGui, QtCore
@ -160,7 +159,7 @@ class CadQueryExecuteScript:
scriptText = cqCodePane.toPlainText().encode('utf-8')
# Check to see if we are executig a CQGI compliant script
if "show_object(" in scriptText or "debug(" in scriptText:
if b"show_object(" in scriptText or b"debug(" in scriptText:
FreeCAD.Console.PrintMessage("Executing CQGI-compliant script.\r\n")
# A repreentation of the CQ script with all the metadata attached
@ -451,7 +450,7 @@ class CadQueryValidateScript:
scriptText = cqCodePane.toPlainText().encode('utf-8')
if ("show_object(" not in scriptText and "# show_object(" in scriptText and "#show_boject(" in scriptText) or ("debug(" not in scriptText and "# debug(" in scriptText and "#debug(" in scriptText):
if (b"show_object(" not in scriptText) and (b"debug(" not in scriptText):
FreeCAD.Console.PrintError("Script did not call show_object or debug, no output available. Script must be CQGI compliant to get build output, variable editing and validation.\r\n")
return

View File

@ -1,4 +1,4 @@
# $Id: __init__.py 7756 2014-07-06 11:48:05Z grubert $
# $Id: __init__.py 8147 2017-08-03 09:01:16Z grubert $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -50,22 +50,66 @@ Subpackages:
- writers: Format-specific output translators.
"""
__docformat__ = 'reStructuredText'
__version__ = '0.12'
"""``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):
__docformat__ = 'reStructuredText'
__version__ = '0.14'
"""Docutils version identifier (complies with PEP 440)::
major.minor[.micro][releaselevel[serial]][.dev]
* The major number will be bumped when the project is feature-complete, and
later if there is a major change in the design or API.
* The minor number is bumped whenever there are new features.
* The micro number is bumped for bug-fix releases. Omitted if micro=0.
* The releaselevel identifier is used for pre-releases, one of 'a' (alpha),
'b' (beta), or 'rc' (release candidate). Omitted for final releases.
* The serial release number identifies prereleases; omitted if 0.
* The '.dev' suffix indicates active development, not a release, before the
version indicated.
For version comparison operations, use `__version_info__`
rather than parsing the text of `__version__`.
"""
# workaround for Python < 2.6:
__version_info__ = (0, 14, 0, 'final', 0, True)
# To add in Docutils 0.15, replacing the line above:
"""
from collections import namedtuple
VersionInfo = namedtuple(
'VersionInfo', 'major minor micro releaselevel serial release')
__version_info__ = VersionInfo(
major=0,
minor=15,
micro=0,
releaselevel='alpha', # development status:
# one of 'alpha', 'beta', 'candidate', 'final'
serial=0, # pre-release number (0 for final releases)
release=False # True for official releases and pre-releases
)
Comprehensive version information tuple. Can be used to test for a
minimally required version, e.g. ::
if __version_info__ >= (0, 13, 0, 'candidate', 2, True)
or in a self-documenting way like ::
if __version_info__ >= docutils.VersionInfo(
major=0, minor=13, micro=0,
releaselevel='candidate', serial=2, release=True)
"""
__version_details__ = ''
"""Optional extra version details (e.g. 'snapshot 2005-05-29, r3410').
(For development and release status see `__version_info__`.)
"""
class ApplicationError(Exception):
# Workaround:
# In Python < 2.6, unicode(<exception instance>) calls `str` on the
# arg and therefore, e.g., unicode(StandardError(u'\u234')) fails
@ -74,6 +118,7 @@ class ApplicationError(StandardError):
def __unicode__(self):
return u', '.join(self.args)
class DataError(ApplicationError): pass

View File

@ -1,4 +1,4 @@
# $Id: core.py 7466 2012-06-25 14:56:51Z milde $
# $Id: core.py 8126 2017-06-23 09:34:28Z milde $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -218,10 +218,10 @@ class Publisher:
self.apply_transforms()
output = self.writer.write(self.document, self.destination)
self.writer.assemble_parts()
except SystemExit, error:
except SystemExit as error:
exit = 1
exit_status = error.code
except Exception, error:
except Exception as error:
if not self.settings: # exception too early to report nicely
raise
if self.settings.traceback: # Propagate exceptions?
@ -279,9 +279,11 @@ class Publisher:
print >>self._stderr, ("""\
Exiting due to error. Use "--traceback" to diagnose.
Please report errors to <docutils-users@lists.sf.net>.
Include "--traceback" output, Docutils version (%s [%s]),
Include "--traceback" output, Docutils version (%s%s),
Python version (%s), your OS type & version, and the
command line used.""" % (__version__, __version_details__,
command line used.""" % (__version__,
docutils.__version_details__ and
' [%s]'%docutils.__version_details__ or '',
sys.version.split()[0]))
def report_SystemMessage(self, error):

View File

@ -0,0 +1,5 @@
# This configuration file is to prevent tools/buildhtml.py from
# processing text files in and below this directory.
[buildhtml application]
prune: .

View File

@ -1,4 +1,4 @@
# $Id: frontend.py 7584 2013-01-01 20:00:21Z milde $
# $Id: frontend.py 8126 2017-06-23 09:34:28Z milde $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -33,14 +33,18 @@ import os
import os.path
import sys
import warnings
import ConfigParser as CP
try:
import ConfigParser as CP
except:
import configparser as CP
import codecs
import optparse
from optparse import SUPPRESS_HELP
import docutils
import docutils.utils
import docutils.nodes
from docutils.utils.error_reporting import locale_encoding, ErrorOutput, ErrorString
from docutils.utils.error_reporting import (locale_encoding, SafeString,
ErrorOutput, ErrorString)
def store_multiple(option, opt, value, parser, *args, **kwargs):
@ -61,7 +65,7 @@ def read_config_file(option, opt, value, parser):
"""
try:
new_settings = parser.get_config_file_settings(value)
except ValueError, error:
except ValueError as error:
parser.error(error)
parser.values.update(new_settings, parser)
@ -205,10 +209,45 @@ def validate_strip_class(setting, value, option_parser,
for cls in value:
normalized = docutils.nodes.make_id(cls)
if cls != normalized:
raise ValueError('invalid class value %r (perhaps %r?)'
raise ValueError('Invalid class value %r (perhaps %r?)'
% (cls, normalized))
return value
def validate_smartquotes_locales(setting, value, option_parser,
config_parser=None, config_section=None):
"""Check/normalize a comma separated list of smart quote definitions.
Return a list of (language-tag, quotes) string tuples."""
# value is a comma separated string list:
value = validate_comma_separated_list(setting, value, option_parser,
config_parser, config_section)
# validate list elements
lc_quotes = []
for item in value:
try:
lang, quotes = item.split(':', 1)
except AttributeError:
# this function is called for every option added to `value`
# -> ignore if already a tuple:
lc_quotes.append(item)
continue
except ValueError:
raise ValueError(u'Invalid value "%s".'
' Format is "<language>:<quotes>".'
% item.encode('ascii', 'backslashreplace'))
# parse colon separated string list:
quotes = quotes.strip()
multichar_quotes = quotes.split(':')
if len(multichar_quotes) == 4:
quotes = multichar_quotes
elif len(quotes) != 4:
raise ValueError('Invalid value "%s". Please specify 4 quotes\n'
' (primary open/close; secondary open/close).'
% item.encode('ascii', 'backslashreplace'))
lc_quotes.append((lang,quotes))
return lc_quotes
def make_paths_absolute(pathdict, keys, base_path=None):
"""
Interpret filesystem path settings relative to the `base_path` given.
@ -310,7 +349,7 @@ class Option(optparse.Option):
value = getattr(values, setting)
try:
new_value = self.validator(setting, value, parser)
except Exception, error:
except Exception as error:
raise (optparse.OptionValueError(
'Error in option "%s":\n %s'
% (opt, ErrorString(error))),
@ -534,8 +573,10 @@ class OptionParser(optparse.OptionParser, docutils.SettingsSpec):
config_section = 'general'
version_template = ('%%prog (Docutils %s [%s], Python %s, on %s)'
% (docutils.__version__, docutils.__version_details__,
version_template = ('%%prog (Docutils %s%s, Python %s, on %s)'
% (docutils.__version__,
docutils.__version_details__ and
' [%s]'%docutils.__version_details__ or '',
sys.version.split()[0], sys.platform))
"""Default version message."""
@ -567,8 +608,8 @@ class OptionParser(optparse.OptionParser, docutils.SettingsSpec):
if read_config_files and not self.defaults['_disable_config']:
try:
config_settings = self.get_standard_config_settings()
except ValueError, error:
self.error(error)
except ValueError as error:
self.error(SafeString(error))
self.set_defaults_from_dict(config_settings.__dict__)
def populate_from_components(self, components):
@ -788,7 +829,7 @@ Skipping "%s" configuration file.
new_value = option.validator(
setting, value, option_parser,
config_parser=self, config_section=section)
except Exception, error:
except Exception as error:
raise (ValueError(
'Error in config file "%s", section "[%s]":\n'
' %s\n'

View File

@ -1,4 +1,4 @@
# $Id: io.py 7596 2013-01-25 13:42:17Z milde $
# $Id: io.py 8129 2017-06-27 14:55:22Z grubert $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -114,7 +114,7 @@ class Input(TransformSpec):
self.successful_encoding = enc
# Return decoded, removing BOMs.
return decoded.replace(u'\ufeff', u'')
except (UnicodeError, LookupError), err:
except (UnicodeError, LookupError) as err:
error = err # in Python 3, the <exception instance> is
# local to the except clause
raise UnicodeError(
@ -122,7 +122,7 @@ class Input(TransformSpec):
'%s.\n(%s)' % (', '.join([repr(enc) for enc in encodings]),
ErrorString(error)))
coding_slug = re.compile(b("coding[:=]\s*([-\w.]+)"))
coding_slug = re.compile(b(r"coding[:=]\s*([-\w.]+)"))
"""Encoding declaration pattern."""
byte_order_marks = ((codecs.BOM_UTF8, 'utf-8'), # 'utf-8-sig' new in v2.5
@ -204,7 +204,7 @@ class FileInput(Input):
"""
def __init__(self, source=None, source_path=None,
encoding=None, error_handler='strict',
autoclose=True, handle_io_errors=None, mode='rU'):
autoclose=True, mode='rU', **kwargs):
"""
:Parameters:
- `source`: either a file-like object (which is read directly), or
@ -214,7 +214,6 @@ class FileInput(Input):
- `error_handler`: the encoding error handler to use.
- `autoclose`: close automatically after read (except when
`sys.stdin` is the source).
- `handle_io_errors`: ignored, deprecated, will be removed.
- `mode`: how the file is to be opened (see standard function
`open`). The default 'rU' provides universal newline support
for text files.
@ -222,6 +221,16 @@ class FileInput(Input):
Input.__init__(self, source, source_path, encoding, error_handler)
self.autoclose = autoclose
self._stderr = ErrorOutput()
# deprecation warning
for key in kwargs:
if key == 'handle_io_errors':
sys.stderr.write('deprecation warning: '
'io.FileInput() argument `handle_io_errors` '
'is ignored since "Docutils 0.10 (2012-12-16)" '
'and will soon be removed.')
else:
raise TypeError('__init__() got an unexpected keyword '
"argument '%s'" % key)
if source is None:
if source_path:
@ -234,7 +243,7 @@ class FileInput(Input):
try:
self.source = open(source_path, mode, **kwargs)
except IOError, error:
except IOError as error:
raise InputError(error.errno, error.strerror, source_path)
else:
self.source = sys.stdin
@ -263,7 +272,7 @@ class FileInput(Input):
data = b('\n').join(data.splitlines()) + b('\n')
else:
data = self.source.read()
except (UnicodeError, LookupError), err: # (in Py3k read() decodes)
except (UnicodeError, LookupError) as err: # (in Py3k read() decodes)
if not self.encoding and self.source_path:
# re-read in binary mode and decode with heuristics
b_source = open(self.source_path, 'rb')
@ -353,7 +362,7 @@ class FileOutput(Output):
kwargs = {}
try:
self.destination = open(self.destination_path, self.mode, **kwargs)
except IOError, error:
except IOError as error:
raise OutputError(error.errno, error.strerror,
self.destination_path)
self.opened = True
@ -369,19 +378,19 @@ class FileOutput(Output):
if ('b' not in self.mode and sys.version_info < (3,0)
or check_encoding(self.destination, self.encoding) is False
):
if sys.version_info >= (3,0) and os.linesep != '\n':
data = data.replace('\n', os.linesep) # fix endings
data = self.encode(data)
if sys.version_info >= (3,0) and os.linesep != '\n':
data = data.replace(b('\n'), b(os.linesep)) # fix endings
try: # In Python < 2.5, try...except has to be nested in try...finally.
try:
self.destination.write(data)
except TypeError, e:
except TypeError as e:
if sys.version_info >= (3,0) and isinstance(data, bytes):
try:
self.destination.buffer.write(data)
except AttributeError:
if check_encoding(self.destination,
if check_encoding(self.destination,
self.encoding) is False:
raise ValueError('Encoding of %s (%s) differs \n'
' from specified encoding (%s)' %
@ -389,7 +398,7 @@ class FileOutput(Output):
self.destination.encoding, self.encoding))
else:
raise e
except (UnicodeError, LookupError), err:
except (UnicodeError, LookupError) as err:
raise UnicodeError(
'Unable to encode output data. output-encoding is: '
'%s.\n(%s)' % (self.encoding, ErrorString(err)))

View File

@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
# $Id: fa.py 4564 2016-08-10 11:48:42Z
# Author: Shahin <me@5hah.in>
# Copyright: This module has been placed in the public domain.
# New language mappings are welcome. Before doing a new translation, please
# read <http://docutils.sf.net/docs/howto/i18n.html>. Two files must be
# translated for each language: one in docutils/languages, the other in
# docutils/parsers/rst/languages.
"""
Persian-language mappings for language-dependent features of Docutils.
"""
__docformat__ = 'reStructuredText'
labels = {
# fixed: language-dependent
u'author': u'نویسنده',
u'authors': u'نویسندگان',
u'organization': u'سازمان',
u'address': u'آدرس',
u'contact': u'تماس',
u'version': u'نسخه',
u'revision': u'بازبینی',
u'status': u'وضعیت',
u'date': u'تاریخ',
u'copyright': u'کپی‌رایت',
u'dedication': u'تخصیص',
u'abstract': u'چکیده',
u'attention': u'توجه!',
u'caution': u'احتیاط!',
u'danger': u'خطر!',
u'error': u'خطا',
u'hint': u'راهنما',
u'important': u'مهم',
u'note': u'یادداشت',
u'tip': u'نکته',
u'warning': u'اخطار',
u'contents': u'محتوا'}
"""Mapping of node class name to label text."""
bibliographic_fields = {
# language-dependent: fixed
u'نویسنده': u'author',
u'نویسندگان': u'authors',
u'سازمان': u'organization',
u'آدرس': u'address',
u'تماس': u'contact',
u'نسخه': u'version',
u'بازبینی': u'revision',
u'وضعیت': u'status',
u'تاریخ': u'date',
u'کپی‌رایت': u'copyright',
u'تخصیص': u'dedication',
u'چکیده': u'abstract'}
"""Persian (lowcased) to canonical name mapping for bibliographic fields."""
author_separators = [u'؛', u'،']
"""List of separator strings for the 'Authors' bibliographic field. Tried in
order."""

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# $Id: lt.py 7668 2013-06-04 12:46:30Z milde $
# $Id: lt.py 7911 2015-08-31 08:23:06Z milde $
# Author: Dalius Dobravolskas <dalius.do...@gmail.com>
# Copyright: This module has been placed in the public domain.
@ -9,7 +9,7 @@
# docutils/parsers/rst/languages.
"""
English-language mappings for language-dependent features of Docutils.
Lithuanian language mappings for language-dependent features of Docutils.
"""
__docformat__ = 'reStructuredText'
@ -54,68 +54,7 @@ bibliographic_fields = {
'autoriaus teisės': 'copyright',
'dedikacija': 'dedication',
'santrauka': 'abstract'}
"""English (lowcased) to canonical name mapping for bibliographic fields."""
author_separators = [';', ',']
"""List of separator strings for the 'Authors' bibliographic field. Tried in
order."""
# -*- coding: utf-8 -*-
# $Id: lt.py 7668 2013-06-04 12:46:30Z milde $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
# New language mappings are welcome. Before doing a new translation, please
# read <http://docutils.sf.net/docs/howto/i18n.html>. Two files must be
# translated for each language: one in docutils/languages, the other in
# docutils/parsers/rst/languages.
"""
English-language mappings for language-dependent features of Docutils.
"""
__docformat__ = 'reStructuredText'
labels = {
# fixed: language-dependent
'author': 'Autorius',
'authors': 'Autoriai',
'organization': 'Organizacija',
'address': 'Adresas',
'contact': 'Kontaktas',
'version': 'Versija',
'revision': 'Revizija',
'status': u'Būsena',
'date': 'Data',
'copyright': u'Autoriaus teisės',
'dedication': 'Dedikacija',
'abstract': 'Santrauka',
'attention': u'Dėmesio!',
'caution': 'Atsargiai!',
'danger': '!PAVOJINGA!',
'error': 'Klaida',
'hint': u'Užuomina',
'important': 'Svarbu',
'note': 'Pastaba',
'tip': 'Patarimas',
'warning': u'Įspėjimas',
'contents': 'Turinys'}
"""Mapping of node class name to label text."""
bibliographic_fields = {
# language-dependent: fixed
'autorius': 'author',
'autoriai': 'authors',
'organizacija': 'organization',
'adresas': 'address',
'kontaktas': 'contact',
'versija': 'version',
'revizija': 'revision',
'būsena': 'status',
'data': 'date',
'autoriaus teisės': 'copyright',
'dedikacija': 'dedication',
'santrauka': 'abstract'}
"""English (lowcased) to canonical name mapping for bibliographic fields."""
"""Lithuanian (lowcased) to canonical name mapping for bibliographic fields."""
author_separators = [';', ',']
"""List of separator strings for the 'Authors' bibliographic field. Tried in

View File

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
# $Id: lv.py 7975 2016-10-20 20:00:19Z milde $
# Copyright: This module has been placed in the public domain.
# New language mappings are welcome. Before doing a new translation, please
# read <http://docutils.sf.net/docs/howto/i18n.html>. Two files must be
# translated for each language: one in docutils/languages, the other in
# docutils/parsers/rst/languages.
"""
Latvian-language mappings for language-dependent features of Docutils.
"""
__docformat__ = 'reStructuredText'
labels = {
# fixed: language-dependent
'author': 'Autors',
'authors': 'Autori',
'organization': 'Organizācija',
'address': 'Adrese',
'contact': 'Kontakti',
'version': 'Versija',
'revision': 'Revīzija',
'status': 'Statuss',
'date': 'Datums',
'copyright': 'Copyright',
'dedication': 'Veltījums',
'abstract': 'Atreferējums',
'attention': 'Uzmanību!',
'caution': 'Piesardzību!',
'danger': '!BĪSTAMI!',
'error': 'Kļūda',
'hint': 'Ieteikums',
'important': 'Svarīgi',
'note': 'Piezīme',
'tip': 'Padoms',
'warning': 'Brīdinājums',
'contents': 'Saturs'}
"""Mapping of node class name to label text."""
bibliographic_fields = {
# language-dependent: fixed
'autors': 'author',
'autori': 'authors',
'organizācija': 'organization',
'adrese': 'address',
'kontakti': 'contact',
'versija': 'version',
'revīzija': 'revision',
'statuss': 'status',
'datums': 'date',
'copyright': 'copyright',
'veltījums': 'dedication',
'atreferējums': 'abstract'}
"""English (lowcased) to canonical name mapping for bibliographic fields."""
author_separators = [';', ',']
"""List of separator strings for the 'Authors' bibliographic field. Tried in
order."""

View File

@ -1,4 +1,5 @@
# $Id: sv.py 4564 2006-05-21 20:44:42Z wiemann $
# -*- coding: utf-8 -*-
# $Id: sv.py 8006 2016-12-22 23:02:44Z milde $
# Author: Adam Chodorowski <chodorowski@users.sourceforge.net>
# Copyright: This module has been placed in the public domain.
@ -14,8 +15,8 @@ Swedish language mappings for language-dependent features of Docutils.
__docformat__ = 'reStructuredText'
labels = {
'author': u'F\u00f6rfattare',
'authors': u'F\u00f6rfattare',
'author': u'Författare',
'authors': u'Författare',
'organization': u'Organisation',
'address': u'Adress',
'contact': u'Kontakt',
@ -27,20 +28,20 @@ labels = {
'dedication': u'Dedikation',
'abstract': u'Sammanfattning',
'attention': u'Observera!',
'caution': u'Varning!',
'caution': u'Akta!', # 'Varning' already used for 'warning'
'danger': u'FARA!',
'error': u'Fel',
'hint': u'V\u00e4gledning',
'hint': u'Vink',
'important': u'Viktigt',
'note': u'Notera',
'tip': u'Tips',
'warning': u'Varning',
'contents': u'Inneh\u00e5ll' }
'contents': u'Innehåll' }
"""Mapping of node class name to label text."""
bibliographic_fields = {
# 'Author' and 'Authors' identical in Swedish; assume the plural:
u'f\u00f6rfattare': 'authors',
u'författare': 'authors',
u' n/a': 'author',
u'organisation': 'organization',
u'adress': 'address',

View File

@ -1,4 +1,4 @@
# $Id: nodes.py 7595 2013-01-21 17:33:56Z milde $
# $Id: nodes.py 7788 2015-02-16 22:10:52Z milde $
# Author: David Goodger <goodger@python.org>
# Maintainer: docutils-develop@lists.sourceforge.net
# Copyright: This module has been placed in the public domain.
@ -304,10 +304,8 @@ if sys.version_info < (3,):
def __repr__(self):
return unicode.__repr__(self)[1:]
else:
reprunicode = unicode
reprunicode = str
def ensure_str(s):
@ -533,7 +531,7 @@ class Element(Node):
parts = [self.tagname]
for name, value in self.attlist():
if value is None: # boolean attribute
parts.append(name)
parts.append('%s="True"' % name)
continue
if isinstance(value, list):
values = [serial_escape('%s' % (v,)) for v in value]
@ -571,7 +569,7 @@ class Element(Node):
assert key.step in (None, 1), 'cannot handle slice with stride'
return self.children[key.start:key.stop]
else:
raise TypeError, ('element index must be an integer, a slice, or '
raise TypeError('element index must be an integer, a slice, or '
'an attribute name string')
def __setitem__(self, key, item):
@ -586,7 +584,7 @@ class Element(Node):
self.setup_child(node)
self.children[key.start:key.stop] = item
else:
raise TypeError, ('element index must be an integer, a slice, or '
raise TypeError('element index must be an integer, a slice, or '
'an attribute name string')
def __delitem__(self, key):
@ -598,7 +596,7 @@ class Element(Node):
assert key.step in (None, 1), 'cannot handle slice with stride'
del self.children[key.start:key.stop]
else:
raise TypeError, ('element index must be an integer, a simple '
raise TypeError('element index must be an integer, a simple '
'slice, or an attribute name string')
def __add__(self, other):
@ -954,7 +952,7 @@ class Element(Node):
'Losing "%s" attribute: %s' % (att, self[att])
self.parent.replace(self, new)
def first_child_matching_class(self, childclass, start=0, end=sys.maxint):
def first_child_matching_class(self, childclass, start=0, end=sys.maxsize):
"""
Return the index of the first child whose class exactly matches.
@ -974,7 +972,7 @@ class Element(Node):
return None
def first_child_not_matching_class(self, childclass, start=0,
end=sys.maxint):
end=sys.maxsize):
"""
Return the index of the first child whose class does *not* match.
@ -1674,7 +1672,7 @@ class system_message(Special, BackLinkable, PreBibliographic, Element):
try:
Element.__init__(self, '', *children, **attributes)
except:
print 'system_message: children=%r' % (children,)
print('system_message: children=%r' % (children,))
raise
def astext(self):

View File

@ -1,4 +1,4 @@
# $Id: __init__.py 7598 2013-01-30 12:39:24Z milde $
# $Id: __init__.py 8068 2017-05-08 22:10:39Z milde $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -101,9 +101,9 @@ class Parser(docutils.parsers.Parser):
('Recognize and link to standalone RFC references (like "RFC 822").',
['--rfc-references'],
{'action': 'store_true', 'validator': frontend.validate_boolean}),
('Base URL for RFC references (default "http://www.faqs.org/rfcs/").',
('Base URL for RFC references (default "http://tools.ietf.org/html/").',
['--rfc-base-url'],
{'metavar': '<URL>', 'default': 'http://www.faqs.org/rfcs/',
{'metavar': '<URL>', 'default': 'http://tools.ietf.org/html/',
'validator': frontend.validate_url_trailing_slash}),
('Set number of spaces for tab expansion (default 8).',
['--tab-width'],
@ -141,7 +141,26 @@ class Parser(docutils.parsers.Parser):
('Change straight quotation marks to typographic form: '
'one of "yes", "no", "alt[ernative]" (default "no").',
['--smart-quotes'],
{'default': False, 'validator': frontend.validate_ternary}),
{'default': False, 'metavar': '<yes/no/alt>',
'validator': frontend.validate_ternary}),
('Characters to use as "smart quotes" for <language>. ',
['--smartquotes-locales'],
{'metavar': '<language:quotes[,language:quotes,...]>',
'action': 'append',
'validator': frontend.validate_smartquotes_locales}),
('Inline markup recognized at word boundaries only '
'(adjacent to punctuation or whitespace). '
'Force character-level inline markup recognition with '
'"\\ " (backslash + space). Default.',
['--word-level-inline-markup'],
{'action': 'store_false', 'dest': 'character_level_inline_markup'}),
('Inline markup recognized anywhere, regardless of surrounding '
'characters. Backslash-escapes must be used to avoid unwanted '
'markup recognition. Useful for East Asian languages. '
'Experimental.',
['--character-level-inline-markup'],
{'action': 'store_true', 'default': False,
'dest': 'character_level_inline_markup'}),
))
config_section = 'restructuredtext parser'
@ -249,12 +268,6 @@ class Directive(object):
- ``lineno`` is the absolute line number of the first line
of the directive.
- ``src`` is the name (or path) of the rst source of the directive.
- ``srcline`` is the line number of the first line of the directive
in its source. It may differ from ``lineno``, if the main source
includes other sources with the ``.. include::`` directive.
- ``content_offset`` is the line offset of the first line of the content from
the beginning of the current input. Used when initiating a nested parse.

View File

@ -1,4 +1,4 @@
# $Id: __init__.py 7621 2013-03-04 13:20:49Z milde $
# $Id: __init__.py 8024 2017-02-06 00:41:48Z goodger $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -13,6 +13,7 @@ import codecs
import sys
from docutils import nodes
from docutils.utils import split_escaped_whitespace, escape2null, unescape
from docutils.parsers.rst.languages import en as _fallback_language_module
if sys.version_info < (2,5):
from docutils._compat import __import__
@ -189,7 +190,7 @@ def path(argument):
def uri(argument):
"""
Return the URI argument with whitespace removed.
Return the URI argument with unescaped whitespace removed.
(Directive option conversion function.)
Raise ``ValueError`` if no argument is found.
@ -197,7 +198,8 @@ def uri(argument):
if argument is None:
raise ValueError('argument required but none supplied')
else:
uri = ''.join(argument.split())
parts = split_escaped_whitespace(escape2null(argument))
uri = ' '.join(''.join(unescape(part).split()) for part in parts)
return uri
def nonnegative_int(argument):
@ -402,3 +404,15 @@ def choice(argument, values):
def format_values(values):
return '%s, or "%s"' % (', '.join(['"%s"' % s for s in values[:-1]]),
values[-1])
def value_or(values, other):
"""
The argument can be any of `values` or `argument_type`.
"""
def auto_or_other(argument):
if argument in values:
return argument
else:
return other(argument)
return auto_or_other

View File

@ -1,4 +1,4 @@
# $Id: misc.py 7487 2012-07-22 21:20:28Z milde $
# $Id: misc.py 7961 2016-07-28 22:02:47Z milde $
# Authors: David Goodger <goodger@python.org>; Dethe Elza
# Copyright: This module has been placed in the public domain.
@ -231,7 +231,7 @@ class Raw(Directive):
raise self.severe(u'Problems with "%s" directive URL "%s":\n%s.'
% (self.name, self.options['url'], ErrorString(error)))
raw_file = io.StringInput(source=raw_text, source_path=source,
encoding=encoding,
encoding=encoding,
error_handler=e_handler)
try:
text = raw_file.read()
@ -477,6 +477,24 @@ class Date(Directive):
except UnicodeEncodeError:
raise self.warning(u'Cannot encode date format string '
u'with locale encoding "%s".' % locale_encoding)
# @@@
# Use timestamp from the `SOURCE_DATE_EPOCH`_ environment variable?
# Pro: Docutils-generated documentation
# can easily be part of `reproducible software builds`__
#
# __ https://reproducible-builds.org/
#
# Con: Changes the specs, hard to predict behaviour,
# no actual use case!
#
# See also the discussion about \date \time \year in TeX
# http://tug.org/pipermail/tex-k/2016-May/002704.html
# source_date_epoch = os.environ.get('SOURCE_DATE_EPOCH')
# if (source_date_epoch
# and self.state.document.settings.use_source_date_epoch):
# text = time.strftime(format_str,
# time.gmtime(int(source_date_epoch)))
# else:
text = time.strftime(format_str)
if sys.version_info< (3, 0):
# `text` is a byte string that may contain non-ASCII characters:

View File

@ -1,4 +1,4 @@
# $Id: tables.py 7747 2014-03-20 10:51:10Z milde $
# $Id: tables.py 8039 2017-02-28 12:19:20Z milde $
# Authors: David Goodger <goodger@python.org>; David Priest
# Copyright: This module has been placed in the public domain.
@ -20,6 +20,10 @@ from docutils.parsers.rst import Directive
from docutils.parsers.rst import directives
def align(argument):
return directives.choice(argument, ('left', 'center', 'right'))
class Table(Directive):
"""
@ -29,7 +33,10 @@ class Table(Directive):
optional_arguments = 1
final_argument_whitespace = True
option_spec = {'class': directives.class_option,
'name': directives.unchanged}
'name': directives.unchanged,
'align': align,
'widths': directives.value_or(('auto', 'grid'),
directives.positive_int_list)}
has_content = True
def make_title(self):
@ -38,6 +45,8 @@ class Table(Directive):
text_nodes, messages = self.state.inline_text(title_text,
self.lineno)
title = nodes.title(title_text, '', *text_nodes)
(title.source,
title.line) = self.state_machine.get_source_and_line(self.lineno)
else:
title = None
messages = []
@ -85,15 +94,19 @@ class Table(Directive):
self.block_text, self.block_text), line=self.lineno)
raise SystemMessagePropagation(error)
@property
def widths(self):
return self.options.get('widths', '')
def get_column_widths(self, max_cols):
if 'widths' in self.options:
col_widths = self.options['widths']
if len(col_widths) != max_cols:
if type(self.widths) == list:
if len(self.widths) != max_cols:
error = self.state_machine.reporter.error(
'"%s" widths do not match the number of columns in table '
'(%s).' % (self.name, max_cols), nodes.literal_block(
self.block_text, self.block_text), line=self.lineno)
raise SystemMessagePropagation(error)
col_widths = self.widths
elif max_cols:
col_widths = [100 // max_cols] * max_cols
else:
@ -130,6 +143,21 @@ class RSTTable(Table):
return [error]
table_node = node[0]
table_node['classes'] += self.options.get('class', [])
if 'align' in self.options:
table_node['align'] = self.options.get('align')
tgroup = table_node[0]
if type(self.widths) == list:
colspecs = [child for child in tgroup.children
if child.tagname == 'colspec']
for colspec, col_width in zip(colspecs, self.widths):
colspec['colwidth'] = col_width
# @@@ the colwidths argument for <tgroup> is not part of the
# XML Exchange Table spec (https://www.oasis-open.org/specs/tm9901.htm)
# and hence violates the docutils.dtd.
if self.widths == 'auto':
table_node['classes'] += ['colwidths-auto']
elif self.widths: # "grid" or list of integers
table_node['classes'] += ['colwidths-given']
self.add_name(table_node)
if title:
table_node.insert(0, title)
@ -141,12 +169,14 @@ class CSVTable(Table):
option_spec = {'header-rows': directives.nonnegative_int,
'stub-columns': directives.nonnegative_int,
'header': directives.unchanged,
'widths': directives.positive_int_list,
'widths': directives.value_or(('auto', ),
directives.positive_int_list),
'file': directives.path,
'url': directives.uri,
'encoding': directives.encoding,
'class': directives.class_option,
'name': directives.unchanged,
'align': align,
# field delimiter char
'delim': directives.single_char_or_whitespace_or_unicode,
# treat whitespace after delimiter as significant
@ -235,8 +265,10 @@ class CSVTable(Table):
return [error]
table = (col_widths, table_head, table_body)
table_node = self.state.build_table(table, self.content_offset,
stub_columns)
stub_columns, widths=self.widths)
table_node['classes'] += self.options.get('class', [])
if 'align' in self.options:
table_node['align'] = self.options.get('align')
self.add_name(table_node)
if title:
table_node.insert(0, title)
@ -356,13 +388,15 @@ class ListTable(Table):
Implement tables whose data is encoded as a uniform two-level bullet list.
For further ideas, see
http://docutils.sf.net/docs/dev/rst/alternatives.html#list-driven-tables
"""
"""
option_spec = {'header-rows': directives.nonnegative_int,
'stub-columns': directives.nonnegative_int,
'widths': directives.positive_int_list,
'widths': directives.value_or(('auto', ),
directives.positive_int_list),
'class': directives.class_option,
'name': directives.unchanged}
'name': directives.unchanged,
'align': align}
def run(self):
if not self.content:
@ -385,6 +419,8 @@ class ListTable(Table):
return [detail.args[0]]
table_node = self.build_table_from_list(table_data, col_widths,
header_rows, stub_columns)
if 'align' in self.options:
table_node['align'] = self.options.get('align')
table_node['classes'] += self.options.get('class', [])
self.add_name(table_node)
if title:
@ -432,10 +468,16 @@ class ListTable(Table):
def build_table_from_list(self, table_data, col_widths, header_rows, stub_columns):
table = nodes.table()
if self.widths == 'auto':
table['classes'] += ['colwidths-auto']
elif self.widths: # "grid" or list of integers
table['classes'] += ['colwidths-given']
tgroup = nodes.tgroup(cols=len(col_widths))
table += tgroup
for col_width in col_widths:
colspec = nodes.colspec(colwidth=col_width)
colspec = nodes.colspec()
if col_width is not None:
colspec.attributes['colwidth'] = col_width
if stub_columns:
colspec.attributes['stub'] = 1
stub_columns -= 1

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# $Id: de.py 7223 2011-11-21 16:43:06Z milde $
# $Id: de.py 8006 2016-12-22 23:02:44Z milde $
# Authors: Engelbert Gruber <grubert@users.sourceforge.net>;
# Lea Wiemann <LeWiemann@gmail.com>
# Copyright: This module has been placed in the public domain.
@ -30,13 +30,14 @@ directives = {
'warnung': 'warning',
'ermahnung': 'admonition',
'kasten': 'sidebar',
'seitenkasten': 'sidebar',
'seitenkasten': 'sidebar', # kept for backwards compatibiltity
'seitenleiste': 'sidebar',
'thema': 'topic',
'zeilen-block': 'line-block',
'zeilenblock': 'line-block',
'parsed-literal (translation required)': 'parsed-literal',
'rubrik': 'rubric',
'epigraph': 'epigraph',
'highlights (translation required)': 'highlights',
'highlights': 'highlights',
u'pull-quote': 'pull-quote', # commonly used in German too
u'seitenansprache': 'pull-quote', # cf. http://www.typografie.info/2/wiki.php?title=Seitenansprache
'zusammengesetzt': 'compound',
@ -45,7 +46,7 @@ directives = {
#'fragen': 'questions',
'tabelle': 'table',
'csv-tabelle': 'csv-table',
'list-table (translation required)': 'list-table',
'listentabelle': 'list-table',
u'mathe': 'math',
u'formel': 'math',
'meta': 'meta',
@ -62,14 +63,14 @@ directives = {
'datum': 'date',
'klasse': 'class',
'rolle': 'role',
u'default-role (translation required)': 'default-role',
u'title (translation required)': 'title',
u'standardrolle': 'default-role',
u'titel': 'title',
'inhalt': 'contents',
'kapitel-nummerierung': 'sectnum',
'abschnitts-nummerierung': 'sectnum',
u'linkziel-fußfnoten': 'target-notes',
u'header (translation required)': 'header',
u'footer (translation required)': 'footer',
u'kapitelnummerierung': 'sectnum',
u'abschnittsnummerierung': 'sectnum',
u'linkziel-fußnoten': 'target-notes',
u'kopfzeilen': 'header',
u'fußzeilen': 'footer',
#u'fußfnoten': 'footnotes',
#'zitate': 'citations',
}
@ -86,7 +87,8 @@ roles = {
'titel-referenz': 'title-reference',
'pep-referenz': 'pep-reference',
'rfc-referenz': 'rfc-reference',
'betonung': 'emphasis',
'betonung': 'emphasis', # for backwards compatibility
'betont': 'emphasis',
'fett': 'strong',
u'wörtlich': 'literal',
u'mathe': 'math',

View File

@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-
# $Id: fa.py 4564 2016-08-10 11:48:42Z
# Author: Shahin <me@5hah.in>
# Copyright: This module has been placed in the public domain.
# New language mappings are welcome. Before doing a new translation, please
# read <http://docutils.sf.net/docs/howto/i18n.html>. Two files must be
# translated for each language: one in docutils/languages, the other in
# docutils/parsers/rst/languages.
"""
Persian-language mappings for language-dependent features of
reStructuredText.
"""
__docformat__ = 'reStructuredText'
directives = {
# language-dependent: fixed
u'توجه': u'attention',
u'احتیاط': u'caution',
u'کد': u'code',
u'بلوک-کد': u'code',
u'کد-منبع': u'code',
u'خطر': u'danger',
u'خطا': u'error',
u'راهنما': u'hint',
u'مهم': u'important',
u'یادداشت': u'note',
u'نکته': u'tip',
u'اخطار': u'warning',
u'تذکر': u'admonition',
u'نوار-کناری': u'sidebar',
u'موضوع': u'topic',
u'بلوک-خط': u'line-block',
u'تلفظ-پردازش-شده': u'parsed-literal',
u'سر-فصل': u'rubric',
u'کتیبه': u'epigraph',
u'نکات-برجسته': u'highlights',
u'نقل-قول': u'pull-quote',
u'ترکیب': u'compound',
u'ظرف': u'container',
#'questions': u'questions',
u'جدول': u'table',
u'جدول-csv': u'csv-table',
u'جدول-لیست': u'list-table',
#'qa': u'questions',
#'faq': u'questions',
u'متا': u'meta',
u'ریاضی': u'math',
#'imagemap': u'imagemap',
u'تصویر': u'image',
u'شکل': u'figure',
u'شامل': u'include',
u'خام': u'raw',
u'جایگزین': u'replace',
u'یونیکد': u'unicode',
u'تاریخ': u'date',
u'کلاس': u'class',
u'قانون': u'role',
u'قانون-پیش‌فرض': u'default-role',
u'عنوان': u'title',
u'محتوا': u'contents',
u'شماره-فصل': u'sectnum',
u'شماره‌گذاری-فصل': u'sectnum',
u'سرآیند': u'header',
u'پاصفحه': u'footer',
#'footnotes': u'footnotes',
#'citations': u'citations',
u'یادداشت-هدف': u'target-notes',
}
"""Persian name to registered (in directives/__init__.py) directive name
mapping."""
roles = {
# language-dependent: fixed
u'مخفف': u'abbreviation',
u'سرنام': u'acronym',
u'کد': u'code',
u'شاخص': u'index',
u'زیرنویس': u'subscript',
u'بالانویس': u'superscript',
u'عنوان': u'title-reference',
u'نیرو': u'pep-reference',
u'rfc-reference (translation required)': u'rfc-reference',
u'تاکید': u'emphasis',
u'قوی': u'strong',
u'لفظی': u'literal',
u'ریاضی': u'math',
u'منبع-نام‌گذاری': u'named-reference',
u'منبع-ناشناس': u'anonymous-reference',
u'منبع-پانویس': u'footnote-reference',
u'منبع-نقل‌فول': u'citation-reference',
u'منبع-جایگزینی': u'substitution-reference',
u'هدف': u'target',
u'منبع-uri': u'uri-reference',
u'uri': u'uri-reference',
u'url': u'uri-reference',
u'خام': u'raw',}
"""Mapping of Persian role names to canonical role names for interpreted text.
"""

View File

@ -0,0 +1,108 @@
# -*- coding: utf-8 -*-
# $Id: lv.py 7975 2016-10-20 20:00:19Z milde $
# Copyright: This module has been placed in the public domain.
# New language mappings are welcome. Before doing a new translation, please
# read <http://docutils.sf.net/docs/howto/i18n.html>. Two files must be
# translated for each language: one in docutils/languages, the other in
# docutils/parsers/rst/languages.
"""
Latvian-language mappings for language-dependent features of
reStructuredText.
"""
__docformat__ = 'reStructuredText'
directives = {
# language-dependent: fixed
'uzmanību': 'attention',
'piesardzību': 'caution',
'kods': 'code',
'koda-bloks': 'code',
'pirmkods': 'code',
'bīstami': 'danger',
'kļūda': 'error',
'ieteikums': 'hint',
'svarīgi': 'important',
'piezīme': 'note',
'padoms': 'tip',
'brīdinājums': 'warning',
'aizrādījums': 'admonition',
'sānjosla': 'sidebar',
'tēma': 'topic',
'rindu-bloks': 'line-block',
'parsēts-literālis': 'parsed-literal',
'rubrika': 'rubric',
'epigrāfs': 'epigraph',
'apskats': 'highlights',
'izvilkuma-citāts': 'pull-quote',
'savienojums': 'compound',
'konteiners': 'container',
#'questions': 'questions',
'tabula': 'table',
'csv-tabula': 'csv-table',
'sarakstveida-tabula': 'list-table',
#'qa': 'questions',
#'faq': 'questions',
'meta': 'meta',
'matemātika': 'math',
#'imagemap': 'imagemap',
'attēls': 'image',
'figūra': 'figure',
'ietvert': 'include',
'burtiski': 'raw',
'aizvieto': 'replace',
'unicode': 'unicode',
'datums': 'date',
'klase': 'class',
'role': 'role',
'noklusējuma-role': 'default-role',
'virsraksts': 'title',
'saturs': 'contents',
'numurēt-sekcijas': 'sectnum',
'galvene': 'header',
'kājene': 'footer',
#'footnotes': 'footnotes',
#'citations': 'citations',
'atsauces-apakšā': 'target-notes',
'restructuredtext-testa-direktīva': 'restructuredtext-test-directive'}
"""English name to registered (in directives/__init__.py) directive name
mapping."""
roles = {
# language-dependent: fixed
'saīsinājums': 'abbreviation',
'īsi': 'abbreviation',
'akronīms': 'acronym',
'kods': 'code',
'indekss': 'index',
'i': 'index',
'apakšraksts': 'subscript',
'apakšā': 'subscript',
'augšraksts': 'superscript',
'augšā': 'superscript',
'virsraksta-atsauce': 'title-reference',
'virsraksts': 'title-reference',
'v': 'title-reference',
'atsauce-uz-pep': 'pep-reference',
'pep': 'pep-reference',
'atsauce-uz-rfc': 'rfc-reference',
'rfc': 'rfc-reference',
'izcēlums': 'emphasis',
'blīvs': 'strong',
'literālis': 'literal',
'matemātika': 'math',
'nosaukta-atsauce': 'named-reference',
'nenosaukta-atsauce': 'anonymous-reference',
'kājenes-atsauce': 'footnote-reference',
'citātā-atsauce': 'citation-reference',
'aizvietojuma-atsauce': 'substitution-reference',
'mēr''kis': 'target',
'atsauce-uz-uri': 'uri-reference',
'uri': 'uri-reference',
'url': 'uri-reference',
'burtiski': 'raw',}
"""Mapping of English role names to canonical role names for interpreted text.
"""

View File

@ -1,4 +1,5 @@
# $Id: sv.py 7119 2011-09-02 13:00:23Z milde $
# -*- coding: utf-8 -*-
# $Id: sv.py 8012 2017-01-03 23:08:19Z milde $
# Author: Adam Chodorowski <chodorowski@users.sourceforge.net>
# Copyright: This module has been placed in the public domain.
@ -13,55 +14,55 @@ Swedish language mappings for language-dependent features of reStructuredText.
__docformat__ = 'reStructuredText'
directives = {
u'observera': 'attention',
u'caution (translation required)': 'caution',
u'code (translation required)': 'code',
u'akta': 'caution', # also 'försiktigt'
u'kod': 'code',
u'fara': 'danger',
u'fel': 'error',
u'v\u00e4gledning': 'hint',
u'vink': 'hint', # also 'hint'
u'viktigt': 'important',
u'notera': 'note',
u'tips': 'tip',
u'varning': 'warning',
u'admonition (translation required)': 'admonition',
u'sidebar (translation required)': 'sidebar',
u'\u00e4mne': 'topic',
u'line-block (translation required)': 'line-block',
u'parsed-literal (translation required)': 'parsed-literal',
u'mellanrubrik': 'rubric',
u'epigraph (translation required)': 'epigraph',
u'highlights (translation required)': 'highlights',
u'anmärkning': 'admonition', # literal 'tillrättavisning', 'förmaning'
u'sidorad': 'sidebar',
u'ämne': 'topic',
u'tema': 'topic',
u'rad-block': 'line-block',
u'parsed-literal (translation required)': 'parsed-literal', # 'tolkad-bokstavlig'?
u'rubrik': 'rubric',
u'epigraf': 'epigraph',
u'höjdpunkter': 'highlights',
u'pull-quote (translation required)': 'pull-quote',
u'compound (translation required)': 'compound',
u'container (translation required)': 'container',
# u'fr\u00e5gor': 'questions',
u'sammansatt': 'compound',
u'container': 'container',
# u'frågor': 'questions',
# NOTE: A bit long, but recommended by http://www.nada.kth.se/dataterm/:
# u'fr\u00e5gor-och-svar': 'questions',
# u'vanliga-fr\u00e5gor': 'questions',
u'table (translation required)': 'table',
u'csv-table (translation required)': 'csv-table',
u'list-table (translation required)': 'list-table',
# u'frågor-och-svar': 'questions',
# u'vanliga-frågor': 'questions',
u'tabell': 'table',
u'csv-tabell': 'csv-table',
u'list-tabell': 'list-table',
u'meta': 'meta',
'math (translation required)': 'math',
u'matematik': 'math',
# u'bildkarta': 'imagemap', # FIXME: Translation might be too literal.
u'bild': 'image',
u'figur': 'figure',
u'inkludera': 'include',
u'r\u00e5': 'raw', # FIXME: Translation might be too literal.
u'ers\u00e4tt': 'replace',
u'inkludera': 'include',
u'rå': 'raw',
u'ersätta': 'replace',
u'unicode': 'unicode',
u'datum': 'date',
u'class (translation required)': 'class',
u'role (translation required)': 'role',
u'default-role (translation required)': 'default-role',
u'title (translation required)': 'title',
u'inneh\u00e5ll': 'contents',
u'klass': 'class',
u'roll': 'role',
u'standardroll': 'default-role',
u'titel': 'title',
u'innehåll': 'contents',
u'sektionsnumrering': 'sectnum',
u'target-notes (translation required)': 'target-notes',
u'header (translation required)': 'header',
u'footer (translation required)': 'footer',
u'sidhuvud': 'header',
u'sidfot': 'footer',
# u'fotnoter': 'footnotes',
# u'citeringar': 'citations',
}
@ -69,26 +70,26 @@ directives = {
mapping."""
roles = {
u'abbreviation (translation required)': 'abbreviation',
u'acronym (translation required)': 'acronym',
u'code (translation required)': 'code',
u'index (translation required)': 'index',
u'subscript (translation required)': 'subscript',
u'superscript (translation required)': 'superscript',
u'title-reference (translation required)': 'title-reference',
u'pep-reference (translation required)': 'pep-reference',
u'rfc-reference (translation required)': 'rfc-reference',
u'emphasis (translation required)': 'emphasis',
u'strong (translation required)': 'strong',
u'literal (translation required)': 'literal',
'math (translation required)': 'math',
u'named-reference (translation required)': 'named-reference',
u'anonymous-reference (translation required)': 'anonymous-reference',
u'footnote-reference (translation required)': 'footnote-reference',
u'citation-reference (translation required)': 'citation-reference',
u'substitution-reference (translation required)': 'substitution-reference',
u'target (translation required)': 'target',
u'uri-reference (translation required)': 'uri-reference',
u'r\u00e5': 'raw',}
u'förkortning': 'abbreviation',
u'akronym': 'acronym',
u'kod': 'code',
u'index': 'index',
u'nedsänkt': 'subscript',
u'upphöjd': 'superscript',
u'titel-referens': 'title-reference',
u'pep-referens': 'pep-reference',
u'rfc-referens': 'rfc-reference',
u'betoning': 'emphasis',
u'stark': 'strong',
u'bokstavlig': 'literal', # also 'ordagranna'
u'matematik': 'math',
u'namngiven-referens': 'named-reference',
u'anonym-referens': 'anonymous-reference',
u'fotnot-referens': 'footnote-reference',
u'citat-referens': 'citation-reference',
u'ersättnings-referens': 'substitution-reference',
u'mål': 'target',
u'uri-referens': 'uri-reference',
u'rå': 'raw',}
"""Mapping of Swedish role names to canonical role names for interpreted text.
"""

View File

@ -1,4 +1,4 @@
# $Id: roles.py 7514 2012-09-14 14:27:12Z milde $
# $Id: roles.py 7937 2016-05-24 10:48:48Z milde $
# Author: Edward Loper <edloper@gradient.cis.upenn.edu>
# Copyright: This module has been placed in the public domain.
@ -334,7 +334,7 @@ def code_role(role, rawtext, text, lineno, inliner, options={}, content=[]):
node = nodes.literal(rawtext, '', classes=classes)
# analyze content and add nodes for every token
# analyse content and add nodes for every token
for classes, value in tokens:
# print (classes, value)
if classes:
@ -351,9 +351,10 @@ code_role.options = {'class': directives.class_option,
register_canonical_role('code', code_role)
def math_role(role, rawtext, text, lineno, inliner, options={}, content=[]):
set_classes(options)
i = rawtext.find('`')
text = rawtext.split('`')[1]
node = nodes.math(rawtext, text)
node = nodes.math(rawtext, text, **options)
return [node], []
register_canonical_role('math', math_role)

View File

@ -1,4 +1,4 @@
# $Id: states.py 7640 2013-03-25 20:57:52Z milde $
# $Id: states.py 8060 2017-04-19 20:00:04Z milde $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -117,6 +117,7 @@ from docutils.parsers.rst import directives, languages, tableparser, roles
from docutils.parsers.rst.languages import en as _fallback_language_module
from docutils.utils import escape2null, unescape, column_width
from docutils.utils import punctuation_chars, roman, urischemes
from docutils.utils import split_escaped_whitespace
class MarkupError(DataError): pass
class UnknownInterpretedRoleError(DataError): pass
@ -225,7 +226,6 @@ class RSTState(StateWS):
# enable the reporter to determine source and source-line
if not hasattr(self.reporter, 'get_source_and_line'):
self.reporter.get_source_and_line = self.state_machine.get_source_and_line
# print "adding get_source_and_line to reporter", self.state_machine.input_offset
def goto_line(self, abs_line_offset):
@ -464,12 +464,144 @@ class Inliner:
"""
def __init__(self):
self.implicit_dispatch = [(self.patterns.uri, self.standalone_uri),]
self.implicit_dispatch = []
"""List of (pattern, bound method) tuples, used by
`self.implicit_inline`."""
def init_customizations(self, settings):
"""Setting-based customizations; run when parsing begins."""
# lookahead and look-behind expressions for inline markup rules
if getattr(settings, 'character_level_inline_markup', False):
start_string_prefix = u'(^|(?<!\x00))'
end_string_suffix = u''
else:
start_string_prefix = (u'(^|(?<=\\s|[%s%s]))' %
(punctuation_chars.openers,
punctuation_chars.delimiters))
end_string_suffix = (u'($|(?=\\s|[\x00%s%s%s]))' %
(punctuation_chars.closing_delimiters,
punctuation_chars.delimiters,
punctuation_chars.closers))
args = locals().copy()
args.update(vars(self.__class__))
parts = ('initial_inline', start_string_prefix, '',
[('start', '', self.non_whitespace_after, # simple start-strings
[r'\*\*', # strong
r'\*(?!\*)', # emphasis but not strong
r'``', # literal
r'_`', # inline internal target
r'\|(?!\|)'] # substitution reference
),
('whole', '', end_string_suffix, # whole constructs
[# reference name & end-string
r'(?P<refname>%s)(?P<refend>__?)' % self.simplename,
('footnotelabel', r'\[', r'(?P<fnend>\]_)',
[r'[0-9]+', # manually numbered
r'\#(%s)?' % self.simplename, # auto-numbered (w/ label?)
r'\*', # auto-symbol
r'(?P<citationlabel>%s)' % self.simplename] # citation reference
)
]
),
('backquote', # interpreted text or phrase reference
'(?P<role>(:%s:)?)' % self.simplename, # optional role
self.non_whitespace_after,
['`(?!`)'] # but not literal
)
]
)
self.start_string_prefix = start_string_prefix
self.end_string_suffix = end_string_suffix
self.parts = parts
self.patterns = Struct(
initial=build_regexp(parts),
emphasis=re.compile(self.non_whitespace_escape_before
+ r'(\*)' + end_string_suffix, re.UNICODE),
strong=re.compile(self.non_whitespace_escape_before
+ r'(\*\*)' + end_string_suffix, re.UNICODE),
interpreted_or_phrase_ref=re.compile(
r"""
%(non_unescaped_whitespace_escape_before)s
(
`
(?P<suffix>
(?P<role>:%(simplename)s:)?
(?P<refend>__?)?
)
)
%(end_string_suffix)s
""" % args, re.VERBOSE | re.UNICODE),
embedded_link=re.compile(
r"""
(
(?:[ \n]+|^) # spaces or beginning of line/string
< # open bracket
%(non_whitespace_after)s
(([^<>]|\x00[<>])+) # anything but unescaped angle brackets
%(non_whitespace_escape_before)s
> # close bracket
)
$ # end of string
""" % args, re.VERBOSE | re.UNICODE),
literal=re.compile(self.non_whitespace_before + '(``)'
+ end_string_suffix, re.UNICODE),
target=re.compile(self.non_whitespace_escape_before
+ r'(`)' + end_string_suffix, re.UNICODE),
substitution_ref=re.compile(self.non_whitespace_escape_before
+ r'(\|_{0,2})'
+ end_string_suffix, re.UNICODE),
email=re.compile(self.email_pattern % args + '$',
re.VERBOSE | re.UNICODE),
uri=re.compile(
(r"""
%(start_string_prefix)s
(?P<whole>
(?P<absolute> # absolute URI
(?P<scheme> # scheme (http, ftp, mailto)
[a-zA-Z][a-zA-Z0-9.+-]*
)
:
(
( # either:
(//?)? # hierarchical URI
%(uric)s* # URI characters
%(uri_end)s # final URI char
)
( # optional query
\?%(uric)s*
%(uri_end)s
)?
( # optional fragment
\#%(uric)s*
%(uri_end)s
)?
)
)
| # *OR*
(?P<email> # email address
""" + self.email_pattern + r"""
)
)
%(end_string_suffix)s
""") % args, re.VERBOSE | re.UNICODE),
pep=re.compile(
r"""
%(start_string_prefix)s
(
(pep-(?P<pepnum1>\d+)(.txt)?) # reference to source file
|
(PEP\s+(?P<pepnum2>\d+)) # reference by name
)
%(end_string_suffix)s""" % args, re.VERBOSE | re.UNICODE),
rfc=re.compile(
r"""
%(start_string_prefix)s
(RFC(-|\s+)?(?P<rfcnum>\d+))
%(end_string_suffix)s""" % args, re.VERBOSE | re.UNICODE))
self.implicit_dispatch.append((self.patterns.uri,
self.standalone_uri))
if settings.pep_references:
self.implicit_dispatch.append((self.patterns.pep,
self.pep_reference))
@ -527,20 +659,11 @@ class Inliner:
# Inline object recognition
# -------------------------
# lookahead and look-behind expressions for inline markup rules
start_string_prefix = (u'(^|(?<=\\s|[%s%s]))' %
(punctuation_chars.openers,
punctuation_chars.delimiters))
end_string_suffix = (u'($|(?=\\s|[\x00%s%s%s]))' %
(punctuation_chars.closing_delimiters,
punctuation_chars.delimiters,
punctuation_chars.closers))
# print start_string_prefix.encode('utf8')
# TODO: support non-ASCII whitespace in the following 4 patterns?
non_whitespace_before = r'(?<![ \n])'
non_whitespace_escape_before = r'(?<![ \n\x00])'
non_unescaped_whitespace_escape_before = r'(?<!(?<!\x00)[ \n\x00])'
non_whitespace_after = r'(?![ \n])'
# See also init_customizations().
non_whitespace_before = r'(?<!\s)'
non_whitespace_escape_before = r'(?<![\s\x00])'
non_unescaped_whitespace_escape_before = r'(?<!(?<!\x00)[\s\x00])'
non_whitespace_after = r'(?!\s)'
# Alphanumerics with isolated internal [-._+:] chars (i.e. not 2 together):
simplename = r'(?:(?!_)\w)+(?:[-._+:](?:(?!_)\w)+)*'
# Valid URI characters (see RFC 2396 & RFC 2732);
@ -560,118 +683,6 @@ class Inliner:
%(emailc)s+(?:\.%(emailc)s*)* # host
%(uri_end)s # final URI char
"""
parts = ('initial_inline', start_string_prefix, '',
[('start', '', non_whitespace_after, # simple start-strings
[r'\*\*', # strong
r'\*(?!\*)', # emphasis but not strong
r'``', # literal
r'_`', # inline internal target
r'\|(?!\|)'] # substitution reference
),
('whole', '', end_string_suffix, # whole constructs
[# reference name & end-string
r'(?P<refname>%s)(?P<refend>__?)' % simplename,
('footnotelabel', r'\[', r'(?P<fnend>\]_)',
[r'[0-9]+', # manually numbered
r'\#(%s)?' % simplename, # auto-numbered (w/ label?)
r'\*', # auto-symbol
r'(?P<citationlabel>%s)' % simplename] # citation reference
)
]
),
('backquote', # interpreted text or phrase reference
'(?P<role>(:%s:)?)' % simplename, # optional role
non_whitespace_after,
['`(?!`)'] # but not literal
)
]
)
patterns = Struct(
initial=build_regexp(parts),
emphasis=re.compile(non_whitespace_escape_before
+ r'(\*)' + end_string_suffix, re.UNICODE),
strong=re.compile(non_whitespace_escape_before
+ r'(\*\*)' + end_string_suffix, re.UNICODE),
interpreted_or_phrase_ref=re.compile(
r"""
%(non_unescaped_whitespace_escape_before)s
(
`
(?P<suffix>
(?P<role>:%(simplename)s:)?
(?P<refend>__?)?
)
)
%(end_string_suffix)s
""" % locals(), re.VERBOSE | re.UNICODE),
embedded_link=re.compile(
r"""
(
(?:[ \n]+|^) # spaces or beginning of line/string
< # open bracket
%(non_whitespace_after)s
([^<>\x00]+(\x00_)?) # anything but angle brackets & nulls
# except escaped trailing low line
%(non_whitespace_before)s
> # close bracket w/o whitespace before
)
$ # end of string
""" % locals(), re.VERBOSE | re.UNICODE),
literal=re.compile(non_whitespace_before + '(``)'
+ end_string_suffix),
target=re.compile(non_whitespace_escape_before
+ r'(`)' + end_string_suffix),
substitution_ref=re.compile(non_whitespace_escape_before
+ r'(\|_{0,2})'
+ end_string_suffix),
email=re.compile(email_pattern % locals() + '$',
re.VERBOSE | re.UNICODE),
uri=re.compile(
(r"""
%(start_string_prefix)s
(?P<whole>
(?P<absolute> # absolute URI
(?P<scheme> # scheme (http, ftp, mailto)
[a-zA-Z][a-zA-Z0-9.+-]*
)
:
(
( # either:
(//?)? # hierarchical URI
%(uric)s* # URI characters
%(uri_end)s # final URI char
)
( # optional query
\?%(uric)s*
%(uri_end)s
)?
( # optional fragment
\#%(uric)s*
%(uri_end)s
)?
)
)
| # *OR*
(?P<email> # email address
""" + email_pattern + r"""
)
)
%(end_string_suffix)s
""") % locals(), re.VERBOSE | re.UNICODE),
pep=re.compile(
r"""
%(start_string_prefix)s
(
(pep-(?P<pepnum1>\d+)(.txt)?) # reference to source file
|
(PEP\s+(?P<pepnum2>\d+)) # reference by name
)
%(end_string_suffix)s""" % locals(), re.VERBOSE | re.UNICODE),
rfc=re.compile(
r"""
%(start_string_prefix)s
(RFC(-|\s+)?(?P<rfcnum>\d+))
%(end_string_suffix)s""" % locals(), re.VERBOSE | re.UNICODE))
def quoted_start(self, match):
"""Test if inline markup start-string is 'quoted'.
@ -787,8 +798,10 @@ class Inliner:
match = self.patterns.embedded_link.search(escaped)
if match: # embedded <URI> or <alias_>
text = unescape(escaped[:match.start(0)])
aliastext = unescape(match.group(2), restore_backslashes=True)
if aliastext.endswith('_') and not (aliastext.endswith(r'\_')
aliastext = match.group(2)
underscore_escaped = aliastext.endswith('\x00_')
aliastext = unescape(aliastext)
if aliastext.endswith('_') and not (underscore_escaped
or self.patterns.uri.match(aliastext)):
aliastype = 'name'
alias = normalize_name(aliastext[:-1])
@ -796,7 +809,9 @@ class Inliner:
target.indirect_reference_name = aliastext[:-1]
else:
aliastype = 'uri'
alias = ''.join(aliastext.split())
alias_parts = split_escaped_whitespace(match.group(2))
alias = ' '.join(''.join(unescape(part).split())
for part in alias_parts)
alias = self.adjust_uri(alias)
if alias.endswith(r'\_'):
alias = alias[:-2] + '_'
@ -1230,6 +1245,8 @@ class Body(RSTState):
def bullet(self, match, context, next_state):
"""Bullet list item."""
bulletlist = nodes.bullet_list()
(bulletlist.source,
bulletlist.line) = self.state_machine.get_source_and_line()
self.parent += bulletlist
bulletlist['bullet'] = match.string[0]
i, blank_finish = self.list_item(match.end())
@ -1460,6 +1477,7 @@ class Body(RSTState):
def option_marker(self, match, context, next_state):
"""Option list item."""
optionlist = nodes.option_list()
(optionlist.source, optionlist.line) = self.state_machine.get_source_and_line()
try:
listitem, blank_finish = self.option_list_item(match)
except MarkupError, error:
@ -1547,6 +1565,9 @@ class Body(RSTState):
def doctest(self, match, context, next_state):
data = '\n'.join(self.state_machine.get_text_block())
# TODO: prepend class value ['pycon'] (Python Console)
# parse with `directives.body.CodeBlock` (returns literal-block
# with class "code" and syntax highlight markup).
self.parent += nodes.doctest_block(data, data)
return [], next_state, []
@ -1747,9 +1768,13 @@ class Body(RSTState):
line=startline+offset)
return [error]
def build_table(self, tabledata, tableline, stub_columns=0):
def build_table(self, tabledata, tableline, stub_columns=0, widths=None):
colwidths, headrows, bodyrows = tabledata
table = nodes.table()
if widths == 'auto':
table['classes'] += ['colwidths-auto']
elif widths: # "grid" or list of integers
table['classes'] += ['colwidths-given']
tgroup = nodes.tgroup(cols=len(colwidths))
table += tgroup
for colwidth in colwidths:
@ -1939,8 +1964,10 @@ class Body(RSTState):
refname = self.is_reference(reference)
if refname:
return 'refname', refname
reference = ''.join([''.join(line.split()) for line in block])
return 'refuri', unescape(reference)
ref_parts = split_escaped_whitespace(' '.join(block))
reference = ' '.join(''.join(unescape(part).split())
for part in ref_parts)
return 'refuri', reference
def is_reference(self, reference):
match = self.explicit.patterns.reference.match(

View File

@ -1,4 +1,4 @@
# $Id: tableparser.py 7320 2012-01-19 22:33:02Z milde $
# $Id: tableparser.py 7898 2015-05-29 20:49:28Z milde $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -511,8 +511,8 @@ class SimpleTableParser(TableParser):
if i == lastcol and line[end:].strip():
text = line[start:].rstrip()
new_end = start + len(text)
columns[i] = (start, new_end)
main_start, main_end = self.columns[-1]
columns[i] = (start, max(main_end, new_end))
if new_end > main_end:
self.columns[-1] = (main_start, new_end)
elif line[end:nextstart].strip():

View File

@ -1,4 +1,4 @@
# $Id: frontmatter.py 7595 2013-01-21 17:33:56Z milde $
# $Id: frontmatter.py 8117 2017-06-18 23:38:18Z milde $
# Author: David Goodger, Ueli Schlaepfer <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -433,6 +433,10 @@ class DocInfo(Transform):
and isinstance(field[-1][0], nodes.paragraph):
utils.clean_rcs_keywords(
field[-1][0], self.rcs_keyword_substitutions)
if normedname not in bibliofields:
classvalue = nodes.make_id(normedname)
if classvalue:
field['classes'].append(classvalue)
docinfo.append(field)
nodelist = []
if len(docinfo) != 0:

View File

@ -1,4 +1,4 @@
# $Id: peps.py 6433 2010-09-28 08:21:25Z milde $
# $Id: peps.py 7995 2016-12-10 17:50:59Z milde $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -32,8 +32,8 @@ class Headers(Transform):
default_priority = 360
pep_url = 'pep-%04d'
pep_cvs_url = ('http://svn.python.org/view/*checkout*'
'/peps/trunk/pep-%04d.txt')
pep_cvs_url = ('http://hg.python.org'
'/peps/file/default/pep-%04d.txt')
rcs_keyword_substitutions = (
(re.compile(r'\$' r'RCSfile: (.+),v \$$', re.IGNORECASE), r'\1'),
(re.compile(r'\$[a-zA-Z]+: (.+) \$$'), r'\1'),)
@ -113,7 +113,7 @@ class Headers(Transform):
elif name in ('replaces', 'replaced-by', 'requires'):
newbody = []
space = nodes.Text(' ')
for refpep in re.split(',?\s+', body.astext()):
for refpep in re.split(r',?\s+', body.astext()):
pepno = int(refpep)
newbody.append(nodes.reference(
refpep, refpep,

View File

@ -1,4 +1,4 @@
# $Id: references.py 7624 2013-03-07 14:10:26Z milde $
# $Id: references.py 8067 2017-05-04 20:10:03Z milde $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -710,6 +710,7 @@ class Substitutions(Transform):
raise CircularSubstitutionDefinitionError
else:
nested[nested_name].append(key)
nested_ref['ref-origin'] = ref
subreflist.append(nested_ref)
except CircularSubstitutionDefinitionError:
parent = ref.parent
@ -721,9 +722,13 @@ class Substitutions(Transform):
line=parent.line, base_node=parent)
parent.replace_self(msg)
else:
# find original ref substitution which cased this error
ref_origin = ref
while ref_origin.hasattr('ref-origin'):
ref_origin = ref_origin['ref-origin']
msg = self.document.reporter.error(
'Circular substitution definition referenced: "%s".'
% refname, base_node=ref)
'Circular substitution definition referenced: '
'"%s".' % refname, base_node=ref_origin)
msgid = self.document.set_id(msg)
prb = nodes.problematic(
ref.rawsource, ref.rawsource, refid=msgid)
@ -893,7 +898,10 @@ class DanglingReferencesVisitor(nodes.SparseNodeVisitor):
msgid = self.document.set_id(msg)
prb = nodes.problematic(
node.rawsource, node.rawsource, refid=msgid)
prbid = self.document.set_id(prb)
try:
prbid = node['ids'][0]
except IndexError:
prbid = self.document.set_id(prb)
msg.add_backref(prbid)
node.replace_self(prb)
else:

View File

@ -1,4 +1,4 @@
# $Id: universal.py 7668 2013-06-04 12:46:30Z milde $
# $Id: universal.py 8144 2017-07-26 21:25:08Z milde $
# -*- coding: utf-8 -*-
# Authors: David Goodger <goodger@python.org>; Ueli Schlaepfer; Günter Milde
# Maintainer: docutils-develop@lists.sourceforge.net
@ -49,6 +49,10 @@ class Decorations(Transform):
def generate_footer(self):
# @@@ Text is hard-coded for now.
# Should be made dynamic (language-dependent).
# @@@ Use timestamp from the `SOURCE_DATE_EPOCH`_ environment variable
# for the datestamp?
# See https://sourceforge.net/p/docutils/patches/132/
# and https://reproducible-builds.org/specs/source-date-epoch/
settings = self.document.settings
if settings.generator or settings.datestamp or settings.source_link \
or settings.source_url:
@ -204,6 +208,7 @@ class StripClassesAndElements(Transform):
if class_value in self.strip_elements:
return 1
class SmartQuotes(Transform):
"""
@ -214,6 +219,20 @@ class SmartQuotes(Transform):
default_priority = 850
nodes_to_skip = (nodes.FixedTextElement, nodes.Special)
"""Do not apply "smartquotes" to instances of these block-level nodes."""
literal_nodes = (nodes.image, nodes.literal, nodes.math,
nodes.raw, nodes.problematic)
"""Do not change quotes in instances of these inline nodes."""
smartquotes_action = 'qDe'
"""Setting to select smartquote transformations.
The default 'qDe' educates normal quote characters: (", '),
em- and en-dashes (---, --) and ellipses (...).
"""
def __init__(self, document, startnode):
Transform.__init__(self, document, startnode=startnode)
self.unsupported_languages = set()
@ -226,11 +245,7 @@ class SmartQuotes(Transform):
False: 'plain'}
for txtnode in txtnodes:
nodetype = texttype[isinstance(txtnode.parent,
(nodes.literal,
nodes.math,
nodes.image,
nodes.raw,
nodes.problematic))]
self.literal_nodes)]
yield (nodetype, txtnode.astext())
@ -245,12 +260,15 @@ class SmartQuotes(Transform):
# print repr(alternative)
document_language = self.document.settings.language_code
lc_smartquotes = self.document.settings.smartquotes_locales
if lc_smartquotes:
smartquotes.smartchars.quotes.update(dict(lc_smartquotes))
# "Educate" quotes in normal text. Handle each block of text
# (TextElement node) as a unit to keep context around inline nodes:
for node in self.document.traverse(nodes.TextElement):
# skip preformatted text blocks and special elements:
if isinstance(node, (nodes.FixedTextElement, nodes.Special)):
if isinstance(node, self.nodes_to_skip):
continue
# nested TextElements are not "block-level" elements:
if isinstance(node.parent, nodes.TextElement):
@ -269,7 +287,7 @@ class SmartQuotes(Transform):
lang = lang.replace('-x-altquot', '')
else:
lang += '-x-altquot'
# drop subtags missing in quotes:
# drop unsupported subtags:
for tag in utils.normalize_language_tag(lang):
if tag in smartquotes.smartchars.quotes:
lang = tag
@ -282,11 +300,12 @@ class SmartQuotes(Transform):
lang = ''
# Iterator educating quotes in plain text:
# '2': set all, using old school en- and em- dash shortcuts
# (see "utils/smartquotes.py" for the attribute setting)
teacher = smartquotes.educate_tokens(self.get_tokens(txtnodes),
attr='2', language=lang)
attr=self.smartquotes_action, language=lang)
for txtnode, newtext in zip(txtnodes, teacher):
txtnode.parent.replace(txtnode, nodes.Text(newtext))
txtnode.parent.replace(txtnode, nodes.Text(newtext,
rawsource=txtnode.rawsource))
self.unsupported_languages = set() # reset
self.unsupported_languages = set() # reset

View File

@ -1,4 +1,4 @@
# $Id: writer_aux.py 7320 2012-01-19 22:33:02Z milde $
# $Id: writer_aux.py 7808 2015-02-27 17:03:32Z milde $
# Author: Lea Wiemann <LeWiemann@gmail.com>
# Copyright: This module has been placed in the public domain.

View File

@ -1,5 +1,5 @@
# coding: utf-8
# $Id: __init__.py 7668 2013-06-04 12:46:30Z milde $
# $Id: __init__.py 8141 2017-07-08 17:05:18Z goodger $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -13,9 +13,10 @@ import sys
import os
import os.path
import re
import itertools
import warnings
import unicodedata
from docutils import ApplicationError, DataError
from docutils import ApplicationError, DataError, __version_info__
from docutils import nodes
import docutils.io
from docutils.utils.error_reporting import ErrorOutput, SafeString
@ -325,7 +326,7 @@ def assemble_option_dict(option_list, options_spec):
raise DuplicateOptionError('duplicate option "%s"' % name)
try:
options[name] = convertor(value)
except (ValueError, TypeError), detail:
except (ValueError, TypeError) as detail:
raise detail.__class__('(option: "%s"; value: %r)\n%s'
% (name, value, ' '.join(detail.args)))
return options
@ -575,7 +576,7 @@ def escape2null(text):
parts.append('\x00' + text[found+1:found+2])
start = found + 2 # skip character after escape
def unescape(text, restore_backslashes=False):
def unescape(text, restore_backslashes=False, respect_whitespace=False):
"""
Return a string with nulls removed or restored to backslashes.
Backslash-escaped spaces are also removed.
@ -587,6 +588,16 @@ def unescape(text, restore_backslashes=False):
text = ''.join(text.split(sep))
return text
def split_escaped_whitespace(text):
"""
Split `text` on escaped whitespace (null+space or null+newline).
Return a list of strings.
"""
strings = text.split('\x00 ')
strings = [string.split('\x00\n') for string in strings]
# flatten list of lists of strings to list of strings:
return list(itertools.chain(*strings))
def strip_combining_chars(text):
if isinstance(text, str) and sys.version_info < (3,0):
return text
@ -595,8 +606,10 @@ def strip_combining_chars(text):
def find_combining_chars(text):
"""Return indices of all combining chars in Unicode string `text`.
>>> from docutils.utils import find_combining_chars
>>> find_combining_chars(u'A t̆ab̆lĕ')
[3, 6, 9]
"""
if isinstance(text, str) and sys.version_info < (3,0):
return []
@ -605,8 +618,10 @@ def find_combining_chars(text):
def column_indices(text):
"""Indices of Unicode string `text` when skipping combining characters.
>>> from docutils.utils import column_indices
>>> column_indices(u'A t̆ab̆lĕ')
[0, 1, 2, 4, 5, 7, 8]
"""
# TODO: account for asian wide chars here instead of using dummy
# replacements in the tableparser?
@ -663,17 +678,21 @@ def normalize_language_tag(tag):
Example:
>>> from docutils.utils import normalize_language_tag
>>> normalize_language_tag('de_AT-1901')
['de-at-1901', 'de-at', 'de-1901', 'de']
>>> normalize_language_tag('de-CH-x_altquot')
['de-ch-x-altquot', 'de-ch', 'de-x-altquot', 'de']
"""
# normalize:
tag = tag.lower().replace('_','-')
tag = tag.lower().replace('-','_')
# split (except singletons, which mark the following tag as non-standard):
tag = re.sub(r'-([a-zA-Z0-9])-', r'-\1_', tag)
taglist = []
subtags = [subtag.replace('_', '-') for subtag in tag.split('-')]
tag = re.sub(r'_([a-zA-Z0-9])_', r'_\1-', tag)
subtags = [subtag for subtag in tag.split('_')]
base_tag = [subtags.pop(0)]
# find all combinations of subtags
taglist = []
for n in range(len(subtags), 0, -1):
for tags in unique_combinations(subtags, n):
taglist.append('-'.join(base_tag+tags))
@ -747,3 +766,42 @@ class DependencyList(object):
except AttributeError:
output_file = None
return '%s(%r, %s)' % (self.__class__.__name__, output_file, self.list)
release_level_abbreviations = {
'alpha': 'a',
'beta': 'b',
'candidate': 'rc',
'final': '',}
def version_identifier(version_info=None):
# to add in Docutils 0.15:
# version_info is a namedtuple, an instance of Docutils.VersionInfo.
"""
Given a `version_info` tuple (default is docutils.__version_info__),
build & return a version identifier string.
"""
if version_info is None:
version_info = __version_info__
if version_info[2]: # version_info.micro
micro = '.%s' % version_info[2]
else:
micro = ''
releaselevel = release_level_abbreviations[
version_info[3]] # version_info.releaselevel
if version_info[4]: # version_info.serial
serial = version_info[4]
else:
serial = ''
if version_info[5]: # version_info.release
dev = ''
else:
dev = '.dev'
version = '%s.%s%s%s%s%s' % (
version_info[0], # version_info.major
version_info[1], # version_info.minor
micro,
releaselevel,
serial,
dev)
return version

View File

@ -4,7 +4,7 @@
"""Lexical analysis of formal languages (i.e. code) using Pygments."""
# :Author: Georg Brandl; Felix Wiemann; Günter Milde
# :Date: $Date: 2011-12-20 15:14:21 +0100 (Die, 20. Dez 2011) $
# :Date: $Date: 2015-04-20 16:05:27 +0200 (Mo, 20 Apr 2015) $
# :Copyright: This module has been placed in the public domain.
from docutils import ApplicationError
@ -13,7 +13,7 @@ try:
from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import _get_ttype_class
with_pygments = True
except ImportError:
except (ImportError, SyntaxError): # pygments 2.0.1 fails with Py 3.1 and 3.2
with_pygments = False
# Filter the following token types from the list of class arguments:

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# :Id: $Id: error_reporting.py 7668 2013-06-04 12:46:30Z milde $
# :Id: $Id: error_reporting.py 8119 2017-06-22 20:59:19Z milde $
# :Copyright: © 2011 Günter Milde.
# :License: Released under the terms of the `2-Clause BSD license`_, in short:
#
@ -44,10 +44,20 @@ try:
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:
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)
except ValueError as error: # OS X may set UTF-8 without language code
# see http://bugs.python.org/issue18378
# and https://sourceforge.net/p/docutils/bugs/298/
if "unknown locale: UTF-8" in error.args:
locale_encoding = "UTF-8"
else:
locale_encoding = None
except: # any other problems determining the locale -> use None
locale_encoding = None
try:
codecs.lookup(locale_encoding or '') # None -> ''
except LookupError:
@ -72,7 +82,7 @@ class SafeString(object):
def __str__(self):
try:
return str(self.data)
except UnicodeEncodeError, err:
except UnicodeEncodeError:
if isinstance(self.data, Exception):
args = [str(SafeString(arg, self.encoding,
self.encoding_errors))
@ -103,7 +113,7 @@ class SafeString(object):
if isinstance(self.data, EnvironmentError):
u = u.replace(": u'", ": '") # normalize filename quoting
return u
except UnicodeError, error: # catch ..Encode.. and ..Decode.. errors
except UnicodeError as 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,
@ -189,7 +199,11 @@ class ErrorOutput(object):
self.stream.write(data)
except UnicodeEncodeError:
self.stream.write(data.encode(self.encoding, self.encoding_errors))
except TypeError: # in Python 3, stderr expects unicode
except TypeError:
if isinstance(data, unicode): # passed stream may expect bytes
self.stream.write(data.encode(self.encoding,
self.encoding_errors))
return
if self.stream in (sys.stderr, sys.stdout):
self.stream.buffer.write(data) # write bytes to raw stream
else:

View File

@ -1,4 +1,4 @@
# :Id: $Id: __init__.py 7218 2011-11-08 17:42:40Z milde $
# :Id: $Id: __init__.py 7865 2015-04-12 10:06:43Z milde $
# :Author: Guenter Milde.
# :License: Released under the terms of the `2-Clause BSD license`_, in short:
#
@ -17,8 +17,9 @@ It contains various modules for conversion between different math formats
:math2html: LaTeX math -> HTML conversion from eLyXer
:latex2mathml: LaTeX math -> presentational MathML
:unichar2tex: Unicode character to LaTeX math translation table
:tex2unichar: LaTeX math to Unicode character translation dictionaries
:unichar2tex: Unicode character to LaTeX math translation table
:tex2unichar: LaTeX math to Unicode character translation dictionaries
:tex2mathml_extern: Wrapper for TeX -> MathML command line converters
"""
# helpers for Docutils math support

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# :Id: $Id: latex2mathml.py 7668 2013-06-04 12:46:30Z milde $
# :Id: $Id: latex2mathml.py 7995 2016-12-10 17:50:59Z milde $
# :Copyright: © 2010 Günter Milde.
# Based on rst2mathml.py from the latex_math sandbox project
# © 2005 Jens Jørgen Mortensen
@ -151,8 +151,8 @@ mathscr = {
}
negatables = {'=': u'\u2260',
'\in': u'\u2209',
'\equiv': u'\u2262'}
r'\in': u'\u2209',
r'\equiv': u'\u2262'}
# LaTeX to MathML translation stuff:
class math:
@ -558,3 +558,14 @@ def handle_keyword(name, node, string):
raise SyntaxError(u'Unknown LaTeX command: ' + name)
return node, skip
def tex2mathml(tex_math, inline=True):
"""Return string with MathML code corresponding to `tex_math`.
`inline`=True is for inline math and `inline`=False for displayed math.
"""
mathml_tree = parse_latex_math(tex_math, inline=inline)
return ''.join(mathml_tree.xml())

View File

@ -14,7 +14,7 @@
# .. _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/
# http://alexfernandez.github.io/elyxer/
# --end--
# Alex 20101110
@ -112,7 +112,7 @@ class BibStylesConfig(object):
u'@conference':u'$authors: “$title”, <i>$journal</i>,{ pp. $pages,} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'@inbook':u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@incollection':u'$authors: <i>$title</i>{ in <i>$booktitle</i>{ ($editor, ed.)}}.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@inproceedings':u'$authors: “$title”, <i>$journal</i>,{ pp. $pages,} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'@inproceedings':u'$authors: “$title”, <i>$booktitle</i>,{ pp. $pages,} $year.{ URL <a href="$url">$url</a>.}{ $note.}',
u'@manual':u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@mastersthesis':u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
u'@misc':u'$authors: <i>$title</i>.{{ $publisher,}{ $howpublished,} $year.}{ URL <a href="$url">$url</a>.}{ $note.}',
@ -245,7 +245,8 @@ class ContainerConfig(object):
u'\\begin_inset Quotes':u'QuoteContainer',
u'\\begin_inset Tabular':u'Table', u'\\begin_inset Text':u'InsetText',
u'\\begin_inset VSpace':u'VerticalSpace', u'\\begin_inset Wrap':u'Wrap',
u'\\begin_inset listings':u'Listing', u'\\begin_inset space':u'Space',
u'\\begin_inset listings':u'Listing',
u'\\begin_inset script':u'ScriptInset', u'\\begin_inset space':u'Space',
u'\\begin_layout':u'Layout', u'\\begin_layout Abstract':u'Abstract',
u'\\begin_layout Author':u'Author',
u'\\begin_layout Bibliography':u'Bibliography',
@ -291,7 +292,7 @@ class EscapeConfig(object):
"Configuration class from elyxer.config file"
chars = {
u'\n':u'', u' -- ':u'', u'\'':u'', u'---':u'', u'`':u'',
u'\n':u'', u' -- ':u'', u' --- ':u'', u'\'':u'', u'`':u'',
}
commands = {
@ -324,21 +325,24 @@ class FormulaConfig(object):
alphacommands = {
u'\\AA':u'Å', u'\\AE':u'Æ',
u'\\AmS':u'<span class="versalitas">AmS</span>', u'\\DH':u'Ð',
u'\\L':u'Ł', u'\\O':u'Ø', u'\\OE':u'Œ', u'\\TH':u'Þ', u'\\aa':u'å',
u'\\ae':u'æ', u'\\alpha':u'α', u'\\beta':u'β', u'\\delta':u'δ',
u'\\dh':u'ð', u'\\epsilon':u'ϵ', u'\\eta':u'η', u'\\gamma':u'γ',
u'\\i':u'ı', u'\\imath':u'ı', u'\\iota':u'ι', u'\\j':u'ȷ',
u'\\jmath':u'ȷ', u'\\kappa':u'κ', u'\\l':u'ł', u'\\lambda':u'λ',
u'\\AmS':u'<span class="versalitas">AmS</span>', u'\\Angstroem':u'',
u'\\DH':u'Ð', u'\\Koppa':u'Ϟ', u'\\L':u'Ł', u'\\Micro':u'µ', u'\\O':u'Ø',
u'\\OE':u'Œ', u'\\Sampi':u'Ϡ', u'\\Stigma':u'Ϛ', u'\\TH':u'Þ',
u'\\aa':u'å', u'\\ae':u'æ', u'\\alpha':u'α', u'\\beta':u'β',
u'\\delta':u'δ', u'\\dh':u'ð', u'\\digamma':u'ϝ', u'\\epsilon':u'ϵ',
u'\\eta':u'η', u'\\eth':u'ð', u'\\gamma':u'γ', u'\\i':u'ı',
u'\\imath':u'ı', u'\\iota':u'ι', u'\\j':u'ȷ', u'\\jmath':u'ȷ',
u'\\kappa':u'κ', u'\\koppa':u'ϟ', u'\\l':u'ł', u'\\lambda':u'λ',
u'\\mu':u'μ', u'\\nu':u'ν', u'\\o':u'ø', u'\\oe':u'œ', u'\\omega':u'ω',
u'\\phi':u'φ', u'\\pi':u'π', u'\\psi':u'ψ', u'\\rho':u'ρ',
u'\\sigma':u'σ', u'\\ss':u'ß', u'\\tau':u'τ', u'\\textcrh':u'ħ',
u'\\th':u'þ', u'\\theta':u'θ', u'\\upsilon':u'υ', u'\\varDelta':u'',
u'\\sampi':u'ϡ', u'\\sigma':u'σ', u'\\ss':u'ß', u'\\stigma':u'ϛ',
u'\\tau':u'τ', u'\\tcohm':u'', u'\\textcrh':u'ħ', u'\\th':u'þ',
u'\\theta':u'θ', u'\\upsilon':u'υ', u'\\varDelta':u'',
u'\\varGamma':u'Γ', u'\\varLambda':u'Λ', u'\\varOmega':u'Ω',
u'\\varPhi':u'Φ', u'\\varPi':u'Π', u'\\varPsi':u'Ψ', u'\\varSigma':u'Σ',
u'\\varTheta':u'Θ', u'\\varUpsilon':u'Υ', u'\\varXi':u'Ξ',
u'\\varepsilon':u'ε', u'\\varkappa':u'ϰ', u'\\varphi':u'φ',
u'\\varpi':u'ϖ', u'\\varrho':u'ϱ', u'\\varsigma':u'ς',
u'\\varbeta':u'ϐ', u'\\varepsilon':u'ε', u'\\varkappa':u'ϰ',
u'\\varphi':u'φ', u'\\varpi':u'ϖ', u'\\varrho':u'ϱ', u'\\varsigma':u'ς',
u'\\vartheta':u'ϑ', u'\\xi':u'ξ', u'\\zeta':u'ζ',
}
@ -376,59 +380,75 @@ class FormulaConfig(object):
commands = {
u'\\ ':u' ', u'\\!':u'', u'\\#':u'#', u'\\$':u'$', u'\\%':u'%',
u'\\&':u'&', u'\\,':u' ', u'\\:':u'', u'\\;':u'',
u'\\APLdownarrowbox':u'', u'\\APLleftarrowbox':u'',
u'\\&':u'&', u'\\,':u' ', u'\\:':u'', u'\\;':u'', u'\\AC':u'',
u'\\APLcomment':u'', u'\\APLdownarrowbox':u'', u'\\APLinput':u'',
u'\\APLinv':u'', u'\\APLleftarrowbox':u'', u'\\APLlog':u'',
u'\\APLrightarrowbox':u'', u'\\APLuparrowbox':u'', u'\\Box':u'',
u'\\Bumpeq':u'', u'\\CIRCLE':u'', u'\\Cap':u'', u'\\CheckedBox':u'',
u'\\Circle':u'', u'\\Coloneqq':u'', u'\\Corresponds':u'',
u'\\Cup':u'', u'\\Delta':u'Δ', u'\\Diamond':u'', u'\\Downarrow':u'',
u'\\EUR':u'', u'\\Game':u'', u'\\Gamma':u'Γ', u'\\Im':u'',
u'\\Join':u'', u'\\LEFTCIRCLE':u'', u'\\LEFTcircle':u'',
u'\\Lambda':u'Λ', u'\\Leftarrow':u'', u'\\Lleftarrow':u'',
u'\\Longleftarrow':u'', u'\\Longleftrightarrow':u'',
u'\\Longrightarrow':u'', u'\\Lsh':u'', u'\\Mapsfrom':u'⇐|',
u'\\Mapsto':u'|⇒', u'\\Omega':u'Ω', u'\\P':u'', u'\\Phi':u'Φ',
u'\\Pi':u'Π', u'\\Pr':u'Pr', u'\\Psi':u'Ψ', u'\\RIGHTCIRCLE':u'',
u'\\RIGHTcircle':u'', u'\\Re':u'', u'\\Rrightarrow':u'',
u'\\Rsh':u'', u'\\S':u'§', u'\\Sigma':u'Σ', u'\\Square':u'',
u'\\Subset':u'', u'\\Supset':u'', u'\\Theta':u'Θ', u'\\Uparrow':u'',
u'\\Updownarrow':u'', u'\\Upsilon':u'Υ', u'\\Vdash':u'',
u'\\Vert':u'', u'\\Vvdash':u'', u'\\XBox':u'', u'\\Xi':u'Ξ',
u'\\Yup':u'', u'\\\\':u'<br/>', u'\\_':u'_', u'\\aleph':u'',
u'\\amalg':u'', u'\\angle':u'', u'\\aquarius':u'',
u'\\arccos':u'arccos', u'\\arcsin':u'arcsin', u'\\arctan':u'arctan',
u'\\arg':u'arg', u'\\aries':u'', u'\\ast':u'', u'\\asymp':u'',
u'\\Bumpeq':u'', u'\\CIRCLE':u'', u'\\Cap':u'',
u'\\CapitalDifferentialD':u'', u'\\CheckedBox':u'', u'\\Circle':u'',
u'\\Coloneqq':u'', u'\\ComplexI':u'', u'\\ComplexJ':u'',
u'\\Corresponds':u'', u'\\Cup':u'', u'\\Delta':u'Δ', u'\\Diamond':u'',
u'\\Diamondblack':u'', u'\\Diamonddot':u'', u'\\DifferentialD':u'',
u'\\Downarrow':u'', u'\\EUR':u'', u'\\Euler':u'',
u'\\ExponetialE':u'', u'\\Finv':u'', u'\\Game':u'', u'\\Gamma':u'Γ',
u'\\Im':u'', u'\\Join':u'', u'\\LEFTCIRCLE':u'', u'\\LEFTcircle':u'',
u'\\LHD':u'', u'\\Lambda':u'Λ', u'\\Lbag':u'', u'\\Leftarrow':u'',
u'\\Lleftarrow':u'', u'\\Longleftarrow':u'',
u'\\Longleftrightarrow':u'', u'\\Longrightarrow':u'', u'\\Lparen':u'',
u'\\Lsh':u'', u'\\Mapsfrom':u'⇐|', u'\\Mapsto':u'|⇒', u'\\Omega':u'Ω',
u'\\P':u'', u'\\Phi':u'Φ', u'\\Pi':u'Π', u'\\Pr':u'Pr', u'\\Psi':u'Ψ',
u'\\Qoppa':u'Ϙ', u'\\RHD':u'', u'\\RIGHTCIRCLE':u'',
u'\\RIGHTcircle':u'', u'\\Rbag':u'', u'\\Re':u'', u'\\Rparen':u'',
u'\\Rrightarrow':u'', u'\\Rsh':u'', u'\\S':u'§', u'\\Sigma':u'Σ',
u'\\Square':u'', u'\\Subset':u'', u'\\Sun':u'', u'\\Supset':u'',
u'\\Theta':u'Θ', u'\\Uparrow':u'', u'\\Updownarrow':u'',
u'\\Upsilon':u'Υ', u'\\Vdash':u'', u'\\Vert':u'', u'\\Vvdash':u'',
u'\\XBox':u'', u'\\Xi':u'Ξ', u'\\Yup':u'', u'\\\\':u'<br/>',
u'\\_':u'_', u'\\aleph':u'', u'\\amalg':u'', u'\\anchor':u'',
u'\\angle':u'', u'\\aquarius':u'', u'\\arccos':u'arccos',
u'\\arcsin':u'arcsin', u'\\arctan':u'arctan', u'\\arg':u'arg',
u'\\aries':u'', u'\\arrowbullet':u'', u'\\ast':u'', u'\\asymp':u'',
u'\\backepsilon':u'', u'\\backprime':u'', u'\\backsimeq':u'',
u'\\backslash':u'\\', u'\\barwedge':u'', u'\\because':u'',
u'\\beth':u'', u'\\between':u'', u'\\bigcap':u'', u'\\bigcirc':u'',
u'\\bigcup':u'', u'\\bigodot':u'', u'\\bigoplus':u'',
u'\\bigotimes':u'', u'\\bigsqcup':u'', u'\\bigstar':u'',
u'\\bigtriangledown':u'', u'\\bigtriangleup':u'', u'\\biguplus':u'',
u'\\bigvee':u'', u'\\bigwedge':u'', u'\\blacklozenge':u'',
u'\\blacksmiley':u'', u'\\blacksquare':u'', u'\\blacktriangle':u'',
u'\\blacktriangledown':u'', u'\\blacktriangleright':u'', u'\\bot':u'',
u'\\bowtie':u'', u'\\box':u'', u'\\boxdot':u'', u'\\bullet':u'',
u'\\backslash':u'\\', u'\\ballotx':u'', u'\\barwedge':u'',
u'\\because':u'', u'\\beth':u'', u'\\between':u'', u'\\bigcap':u'',
u'\\bigcirc':u'', u'\\bigcup':u'', u'\\bigodot':u'',
u'\\bigoplus':u'', u'\\bigotimes':u'', u'\\bigsqcup':u'',
u'\\bigstar':u'', u'\\bigtriangledown':u'', u'\\bigtriangleup':u'',
u'\\biguplus':u'', u'\\bigvee':u'', u'\\bigwedge':u'',
u'\\biohazard':u'', u'\\blacklozenge':u'', u'\\blacksmiley':u'',
u'\\blacksquare':u'', u'\\blacktriangle':u'',
u'\\blacktriangledown':u'', u'\\blacktriangleleft':u'',
u'\\blacktriangleright':u'', u'\\blacktriangleup':u'', u'\\bot':u'',
u'\\bowtie':u'', u'\\box':u'', u'\\boxast':u'', u'\\boxbar':u'',
u'\\boxbox':u'', u'\\boxbslash':u'', u'\\boxcircle':u'',
u'\\boxdot':u'', u'\\boxminus':u'', u'\\boxplus':u'',
u'\\boxslash':u'', u'\\boxtimes':u'', u'\\bullet':u'',
u'\\bumpeq':u'', u'\\cancer':u'', u'\\cap':u'', u'\\capricornus':u'',
u'\\cdot':u'', u'\\cdots':u'', u'\\centerdot':u'',
u'\\checkmark':u'', u'\\chi':u'χ', u'\\circ':u'', u'\\circeq':u'',
u'\\circledR':u'®', u'\\circledast':u'', u'\\circledcirc':u'',
u'\\circleddash':u'', u'\\clubsuit':u'', u'\\coloneqq':u'',
u'\\cat':u'', u'\\cdot':u'', u'\\cdots':u'', u'\\cent':u'¢',
u'\\centerdot':u'', u'\\checkmark':u'', u'\\chi':u'χ', u'\\circ':u'',
u'\\circeq':u'', u'\\circlearrowleft':u'', u'\\circlearrowright':u'',
u'\\circledR':u'®', u'\\circledast':u'', u'\\circledbslash':u'',
u'\\circledcirc':u'', u'\\circleddash':u'', u'\\circledgtr':u'',
u'\\circledless':u'', u'\\clubsuit':u'', u'\\colon':u': ', u'\\coloneqq':u'',
u'\\complement':u'', u'\\cong':u'', u'\\coprod':u'',
u'\\copyright':u'©', u'\\cos':u'cos', u'\\cosh':u'cosh', u'\\cot':u'cot',
u'\\coth':u'coth', u'\\csc':u'csc', u'\\cup':u'',
u'\\curvearrowleft':u'', u'\\curvearrowright':u'', u'\\dag':u'',
u'\\dagger':u'', u'\\daleth':u'', u'\\dashleftarrow':u'',
u'\\dashv':u'', u'\\ddag':u'', u'\\ddagger':u'', u'\\ddots':u'',
u'\\deg':u'deg', u'\\det':u'det', u'\\diagdown':u'', u'\\diagup':u'',
u'\\diamond':u'', u'\\diamondsuit':u'', u'\\dim':u'dim', u'\\div':u'÷',
u'\\divideontimes':u'', u'\\dotdiv':u'', u'\\doteq':u'',
u'\\doteqdot':u'', u'\\dotplus':u'', u'\\dots':u'',
u'\\doublebarwedge':u'', u'\\downarrow':u'', u'\\downdownarrows':u'',
u'\\downharpoonleft':u'', u'\\downharpoonright':u'', u'\\earth':u'',
u'\\ell':u'', u'\\emptyset':u'', u'\\eqcirc':u'', u'\\eqcolon':u'',
u'\\eqsim':u'', u'\\euro':u'', u'\\exists':u'', u'\\exp':u'exp',
u'\\fallingdotseq':u'', u'\\female':u'', u'\\flat':u'',
u'\\forall':u'', u'\\frown':u'', u'\\frownie':u'', u'\\gcd':u'gcd',
u'\\coth':u'coth', u'\\csc':u'csc', u'\\cup':u'', u'\\curlyvee':u'',
u'\\curlywedge':u'', u'\\curvearrowleft':u'',
u'\\curvearrowright':u'', u'\\dag':u'', u'\\dagger':u'',
u'\\daleth':u'', u'\\dashleftarrow':u'', u'\\dashv':u'',
u'\\ddag':u'', u'\\ddagger':u'', u'\\ddots':u'', u'\\deg':u'deg',
u'\\det':u'det', u'\\diagdown':u'', u'\\diagup':u'',
u'\\diameter':u'', u'\\diamond':u'', u'\\diamondsuit':u'',
u'\\dim':u'dim', u'\\div':u'÷', u'\\divideontimes':u'',
u'\\dotdiv':u'', u'\\doteq':u'', u'\\doteqdot':u'', u'\\dotplus':u'',
u'\\dots':u'', u'\\doublebarwedge':u'', u'\\downarrow':u'',
u'\\downdownarrows':u'', u'\\downharpoonleft':u'',
u'\\downharpoonright':u'', u'\\dsub':u'', u'\\earth':u'',
u'\\eighthnote':u'', u'\\ell':u'', u'\\emptyset':u'',
u'\\eqcirc':u'', u'\\eqcolon':u'', u'\\eqsim':u'', u'\\euro':u'',
u'\\exists':u'', u'\\exp':u'exp', u'\\fallingdotseq':u'',
u'\\fcmp':u'', u'\\female':u'', u'\\flat':u'', u'\\forall':u'',
u'\\fourth':u'', u'\\frown':u'', u'\\frownie':u'', u'\\gcd':u'gcd',
u'\\gemini':u'', u'\\geq)':u'', u'\\geqq':u'', u'\\geqslant':u'',
u'\\gets':u'', u'\\gg':u'', u'\\ggg':u'', u'\\gimel':u'',
u'\\gneqq':u'', u'\\gnsim':u'', u'\\gtrdot':u'', u'\\gtreqless':u'',
@ -439,41 +459,44 @@ class FormulaConfig(object):
u'\\hslash':u'', u'\\idotsint':u'<span class="bigsymbol">∫⋯∫</span>',
u'\\iiint':u'<span class="bigsymbol">∭</span>',
u'\\iint':u'<span class="bigsymbol">∬</span>', u'\\imath':u'ı',
u'\\inf':u'inf', u'\\infty':u'', u'\\invneg':u'', u'\\jmath':u'ȷ',
u'\\jupiter':u'', u'\\ker':u'ker', u'\\land':u'',
u'\\landupint':u'<span class="bigsymbol">∱</span>', u'\\langle':u'',
u'\\lbrace':u'{', u'\\lbrace)':u'{', u'\\lbrack':u'[', u'\\lceil':u'',
u'\\ldots':u'', u'\\leadsto':u'', u'\\leftarrow)':u'',
u'\\leftarrowtail':u'', u'\\leftarrowtobar':u'',
u'\\inf':u'inf', u'\\infty':u'', u'\\intercal':u'',
u'\\interleave':u'', u'\\invamp':u'', u'\\invneg':u'',
u'\\jmath':u'ȷ', u'\\jupiter':u'', u'\\ker':u'ker', u'\\land':u'',
u'\\landupint':u'<span class="bigsymbol">∱</span>', u'\\lang':u'',
u'\\langle':u'', u'\\lblot':u'', u'\\lbrace':u'{', u'\\lbrace)':u'{',
u'\\lbrack':u'[', u'\\lceil':u'', u'\\ldots':u'', u'\\leadsto':u'',
u'\\leftarrow)':u'', u'\\leftarrowtail':u'', u'\\leftarrowtobar':u'',
u'\\leftharpoondown':u'', u'\\leftharpoonup':u'',
u'\\leftleftarrows':u'', u'\\leftleftharpoons':u'', u'\\leftmoon':u'',
u'\\leftrightarrow':u'', u'\\leftrightarrows':u'',
u'\\leftrightharpoons':u'', u'\\leftthreetimes':u'', u'\\leo':u'',
u'\\leq)':u'', u'\\leqq':u'', u'\\leqslant':u'', u'\\lessdot':u'',
u'\\lesseqgtr':u'', u'\\lesseqqgtr':u'', u'\\lessgtr':u'',
u'\\lesssim':u'', u'\\lfloor':u'', u'\\lg':u'lg', u'\\lhd':u'',
u'\\libra':u'', u'\\lightning':u'', u'\\liminf':u'liminf',
u'\\limsup':u'limsup', u'\\ll':u'', u'\\lll':u'', u'\\ln':u'ln',
u'\\lesssim':u'', u'\\lfloor':u'', u'\\lg':u'lg', u'\\lgroup':u'',
u'\\lhd':u'', u'\\libra':u'', u'\\lightning':u'', u'\\limg':u'',
u'\\liminf':u'liminf', u'\\limsup':u'limsup', u'\\ll':u'',
u'\\llbracket':u'', u'\\llcorner':u'', u'\\lll':u'', u'\\ln':u'ln',
u'\\lneqq':u'', u'\\lnot':u'¬', u'\\lnsim':u'', u'\\log':u'log',
u'\\longleftarrow':u'', u'\\longleftrightarrow':u'',
u'\\longmapsto':u'', u'\\longrightarrow':u'', u'\\looparrowleft':u'',
u'\\looparrowright':u'', u'\\lor':u'', u'\\lozenge':u'',
u'\\ltimes':u'', u'\\lyxlock':u'', u'\\male':u'', u'\\maltese':u'',
u'\\mapsfrom':u'', u'\\mapsto':u'', u'\\mathcircumflex':u'^',
u'\\max':u'max', u'\\measuredangle':u'', u'\\mercury':u'',
u'\\mho':u'', u'\\mid':u'', u'\\min':u'min', u'\\models':u'',
u'\\mp':u'', u'\\multimap':u'', u'\\nLeftarrow':u'',
u'\\nLeftrightarrow':u'', u'\\nRightarrow':u'', u'\\nVDash':u'',
u'\\nabla':u'', u'\\napprox':u'', u'\\natural':u'', u'\\ncong':u'',
u'\\nearrow':u'', u'\\neg':u'¬', u'\\neg)':u'¬', u'\\neptune':u'',
u'\\nequiv':u'', u'\\newline':u'<br/>', u'\\nexists':u'',
u'\\ngeqslant':u'', u'\\ngtr':u'', u'\\ngtrless':u'', u'\\ni':u'',
u'\\ni)':u'', u'\\nleftarrow':u'', u'\\nleftrightarrow':u'',
u'\\nleqslant':u'', u'\\nless':u'', u'\\nlessgtr':u'', u'\\nmid':u'',
u'\\nolimits':u'', u'\\nonumber':u'', u'\\not':u'¬', u'\\not<':u'',
u'\\not=':u'', u'\\not>':u'', u'\\notbackslash':u'', u'\\notin':u'',
u'\\notni':u'', u'\\notslash':u'', u'\\nparallel':u'',
u'\\nprec':u'', u'\\nrightarrow':u'', u'\\nsim':u'', u'\\nsimeq':u'',
u'\\lrcorner':u'', u'\\ltimes':u'', u'\\lyxlock':u'', u'\\male':u'',
u'\\maltese':u'', u'\\mapsfrom':u'', u'\\mapsto':u'',
u'\\mathcircumflex':u'^', u'\\max':u'max', u'\\measuredangle':u'',
u'\\medbullet':u'', u'\\medcirc':u'', u'\\mercury':u'', u'\\mho':u'',
u'\\mid':u'', u'\\min':u'min', u'\\models':u'', u'\\mp':u'',
u'\\multimap':u'', u'\\nLeftarrow':u'', u'\\nLeftrightarrow':u'',
u'\\nRightarrow':u'', u'\\nVDash':u'', u'\\nabla':u'',
u'\\napprox':u'', u'\\natural':u'', u'\\ncong':u'', u'\\nearrow':u'',
u'\\neg':u'¬', u'\\neg)':u'¬', u'\\neptune':u'', u'\\nequiv':u'',
u'\\newline':u'<br/>', u'\\nexists':u'', u'\\ngeqslant':u'',
u'\\ngtr':u'', u'\\ngtrless':u'', u'\\ni':u'', u'\\ni)':u'',
u'\\nleftarrow':u'', u'\\nleftrightarrow':u'', u'\\nleqslant':u'',
u'\\nless':u'', u'\\nlessgtr':u'', u'\\nmid':u'', u'\\nolimits':u'',
u'\\nonumber':u'', u'\\not':u'¬', u'\\not<':u'', u'\\not=':u'',
u'\\not>':u'', u'\\notbackslash':u'', u'\\notin':u'', u'\\notni':u'',
u'\\notslash':u'', u'\\nparallel':u'', u'\\nprec':u'',
u'\\nrightarrow':u'', u'\\nsim':u'', u'\\nsimeq':u'',
u'\\nsqsubset':u'⊏̸', u'\\nsubseteq':u'', u'\\nsucc':u'',
u'\\nsucccurlyeq':u'', u'\\nsupset':u'', u'\\nsupseteq':u'',
u'\\ntriangleleft':u'', u'\\ntrianglelefteq':u'',
@ -485,31 +508,40 @@ class FormulaConfig(object):
u'\\ointclockwise':u'<span class="bigsymbol">∲</span>',
u'\\ointctrclockwise':u'<span class="bigsymbol">∳</span>',
u'\\ominus':u'', u'\\oplus':u'', u'\\oslash':u'', u'\\otimes':u'',
u'\\owns':u'', u'\\parallel':u'', u'\\partial':u'', u'\\perp':u'',
u'\\pisces':u'', u'\\pitchfork':u'', u'\\pluto':u'', u'\\pm':u'±',
u'\\pointer':u'', u'\\pounds':u'£', u'\\prec':u'',
u'\\preccurlyeq':u'', u'\\preceq':u'', u'\\precsim':u'',
u'\\prime':u'', u'\\prompto':u'', u'\\qquad':u' ', u'\\quad':u' ',
u'\\quarternote':u'', u'\\rangle':u'', u'\\rbrace':u'}',
u'\\rbrace)':u'}', u'\\rbrack':u']', u'\\rceil':u'', u'\\rfloor':u'',
u'\\rhd':u'', u'\\rightarrow)':u'', u'\\rightarrowtail':u'',
u'\\owns':u'', u'\\parallel':u'', u'\\partial':u'', u'\\pencil':u'',
u'\\perp':u'', u'\\pisces':u'', u'\\pitchfork':u'', u'\\pluto':u'',
u'\\pm':u'±', u'\\pointer':u'', u'\\pointright':u'', u'\\pounds':u'£',
u'\\prec':u'', u'\\preccurlyeq':u'', u'\\preceq':u'',
u'\\precsim':u'', u'\\prime':u'', u'\\prompto':u'', u'\\qoppa':u'ϙ',
u'\\qquad':u' ', u'\\quad':u' ', u'\\quarternote':u'',
u'\\radiation':u'', u'\\rang':u'', u'\\rangle':u'', u'\\rblot':u'',
u'\\rbrace':u'}', u'\\rbrace)':u'}', u'\\rbrack':u']', u'\\rceil':u'',
u'\\recycle':u'', u'\\rfloor':u'', u'\\rgroup':u'', u'\\rhd':u'',
u'\\rightangle':u'', u'\\rightarrow)':u'', u'\\rightarrowtail':u'',
u'\\rightarrowtobar':u'', u'\\rightharpoondown':u'',
u'\\rightharpoonup':u'', u'\\rightharpooondown':u'',
u'\\rightharpooonup':u'', u'\\rightleftarrows':u'',
u'\\rightleftharpoons':u'', u'\\rightmoon':u'',
u'\\rightrightarrows':u'', u'\\rightrightharpoons':u'',
u'\\rightthreetimes':u'', u'\\risingdotseq':u'', u'\\rtimes':u'',
u'\\rightthreetimes':u'', u'\\rimg':u'', u'\\risingdotseq':u'',
u'\\rrbracket':u'', u'\\rsub':u'', u'\\rtimes':u'',
u'\\sagittarius':u'', u'\\saturn':u'', u'\\scorpio':u'',
u'\\searrow':u'', u'\\sec':u'sec', u'\\setminus':u'', u'\\sharp':u'',
u'\\simeq':u'', u'\\sin':u'sin', u'\\sinh':u'sinh', u'\\slash':u'',
u'\\smile':u'', u'\\smiley':u'', u'\\spadesuit':u'',
u'\\sphericalangle':u'', u'\\sqcap':u'', u'\\sqcup':u'',
u'\\sqsubset':u'', u'\\sqsubseteq':u'', u'\\sqsupset':u'',
u'\\sqsupseteq':u'', u'\\square':u'', u'\\star':u'',
u'\\searrow':u'', u'\\sec':u'sec', u'\\second':u'', u'\\setminus':u'',
u'\\sharp':u'', u'\\simeq':u'', u'\\sin':u'sin', u'\\sinh':u'sinh',
u'\\sixteenthnote':u'', u'\\skull':u'', u'\\slash':u'',
u'\\smallsetminus':u'', u'\\smalltriangledown':u'',
u'\\smalltriangleleft':u'', u'\\smalltriangleright':u'',
u'\\smalltriangleup':u'', u'\\smile':u'', u'\\smiley':u'',
u'\\spadesuit':u'', u'\\spddot':u'¨', u'\\sphat':u'',
u'\\sphericalangle':u'', u'\\spot':u'', u'\\sptilde':u'~',
u'\\sqcap':u'', u'\\sqcup':u'', u'\\sqsubset':u'',
u'\\sqsubseteq':u'', u'\\sqsupset':u'', u'\\sqsupseteq':u'',
u'\\square':u'', u'\\sslash':u'', u'\\star':u'', u'\\steaming':u'',
u'\\subseteqq':u'', u'\\subsetneqq':u'', u'\\succ':u'',
u'\\succcurlyeq':u'', u'\\succeq':u'', u'\\succnsim':u'',
u'\\succsim':u'', u'\\sun':u'', u'\\sup':u'sup', u'\\supseteqq':u'',
u'\\supsetneqq':u'', u'\\surd':u'', u'\\swarrow':u'', u'\\tan':u'tan',
u'\\supsetneqq':u'', u'\\surd':u'', u'\\swarrow':u'',
u'\\swords':u'', u'\\talloblong':u'', u'\\tan':u'tan',
u'\\tanh':u'tanh', u'\\taurus':u'', u'\\textasciicircum':u'^',
u'\\textasciitilde':u'~', u'\\textbackslash':u'\\',
u'\\textcopyright':u'©\'', u'\\textdegree':u'°', u'\\textellipsis':u'',
@ -520,20 +552,21 @@ class FormulaConfig(object):
u'\\textregistered':u'®', u'\\textrightarrow':u'',
u'\\textsection':u'§', u'\\texttrademark':u'',
u'\\texttwosuperior':u'²', u'\\textvisiblespace':u' ',
u'\\therefore':u'', u'\\top':u'', u'\\triangle':u'',
u'\\therefore':u'', u'\\third':u'', u'\\top':u'', u'\\triangle':u'',
u'\\triangleleft':u'', u'\\trianglelefteq':u'', u'\\triangleq':u'',
u'\\triangleright':u'', u'\\trianglerighteq':u'',
u'\\twoheadleftarrow':u'', u'\\twoheadrightarrow':u'',
u'\\twonotes':u'', u'\\udot':u'', u'\\unlhd':u'', u'\\unrhd':u'',
u'\\unrhl':u'', u'\\uparrow':u'', u'\\updownarrow':u'',
u'\\upharpoonleft':u'', u'\\upharpoonright':u'', u'\\uplus':u'',
u'\\upuparrows':u'', u'\\uranus':u'', u'\\vDash':u'',
u'\\varclubsuit':u'', u'\\vardiamondsuit':u'', u'\\varheartsuit':u'',
u'\\varnothing':u'', u'\\varspadesuit':u'', u'\\vdash':u'',
u'\\vdots':u'', u'\\vee':u'', u'\\vee)':u'', u'\\veebar':u'',
u'\\vert':u'', u'\\virgo':u'', u'\\wedge':u'', u'\\wedge)':u'',
u'\\wp':u'', u'\\wr':u'', u'\\yen':u'¥', u'\\{':u'{', u'\\|':u'',
u'\\}':u'}',
u'\\twonotes':u'', u'\\udot':u'', u'\\ulcorner':u'', u'\\unlhd':u'',
u'\\unrhd':u'', u'\\unrhl':u'', u'\\uparrow':u'',
u'\\updownarrow':u'', u'\\upharpoonleft':u'', u'\\upharpoonright':u'',
u'\\uplus':u'', u'\\upuparrows':u'', u'\\uranus':u'',
u'\\urcorner':u'', u'\\vDash':u'', u'\\varclubsuit':u'',
u'\\vardiamondsuit':u'', u'\\varheartsuit':u'', u'\\varnothing':u'',
u'\\varspadesuit':u'', u'\\vdash':u'', u'\\vdots':u'', u'\\vee':u'',
u'\\vee)':u'', u'\\veebar':u'', u'\\vert':u'', u'\\virgo':u'',
u'\\warning':u'', u'\\wasylozenge':u'', u'\\wedge':u'',
u'\\wedge)':u'', u'\\wp':u'', u'\\wr':u'', u'\\yen':u'¥',
u'\\yinyang':u'', u'\\{':u'{', u'\\|':u'', u'\\}':u'}',
}
decoratedcommand = {
@ -580,7 +613,9 @@ class FormulaConfig(object):
}
hybridfunctions = {
u'\\addcontentsline':[u'{$p!}{$q!}{$r!}',u'f0{}',u'ignored',],
u'\\addtocontents':[u'{$p!}{$q!}',u'f0{}',u'ignored',],
u'\\backmatter':[u'',u'f0{}',u'ignored',],
u'\\binom':[u'{$1}{$2}',u'f2{(}f0{f1{$1}f1{$2}}f2{)}',u'span class="binom"',u'span class="binomstack"',u'span class="bigsymbol"',],
u'\\boxed':[u'{$1}',u'f0{$1}',u'span class="boxed"',],
u'\\cfrac':[u'[$p!]{$1}{$2}',u'f0{f3{(}f1{$1}f3{)/(}f2{$2}f3{)}}',u'span class="fullfraction"',u'span class="numerator align-$p"',u'span class="denominator"',u'span class="ignored"',],
@ -589,15 +624,21 @@ class FormulaConfig(object):
u'\\dbinom':[u'{$1}{$2}',u'(f0{f1{f2{$1}}f1{f2{}}f1{f2{$2}}})',u'span class="binomial"',u'span class="binomrow"',u'span class="binomcell"',],
u'\\dfrac':[u'{$1}{$2}',u'f0{f3{(}f1{$1}f3{)/(}f2{$2}f3{)}}',u'span class="fullfraction"',u'span class="numerator"',u'span class="denominator"',u'span class="ignored"',],
u'\\displaystyle':[u'{$1}',u'f0{$1}',u'span class="displaystyle"',],
u'\\fancyfoot':[u'[$p!]{$q!}',u'f0{}',u'ignored',],
u'\\fancyhead':[u'[$p!]{$q!}',u'f0{}',u'ignored',],
u'\\fbox':[u'{$1}',u'f0{$1}',u'span class="fbox"',],
u'\\fboxrule':[u'{$p!}',u'f0{}',u'ignored',],
u'\\fboxsep':[u'{$p!}',u'f0{}',u'ignored',],
u'\\fcolorbox':[u'{$p!}{$q!}{$1}',u'f0{$1}',u'span class="boxed" style="border-color: $p; background: $q;"',],
u'\\frac':[u'{$1}{$2}',u'f0{f3{(}f1{$1}f3{)/(}f2{$2}f3{)}}',u'span class="fraction"',u'span class="numerator"',u'span class="denominator"',u'span class="ignored"',],
u'\\framebox':[u'[$p!][$q!]{$1}',u'f0{$1}',u'span class="framebox align-$q" style="width: $p;"',],
u'\\frontmatter':[u'',u'f0{}',u'ignored',],
u'\\href':[u'[$o]{$u!}{$t!}',u'f0{$t}',u'a href="$u"',],
u'\\hspace':[u'{$p!}',u'f0{ }',u'span class="hspace" style="width: $p;"',],
u'\\leftroot':[u'{$p!}',u'f0{ }',u'span class="leftroot" style="width: $p;px"',],
u'\\mainmatter':[u'',u'f0{}',u'ignored',],
u'\\markboth':[u'{$p!}{$q!}',u'f0{}',u'ignored',],
u'\\markright':[u'{$p!}',u'f0{}',u'ignored',],
u'\\nicefrac':[u'{$1}{$2}',u'f0{f1{$1}f2{$2}}',u'span class="fraction"',u'sup class="numerator"',u'sub class="denominator"',u'span class="ignored"',],
u'\\parbox':[u'[$p!]{$w!}{$1}',u'f0{1}',u'div class="Boxed" style="width: $w;"',],
u'\\raisebox':[u'{$p!}{$1}',u'f0{$1.font}',u'span class="raisebox" style="vertical-align: $p;"',],
@ -610,6 +651,7 @@ class FormulaConfig(object):
u'\\tbinom':[u'{$1}{$2}',u'(f0{f1{f2{$1}}f1{f2{}}f1{f2{$2}}})',u'span class="binomial"',u'span class="binomrow"',u'span class="binomcell"',],
u'\\textcolor':[u'{$p!}{$1}',u'f0{$1}',u'span style="color: $p;"',],
u'\\textstyle':[u'{$1}',u'f0{$1}',u'span class="textstyle"',],
u'\\thispagestyle':[u'{$p!}',u'f0{}',u'ignored',],
u'\\unit':[u'[$0]{$1}',u'$0f0{$1.font}',u'span class="unit"',],
u'\\unitfrac':[u'[$0]{$1}{$2}',u'$0f0{f1{$1.font}f2{$2.font}}',u'span class="fraction"',u'sup class="unit"',u'sub class="unit"',],
u'\\uproot':[u'{$p!}',u'f0{ }',u'span class="uproot" style="width: $p;px"',],
@ -627,24 +669,24 @@ class FormulaConfig(object):
}
limitcommands = {
u'\\int':u'', u'\\intop':u'', u'\\lim':u'lim', u'\\prod':u'',
u'\\smallint':u'', u'\\sum':u'',
u'\\biginterleave':u'', u'\\bigsqcap':u'', u'\\fint':u'',
u'\\iiiint':u'', u'\\int':u'', u'\\intop':u'', u'\\lim':u'lim',
u'\\prod':u'', u'\\smallint':u'', u'\\sqint':u'', u'\\sum':u'',
u'\\varointclockwise':u'', u'\\varprod':u'', u'\\zcmp':u'',
u'\\zhide':u'', u'\\zpipe':u'', u'\\zproject':u'',
}
# TODO: setting for simple enlarged vs. piecewise symbols
for key in (u'\\int', u'\\intop', u'\\prod', u'\\sum'):
limitcommands[key] = '<span class="symbol">%s</span>' % limitcommands[key]
misccommands = {
u'\\limits':u'LimitPreviousCommand', u'\\newcommand':u'MacroDefinition',
u'\\renewcommand':u'MacroDefinition',
u'\\setcounter':u'SetCounterFunction', u'\\tag':u'FormulaTag',
u'\\tag*':u'FormulaTag',
u'\\tag*':u'FormulaTag', u'\\today':u'TodayCommand',
}
modified = {
u'\n':u'', u' ':u'', u'$':u'', u'&':u' ', u'\'':u'', u'+':u'+',
u',':u',', u'-':u'', u'/':u'', u'<':u'&lt;', u'=':u'=',
u'>':u'&gt;', u'@':u'', u'~':u'',
u'\n':u'', u' ':u'', u'$':u'', u'&':u' ', u'\'':u'', u'+':u'+',
u',':u',', u'-':u'', u'/':u'', u':':u' : ', u'<':u'&lt;',
u'=':u'=', u'>':u'&gt;', u'@':u'', u'~':u'',
}
onefunctions = {
@ -664,13 +706,58 @@ class FormulaConfig(object):
}
spacedcommands = {
u'\\Leftrightarrow':u'', u'\\Rightarrow':u'', u'\\approx':u'',
u'\\dashrightarrow':u'', u'\\equiv':u'', u'\\ge':u'', u'\\geq':u'',
u'\\Bot':u'', u'\\Doteq':u'', u'\\DownArrowBar':u'',
u'\\DownLeftTeeVector':u'', u'\\DownLeftVectorBar':u'',
u'\\DownRightTeeVector':u'', u'\\DownRightVectorBar':u'',
u'\\Equal':u'', u'\\LeftArrowBar':u'', u'\\LeftDownTeeVector':u'',
u'\\LeftDownVectorBar':u'', u'\\LeftTeeVector':u'',
u'\\LeftTriangleBar':u'', u'\\LeftUpTeeVector':u'',
u'\\LeftUpVectorBar':u'', u'\\LeftVectorBar':u'',
u'\\Leftrightarrow':u'', u'\\Longmapsfrom':u'', u'\\Longmapsto':u'',
u'\\MapsDown':u'', u'\\MapsUp':u'', u'\\Nearrow':u'',
u'\\NestedGreaterGreater':u'', u'\\NestedLessLess':u'',
u'\\NotGreaterLess':u'', u'\\NotGreaterTilde':u'',
u'\\NotLessTilde':u'', u'\\Nwarrow':u'', u'\\Proportion':u'',
u'\\RightArrowBar':u'', u'\\RightDownTeeVector':u'',
u'\\RightDownVectorBar':u'', u'\\RightTeeVector':u'',
u'\\RightTriangleBar':u'', u'\\RightUpTeeVector':u'',
u'\\RightUpVectorBar':u'', u'\\RightVectorBar':u'',
u'\\Rightarrow':u'', u'\\Same':u'', u'\\Searrow':u'',
u'\\Swarrow':u'', u'\\Top':u'', u'\\UpArrowBar':u'', u'\\VDash':u'',
u'\\approx':u'', u'\\approxeq':u'', u'\\backsim':u'', u'\\barin':u'',
u'\\barleftharpoon':u'', u'\\barrightharpoon':u'', u'\\bij':u'',
u'\\coloneq':u'', u'\\corresponds':u'', u'\\curlyeqprec':u'',
u'\\curlyeqsucc':u'', u'\\dashrightarrow':u'', u'\\dlsh':u'',
u'\\downdownharpoons':u'', u'\\downuparrows':u'',
u'\\downupharpoons':u'', u'\\drsh':u'', u'\\eqslantgtr':u'',
u'\\eqslantless':u'', u'\\equiv':u'', u'\\ffun':u'', u'\\finj':u'',
u'\\ge':u'', u'\\geq':u'', u'\\ggcurly':u'', u'\\gnapprox':u'',
u'\\gneq':u'', u'\\gtrapprox':u'', u'\\hash':u'', u'\\iddots':u'',
u'\\implies':u' ⇒ ', u'\\in':u'', u'\\le':u'', u'\\leftarrow':u'',
u'\\leq':u'', u'\\ne':u'', u'\\neq':u'', u'\\not\\in':u'',
u'\\propto':u'', u'\\rightarrow':u'', u'\\rightsquigarrow':u'',
u'\\sim':u'~', u'\\subset':u'', u'\\subseteq':u'', u'\\supset':u'',
u'\\supseteq':u'', u'\\times':u'×', u'\\to':u'',
u'\\leftarrowtriangle':u'', u'\\leftbarharpoon':u'',
u'\\leftrightarrowtriangle':u'', u'\\leftrightharpoon':u'',
u'\\leftrightharpoondown':u'', u'\\leftrightharpoonup':u'',
u'\\leftrightsquigarrow':u'', u'\\leftslice':u'',
u'\\leftsquigarrow':u'', u'\\leftupdownharpoon':u'', u'\\leq':u'',
u'\\lessapprox':u'', u'\\llcurly':u'', u'\\lnapprox':u'',
u'\\lneq':u'', u'\\longmapsfrom':u'', u'\\multimapboth':u'',
u'\\multimapdotbothA':u'', u'\\multimapdotbothB':u'',
u'\\multimapinv':u'', u'\\nVdash':u'', u'\\ne':u'', u'\\neq':u'',
u'\\ngeq':u'', u'\\nleq':u'', u'\\nni':u'', u'\\not\\in':u'',
u'\\notasymp':u'', u'\\npreceq':u'', u'\\nsqsubseteq':u'',
u'\\nsqsupseteq':u'', u'\\nsubset':u'', u'\\nsucceq':u'',
u'\\pfun':u'', u'\\pinj':u'', u'\\precapprox':u'', u'\\preceqq':u'',
u'\\precnapprox':u'', u'\\precnsim':u'', u'\\propto':u'',
u'\\psur':u'', u'\\rightarrow':u'', u'\\rightarrowtriangle':u'',
u'\\rightbarharpoon':u'', u'\\rightleftharpoon':u'',
u'\\rightslice':u'', u'\\rightsquigarrow':u'',
u'\\rightupdownharpoon':u'', u'\\sim':u'~', u'\\strictfi':u'',
u'\\strictif':u'', u'\\subset':u'', u'\\subseteq':u'',
u'\\subsetneq':u'', u'\\succapprox':u'', u'\\succeqq':u'',
u'\\succnapprox':u'', u'\\supset':u'', u'\\supseteq':u'',
u'\\supsetneq':u'', u'\\times':u'×', u'\\to':u'',
u'\\updownarrows':u'', u'\\updownharpoons':u'', u'\\upupharpoons':u'',
u'\\vartriangleleft':u'', u'\\vartriangleright':u'',
}
starts = {
@ -695,7 +782,7 @@ class FormulaConfig(object):
unmodified = {
u'characters':[u'.',u'*',u'',u'(',u')',u'[',u']',u':',u'·',u'!',u';',u'|',u'§',u'"',],
u'characters':[u'.',u'*',u'',u'(',u')',u'[',u']',u'·',u'!',u';',u'|',u'§',u'"',],
}
urls = {
@ -706,7 +793,7 @@ class GeneralConfig(object):
"Configuration class from elyxer.config file"
version = {
u'date':u'2011-06-27', u'lyxformat':u'413', u'number':u'1.2.3',
u'date':u'2015-02-26', u'lyxformat':u'413', u'number':u'1.2.5',
}
class HeaderConfig(object):
@ -735,6 +822,7 @@ class ImageConfig(object):
u'imagemagick':u'convert[ -density $scale][ -define $format:use-cropbox=true] "$input" "$output"',
u'inkscape':u'inkscape "$input" --export-png="$output"',
u'lyx':u'lyx -C "$input" "$output"',
}
cropboxformats = {
@ -860,6 +948,10 @@ class TagConfig(object):
u'Comment':u'', u'Greyedout':u'span class="greyedout"', u'Note':u'',
}
script = {
u'subscript':u'sub', u'superscript':u'sup',
}
shaped = {
u'italic':u'i', u'slanted':u'i', u'smallcaps':u'span class="versalitas"',
}
@ -889,7 +981,8 @@ class TranslationConfig(object):
languages = {
u'american':u'en', u'british':u'en', u'deutsch':u'de', u'dutch':u'nl',
u'english':u'en', u'french':u'fr', u'ngerman':u'de', u'spanish':u'es',
u'english':u'en', u'french':u'fr', u'ngerman':u'de', u'russian':u'ru',
u'spanish':u'es',
}
@ -936,7 +1029,7 @@ class CommandLineParser(object):
initial = args[0]
del args[0]
return key, self.readquoted(args, initial)
value = args[0]
value = args[0].decode('utf-8')
del args[0]
if isinstance(current, list):
current.append(value)
@ -945,8 +1038,10 @@ class CommandLineParser(object):
def readquoted(self, args, initial):
"Read a value between quotes"
Trace.error('Oops')
value = initial[1:]
while len(args) > 0 and not args[0].endswith('"') and not args[0].startswith('--'):
Trace.error('Appending ' + args[0])
value += ' ' + args[0]
del args[0]
if len(args) == 0 or args[0].startswith('--'):
@ -983,6 +1078,7 @@ class Options(object):
unicode = False
iso885915 = False
css = []
favicon = ''
title = None
directory = None
destdirectory = None
@ -1062,6 +1158,8 @@ class Options(object):
Options.copyimages = True
if Options.css == []:
Options.css = ['http://elyxer.nongnu.org/lyx.css']
if Options.favicon == '':
pass # no default favicon
if Options.html:
Options.simplemath = True
if Options.toc and not Options.tocfor:
@ -1069,6 +1167,8 @@ class Options(object):
Options.tocfor = Options.toctarget
if Options.nocopy:
Trace.error('Option --nocopy is deprecated; it is no longer needed')
if Options.jsmath:
Trace.error('Option --jsmath is deprecated; use --mathjax instead')
# set in Trace if necessary
for param in dir(Trace):
if param.endswith('mode'):
@ -1088,6 +1188,7 @@ class Options(object):
return
Options.marginfoot = False
Options.letterfoot = False
Options.hoverfoot = False
options = Options.footnotes.split(',')
for option in options:
footoption = option + 'foot'
@ -1113,7 +1214,8 @@ class Options(object):
Trace.error(' Options for HTML output:')
Trace.error(' --title "title": set the generated page title')
Trace.error(' --css "file.css": use a custom CSS file')
Trace.error(' --embedcss "file.css": embed styles from elyxer.a CSS file into the output')
Trace.error(' --embedcss "file.css": embed styles from a CSS file into the output')
Trace.error(' --favicon "icon.ico": insert the specified favicon in the header.')
Trace.error(' --html: output HTML 4.0 instead of the default XHTML')
Trace.error(' --unicode: full Unicode output')
Trace.error(' --iso885915: output a document with ISO-8859-15 encoding')
@ -1143,8 +1245,8 @@ class Options(object):
Trace.error(' --notoclabels: omit the part labels in the TOC, such as Chapter')
Trace.error(' --lowmem: do the conversion on the fly (conserve memory)')
Trace.error(' --raw: generate HTML without header or footer.')
Trace.error(' --jsmath "URL": use jsMath from elyxer.the given URL to display equations')
Trace.error(' --mathjax "URL": use MathJax from elyxer.the given URL to display equations')
Trace.error(' --mathjax remote: use MathJax remotely to display equations')
Trace.error(' --mathjax "URL": use MathJax from the given URL to display equations')
Trace.error(' --googlecharts: use Google Charts to generate formula images')
Trace.error(' --template "file": use a template, put everything in <!--$content-->')
Trace.error(' --copyright: add a copyright notice at the bottom')
@ -1152,6 +1254,7 @@ class Options(object):
Trace.error(' --toc: (deprecated) create a table of contents')
Trace.error(' --toctarget "page": (deprecated) generate a TOC for the given page')
Trace.error(' --nocopy: (deprecated) maintained for backwards compatibility')
Trace.error(' --jsmath "URL": use jsMath from the given URL to display equations')
sys.exit()
def showversion(self):
@ -3536,11 +3639,17 @@ class BarredText(TaggedText):
return
self.output.tag = TagConfig.barred[self.type]
class LangLine(BlackBox):
class LangLine(TaggedText):
"A line with language information"
def process(self):
self.lang = self.header[1]
"Only generate a span with lang info when the language is recognized."
lang = self.header[1]
if not lang in TranslationConfig.languages:
self.output = ContentsOutput()
return
isolang = TranslationConfig.languages[lang]
self.output = TaggedOutput().settag('span lang="' + isolang + '"', False)
class InsetLength(BlackBox):
"A length measure inside an inset."
@ -3908,8 +4017,7 @@ class Reference(Link):
self.replace('@', partkey and partkey.number)
self.replace(u'', partkey and partkey.tocentry)
if not '$' in self.formatted or not partkey or not partkey.titlecontents:
if '$' in self.formatted:
Trace.error('No title in ' + unicode(partkey))
# there is a $ left, but it should go away on preprocessing
self.contents = [Constant(self.formatted)]
return
pieces = self.formatted.split('$')
@ -3993,7 +4101,7 @@ class FormulaCommand(FormulaBit):
def emptycommand(self, pos):
"""Check for an empty command: look for command disguised as ending.
Special case against '{ \{ \} }' situation."""
Special case against '{ \\{ \\} }' situation."""
command = ''
if not pos.isout():
ending = pos.nextending()
@ -4452,7 +4560,7 @@ class EquationEnvironment(MultiRowFormula):
self.parserows(pos)
class BeginCommand(CommandBit):
"A \\begin{}...\end command and what it entails (array, cases, aligned)"
"A \\begin{}...\\end command and what it entails (array, cases, aligned)"
commandmap = {FormulaConfig.array['begin']:''}
@ -4481,6 +4589,8 @@ class BeginCommand(CommandBit):
FormulaCommand.types += [BeginCommand]
import datetime
class CombiningFunction(OneParamFunction):
@ -4697,6 +4807,16 @@ class BracketProcessor(MathsProcessor):
command.output = ContentsOutput()
command.contents = bracket.getcontents()
class TodayCommand(EmptyCommand):
"Shows today's date."
commandmap = None
def parsebit(self, pos):
"Parse a command without parameters"
self.output = FixedOutput()
self.html = [datetime.date.today().strftime('%b %d, %Y')]
FormulaCommand.types += [
DecoratingFunction, CombiningFunction, LimitCommand, BracketCommand,

View File

@ -0,0 +1,147 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# :Id: $Id: tex2mathml_extern.py 7861 2015-04-10 23:48:51Z milde $
# :Copyright: © 2015 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
# Wrappers for TeX->MathML conversion by external tools
# =====================================================
import subprocess
document_template = r"""\documentclass{article}
\usepackage{amsmath}
\begin{document}
%s
\end{document}
"""
def latexml(math_code, reporter=None):
"""Convert LaTeX math code to MathML with LaTeXML_
.. _LaTeXML: http://dlmf.nist.gov/LaTeXML/
"""
p = subprocess.Popen(['latexml',
'-', # read from stdin
# '--preload=amsmath',
'--inputencoding=utf8',
],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True)
p.stdin.write((document_template % math_code).encode('utf8'))
p.stdin.close()
latexml_code = p.stdout.read()
latexml_err = p.stderr.read().decode('utf8')
if reporter and latexml_err.find('Error') >= 0 or not latexml_code:
reporter.error(latexml_err)
post_p = subprocess.Popen(['latexmlpost',
'-',
'--nonumbersections',
'--format=xhtml',
# '--linelength=78', # experimental
'--'
],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True)
post_p.stdin.write(latexml_code)
post_p.stdin.close()
result = post_p.stdout.read().decode('utf8')
post_p_err = post_p.stderr.read().decode('utf8')
if reporter and post_p_err.find('Error') >= 0 or not result:
reporter.error(post_p_err)
# extract MathML code:
start,end = result.find('<math'), result.find('</math>')+7
result = result[start:end]
if 'class="ltx_ERROR' in result:
raise SyntaxError(result)
return result
def ttm(math_code, reporter=None):
"""Convert LaTeX math code to MathML with TtM_
.. _TtM: http://hutchinson.belmont.ma.us/tth/mml/
"""
p = subprocess.Popen(['ttm',
# '-i', # italic font for equations. Default roman.
'-u', # unicode character encoding. (Default iso-8859-1).
'-r', # output raw MathML (no preamble or postlude)
],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True)
p.stdin.write((document_template % math_code).encode('utf8'))
p.stdin.close()
result = p.stdout.read()
err = p.stderr.read().decode('utf8')
if err.find('**** Unknown') >= 0:
msg = '\n'.join([line for line in err.splitlines()
if line.startswith('****')])
raise SyntaxError('\nMessage from external converter TtM:\n'+ msg)
if reporter and err.find('**** Error') >= 0 or not result:
reporter.error(err)
start,end = result.find('<math'), result.find('</math>')+7
result = result[start:end]
return result
def blahtexml(math_code, inline=True, reporter=None):
"""Convert LaTeX math code to MathML with blahtexml_
.. _blahtexml: http://gva.noekeon.org/blahtexml/
"""
options = ['--mathml',
'--indented',
'--spacing', 'moderate',
'--mathml-encoding', 'raw',
'--other-encoding', 'raw',
'--doctype-xhtml+mathml',
'--annotate-TeX',
]
if inline:
mathmode_arg = ''
else:
mathmode_arg = 'mode="display"'
options.append('--displaymath')
p = subprocess.Popen(['blahtexml']+options,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True)
p.stdin.write(math_code.encode('utf8'))
p.stdin.close()
result = p.stdout.read().decode('utf8')
err = p.stderr.read().decode('utf8')
print err
if result.find('<error>') >= 0:
raise SyntaxError('\nMessage from external converter blahtexml:\n'
+result[result.find('<message>')+9:result.find('</message>')])
if reporter and (err.find('**** Error') >= 0 or not result):
reporter.error(err)
start,end = result.find('<markup>')+9, result.find('</markup>')
result = ('<math xmlns="http://www.w3.org/1998/Math/MathML"%s>\n'
'%s</math>\n') % (mathmode_arg, result[start:end])
return result
# self-test
if __name__ == "__main__":
example = ur'\frac{\partial \sin^2(\alpha)}{\partial \vec r} \varpi \, \text{Grüße}'
# print latexml(example).encode('utf8')
# print ttm(example)#.encode('utf8')
print blahtexml(example).encode('utf8')

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# :Copyright: © 2011 Günter Milde.
# :Id: $Id: punctuation_chars.py 8016 2017-01-17 15:06:17Z milde $
# :Copyright: © 2011, 2017 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,
@ -9,29 +10,38 @@
# This file is offered as-is, without any warranty.
#
# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause
# :Id: $Id: punctuation_chars.py 7668 2013-06-04 12:46:30Z milde $
#
# This file is generated by
# ``docutils/tools/dev/generate_punctuation_chars.py``.
# ::
import sys, re
import unicodedata
# punctuation characters around inline markup
# ===========================================
#
# This module provides the lists of characters for the implementation of
# the `inline markup recognition rules`_ in the reStructuredText parser
# (states.py)
#
# .. _inline markup recognition rules:
# ../../docs/ref/rst/restructuredtext.html#inline-markup
"""Docutils character category patterns.
# Docutils punctuation category sample strings
# --------------------------------------------
#
# The sample strings are generated by punctuation_samples() and put here
# literal to avoid the time-consuming generation with every Docutils run.
# As the samples are used inside ``[ ]`` in regular expressions, hyphen and
# square brackets are escaped. ::
Patterns for the implementation of the `inline markup recognition rules`_
in the reStructuredText parser `docutils.parsers.rst.states.py` based
on Unicode character categories.
The patterns are used inside ``[ ]`` in regular expressions.
Rule (5) requires determination of matching open/close pairs. However, the
pairing of open/close quotes is ambiguous due to different typographic
conventions in different languages. The ``quote_pairs`` function tests
whether two characters form an open/close pair.
The patterns are generated by
``docutils/tools/dev/generate_punctuation_chars.py`` to prevent dependence
on the Python version and avoid the time-consuming generation with every
Docutils run. See there for motives and implementation details.
The category of some characters changed with the development of the
Unicode standard. The current lists are generated with the help of the
"unicodedata" module of Python 2.7.13 (based on Unicode version 5.2.0).
.. _inline markup recognition rules:
http://docutils.sf.net/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules
"""
openers = (u'"\'(<\\[{\u0f3a\u0f3c\u169b\u2045\u207d\u208d\u2329\u2768'
u'\u276a\u276c\u276e\u2770\u2772\u2774\u27c5\u27e6\u27e8\u27ea'
@ -84,272 +94,29 @@ closing_delimiters = u'\\\\.,;!?'
# Matching open/close quotes
# --------------------------
# Rule (5) requires determination of matching open/close pairs. However,
# the pairing of open/close quotes is ambigue due to different typographic
# conventions in different languages.
quote_pairs = {u'\xbb': u'\xbb', # Swedish
u'\u2018': u'\u201a', # Greek
u'\u2019': u'\u2019', # Swedish
u'\u201a': u'\u2018\u2019', # German, Polish
u'\u201c': u'\u201e', # German
u'\u201e': u'\u201c\u201d',
u'\u201d': u'\u201d', # Swedish
u'\u203a': u'\u203a', # Swedish
}
quote_pairs = {# open char: matching closing characters # usage example
u'\xbb': u'\xbb', # » » Swedish
u'\u2018': u'\u201a', # Albanian/Greek/Turkish
u'\u2019': u'\u2019', # Swedish
u'\u201a': u'\u2018\u2019', # German Polish
u'\u201c': u'\u201e', # “ „ Albanian/Greek/Turkish
u'\u201e': u'\u201c\u201d', # „ “ German „ ” Polish
u'\u201d': u'\u201d', # ” ” Swedish
u'\u203a': u'\u203a', # Swedish
}
"""Additional open/close quote pairs."""
def match_chars(c1, c2):
"""Test whether `c1` and `c2` are a matching open/close character pair.
Matching open/close pairs are at the same position in
`punctuation_chars.openers` and `punctuation_chars.closers`.
The pairing of open/close quotes is ambiguous due to different
typographic conventions in different languages,
so we test for additional matches stored in `quote_pairs`.
"""
try:
i = openers.index(c1)
except ValueError: # c1 not in openers
return False
return c2 == closers[i] or c2 in quote_pairs.get(c1, '')
# Running this file as a standalone module checks the definitions against a
# re-calculation::
if __name__ == '__main__':
# Unicode punctuation character categories
# ----------------------------------------
unicode_punctuation_categories = {
# 'Pc': 'Connector', # not used in Docutils inline markup recognition
'Pd': 'Dash',
'Ps': 'Open',
'Pe': 'Close',
'Pi': 'Initial quote', # may behave like Ps or Pe depending on usage
'Pf': 'Final quote', # may behave like Ps or Pe depending on usage
'Po': 'Other'
}
"""Unicode character categories for punctuation"""
# generate character pattern strings
# ==================================
def unicode_charlists(categories, cp_min=0, cp_max=None):
"""Return dictionary of Unicode character lists.
For each of the `catagories`, an item contains a list with all Unicode
characters with `cp_min` <= code-point <= `cp_max` that belong to
the category.
The default values check every code-point supported by Python
(`sys.maxint` is 0x10FFFF in a "wide" build and 0xFFFF in a "narrow"
build, i.e. ucs4 and ucs2 respectively).
"""
# Determine highest code point with one of the given categories
# (may shorten the search time considerably if there are many
# categories with not too high characters):
if cp_max is None:
cp_max = max(x for x in xrange(sys.maxunicode+1)
if unicodedata.category(unichr(x)) in categories)
# print cp_max # => 74867 for unicode_punctuation_categories
charlists = {}
for cat in categories:
charlists[cat] = [unichr(x) for x in xrange(cp_min, cp_max+1)
if unicodedata.category(unichr(x)) == cat]
return charlists
# Character categories in Docutils
# --------------------------------
def punctuation_samples():
"""Docutils punctuation category sample strings.
Return list of sample strings for the categories "Open", "Close",
"Delimiters" and "Closing-Delimiters" used in the `inline markup
recognition rules`_.
"""
# Lists with characters in Unicode punctuation character categories
cp_min = 160 # ASCII chars have special rules for backwards compatibility
ucharlists = unicode_charlists(unicode_punctuation_categories, cp_min)
# match opening/closing characters
# --------------------------------
# Rearange the lists to ensure matching characters at the same
# index position.
# low quotation marks are also used as closers (e.g. in Greek)
# move them to category Pi:
ucharlists['Ps'].remove(u'') # 201A SINGLE LOW-9 QUOTATION MARK
ucharlists['Ps'].remove(u'') # 201E DOUBLE LOW-9 QUOTATION MARK
ucharlists['Pi'] += [u'', u'']
ucharlists['Pi'].remove(u'') # 201B SINGLE HIGH-REVERSED-9 QUOTATION MARK
ucharlists['Pi'].remove(u'') # 201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK
ucharlists['Pf'] += [u'', u'']
# 301F LOW DOUBLE PRIME QUOTATION MARK misses the opening pendant:
ucharlists['Ps'].insert(ucharlists['Pe'].index(u'\u301f'), u'\u301d')
# print u''.join(ucharlists['Ps']).encode('utf8')
# print u''.join(ucharlists['Pe']).encode('utf8')
# print u''.join(ucharlists['Pi']).encode('utf8')
# print u''.join(ucharlists['Pf']).encode('utf8')
# The Docutils character categories
# ---------------------------------
#
# The categorization of ASCII chars is non-standard to reduce
# both false positives and need for escaping. (see `inline markup
# recognition rules`_)
# allowed before markup if there is a matching closer
openers = [u'"\'(<\\[{']
for cat in ('Ps', 'Pi', 'Pf'):
openers.extend(ucharlists[cat])
# allowed after markup if there is a matching opener
closers = [u'"\')>\\]}']
for cat in ('Pe', 'Pf', 'Pi'):
closers.extend(ucharlists[cat])
# non-matching, allowed on both sides
delimiters = [u'\\-/:']
for cat in ('Pd', 'Po'):
delimiters.extend(ucharlists[cat])
# non-matching, after markup
closing_delimiters = [r'\\.,;!?']
# # Test open/close matching:
# for i in range(min(len(openers),len(closers))):
# print '%4d %s %s' % (i, openers[i].encode('utf8'),
# closers[i].encode('utf8'))
return [u''.join(chars) for chars in (openers, closers, delimiters,
closing_delimiters)]
def separate_wide_chars(s):
"""Return (s1,s2) with characters above 0xFFFF in s2"""
maxunicode_narrow = 0xFFFF
l1 = [ch for ch in s if ord(ch) <= maxunicode_narrow]
l2 = [ch for ch in s if ord(ch) > maxunicode_narrow]
return ''.join(l1), ''.join(l2)
def mark_intervals(s):
"""Return s with shortcut notation for runs of consecutive characters
Sort string and replace 'cdef' by 'c-f' and similar.
"""
l =[]
s = [ord(ch) for ch in s]
s.sort()
for n in s:
try:
if l[-1][-1]+1 == n:
l[-1].append(n)
else:
l.append([n])
except IndexError:
l.append([n])
l2 = []
for i in l:
i = [unichr(n) for n in i]
if len(i) > 2:
i = i[0], u'-', i[-1]
l2.extend(i)
return ''.join(l2)
def wrap_string(s, startstring= "(",
endstring = ")", wrap=65):
"""Line-wrap a unicode string literal definition."""
c = len(startstring)
contstring = "'\n" + ' ' * len(startstring) + "u'"
l = [startstring]
for ch in s:
c += 1
if ch == '\\' and c > wrap:
c = len(startstring)
ch = contstring + ch
l.append(ch)
l.append(endstring)
return ''.join(l)
# print results
# =============
# (re) create and compare the samples:
(o, c, d, cd) = punctuation_samples()
o, o_wide = separate_wide_chars(o)
c, c_wide = separate_wide_chars(c)
d, d_wide = separate_wide_chars(d)
d = d[:5] + mark_intervals(d[5:])
d_wide = mark_intervals(d_wide)
if sys.maxunicode >= 0x10FFFF: # "wide" build
d += d_wide
if o != openers:
print '- openers = ur"""%s"""' % openers.encode('utf8')
print '+ openers = ur"""%s"""' % o.encode('utf8')
if o_wide:
print '+ openers-wide = ur"""%s"""' % o_wide.encode('utf8')
if c != closers:
print '- closers = ur"""%s"""' % closers.encode('utf8')
print '+ closers = ur"""%s"""' % c.encode('utf8')
if c_wide:
print '+ closers-wide = ur"""%s"""' % c_wide.encode('utf8')
if d != delimiters:
print '- delimiters = ur"%s"' % delimiters.encode('utf8')
print '+ delimiters = ur"%s"' % d.encode('utf8')
if cd != closing_delimiters:
print '- closing_delimiters = ur"%s"' % closing_delimiters.encode('utf8')
print '+ closing_delimiters = ur"%s"' % cd.encode('utf8')
# closing_delimiters are all ASCII characters
# Print literal code to define the character sets:
# `openers` and `closers` must be verbose and keep order because they are
# also used in `match_chars()`.
print wrap_string(repr(o), startstring='openers = (')
print wrap_string(repr(c), startstring='closers = (')
# delimiters: sort and use shortcut for intervals (saves ~150 characters):
print wrap_string(repr(d), startstring='delimiters = (')
# add characters in the upper plane only in a "wide" build:
print 'if sys.maxunicode >= 0x10FFFF: # "wide" build'
print wrap_string(repr(d_wide), startstring=' delimiters += (')
print 'closing_delimiters =', repr(cd)
# test prints
# print "wide" Unicode characters:
# ucharlists = unicode_charlists(unicode_punctuation_categories)
# for key in ucharlists:
# if key.endswith('wide'):
# print key, ucharlists[key]
# print 'openers = ', repr(openers)
# print 'closers = ', repr(closers)
# print 'delimiters = ', repr(delimiters)
# print 'closing_delimiters = ', repr(closing_delimiters)
# ucharlists = unicode_charlists(unicode_punctuation_categories)
# for cat, chars in ucharlists.items():
# # print cat, chars
# # compact output (visible with a comprehensive font):
# print (u":%s: %s" % (cat, u''.join(chars))).encode('utf8')
# verbose print
# print 'openers:'
# for ch in openers:
# print ch.encode('utf8'), unicodedata.name(ch)
# print 'closers:'
# for ch in closers:
# print ch.encode('utf8'), unicodedata.name(ch)
# print 'delimiters:'
# for ch in delimiters:
# print ch.encode('utf8'), unicodedata.name(ch)
# print 'closing_delimiters:'
# for ch in closing_delimiters:
# print ch.encode('utf8'), unicodedata.name(ch)
return c2 == closers[i] or c2 in quote_pairs.get(c1, u'')

View File

@ -1,7 +1,7 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# :Id: $Id: smartquotes.py 7716 2013-08-21 21:54:57Z milde $
# :Id: $Id: smartquotes.py 8095 2017-05-30 21:04:18Z milde $
# :Copyright: © 2010 Günter Milde,
# original `SmartyPants`_: © 2003 John Gruber
# smartypants.py: © 2004, 2007 Chad Miller
@ -17,25 +17,25 @@
r"""
========================
SmartyPants for Docutils
========================
=========================
Smart Quotes for Docutils
=========================
Synopsis
========
Smart-quotes for Docutils.
"SmartyPants" is a free web publishing plug-in for Movable Type, Blosxom, and
BBEdit that easily translates plain ASCII punctuation characters into "smart"
typographic punctuation characters.
The original "SmartyPants" is a free web publishing plug-in for Movable Type,
Blosxom, and BBEdit that easily translates plain ASCII punctuation characters
into "smart" typographic punctuation characters.
``smartquotes.py`` is an adaption of "SmartyPants" to Docutils_.
`smartypants.py`, endeavours to be a functional port of
SmartyPants to Python, for use with Pyblosxom_.
* Using Unicode instead of HTML entities for typographic punctuation
characters, it works for any output format that supports Unicode.
* Supports `language specific quote characters`__.
__ http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks
`smartquotes.py` is an adaption of Smartypants to Docutils_. By using Unicode
characters instead of HTML entities for typographic quotes, it works for any
output format that supports Unicode.
Authors
=======
@ -43,7 +43,7 @@ Authors
`John Gruber`_ did all of the hard work of writing this software in Perl for
`Movable Type`_ and almost all of this useful documentation. `Chad Miller`_
ported it to Python to use with Pyblosxom_.
Adapted to Docutils_ by Günter Milde
Adapted to Docutils_ by Günter Milde.
Additional Credits
==================
@ -160,102 +160,25 @@ appropriate, such as source code or example markup.
Backslash Escapes
=================
If you need to use literal straight quotes (or plain hyphens and
periods), SmartyPants accepts the following backslash escape sequences
to force non-smart punctuation. It does so by transforming the escape
sequence into a character:
If you need to use literal straight quotes (or plain hyphens and periods),
`smartquotes` accepts the following backslash escape sequences to force
ASCII-punctuation. Mind, that you need two backslashes as Docutils expands it,
too.
======== ===== =========
Escape Value Character
======== ===== =========
``\\\\`` &#92; \\
\\" &#34; "
\\' &#39; '
\\. &#46; .
\\- &#45; \-
\\` &#96; \`
======== ===== =========
======== =========
Escape Character
======== =========
``\\`` \\
``\\"`` \\"
``\\'`` \\'
``\\.`` \\.
``\\-`` \\-
``\\``` \\`
======== =========
This is useful, for example, when you want to use straight quotes as
foot and inch marks: 6\\'2\\" tall; a 17\\" iMac.
Options
=======
For Pyblosxom users, the ``smartypants_attributes`` attribute is where you
specify configuration options.
Numeric values are the easiest way to configure SmartyPants' behavior:
"0"
Suppress all transformations. (Do nothing.)
"1"
Performs default SmartyPants transformations: quotes (including
\`\`backticks'' -style), em-dashes, and ellipses. "``--``" (dash dash)
is used to signify an em-dash; there is no support for en-dashes.
"2"
Same as smarty_pants="1", except that it uses the old-school typewriter
shorthand for dashes: "``--``" (dash dash) for en-dashes, "``---``"
(dash dash dash)
for em-dashes.
"3"
Same as smarty_pants="2", but inverts the shorthand for dashes:
"``--``" (dash dash) for em-dashes, and "``---``" (dash dash dash) for
en-dashes.
"-1"
Stupefy mode. Reverses the SmartyPants transformation process, turning
the characters produced by SmartyPants into their ASCII equivalents.
E.g. "" is turned into a simple double-quote (\"), "" is
turned into two dashes, etc.
The following single-character attribute values can be combined to toggle
individual transformations from within the smarty_pants attribute. For
example, to educate normal quotes and em-dashes, but not ellipses or
\`\`backticks'' -style quotes:
``py['smartypants_attributes'] = "1"``
"q"
Educates normal quote characters: (") and (').
"b"
Educates \`\`backticks'' -style double quotes.
"B"
Educates \`\`backticks'' -style double quotes and \`single' quotes.
"d"
Educates em-dashes.
"D"
Educates em-dashes and en-dashes, using old-school typewriter shorthand:
(dash dash) for en-dashes, (dash dash dash) for em-dashes.
"i"
Educates em-dashes and en-dashes, using inverted old-school typewriter
shorthand: (dash dash) for em-dashes, (dash dash dash) for en-dashes.
"e"
Educates ellipses.
"w"
Translates any instance of ``&quot;`` into a normal double-quote character.
This should be of no interest to most people, but of particular interest
to anyone who writes their posts using Dreamweaver, as Dreamweaver
inexplicably uses this entity to represent a literal double-quote
character. SmartyPants only educates normal quotes, not entities (because
ordinarily, entities are used for the explicit purpose of representing the
specific character they represent). The "w" option must be used in
conjunction with one (or both) of the other quote options ("q" or "b").
Thus, if you wish to apply all SmartyPants transformations (quotes, en-
and em-dashes, and ellipses) and also translate ``&quot;`` entities into
regular quotes so SmartyPants can educate them, you should pass the
following to the smarty_pants attribute:
Caveats
=======
@ -274,7 +197,7 @@ If you're the sort of person who just doesn't care, you might well want to
continue not caring. Using straight quotes -- and sticking to the 7-bit
ASCII character set in general -- is certainly a simpler way to live.
Even if you I *do* care about accurate typography, you still might want to
Even if you *do* care about accurate typography, you still might want to
think twice before educating the quote characters in your weblog. One side
effect of publishing curly quote characters is that it makes your
weblog a bit harder for others to quote from using copy-and-paste. What
@ -300,21 +223,52 @@ Algorithmic Shortcomings
------------------------
One situation in which quotes will get curled the wrong way is when
apostrophes are used at the start of leading contractions. For example:
apostrophes are used at the start of leading contractions. For example::
``'Twas the night before Christmas.``
'Twas the night before Christmas.
In the case above, SmartyPants will turn the apostrophe into an opening
single-quote, when in fact it should be a closing one. I don't think
this problem can be solved in the general case -- every word processor
I've tried gets this wrong as well. In such cases, it's best to use the
proper character for closing single-quotes (````) by hand.
single-quote, when in fact it should be the `right single quotation mark`
character which is also "the preferred character to use for apostrophe"
(Unicode). I don't think this problem can be solved in the general case --
every word processor I've tried gets this wrong as well. In such cases, it's
best to use the proper character for closing single-quotes () by hand.
In English, the same character is used for apostrophe and closing single
quote (both plain and "smart" ones). For other locales (French, Italean,
Swiss, ...) "smart" single closing quotes differ from the curly apostrophe.
.. class:: language-fr
Il dit : "C'est 'super' !"
If the apostrophe is used at the end of a word, it cannot be distinguished
from a single quote by the algorithm. Therefore, a text like::
.. class:: language-de-CH
"Er sagt: 'Ich fass' es nicht.'"
will get a single closing guillemet instead of an apostrophe.
This can be prevented by use use of the curly apostrophe character () in
the source::
- "Er sagt: 'Ich fass' es nicht.'"
+ "Er sagt: 'Ich fass es nicht.'"
Version History
===============
1.7 2012-11-19
1.8: 2017-04-24
- Command line front-end.
1.7.1: 2017-03-19
- Update and extend language-dependent quotes.
- Differentiate apostrophe from single quote.
1.7: 2012-11-19
- Internationalization: language-dependent quotes.
1.6.1: 2012-11-06
@ -358,10 +312,72 @@ Version History
- Initial release
"""
options = r"""
Options
=======
Numeric values are the easiest way to configure SmartyPants' behavior:
:0: Suppress all transformations. (Do nothing.)
:1: Performs default SmartyPants transformations: quotes (including
\`\`backticks'' -style), em-dashes, and ellipses. "``--``" (dash dash)
is used to signify an em-dash; there is no support for en-dashes
:2: Same as smarty_pants="1", except that it uses the old-school typewriter
shorthand for dashes: "``--``" (dash dash) for en-dashes, "``---``"
(dash dash dash)
for em-dashes.
:3: Same as smarty_pants="2", but inverts the shorthand for dashes:
"``--``" (dash dash) for em-dashes, and "``---``" (dash dash dash) for
en-dashes.
:-1: Stupefy mode. Reverses the SmartyPants transformation process, turning
the characters produced by SmartyPants into their ASCII equivalents.
E.g. the LEFT DOUBLE QUOTATION MARK () is turned into a simple
double-quote (\"), "" is turned into two dashes, etc.
The following single-character attribute values can be combined to toggle
individual transformations from within the smarty_pants attribute. For
example, ``"1"`` is equivalent to ``"qBde"``.
:q: Educates normal quote characters: (") and (').
:b: Educates \`\`backticks'' -style double quotes.
:B: Educates \`\`backticks'' -style double quotes and \`single' quotes.
:d: Educates em-dashes.
:D: Educates em-dashes and en-dashes, using old-school typewriter shorthand:
(dash dash) for en-dashes, (dash dash dash) for em-dashes.
:i: Educates em-dashes and en-dashes, using inverted old-school typewriter
shorthand: (dash dash) for em-dashes, (dash dash dash) for en-dashes.
:e: Educates ellipses.
:w: Translates any instance of ``&quot;`` into a normal double-quote character.
This should be of no interest to most people, but of particular interest
to anyone who writes their posts using Dreamweaver, as Dreamweaver
inexplicably uses this entity to represent a literal double-quote
character. SmartyPants only educates normal quotes, not entities (because
ordinarily, entities are used for the explicit purpose of representing the
specific character they represent). The "w" option must be used in
conjunction with one (or both) of the other quote options ("q" or "b").
Thus, if you wish to apply all SmartyPants transformations (quotes, en-
and em-dashes, and ellipses) and also translate ``&quot;`` entities into
regular quotes so SmartyPants can educate them, you should pass the
following to the smarty_pants attribute:
"""
default_smartypants_attr = "1"
import re
import re, sys
class smartchars(object):
"""Smart quotes and dashes
@ -370,75 +386,116 @@ class smartchars(object):
endash = u'' # "&#8211;" EN DASH
emdash = u'' # "&#8212;" EM DASH
ellipsis = u'' # "&#8230;" HORIZONTAL ELLIPSIS
apostrophe = u'' # "&#8217;" RIGHT SINGLE QUOTATION MARK
# quote characters (language-specific, set in __init__())
# [1] http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks
# [2] http://de.wikipedia.org/wiki/Anf%C3%BChrungszeichen#Andere_Sprachen
# [3] https://fr.wikipedia.org/wiki/Guillemet
# [4] http://typographisme.net/post/Les-espaces-typographiques-et-le-web
# [5] http://www.btb.termiumplus.gc.ca/tpv2guides/guides/redac/index-fra.html
# [6] https://en.wikipedia.org/wiki/Hebrew_punctuation#Quotation_marks
# [7] http://www.tustep.uni-tuebingen.de/bi/bi00/bi001t1-anfuehrung.pdf
# [8] http://www.korrekturavdelingen.no/anforselstegn.htm
# [9] Typografisk håndbok. Oslo: Spartacus. 2000. s. 67. ISBN 8243001530.
# [10] http://www.typografi.org/sitat/sitatart.html
#
# English smart quotes (open primary, close primary, open secondary, close
# secondary) are:
# opquote = u'“' # "&#8220;" LEFT DOUBLE QUOTATION MARK
# cpquote = u'”' # "&#8221;" RIGHT DOUBLE QUOTATION MARK
# osquote = u'' # "&#8216;" LEFT SINGLE QUOTATION MARK
# csquote = u'' # "&#8217;" RIGHT SINGLE QUOTATION MARK
# For other languages see:
# http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks
# http://de.wikipedia.org/wiki/Anf%C3%BChrungszeichen#Andere_Sprachen
# TODO: configuration option, e.g.::
#
# smartquote-locales: nl: „“’’, # apostrophe for ``'s Gravenhage``
# nr: se, # alias
# fr: « : »: : , # :-separated list with NBSPs
quotes = {'af': u'“”‘’',
'af-x-altquot': u'„”‚’',
'bg': u'„“‚‘', # Bulgarian, https://bg.wikipedia.org/wiki/Кавички
'ca': u'«»“”',
'ca-x-altquot': u'“”‘’',
'cs': u'„“‚‘',
'cs-x-altquot': u'»«›‹',
'da': u'»«',
'da': u'»«',
'da-x-altquot': u'„“‚‘',
# 'da-x-altquot2': u'””’’',
'de': u'„“‚‘',
'de-x-altquot': u'»«›‹',
'de-CH': u'«»‹›',
'de-ch': u'«»‹›',
'el': u'«»“”',
'en': u'“”‘’',
'en-UK': u'‘’“”',
'en-uk-x-altquot': u'‘’“”', # Attention: " → and ' → “ !
'eo': u'“”‘’',
'es': u'«»“”',
'et': u'„“‚‘', # no secondary quote listed in
'et-x-altquot': u'»«›‹', # the sources above (wikipedia.org)
'eu': u'«»‹›',
'es-x-altquot': u'“”‘’',
'et': u'„“‚‘', # no secondary quote listed in
'et-x-altquot': u'«»‹›', # the sources above (wikipedia.org)
'eu': u'«»‹›',
'fi': u'””’’',
'fi-x-altquot': u'»»’’',
'fr': (u'« ', u' »', u'', u''), # with narrow no-break space
'fr-x-altquot': u'«»‹›', # for use with manually set spaces
# 'fr-x-altquot': (u'“ ', u' ”', u'', u''), # rarely used
'fr-CH': u'«»‹›',
'fi-x-altquot': u'»»',
'fr': (u'« ', u' »', u'', u''), # full no-break space
'fr-x-altquot': (u'« ', u' »', u'', u''), # narrow no-break space
'fr-ch': u'«»‹›',
'fr-ch-x-altquot': (u'« ', u' »', u'', u''), # narrow no-break space, http://typoguide.ch/
'gl': u'«»“”',
'he': u'”“»«',
'he-x-altquot': u'„”‚’',
'he': u'”“»«', # Hebrew is RTL, test position:
'he-x-altquot': u'„”‚’', # low quotation marks are opening.
# 'he-x-altquot': u'“„‘‚', # RTL: low quotation marks opening
'hr': u'„”‘’', # http://hrvatska-tipografija.com/polunavodnici/
'hr-x-altquot': u'»«›‹',
'hsb': u'„“‚‘',
'hsb-x-altquot':u'»«›‹',
'hu': u'„”«»',
'is': u'„“‚‘',
'it': u'«»“”',
'it-CH': u'«»‹›',
'it-ch': u'«»‹›',
'it-x-altquot': u'“”‘’',
# 'it-x-altquot2': u'“„‘‚', # [7] in headlines
'ja': u'「」『』',
'lt': u'„“‚‘',
'lv': u'„“‚‘',
'mk': u'„“‚‘', # Macedonian, https://mk.wikipedia.org/wiki/Правопис_и_правоговораакедонскиот_јазик
'nl': u'“”‘’',
'nl-x-altquot': u'„”‚’',
# 'nl-x-altquot2': u'””’’',
'nb': u'«»’’', # Norsk bokmål (canonical form 'no')
'nn': u'«»’’', # Nynorsk [10]
'nn-x-altquot': u'«»‘’', # [8], [10]
# 'nn-x-altquot2': u'«»«»', # [9], [10
# 'nn-x-altquot3': u'„“‚‘', # [10]
'no': u'«»’’', # Norsk bokmål [10]
'no-x-altquot': u'«»‘’', # [8], [10]
# 'no-x-altquot2': u'«»«»', # [9], [10
# 'no-x-altquot3': u'„“‚‘', # [10]
'pl': u'„”«»',
'pl-x-altquot': u'«»“”',
'pl-x-altquot': u'«»‚’',
# 'pl-x-altquot2': u'„”‚’', # https://pl.wikipedia.org/wiki/Cudzys%C5%82%C3%B3w
'pt': u'«»“”',
'pt-BR': u'“”‘’',
'pt-br': u'“”‘’',
'ro': u'„”«»',
'ro-x-altquot': u'«»„”',
'ru': u'«»„“',
'sk': u'„“‚‘',
'sh': u'„”‚’', # Serbo-Croatian
'sh-x-altquot': u'»«›‹',
'sk': u'„“‚‘', # Slovak
'sk-x-altquot': u'»«›‹',
'sv': u'„“‚‘',
'sv-x-altquot': u'»«›‹',
'zh-CN': u'“”‘’',
'it': u'«»“”',
'zh-TW': u'「」『』',
'sl': u'„“‚‘', # Slovenian
'sl-x-altquot': u'»«›‹',
'sq': u'«»‹›', # Albanian
'sq-x-altquot': u'“„‘‚',
'sr': u'„”’’',
'sr-x-altquot': u'»«›‹',
'sv': u'””’’',
'sv-x-altquot': u'»»››',
'tr': u'“”‘’',
'tr-x-altquot': u'«»‹›',
# 'tr-x-altquot2': u'“„‘‚', # [7] antiquated?
'uk': u'«»„“',
'uk-x-altquot': u'„“‚‘',
'zh-cn': u'“”‘’',
'zh-tw': u'「」『』',
}
def __init__(self, language='en'):
self.language = language
try:
(self.opquote, self.cpquote,
self.osquote, self.csquote) = self.quotes[language]
self.osquote, self.csquote) = self.quotes[language.lower()]
except KeyError:
self.opquote, self.cpquote, self.osquote, self.csquote = u'""\'\''
@ -476,9 +533,8 @@ def educate_tokens(text_tokens, attr=default_smartypants_attr, language='en'):
do_ellipses = False
do_stupefy = False
if attr == "0": # Do nothing.
yield text
elif attr == "1": # Do everything, turn all options on.
# if attr == "0": # pass tokens unchanged (see below).
if attr == "1": # Do everything, turn all options on.
do_quotes = True
do_backticks = True
do_dashes = 1
@ -550,7 +606,10 @@ def educate_tokens(text_tokens, attr=default_smartypants_attr, language='en'):
text = educateSingleBackticks(text, language)
if do_quotes:
text = educateQuotes(prev_token_last_char+text, language)[1:]
# Replace plain quotes in context to prevent converstion to
# 2-character sequence in French.
context = prev_token_last_char.replace('"',';').replace("'",';')
text = educateQuotes(context+text, language)[1:]
if do_stupefy:
text = stupefyEntities(text, language)
@ -591,7 +650,8 @@ def educateQuotes(text, language='en'):
text = re.sub(r"""'"(?=\w)""", smart.osquote+smart.opquote, text)
# Special case for decade abbreviations (the '80s):
text = re.sub(r"""\b'(?=\d{2}s)""", smart.csquote, text)
if language.startswith('en'): # TODO similar cases in other languages?
text = re.sub(r"""'(?=\d{2}s)""", smart.apostrophe, text, re.UNICODE)
close_class = r"""[^\ \t\r\n\[\{\(\-]"""
dec_dashes = r"""&#8211;|&#8212;"""
@ -608,21 +668,31 @@ def educateQuotes(text, language='en'):
)
' # the quote
(?=\w) # followed by a word character
""" % (dec_dashes,), re.VERBOSE)
""" % (dec_dashes,), re.VERBOSE | re.UNICODE)
text = opening_single_quotes_regex.sub(r'\1'+smart.osquote, text)
# In many locales, single closing quotes are different from apostrophe:
if smart.csquote != smart.apostrophe:
apostrophe_regex = re.compile(r"(?<=(\w|\d))'(?=\w)", re.UNICODE)
text = apostrophe_regex.sub(smart.apostrophe, text)
# TODO: keep track of quoting level to recognize apostrophe in, e.g.,
# "Ich fass' es nicht."
closing_single_quotes_regex = re.compile(r"""
(%s)
'
(?!\s | s\b | \d)
""" % (close_class,), re.VERBOSE)
(?!\s | # whitespace
s\b |
\d # digits ('80s)
)
""" % (close_class,), re.VERBOSE | re.UNICODE)
text = closing_single_quotes_regex.sub(r'\1'+smart.csquote, text)
closing_single_quotes_regex = re.compile(r"""
(%s)
'
(\s | s\b)
""" % (close_class,), re.VERBOSE)
""" % (close_class,), re.VERBOSE | re.UNICODE)
text = closing_single_quotes_regex.sub(r'\1%s\2' % smart.csquote, text)
# Any remaining single quotes should be opening ones:
@ -855,52 +925,98 @@ def tokenize(text):
if __name__ == "__main__":
import locale
import itertools
try:
locale.setlocale(locale.LC_ALL, '')
import locale # module missing in Jython
locale.setlocale(locale.LC_ALL, '') # set to user defaults
defaultlanguage = locale.getdefaultlocale()[0]
except:
pass
defaultlanguage = 'en'
from docutils.core import publish_string
docstring_html = publish_string(__doc__, writer_name='html')
print docstring_html
# Normalize and drop unsupported subtags:
defaultlanguage = defaultlanguage.lower().replace('-','_')
# split (except singletons, which mark the following tag as non-standard):
defaultlanguage = re.sub(r'_([a-zA-Z0-9])_', r'_\1-', defaultlanguage)
_subtags = [subtag for subtag in defaultlanguage.split('_')]
_basetag = _subtags.pop(0)
# find all combinations of subtags
for n in range(len(_subtags), 0, -1):
for tags in itertools.combinations(_subtags, n):
_tag = '-'.join((_basetag,)+tags)
if _tag in smartchars.quotes:
defaultlanguage = _tag
break
else:
if _basetag in smartchars.quotes:
defaultlanguage = _basetag
else:
defaultlanguage = 'en'
# Unit test output goes out stderr.
import unittest
sp = smartyPants
import argparse
parser = argparse.ArgumentParser(
description='Filter stdin making ASCII punctuation "smart".')
# parser.add_argument("text", help="text to be acted on")
parser.add_argument("-a", "--action", default="1",
help="what to do with the input (see --actionhelp)")
parser.add_argument("-e", "--encoding", default="utf8",
help="text encoding")
parser.add_argument("-l", "--language", default=defaultlanguage,
help="text language (BCP47 tag), Default: %s"%defaultlanguage)
parser.add_argument("-q", "--alternative-quotes", action="store_true",
help="use alternative quote style")
parser.add_argument("--doc", action="store_true",
help="print documentation")
parser.add_argument("--actionhelp", action="store_true",
help="list available actions")
parser.add_argument("--stylehelp", action="store_true",
help="list available quote styles")
parser.add_argument("--test", action="store_true",
help="perform short self-test")
args = parser.parse_args()
class TestSmartypantsAllAttributes(unittest.TestCase):
# the default attribute is "1", which means "all".
if args.doc:
print (__doc__)
elif args.actionhelp:
print(options)
elif args.stylehelp:
print()
print("Available styles (primary open/close, secondary open/close)")
print("language tag quotes")
print("============ ======")
for key in sorted(smartchars.quotes.keys()):
print("%-14s %s" % (key, smartchars.quotes[key]))
elif args.test:
# Unit test output goes to stderr.
import unittest
def test_dates(self):
self.assertEqual(sp("1440-80's"), u"1440-80s")
self.assertEqual(sp("1440-'80s"), u"1440-80s")
self.assertEqual(sp("1440---'80s"), u"144080s")
self.assertEqual(sp("1960s"), "1960s") # no effect.
self.assertEqual(sp("1960's"), u"1960s")
self.assertEqual(sp("one two '60s"), u"one two 60s")
self.assertEqual(sp("'60s"), u"60s")
class TestSmartypantsAllAttributes(unittest.TestCase):
# the default attribute is "1", which means "all".
def test_dates(self):
self.assertEqual(smartyPants("1440-80's"), u"1440-80s")
self.assertEqual(smartyPants("1440-'80s"), u"1440-80s")
self.assertEqual(smartyPants("1440---'80s"), u"144080s")
self.assertEqual(smartyPants("1960's"), u"1960s")
self.assertEqual(smartyPants("one two '60s"), u"one two 60s")
self.assertEqual(smartyPants("'60s"), u"60s")
def test_ordinal_numbers(self):
self.assertEqual(sp("21st century"), "21st century") # no effect.
self.assertEqual(sp("3rd"), "3rd") # no effect.
def test_educated_quotes(self):
self.assertEqual(smartyPants('"Isn\'t this fun?"'), u'“Isnt this fun?”')
def test_educated_quotes(self):
self.assertEqual(sp('''"Isn't this fun?"'''), u'“Isnt this fun?”')
def test_html_tags(self):
text = '<a src="foo">more</a>'
self.assertEqual(smartyPants(text), text)
def test_html_tags(self):
text = '<a src="foo">more</a>'
self.assertEqual(sp(text), text)
suite = unittest.TestLoader().loadTestsFromTestCase(
TestSmartypantsAllAttributes)
unittest.TextTestRunner().run(suite)
unittest.main()
__author__ = "Chad Miller <smartypantspy@chad.org>"
__version__ = "1.5_1.6: Fri, 27 Jul 2007 07:06:40 -0400"
__url__ = "http://wiki.chad.org/SmartyPantsPy"
__description__ = "Smart-quotes, smart-ellipses, and smart-dashes for weblog entries in pyblosxom"
else:
if args.alternative_quotes:
if '-x-altquot' in args.language:
args.language = args.language.replace('-x-altquot', '')
else:
args.language += '-x-altquot'
text = sys.stdin.read().decode(args.encoding)
print(smartyPants(text, attr=args.action,
language=args.language).encode(args.encoding))

View File

@ -1,4 +1,4 @@
# $Id: urischemes.py 7464 2012-06-25 13:16:03Z milde $
# $Id: urischemes.py 7922 2015-09-22 15:28:09Z milde $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -113,7 +113,7 @@ schemes = {
'tel': ('a connection to a terminal that handles normal voice '
'telephone calls, a voice mailbox or another voice messaging '
'system or a service that can be operated using DTMF tones; '
'RFC 2806.'),
'RFC 3966.'),
'telephone': 'telephone',
'telnet': 'Reference to interactive sessions; RFC 4248',
'tftp': 'Trivial File Transfer Protocol; RFC 3617',

View File

@ -1,4 +1,4 @@
# $Id: __init__.py 7648 2013-04-18 07:36:22Z milde $
# $Id: __init__.py 7969 2016-08-18 21:40:00Z milde $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
@ -120,13 +120,18 @@ class UnfilteredWriter(Writer):
_writer_aliases = {
'html': 'html4css1',
'html': 'html4css1', # may change to html5 some day
'html4': 'html4css1',
'html5': 'html5_polyglot',
'latex': 'latex2e',
'pprint': 'pseudoxml',
'pformat': 'pseudoxml',
'pdf': 'rlpdf',
'xml': 'docutils_xml',
's5': 's5_html'}
's5': 's5_html',
'xelatex': 'xetex',
'xhtml': 'html5_polyglot',
'xhtml10': 'html4css1',
'xml': 'docutils_xml'}
def get_writer_class(writer_name):
"""Return the Writer class from the `writer_name` module."""

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
# $Id: docutils_xml.py 7497 2012-08-16 15:17:29Z milde $
# $Id: docutils_xml.py 7966 2016-08-18 13:06:09Z milde $
# Author: David Goodger, Paul Tremblay, Guenter Milde
# Maintainer: docutils-develop@lists.sourceforge.net
# Copyright: This module has been placed in the public domain.
@ -46,7 +46,7 @@ class Writer(writers.Writer):
['--newlines'],
{'action': 'store_true', 'validator': frontend.validate_boolean}),
('Generate XML with indents and newlines.',
['--indents'],
['--indents'], #@ TODO use integer value for number of spaces?
{'action': 'store_true', 'validator': frontend.validate_boolean}),
('Omit the XML declaration. Use with caution.',
['--no-xml-declaration'],
@ -105,9 +105,10 @@ class XMLTranslator(nodes.GenericNodeVisitor):
self.newline = '\n'
if settings.indents:
self.newline = '\n'
self.indent = ' '
self.indent = ' ' #@ TODO make this configurable?
self.level = 0 # indentation level
self.in_simple = 0 # level of nesting inside mixed-content elements
self.fixed_text = 0 # level of nesting inside FixedText elements
# Output
self.output = []
@ -125,13 +126,19 @@ class XMLTranslator(nodes.GenericNodeVisitor):
# generic visit and depart methods
# --------------------------------
simple_nodes = (nodes.TextElement,
nodes.image, nodes.colspec, nodes.transition) # empty elements
def default_visit(self, node):
"""Default node visit method."""
if not self.in_simple:
self.output.append(self.indent*self.level)
self.output.append(node.starttag(xml.sax.saxutils.quoteattr))
self.level += 1
if isinstance(node, nodes.TextElement):
# @@ make nodes.literal an instance of FixedTextElement?
if isinstance(node, (nodes.FixedTextElement, nodes.literal)):
self.fixed_text += 1
if isinstance(node, self.simple_nodes):
self.in_simple += 1
if not self.in_simple:
self.output.append(self.newline)
@ -142,7 +149,9 @@ class XMLTranslator(nodes.GenericNodeVisitor):
if not self.in_simple:
self.output.append(self.indent*self.level)
self.output.append(node.endtag())
if isinstance(node, nodes.TextElement):
if isinstance(node, (nodes.FixedTextElement, nodes.literal)):
self.fixed_text -= 1
if isinstance(node, self.simple_nodes):
self.in_simple -= 1
if not self.in_simple:
self.output.append(self.newline)
@ -153,6 +162,9 @@ class XMLTranslator(nodes.GenericNodeVisitor):
def visit_Text(self, node):
text = xml.sax.saxutils.escape(node.astext())
# indent text if we are not in a FixedText element:
if not self.fixed_text:
text = text.replace('\n', '\n'+self.indent*self.level)
self.output.append(text)
def depart_Text(self, node):

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7614 2013-02-21 15:55:51Z milde $
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
@ -28,6 +28,14 @@ table.borderless td, table.borderless th {
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
@ -152,12 +160,12 @@ h2.subtitle {
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left {
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right {
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
@ -168,6 +176,11 @@ img.align-center, .figure.align-center, object.align-center {
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
@ -185,6 +198,15 @@ div.align-right {
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }

View File

@ -0,0 +1,214 @@
# .. coding: utf8
# $Id: __init__.py 8041 2017-03-01 11:02:33Z milde $
# :Author: Günter Milde <milde@users.sf.net>
# Based on the html4css1 writer by David Goodger.
# :Maintainer: docutils-develop@lists.sourceforge.net
# :Copyright: © 2005, 2009, 2015 Günter Milde,
# portions from html4css1 © David Goodger.
# :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
# Use "best practice" as recommended by the W3C:
# http://www.w3.org/2009/cheatsheet/
"""
Plain HyperText Markup Language document tree Writer.
The output conforms to the `HTML5` specification.
The cascading style sheet "minimal.css" is required for proper viewing,
the style sheet "plain.css" improves reading experience.
"""
__docformat__ = 'reStructuredText'
import os.path
import docutils
from docutils import frontend, nodes, writers, io
from docutils.transforms import writer_aux
from docutils.writers import _html_base
class Writer(writers._html_base.Writer):
supported = ('html', 'html5', 'html4', 'xhtml', 'xhtml10')
"""Formats this writer supports."""
default_stylesheets = ['minimal.css','plain.css']
default_stylesheet_dirs = ['.', os.path.abspath(os.path.dirname(__file__))]
default_template = 'template.txt'
default_template_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)), default_template)
settings_spec = (
'HTML-Specific Options',
None,
(('Specify the template file (UTF-8 encoded). Default is "%s".'
% default_template_path,
['--template'],
{'default': default_template_path, 'metavar': '<file>'}),
('Comma separated list of stylesheet URLs. '
'Overrides previous --stylesheet and --stylesheet-path settings.',
['--stylesheet'],
{'metavar': '<URL[,URL,...]>', 'overrides': 'stylesheet_path',
'validator': frontend.validate_comma_separated_list}),
('Comma separated list of stylesheet paths. '
'Relative paths are expanded if a matching file is found in '
'the --stylesheet-dirs. With --link-stylesheet, '
'the path is rewritten relative to the output HTML file. '
'Default: "%s"' % ','.join(default_stylesheets),
['--stylesheet-path'],
{'metavar': '<file[,file,...]>', 'overrides': 'stylesheet',
'validator': frontend.validate_comma_separated_list,
'default': default_stylesheets}),
('Embed the stylesheet(s) in the output HTML file. The stylesheet '
'files must be accessible during processing. This is the default.',
['--embed-stylesheet'],
{'default': 1, 'action': 'store_true',
'validator': frontend.validate_boolean}),
('Link to the stylesheet(s) in the output HTML file. '
'Default: embed stylesheets.',
['--link-stylesheet'],
{'dest': 'embed_stylesheet', 'action': 'store_false'}),
('Comma-separated list of directories where stylesheets are found. '
'Used by --stylesheet-path when expanding relative path arguments. '
'Default: "%s"' % default_stylesheet_dirs,
['--stylesheet-dirs'],
{'metavar': '<dir[,dir,...]>',
'validator': frontend.validate_comma_separated_list,
'default': default_stylesheet_dirs}),
('Specify the initial header level. Default is 1 for "<h1>". '
'Does not affect document title & subtitle (see --no-doc-title).',
['--initial-header-level'],
{'choices': '1 2 3 4 5 6'.split(), 'default': '1',
'metavar': '<level>'}),
('Format for footnote references: one of "superscript" or '
'"brackets". Default is "brackets".',
['--footnote-references'],
{'choices': ['superscript', 'brackets'], 'default': 'brackets',
'metavar': '<format>',
'overrides': 'trim_footnote_reference_space'}),
('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': '<format>'}),
('Remove extra vertical whitespace between items of "simple" bullet '
'lists and enumerated lists. Default: enabled.',
['--compact-lists'],
{'default': True, 'action': 'store_true',
'validator': frontend.validate_boolean}),
('Disable compact simple bullet and enumerated lists.',
['--no-compact-lists'],
{'dest': 'compact_lists', 'action': 'store_false'}),
('Remove extra vertical whitespace between items of simple field '
'lists. Default: enabled.',
['--compact-field-lists'],
{'default': True, 'action': 'store_true',
'validator': frontend.validate_boolean}),
('Disable compact simple field lists.',
['--no-compact-field-lists'],
{'dest': 'compact_field_lists', 'action': 'store_false'}),
('Added to standard table classes. '
'Defined styles: borderless, booktabs, '
'align-left, align-center, align-right, colwidths-auto. '
'Default: ""',
['--table-style'],
{'default': ''}),
('Math output format (one of "MathML", "HTML", "MathJax", '
'or "LaTeX") and option(s). '
'Default: "HTML math.css"',
['--math-output'],
{'default': 'HTML math.css'}),
('Prepend an XML declaration. (Thwarts HTML5 conformance.) '
'Default: False',
['--xml-declaration'],
{'default': False, 'action': 'store_true',
'validator': frontend.validate_boolean}),
('Omit the XML declaration.',
['--no-xml-declaration'],
{'dest': 'xml_declaration', 'action': 'store_false'}),
('Obfuscate email addresses to confuse harvesters while still '
'keeping email links usable with standards-compliant browsers.',
['--cloak-email-addresses'],
{'action': 'store_true', 'validator': frontend.validate_boolean}),))
config_section = 'html5 writer'
def __init__(self):
self.parts = {}
self.translator_class = HTMLTranslator
class HTMLTranslator(writers._html_base.HTMLTranslator):
"""
This writer generates `polyglot markup`: HTML5 that is also valid XML.
Safe subclassing: when overriding, treat ``visit_*`` and ``depart_*``
methods as a unit to prevent breaks due to internal changes. See the
docstring of docutils.writers._html_base.HTMLTranslator for details
and examples.
"""
# <acronym> tag not supported in HTML5. Use the <abbr> tag instead.
def visit_acronym(self, node):
# @@@ implementation incomplete ("title" attribute)
self.body.append(self.starttag(node, 'abbr', ''))
def depart_acronym(self, node):
self.body.append('</abbr>')
# no meta tag in HTML5
def visit_authors(self, node):
self.visit_docinfo_item(node, 'authors', meta=False)
def depart_authors(self, node):
self.depart_docinfo_item()
# no meta tag in HTML5
def visit_copyright(self, node):
self.visit_docinfo_item(node, 'copyright', meta=False)
def depart_copyright(self, node):
self.depart_docinfo_item()
# no meta tag in HTML5
def visit_date(self, node):
self.visit_docinfo_item(node, 'date', meta=False)
def depart_date(self, node):
self.depart_docinfo_item()
# TODO: use HTML5 <footer> element?
# def visit_footer(self, node):
# def depart_footer(self, node):
# TODO: use the new HTML5 element <aside>? (Also for footnote text)
# def visit_footnote(self, node):
# def depart_footnote(self, node):
# Meta tags: 'lang' attribute replaced by 'xml:lang' in XHTML 1.1
# HTML5/polyglot recommends using both
def visit_meta(self, node):
if node.hasattr('lang'):
node['xml:lang'] = node['lang']
# del(node['lang'])
meta = self.emptytag(node, 'meta', **node.non_default_attributes())
self.add_meta(meta)
def depart_meta(self, node):
pass
# no meta tag in HTML5
def visit_organization(self, node):
self.visit_docinfo_item(node, 'organization', meta=False)
def depart_organization(self, node):
self.depart_docinfo_item()
# TODO: use the new HTML5 element <section>?
# def visit_section(self, node):
# def depart_section(self, node):
# TODO: use the new HTML5 element <aside>?
# def visit_topic(self, node):
# def depart_topic(self, node):

View File

@ -0,0 +1,260 @@
/* Minimal style sheet for the HTML output of Docutils. */
/* */
/* :Author: Günter Milde, based on html4css1.css by David Goodger */
/* :Id: $Id: minimal.css 8036 2017-02-14 13:05:46Z milde $ */
/* :Copyright: © 2015 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 */
/* This CSS2.1_ stylesheet defines rules for Docutils elements without */
/* HTML equivalent. It is required to make the document semantic visible. */
/* */
/* .. _CSS2.1: http://www.w3.org/TR/CSS2 */
/* .. _validates: http://jigsaw.w3.org/css-validator/validator$link */
/* alignment of text and inline objects inside block objects*/
.align-left { text-align: left; }
.align-right { text-align: right; }
.align-center { clear: both; text-align: center; }
.align-top { vertical-align: top; }
.align-middle { vertical-align: middle; }
.align-bottom { vertical-align: bottom; }
/* titles */
h1.title, p.subtitle {
text-align: center;
}
p.admonition-title,
p.topic-title,
p.sidebar-title,
p.rubric,
p.system-message-title {
font-weight: bold;
}
h1 + p.subtitle,
h1 + p.section-subtitle {
font-size: 1.6em;
}
h2 + p.section-subtitle { font-size: 1.28em; }
p.subtitle,
p.section-subtitle,
p.sidebar-subtitle {
font-weight: bold;
margin-top: -0.5em;
}
p.sidebar-title,
p.rubric {
font-size: larger;
}
p.rubric { color: maroon; }
a.toc-backref {
color: black;
text-decoration: none; }
/* Warnings, Errors */
div.caution p.admonition-title,
div.attention p.admonition-title,
div.danger p.admonition-title,
div.error p.admonition-title,
div.warning p.admonition-title,
div.system-messages h1,
div.error,
span.problematic,
p.system-message-title {
color: red;
}
/* inline literals */
span.docutils.literal {
font-family: monospace;
white-space: pre-wrap;
}
/* do not wraph at hyphens and similar: */
.literal > span.pre { white-space: nowrap; }
/* Lists */
/* compact and simple lists: no margin between items */
.simple li, .compact li,
.simple ul, .compact ul,
.simple ol, .compact ol,
.simple > li p, .compact > li p,
dl.simple > dd, dl.compact > dd {
margin-top: 0;
margin-bottom: 0;
}
/* Table of Contents */
div.topic.contents { margin: 0; }
ul.auto-toc {
list-style-type: none;
padding-left: 1.5em; }
/* Enumerated Lists */
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 }
dt span.classifier { font-style: italic }
dt span.classifier:before {
font-style: normal;
margin: 0.5em;
content: ":";
}
/* Field Lists and drivatives */
/* bold field name, content starts on the same line */
dl.field-list > dt,
dl.option-list > dt,
dl.docinfo > dt,
dl.footnote > dt,
dl.citation > dt {
font-weight: bold;
clear: left;
float: left;
margin: 0;
padding: 0;
padding-right: 0.5em;
}
/* Offset for field content (corresponds to the --field-name-limit option) */
dl.field-list > dd,
dl.option-list > dd,
dl.docinfo > dd {
margin-left: 9em; /* ca. 14 chars in the test examples */
}
/* start field-body on a new line after long field names */
dl.field-list > dd > *:first-child,
dl.option-list > dd > *:first-child
{
display: inline-block;
width: 100%;
margin: 0;
}
/* field names followed by a colon */
dl.field-list > dt:after,
dl.docinfo > dt:after {
content: ":";
}
/* Bibliographic Fields (docinfo) */
pre.address { font: inherit; }
dd.authors > p { margin: 0; }
/* Option Lists */
dl.option-list { margin-left: 40px; }
dl.option-list > dt { font-weight: normal; }
span.option { white-space: nowrap; }
/* Footnotes and Citations */
dl.footnote.superscript > dd {margin-left: 1em; }
dl.footnote.brackets > dd {margin-left: 2em; }
dl > dt.label { font-weight: normal; }
a.footnote-reference.brackets:before,
dt.label > span.brackets:before { content: "["; }
a.footnote-reference.brackets:after,
dt.label > span.brackets:after { content: "]"; }
a.footnote-reference.superscript,
dl.footnote.superscript > dt.label {
vertical-align: super;
font-size: smaller;
}
dt.label > span.fn-backref { margin-left: 0.2em; }
dt.label > span.fn-backref > a { font-style: italic; }
/* Line Blocks */
div.line-block { display: block; }
div.line-block div.line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 40px;
}
/* Figures, Images, and Tables */
.figure.align-left,
img.align-left,
object.align-left,
table.align-left {
margin-right: auto;
}
.figure.align-center,
img.align-center,
object.align-center {
margin-left: auto;
margin-right: auto;
display: block;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.figure.align-right,
img.align-right,
object.align-right,
table.align-right {
margin-left: auto;
}
/* reset inner alignment in figures and tables */
/* div.align-left, div.align-center, div.align-right, */
table.align-left, table.align-center, table.align-right
{ text-align: inherit }
/* Admonitions and System Messages */
div.admonition,
div.system-message,
div.sidebar{
margin: 40px;
border: medium outset;
padding-right: 1em;
padding-left: 1em;
}
/* Sidebar */
div.sidebar {
width: 30%;
max-width: 26em;
float: right;
clear: right;
}
/* Text Blocks */
div.topic,
pre.literal-block,
pre.doctest-block,
pre.math,
pre.code {
margin-right: 40px;
margin-left: 40px;
}
pre.code .ln { color: gray; } /* line numbers */
/* Tables */
table { border-collapse: collapse; }
td, th {
border-style: solid;
border-color: silver;
padding: 0 1ex;
border-width: thin;
}
td > p:first-child, th > p:first-child { margin-top: 0; }
td > p, th > p { margin-bottom: 0; }
table > caption {
text-align: left;
margin-bottom: 0.25em
}
table.borderless td, table.borderless th {
border: 0;
padding: 0;
padding-right: 0.5em /* separate table cells */
}

View File

@ -0,0 +1,288 @@
/* CSS31_ style sheet for the output of Docutils HTML writers. */
/* Rules for easy reading and pre-defined style variants. */
/* */
/* :Author: Günter Milde, based on html4css1.css by David Goodger */
/* :Id: $Id: plain.css 8120 2017-06-22 21:02:40Z milde $ */
/* :Copyright: © 2015 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 */
/* .. _CSS3: http://www.w3.org/TR/CSS3 */
/* Document Structure */
/* ****************** */
/* "page layout" */
body {
padding: 0 5%;
margin: 8px 0;
}
div.document {
line-height:1.3;
counter-reset: table;
/* counter-reset: figure; */
/* avoid long lines --> better reading */
/* OTOH: lines should not be too short because of missing hyphenation, */
max-width: 50em;
margin: auto;
}
/* Sections */
/* Transitions */
hr.docutils {
width: 80%;
margin-top: 1em;
margin-bottom: 1em;
clear: both;
}
/* Paragraphs */
/* ========== */
/* vertical space (parskip) */
p, ol, ul, dl,
div.line-block,
table{
margin-top: 0.5em;
margin-bottom: 0.5em;
}
h1, h2, h3, h4, h5, h6,
dl > dd {
margin-bottom: 0.5em;
}
/* Lists */
/* ========== */
/* Definition Lists */
dl > dd > p:first-child { margin-top: 0; }
/* :last-child is not part of CSS 2.1 (introduced in CSS 3) */
dl > dd > p:last-child { margin-bottom: 0; }
/* lists nested in definition lists */
/* :only-child is not part of CSS 2.1 (introduced in CSS 3) */
dd > ul:only-child, dd > ol:only-child { padding-left: 1em; }
/* Description Lists */
/* styled like in most dictionaries, encyclopedias etc. */
dl.description > dt {
font-weight: bold;
clear: left;
float: left;
margin: 0;
padding: 0;
padding-right: 0.5em;
}
/* Field Lists */
/* example for custom field-name width */
dl.field-list.narrow > dd {
margin-left: 5em;
}
/* run-in: start field-body on same line after long field names */
dl.field-list.run-in > dd p {
display: block;
}
/* Bibliographic Fields */
/* generally, bibliographic fields use special definition list dl.docinfo */
/* but dedication and abstract are placed into "topic" divs */
div.abstract p.topic-title {
text-align: center;
}
div.dedication {
margin: 2em 5em;
text-align: center;
font-style: italic;
}
div.dedication p.topic-title {
font-style: normal;
}
/* Citations */
dl.citation dt.label {
font-weight: bold;
}
span.fn-backref {
font-weight: normal;
}
/* Text Blocks */
/* ============ */
/* Literal Blocks */
pre.literal-block, pre.doctest-block,
pre.math, pre.code {
margin-left: 1.5em;
margin-right: 1.5em
}
/* Block Quotes */
blockquote,
div.topic {
margin-left: 1.5em;
margin-right: 1.5em
}
blockquote > table,
div.topic > table {
margin-top: 0;
margin-bottom: 0;
}
blockquote p.attribution,
div.topic p.attribution {
text-align: right;
margin-left: 20%;
}
/* Tables */
/* ====== */
/* th { vertical-align: bottom; } */
table tr { text-align: left; }
/* "booktabs" style (no vertical lines) */
table.booktabs {
border: 0;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.booktabs * {
border: 0;
}
table.booktabs th {
border-bottom: thin solid;
}
/* numbered tables (counter defined in div.document) */
table.numbered > caption:before {
counter-increment: table;
content: "Table " counter(table) ": ";
font-weight: bold;
}
/* Explicit Markup Blocks */
/* ====================== */
/* Footnotes and Citations */
/* ----------------------- */
/* line on the left */
dl.footnote {
padding-left: 1ex;
border-left: solid;
border-left-width: thin;
}
/* Directives */
/* ---------- */
/* Body Elements */
/* ~~~~~~~~~~~~~ */
/* Images and Figures */
/* let content flow to the side of aligned images and figures */
.figure.align-left,
img.align-left,
object.align-left {
display: block;
clear: left;
float: left;
margin-right: 1em
}
.figure.align-right,
img.align-right,
object.align-right {
display: block;
clear: right;
float: right;
margin-left: 1em
}
/* Stop floating sidebars, images and figures at section level 1,2,3 */
h1, h2, h3 { clear: both; }
/* Sidebar */
/* Move into the margin. In a layout with fixed margins, */
/* it can be moved into the margin completely. */
div.sidebar {
width: 30%;
max-width: 26em;
margin-left: 1em;
margin-right: -5.5%;
background-color: #ffffee ;
}
/* Code */
pre.code, code { background-color: #eeeeee }
pre.code .ln { color: gray; } /* line numbers */
/* basic highlighting: for a complete scheme, see */
/* http://docutils.sourceforge.net/sandbox/stylesheets/ */
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
/* Math */
/* styled separately (see math.css for math-output=HTML) */
/* Epigraph */
/* Highlights */
/* Pull-Quote */
/* Compound Paragraph */
/* Container */
/* can be styled in a custom stylesheet */
/* Document Header and Footer */
div.footer, div.header {
clear: both;
font-size: smaller;
}
/* Inline Markup */
/* ============= */
/* Emphasis */
/* em */
/* Strong Emphasis */
/* strong */
/* Interpreted Text */
/* span.interpreted */
/* Title Reference */
/* cite */
/* Inline Literals */
/* possible values: normal, nowrap, pre, pre-wrap, pre-line */
/* span.docutils.literal { white-space: pre-wrap; } */
/* Hyperlink References */
a { text-decoration: none; }
/* External Targets */
/* span.target.external */
/* Internal Targets */
/* span.target.internal */
/* Footnote References */
/* a.footnote-reference */
/* Citation References */
/* a.citation-reference */

View File

@ -0,0 +1,8 @@
%(head_prefix)s
%(head)s
%(stylesheet)s
%(body_prefix)s
%(body_pre_docinfo)s
%(docinfo)s
%(body)s
%(body_suffix)s

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,4 @@
$head_prefix% generated by Docutils <http://docutils.sourceforge.net/>
\usepackage{fixltx2e} % LaTeX patches, \textsubscript
\usepackage{cmap} % fix search and cut-and-paste in Acrobat
$requirements
%%% Custom LaTeX preamble

View File

@ -0,0 +1,738 @@
% ==================================================================
% 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}}

View File

@ -1,7 +1,12 @@
$head_prefix% generated by Docutils <http://docutils.sourceforge.net/>
% rubber: set program xelatex
\usepackage[no-sscript]{xltxtra} % loads fixltx2e, metalogo, xunicode, fontspec
\usepackage{fontspec}
% \defaultfontfeatures{Scale=MatchLowercase}
% straight double quotes (defined T1 but missing in TU):
\ifdefined \UnicodeEncodingName
\DeclareTextCommand{\textquotedbl}{\UnicodeEncodingName}{%
{\addfontfeatures{RawFeature=-tlig,Mapping=}\char34}}%
\fi
$requirements
%%% Custom LaTeX preamble
$latex_preamble

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# $Id: manpage.py 7628 2013-03-09 10:19:35Z grubert $
# $Id: manpage.py 8116 2017-06-18 19:09:40Z milde $
# Author: Engelbert Gruber <grubert@users.sourceforge.net>
# Copyright: This module is put into the public domain.
@ -368,7 +368,7 @@ class Translator(nodes.NodeVisitor):
tmpl = (".TH %(title_upper)s %(manual_section)s"
" \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n"
".SH NAME\n"
"%(title)s \- %(subtitle)s\n")
"%(title)s \\- %(subtitle)s\n")
return tmpl % self._docinfo
def append_header(self):
@ -403,7 +403,7 @@ class Translator(nodes.NodeVisitor):
self.defs['strong'][0],
self.language.labels.get(name, name).upper(),
self.defs['strong'][1],
)
)
self.body.append(name)
self.visit_block_quote(node)
@ -755,6 +755,12 @@ class Translator(nodes.NodeVisitor):
depart_important = depart_admonition
def visit_inline(self, node):
pass
def depart_inline(self, node):
pass
def visit_label(self, node):
# footnote and citation
if (isinstance(node.parent, nodes.footnote)
@ -818,7 +824,7 @@ class Translator(nodes.NodeVisitor):
# BUG/HACK: indent alway uses the _last_ indention,
# thus we need two of them.
self.indent(LITERAL_BLOCK_INDENT)
self.indent(0)
self.indent(0)
self.body.append(self.defs['literal_block'][0])
self._in_literal = True

View File

@ -1,4 +1,4 @@
# $Id: __init__.py 7717 2013-08-21 22:01:21Z milde $
# $Id: __init__.py 8131 2017-07-03 22:06:53Z dkuhlman $
# Author: Dave Kuhlman <dkuhlman@rexx.com>
# Copyright: This module has been placed in the public domain.
@ -23,12 +23,18 @@ import re
import StringIO
import copy
import urllib2
import itertools
import docutils
try:
import locale # module missing in Jython
except ImportError:
pass
from docutils import frontend, nodes, utils, writers, languages
from docutils.readers import standalone
from docutils.transforms import references
IMAGE_NAME_COUNTER = itertools.count()
WhichElementTree = ''
try:
# 1. Try to use lxml.
@ -58,7 +64,7 @@ try:
import pygments.lexers
from pygmentsformatter import OdtPygmentsProgFormatter, \
OdtPygmentsLaTeXFormatter
except ImportError, exp:
except (ImportError, SyntaxError), exp:
pygments = None
# check for the Python Imaging Library
@ -569,6 +575,48 @@ class Writer(writers.Writer):
s1 = self.create_meta()
self.write_zip_str(zfile, 'meta.xml', s1)
s1 = self.get_stylesheet()
# Set default language in document to be generated.
# Language is specified by the -l/--language command line option.
# The format is described in BCP 47. If region is omitted, we use
# local.normalize(ll) to obtain a region.
language_code = None
region_code = None
if self.visitor.language_code:
language_ids = self.visitor.language_code.replace('_', '-')
language_ids = language_ids.split('-')
# first tag is primary language tag
language_code = language_ids[0].lower()
# 2-letter region subtag may follow in 2nd or 3rd position
for subtag in language_ids[1:]:
if len(subtag) == 2 and subtag.isalpha():
region_code = subtag.upper()
break
elif len(subtag) == 1:
break # 1-letter tag is never before valid region tag
if region_code is None:
try:
rcode = locale.normalize(language_code)
except NameError:
rcode = language_code
rcode = rcode.split('_')
if len(rcode) > 1:
rcode = rcode[1].split('.')
region_code = rcode[0]
if region_code is None:
self.document.reporter.warning(
'invalid language-region.\n'
' Could not find region with locale.normalize().\n'
' Please specify both language and region (ll-RR).\n'
' Examples: es-MX (Spanish, Mexico),\n'
' en-AU (English, Australia).')
# Update the style ElementTree with the language and region.
# Note that we keep a reference to the modified node because
# it is possible that ElementTree will throw away the Python
# representation of the updated node if we do not.
updated, new_dom_styles, updated_node = self.update_stylesheet(
self.visitor.get_dom_stylesheet(), language_code, region_code)
if updated:
s1 = etree.tostring(new_dom_styles)
self.write_zip_str(zfile, 'styles.xml', s1)
self.store_embedded_files(zfile)
self.copy_from_stylesheet(zfile)
@ -580,7 +628,58 @@ class Writer(writers.Writer):
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):
def update_stylesheet(self, stylesheet_root, language_code, region_code):
"""Update xml style sheet element with language and region/country."""
updated = False
modified_nodes = set()
if language_code is not None or region_code is not None:
n1 = stylesheet_root.find(
'{urn:oasis:names:tc:opendocument:xmlns:office:1.0}'
'styles')
if n1 is None:
raise RuntimeError(
"Cannot find 'styles' element in styles.odt/styles.xml")
n2_nodes = n1.findall(
'{urn:oasis:names:tc:opendocument:xmlns:style:1.0}'
'default-style')
if not n2_nodes:
raise RuntimeError(
"Cannot find 'default-style' "
"element in styles.xml")
for node in n2_nodes:
family = node.attrib.get(
'{urn:oasis:names:tc:opendocument:xmlns:style:1.0}'
'family')
if family == 'paragraph' or family == 'graphic':
n3 = node.find(
'{urn:oasis:names:tc:opendocument:xmlns:style:1.0}'
'text-properties')
if n3 is None:
raise RuntimeError(
"Cannot find 'text-properties' "
"element in styles.xml")
if language_code is not None:
n3.attrib[
'{urn:oasis:names:tc:opendocument:xmlns:'
'xsl-fo-compatible:1.0}language'] = language_code
n3.attrib[
'{urn:oasis:names:tc:opendocument:xmlns:'
'style:1.0}language-complex'] = language_code
updated = True
modified_nodes.add(n3)
if region_code is not None:
n3.attrib[
'{urn:oasis:names:tc:opendocument:xmlns:'
'xsl-fo-compatible:1.0}country'] = region_code
n3.attrib[
'{urn:oasis:names:tc:opendocument:xmlns:'
'style:1.0}country-complex'] = region_code
updated = True
modified_nodes.add(n3)
return updated, stylesheet_root, modified_nodes
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--).
@ -594,9 +693,7 @@ class Writer(writers.Writer):
if source is None:
continue
try:
# encode/decode
destination1 = destination.decode('latin-1').encode('utf-8')
zfile.write(source, destination1)
zfile.write(source, destination)
except OSError, e:
self.document.reporter.warning(
"Can't open file %s." % (source, ))
@ -727,8 +824,8 @@ class Writer(writers.Writer):
#s1 = doc.toprettyxml(' ')
return s1
# class ODFTranslator(nodes.SparseNodeVisitor):
# class ODFTranslator(nodes.SparseNodeVisitor):
class ODFTranslator(nodes.GenericNodeVisitor):
used_styles = (
@ -786,15 +883,17 @@ class ODFTranslator(nodes.GenericNodeVisitor):
'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 = { }
self.language_code = self.settings.language_code
self.language = languages.get_language(
self.language_code,
document.reporter)
self.format_map = {}
if self.settings.odf_config_file:
from ConfigParser import ConfigParser
@ -804,8 +903,9 @@ class ODFTranslator(nodes.GenericNodeVisitor):
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')
rststyle, ))
if sys.version_info.major == 2:
self.format_map[rststyle] = format.decode('utf-8')
self.section_level = 0
self.section_count = 0
# Create ElementTree content and styles documents.
@ -872,6 +972,8 @@ class ODFTranslator(nodes.GenericNodeVisitor):
self.table_styles = None
self.in_citation = False
# Keep track of nested styling classes
self.inline_style_count_stack = []
def get_str_stylesheet(self):
return self.str_stylesheet
@ -982,18 +1084,18 @@ class ODFTranslator(nodes.GenericNodeVisitor):
'style:name': style_name,
'style:master-page-name': "rststyle-pagedefault",
'style:family': "paragraph",
}, nsdict=SNSD)
}, nsdict=SNSD)
if current_style:
el1.set('style:parent-style-name', current_style)
el.set('text:style-name', style_name)
def rststyle(self, name, parameters=( )):
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.
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)
@ -1010,6 +1112,9 @@ class ODFTranslator(nodes.GenericNodeVisitor):
new_content = etree.tostring(self.dom_stylesheet)
return new_content
def get_dom_stylesheet(self):
return self.dom_stylesheet
def setup_paper(self, root_el):
try:
fin = os.popen("paperconf -s 2> /dev/null")
@ -2058,7 +2163,7 @@ class ODFTranslator(nodes.GenericNodeVisitor):
# Capture the image file.
if 'uri' in node.attributes:
source = node.attributes['uri']
if not source.startswith('http:'):
if not (source.startswith('http:') or source.startswith('https:')):
if not source.startswith(os.sep):
docsource, line = utils.get_source_line(node)
if docsource:
@ -2077,7 +2182,7 @@ class ODFTranslator(nodes.GenericNodeVisitor):
self.image_count += 1
filename = os.path.split(source)[1]
destination = 'Pictures/1%08x%s' % (self.image_count, filename, )
if source.startswith('http:'):
if source.startswith('http:') or source.startswith('https:'):
try:
imgfile = urllib2.urlopen(source)
content = imgfile.read()
@ -2118,70 +2223,151 @@ class ODFTranslator(nodes.GenericNodeVisitor):
def get_image_width_height(self, node, attr):
size = None
unit = None
if attr in node.attributes:
size = node.attributes[attr]
unit = size[-2:]
if unit.isalpha():
size = size[:-2]
else:
unit = 'px'
size = size.strip()
# For conversion factors, see:
# http://www.unitconversion.org/unit_converter/typography-ex.html
try:
size = float(size)
except ValueError, e:
if size.endswith('%'):
if attr == 'height':
# Percentage allowed for width but not height.
raise ValueError('percentage not allowed for height')
size = size.rstrip(' %')
size = float(size) / 100.0
unit = '%'
else:
size, unit = convert_to_cm(size)
except ValueError, exp:
self.document.reporter.warning(
'Invalid %s for image: "%s"' % (
attr, node.attributes[attr]))
size = [size, unit]
return size
'Invalid %s for image: "%s". '
'Error: "%s".' % (
attr, node.attributes[attr], exp))
return size, unit
def convert_to_cm(self, size):
"""Convert various units to centimeters.
Note that a call to this method should be wrapped in:
try: except ValueError:
"""
size = size.strip()
if size.endswith('px'):
size = float(size[:-2]) * 0.026 # convert px to cm
elif size.endswith('in'):
size = float(size[:-2]) * 2.54 # convert in to cm
elif size.endswith('pt'):
size = float(size[:-2]) * 0.035 # convert pt to cm
elif size.endswith('pc'):
size = float(size[:-2]) * 2.371 # convert pc to cm
elif size.endswith('mm'):
size = float(size[:-2]) * 10.0 # convert mm to cm
elif size.endswith('cm'):
size = float(size[:-2])
else:
raise ValueError('unknown unit type')
unit = 'cm'
return size, unit
def get_image_scale(self, node):
if 'scale' in node.attributes:
scale = node.attributes['scale']
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:
scale = int(scale)
except ValueError:
self.document.reporter.warning(
'Invalid scale for image: "%s"' % (
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
else:
scale = 1.0
return scale
def get_image_scaled_width_height(self, node, source):
"""Return the image size in centimeters adjusted by image attrs."""
scale = self.get_image_scale(node)
width = self.get_image_width_height(node, 'width')
height = self.get_image_width_height(node, 'height')
width, width_unit = 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)
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']
if width is None:
width = imageobj.size[0]
width = float(width) * 0.026 # convert px to cm
if height is None:
height = imageobj.size[1]
height = float(height) * 0.026 # convert px to cm
if width_unit == '%':
factor = width
image_width = imageobj.size[0]
image_width = float(image_width) * 0.026 # convert px to cm
image_height = imageobj.size[1]
image_height = float(image_height) * 0.026 # convert px to cm
line_width = self.get_page_width()
width = factor * line_width
factor = (factor * line_width) / image_width
height = factor * image_height
width *= scale
height *= scale
width = '%.2fcm' % width
height = '%.2fcm' % height
return width, height
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 get_page_width(self):
"""Return the document's page width in centimeters."""
root = self.get_dom_stylesheet()
nodes = root.iterfind(
'.//{urn:oasis:names:tc:opendocument:xmlns:style:1.0}'
'page-layout/'
'{urn:oasis:names:tc:opendocument:xmlns:style:1.0}'
'page-layout-properties')
width = None
for node in nodes:
page_width = node.get(
'{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
'page-width')
margin_left = node.get(
'{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
'margin-left')
margin_right = node.get(
'{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
'margin-right')
if (page_width is None or
margin_left is None or
margin_right is None):
continue
try:
page_width, _ = self.convert_to_cm(page_width)
margin_left, _ = self.convert_to_cm(margin_left)
margin_right, _ = self.convert_to_cm(margin_right)
except ValueError, exp:
self.document.reporter.warning(
'Stylesheet file contains invalid page width '
'or margin size.')
width = page_width - margin_left - margin_right
if width is None:
# We can't find the width in styles, so we make a guess.
# Use a width of 6 in = 15.24 cm.
width = 15.24
return width
def generate_figure(self, node, source, destination, current_element):
caption = None
@ -2222,6 +2408,7 @@ class ODFTranslator(nodes.GenericNodeVisitor):
el2 = SubElement(el1, 'style:text-properties',
attrib=attrib, nsdict=SNSD)
style_name = 'rstframestyle%d' % self.image_style_count
draw_name = 'graphics%d' % IMAGE_NAME_COUNTER.next()
# Add the styles
attrib = {
'style:name': style_name,
@ -2252,7 +2439,7 @@ class ODFTranslator(nodes.GenericNodeVisitor):
'style:graphic-properties', attrib=attrib, nsdict=SNSD)
attrib = {
'draw:style-name': style_name,
'draw:name': 'Frame1',
'draw:name': draw_name,
'text:anchor-type': 'paragraph',
'draw:z-index': '0',
}
@ -2326,12 +2513,13 @@ class ODFTranslator(nodes.GenericNodeVisitor):
attrib['style:wrap'] = 'none'
el2 = SubElement(el1,
'style:graphic-properties', attrib=attrib, nsdict=SNSD)
draw_name = 'graphics%d' % IMAGE_NAME_COUNTER.next()
# 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:name': draw_name,
'draw:z-index': '1',
}
if isinstance(node.parent, nodes.TextElement):
@ -2399,14 +2587,26 @@ class ODFTranslator(nodes.GenericNodeVisitor):
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)})
if styles:
el = self.current_element
for inline_style in styles:
el = SubElement(el, 'text:span',
attrib={'text:style-name':
self.rststyle(inline_style)})
count = len(styles)
else:
# No style was specified so use a default style (old code
# crashed if no style was given)
el = SubElement(self.current_element, 'text:span')
count = 1
self.set_current_element(el)
self.inline_style_count_stack.append(count)
def depart_inline(self, node):
self.set_to_parent()
count = self.inline_style_count_stack.pop()
for x in range(count):
self.set_to_parent()
def _calculate_code_block_padding(self, line):
count = 0
@ -3251,14 +3451,19 @@ class ODFTranslator(nodes.GenericNodeVisitor):
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 hasattr(self.language, 'labels'):
translated_label = self.language.labels[label]
else:
translated_label = label
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, ))
el1.text = '%s!' % (translated_label.capitalize(), )
s1 = self.rststyle('admon-%s-body', (label, ))
self.paragraph_style_stack.append(s1)
#

View File

@ -1,7 +1,7 @@
/*
:Author: David Goodger
:Contact: goodger@python.org
:date: $Date: 2006-05-21 22:44:42 +0200 (Son, 21. Mai 2006) $
:date: $Date: 2006-05-21 22:44:42 +0200 (So, 21 Mai 2006) $
:version: $Revision: 4564 $
:copyright: This stylesheet has been placed in the public domain.

View File

@ -2,8 +2,8 @@
# -*- coding: utf-8 -*-
# :Author: Günter Milde <milde@users.sourceforge.net>
# :Revision: $Revision: 7668 $
# :Date: $Date: 2013-06-04 14:46:30 +0200 (Die, 04. Jun 2013) $
# :Revision: $Revision: 8046 $
# :Date: $Date: 2017-03-11 13:09:36 +0100 (Sa, 11 Mär 2017) $
# :Copyright: © 2010 Günter Milde.
# :License: Released under the terms of the `2-Clause BSD license`_, in short:
#
@ -17,8 +17,9 @@
"""
XeLaTeX document tree Writer.
A variant of Docutils' standard 'latex2e' writer producing output
suited for processing with XeLaTeX (http://tug.org/xetex/).
A variant of Docutils' standard 'latex2e' writer producing LaTeX output
suited for processing with the Unicode-aware TeX engines
LuaTeX and XeTeX.
"""
__docformat__ = 'reStructuredText'
@ -32,9 +33,9 @@ from docutils import frontend, nodes, utils, writers, languages
from docutils.writers import latex2e
class Writer(latex2e.Writer):
"""A writer for Unicode-based LaTeX variants (XeTeX, LuaTeX)"""
"""A writer for Unicode-aware LaTeX variants (XeTeX, LuaTeX)"""
supported = ('xetex','xelatex','luatex')
supported = ('lxtex', 'xetex','xelatex','luatex', 'lualatex')
"""Formats this writer supports."""
default_template = 'xelatex.tex'
@ -54,7 +55,7 @@ class Writer(latex2e.Writer):
template=('Template file. Default: "%s".' % default_template,
['--template'], {'default': default_template, 'metavar': '<file>'}),
latex_preamble=('Customization by LaTeX code in the preamble. '
'Default: select PDF standard fonts (Times, Helvetica, Courier).',
'Default: select "Linux Libertine" fonts.',
['--latex-preamble'],
{'default': default_preamble}),
)
@ -98,6 +99,11 @@ class Babel(latex2e.Babel):
for key in ('af', # 'afrikaans',
'de-AT', # 'naustrian',
'de-AT-1901', # 'austrian',
# TODO: use variant=... for English variants
'en-CA', # 'canadian',
'en-GB', # 'british',
'en-NZ', # 'newzealand',
'en-US', # 'american',
'fr-CA', # 'canadien',
'grc-ibycus', # 'ibycus', (Greek Ibycus encoding)
'sr-Latn', # 'serbian script=latin'
@ -109,12 +115,12 @@ class Babel(latex2e.Babel):
self.reporter = reporter
self.language = self.language_name(language_code)
self.otherlanguages = {}
self.warn_msg = 'Language "%s" not supported by XeTeX (polyglossia).'
self.warn_msg = 'Language "%s" not supported by Polyglossia.'
self.quote_index = 0
self.quotes = ('"', '"')
# language dependent configuration:
# double quotes are "active" in some languages (e.g. German).
self.literal_double_quote = u'"' # TODO: use \textquotedbl
self.literal_double_quote = u'"' # TODO: use \textquotedbl ?
def __call__(self):
setup = [r'\usepackage{polyglossia}',
@ -126,6 +132,12 @@ class Babel(latex2e.Babel):
class XeLaTeXTranslator(latex2e.LaTeXTranslator):
"""
Generate code for LaTeX using Unicode fonts (XeLaTex or LuaLaTeX).
See the docstring of docutils.writers._html_base.HTMLTranslator for
notes on and examples of safe subclassing.
"""
def __init__(self, document):
self.is_xetex = True # typeset with XeTeX or LuaTeX engine

View File

@ -358,7 +358,10 @@ class FoldingPanel(Panel):
self.sizeHint().height())
if self._native:
if os.environ['QT_API'].lower() not in PYQT5_API:
opt = QtGui.QStyleOptionViewItemV2()
try:
opt = QtGui.QStyleOptionViewItemV2()
except:
opt = QtWidgets.QStyleOptionViewItem()
else:
opt = QtWidgets.QStyleOptionViewItem()
opt.rect = rect

View File

@ -58,7 +58,7 @@ __version__ = '2.10.0'
#: Qt API environment variable name
QT_API = 'QT_API'
#: names of the expected PyQt5 api
PYQT5_API = ['pyqt5']
PYQT5_API = ['pyqt5','pyside2']
#: names of the expected PyQt4 api
PYQT4_API = [
'pyqt', # name used in IPython.qt