summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rwxr-xr-xtools/buildhtml.py226
-rw-r--r--tools/docutils.conf16
-rw-r--r--tools/editors/README.txt19
-rw-r--r--tools/editors/emacs/README.txt91
-rw-r--r--tools/editors/emacs/docutils.conf2
-rw-r--r--tools/editors/emacs/restructuredtext.el596
-rw-r--r--tools/editors/emacs/rst-html.el129
-rw-r--r--tools/editors/emacs/rst-mode.el700
-rw-r--r--tools/editors/emacs/tests/tests-adjust-section.el240
-rw-r--r--tools/pep-html-template27
-rwxr-xr-xtools/pep.py27
-rwxr-xr-xtools/quicktest.py211
-rwxr-xr-xtools/rst2html.py25
-rwxr-xr-xtools/rst2latex.py25
-rwxr-xr-xtools/rst2newlatex.py27
-rwxr-xr-xtools/rst2pseudoxml.py25
-rwxr-xr-xtools/rst2xml.py25
-rw-r--r--tools/stylesheets/default.css263
-rw-r--r--tools/stylesheets/latex-notes.txt40
-rw-r--r--tools/stylesheets/latex.tex970
-rw-r--r--tools/stylesheets/pep.css240
-rw-r--r--tools/stylesheets/style.tex74
-rwxr-xr-xtools/unicode2rstsubs.py195
23 files changed, 4193 insertions, 0 deletions
diff --git a/tools/buildhtml.py b/tools/buildhtml.py
new file mode 100755
index 000000000..e9ee0d16d
--- /dev/null
+++ b/tools/buildhtml.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+Generates .html from all the .txt files in a directory.
+
+Ordinary .txt files are understood to be standalone reStructuredText.
+Files named ``pep-*.txt`` are interpreted as reStructuredText PEPs.
+"""
+# Once PySource is here, build .html from .py as well.
+
+__docformat__ = 'reStructuredText'
+
+
+try:
+ import locale
+ locale.setlocale(locale.LC_ALL, '')
+except:
+ pass
+
+import sys
+import os
+import os.path
+import copy
+import docutils
+from docutils import ApplicationError
+from docutils import core, frontend
+from docutils.parsers import rst
+from docutils.readers import standalone, pep
+from docutils.writers import html4css1, pep_html
+
+
+usage = '%prog [options] [<directory> ...]'
+description = ('Generates .html from all the reStructuredText .txt files '
+ '(including PEPs) in each <directory> '
+ '(default is the current directory).')
+
+
+class SettingsSpec(docutils.SettingsSpec):
+
+ """
+ Runtime settings & command-line options for the front end.
+ """
+
+ # Can't be included in OptionParser below because we don't want to
+ # override the base class.
+ settings_spec = (
+ 'Build-HTML Options',
+ None,
+ (('Recursively scan subdirectories for files to process. This is '
+ 'the default.',
+ ['--recurse'],
+ {'action': 'store_true', 'default': 1,
+ 'validator': frontend.validate_boolean}),
+ ('Do not scan subdirectories for files to process.',
+ ['--local'], {'dest': 'recurse', 'action': 'store_false'}),
+ ('Do not process files in <directory>. This option may be used '
+ 'more than once to specify multiple directories.',
+ ['--prune'],
+ {'metavar': '<directory>', 'action': 'append',
+ 'validator': frontend.validate_colon_separated_string_list}),
+ ('Work silently (no progress messages). Independent of "--quiet".',
+ ['--silent'],
+ {'action': 'store_true', 'validator': frontend.validate_boolean}),))
+
+ relative_path_settings = ('prune',)
+ config_section = 'buildhtml application'
+ config_section_dependencies = ('applications',)
+
+
+class OptionParser(frontend.OptionParser):
+
+ """
+ Command-line option processing for the ``buildhtml.py`` front end.
+ """
+
+ def check_values(self, values, args):
+ frontend.OptionParser.check_values(self, values, args)
+ values._source = None
+ return values
+
+ def check_args(self, args):
+ source = destination = None
+ if args:
+ self.values._directories = args
+ else:
+ self.values._directories = [os.getcwd()]
+ return source, destination
+
+
+class Struct:
+
+ """Stores data attributes for dotted-attribute access."""
+
+ def __init__(self, **keywordargs):
+ self.__dict__.update(keywordargs)
+
+
+class Builder:
+
+ def __init__(self):
+ self.publishers = {
+ '': Struct(components=(pep.Reader, rst.Parser, pep_html.Writer,
+ SettingsSpec)),
+ '.txt': Struct(components=(rst.Parser, standalone.Reader,
+ html4css1.Writer, SettingsSpec),
+ reader_name='standalone',
+ writer_name='html'),
+ 'PEPs': Struct(components=(rst.Parser, pep.Reader,
+ pep_html.Writer, SettingsSpec),
+ reader_name='pep',
+ writer_name='pep_html')}
+ """Publisher-specific settings. Key '' is for the front-end script
+ itself. ``self.publishers[''].components`` must contain a superset of
+ all components used by individual publishers."""
+
+ self.setup_publishers()
+
+ def setup_publishers(self):
+ """
+ Manage configurations for individual publishers.
+
+ Each publisher (combination of parser, reader, and writer) may have
+ its own configuration defaults, which must be kept separate from those
+ of the other publishers. Setting defaults are combined with the
+ config file settings and command-line options by
+ `self.get_settings()`.
+ """
+ for name, publisher in self.publishers.items():
+ option_parser = OptionParser(
+ components=publisher.components, read_config_files=1,
+ usage=usage, description=description)
+ publisher.option_parser = option_parser
+ publisher.setting_defaults = option_parser.get_default_values()
+ frontend.make_paths_absolute(publisher.setting_defaults.__dict__,
+ option_parser.relative_path_settings)
+ publisher.config_settings = (
+ option_parser.get_standard_config_settings())
+ self.settings_spec = self.publishers[''].option_parser.parse_args(
+ values=frontend.Values()) # no defaults; just the cmdline opts
+ self.initial_settings = self.get_settings('')
+
+ def get_settings(self, publisher_name, directory=None):
+ """
+ Return a settings object, from multiple sources.
+
+ Copy the setting defaults, overlay the startup config file settings,
+ then the local config file settings, then the command-line options.
+ Assumes the current directory has been set.
+ """
+ publisher = self.publishers[publisher_name]
+ settings = frontend.Values(publisher.setting_defaults.__dict__)
+ settings.update(publisher.config_settings, publisher.option_parser)
+ if directory:
+ local_config = publisher.option_parser.get_config_file_settings(
+ os.path.join(directory, 'docutils.conf'))
+ frontend.make_paths_absolute(
+ local_config, publisher.option_parser.relative_path_settings,
+ directory)
+ settings.update(local_config, publisher.option_parser)
+ settings.update(self.settings_spec.__dict__, publisher.option_parser)
+ return settings
+
+ def run(self, directory=None, recurse=1):
+ recurse = recurse and self.initial_settings.recurse
+ if directory:
+ self.directories = [directory]
+ elif self.settings_spec._directories:
+ self.directories = self.settings_spec._directories
+ else:
+ self.directories = [os.getcwd()]
+ for directory in self.directories:
+ os.path.walk(directory, self.visit, recurse)
+
+ def visit(self, recurse, directory, names):
+ settings = self.get_settings('', directory)
+ if settings.prune and (os.path.abspath(directory) in settings.prune):
+ print >>sys.stderr, '/// ...Skipping directory (pruned):', directory
+ sys.stderr.flush()
+ names[:] = []
+ return
+ if not self.initial_settings.silent:
+ print >>sys.stderr, '/// Processing directory:', directory
+ sys.stderr.flush()
+ prune = 0
+ for name in names:
+ if name.endswith('.txt'):
+ prune = self.process_txt(directory, name)
+ if prune:
+ break
+ if not recurse:
+ del names[:]
+
+ def process_txt(self, directory, name):
+ if name.startswith('pep-'):
+ publisher = 'PEPs'
+ else:
+ publisher = '.txt'
+ settings = self.get_settings(publisher, directory)
+ pub_struct = self.publishers[publisher]
+ if settings.prune and (directory in settings.prune):
+ return 1
+ settings._source = os.path.normpath(os.path.join(directory, name))
+ settings._destination = settings._source[:-4]+'.html'
+ if not self.initial_settings.silent:
+ print >>sys.stderr, ' ::: Processing:', name
+ sys.stderr.flush()
+ try:
+ core.publish_file(source_path=settings._source,
+ destination_path=settings._destination,
+ reader_name=pub_struct.reader_name,
+ parser_name='restructuredtext',
+ writer_name=pub_struct.writer_name,
+ settings=settings)
+ except ApplicationError, error:
+ print >>sys.stderr, (' Error (%s): %s'
+ % (error.__class__.__name__, error))
+
+
+if __name__ == "__main__":
+ Builder().run()
diff --git a/tools/docutils.conf b/tools/docutils.conf
new file mode 100644
index 000000000..9f218d3bf
--- /dev/null
+++ b/tools/docutils.conf
@@ -0,0 +1,16 @@
+[general]
+# These entries affect all processing:
+source-link: yes
+datestamp: %Y-%m-%d %H:%M UTC
+generator: on
+
+[html4css1 writer]
+# These entries affect HTML output:
+stylesheet-path: stylesheets/default.css
+field-name-limit: 20
+
+[pep_html writer]
+# These entries affect reStructuredText-style PEPs:
+template: pep-html-template
+stylesheet-path: stylesheets/pep.css
+python-home: http://www.python.org
diff --git a/tools/editors/README.txt b/tools/editors/README.txt
new file mode 100644
index 000000000..f3786ef2e
--- /dev/null
+++ b/tools/editors/README.txt
@@ -0,0 +1,19 @@
+======================================
+ Editor Support for reStructuredText_
+======================================
+
+:Date: $Date$
+
+The files in this directory contain support code for reStructuredText
+editing for the following editors:
+
+* `Emacs <emacs>`__
+
+External links:
+
+* `reStructuredText syntax highlighting mode for vim
+ <http://www.vim.org/scripts/script.php?script_id=973>`__
+
+Additions are welcome.
+
+.. _reStructuredText: http://docutils.sf.net/rst.html
diff --git a/tools/editors/emacs/README.txt b/tools/editors/emacs/README.txt
new file mode 100644
index 000000000..d4359213b
--- /dev/null
+++ b/tools/editors/emacs/README.txt
@@ -0,0 +1,91 @@
+.. -*- coding: iso-8859-1 -*-
+
+=====================================
+ Emacs Support for reStructuredText_
+=====================================
+
+:Date: $Date$
+
+
+Directory Contents
+==================
+
+This directory contains the following Emacs lisp package files:
+
+* restructuredtext.el by Martin Blais and David Goodger
+
+ Support code for editing reStructuredText with Emacs indented-text
+ mode.
+
+* rst-mode.el by Stefan Merten
+
+ Provides support for documents marked up using the reStructuredText
+ format, including font locking as well as some convenience functions
+ for editing.
+
+* rst-html.el by Martin Blais
+
+ Provides a few functions and variables that can help in automating
+ the conversion of reST documents to HTML from within Emacs.
+
+Each file includes specific usage instructions. To install a package,
+put a copy of the package file in a directory on your ``load-path``
+(use ``C-h v load-path`` to check).
+
+
+Character Processing Notes
+==========================
+
+Since reStructuredText punts on the issue of character processing,
+here are some useful resources for Emacs users in the Unicode world:
+
+* `xmlunicode.el and unichars.el from Norman Walsh
+ <http://nwalsh.com/emacs/xmlchars/index.html>`__
+
+* `An essay by Tim Bray, with example code
+ <http://www.tbray.org/ongoing/When/200x/2003/09/27/UniEmacs>`__
+
+* For Emacs users on Mac OS X, here are some useful useful additions
+ to your .emacs file.
+
+ - To get direct keyboard input of non-ASCII characters (like
+ "option-e e" resulting in "é" [eacute]), first enable the option
+ key by setting the command key as your meta key::
+
+ (setq mac-command-key-is-meta t) ;; nil for option key
+
+ Next, use one of these lines::
+
+ (set-keyboard-coding-system 'mac-roman)
+ (setq mac-keyboard-text-encoding kTextEncodingISOLatin1)
+
+ I prefer the first line, because it enables non-Latin-1 characters
+ as well (em-dash, curly quotes, etc.).
+
+ - To enable the display of all characters in the Mac-Roman charset,
+ first create a fontset listing the fonts to use for each range of
+ characters using charsets that Emacs understands::
+
+ (create-fontset-from-fontset-spec
+ "-apple-monaco-medium-r-normal--10-*-*-*-*-*-fontset-monaco,
+ ascii:-apple-monaco-medium-r-normal--10-100-75-75-m-100-mac-roman,
+ latin-iso8859-1:-apple-monaco-medium-r-normal--10-100-75-75-m-100-mac-roman,
+ mule-unicode-0100-24ff:-apple-monaco-medium-r-normal--10-100-75-75-m-100-mac-roman")
+
+ Latin-1 doesn't cover characters like em-dash and curly quotes, so
+ "mule-unicode-0100-24ff" is needed.
+
+ Next, use that fontset::
+
+ (set-frame-font "fontset-monaco")
+
+ Other useful resources are in `Andrew Choi's Emacs 21 for Mac OS X
+ FAQ <http://members.shaw.ca/akochoi-emacs/stories/faq.html>`__.
+
+No matter what platform (or editor) you're using, I recommend the
+ProFont__ programmer's font. It's monospaced, small but readable,
+similar characters are visually distinctive (like "1lI|", "0O", "ao",
+and ".,"), and free.
+
+__ http://www.tobias-jung.de/seekingprofont/
+.. _reStructuredText: http://docutils.sf.net/rst.html
diff --git a/tools/editors/emacs/docutils.conf b/tools/editors/emacs/docutils.conf
new file mode 100644
index 000000000..a74f08d4a
--- /dev/null
+++ b/tools/editors/emacs/docutils.conf
@@ -0,0 +1,2 @@
+[general]
+input_encoding: latin-1
diff --git a/tools/editors/emacs/restructuredtext.el b/tools/editors/emacs/restructuredtext.el
new file mode 100644
index 000000000..fe39265b2
--- /dev/null
+++ b/tools/editors/emacs/restructuredtext.el
@@ -0,0 +1,596 @@
+;; Authors: David Goodger <goodger@python.org>,
+;; Martin Blais <blais@furius.ca>
+;; Date: $Date$
+;; Copyright: This module has been placed in the public domain.
+;;
+;; Support code for editing reStructuredText with Emacs indented-text mode.
+;; The goal is to create an integrated reStructuredText editing mode.
+;;
+;; Installation instructions
+;; -------------------------
+;;
+;; Add this line to your .emacs file::
+;;
+;; (require 'restructuredtext)
+;;
+;; You should bind the versatile sectioning command to some key in the text-mode
+;; hook. Something like this::
+;;
+;; (defun user-rst-mode-hook ()
+;; (local-set-key [(control ?=)] 'rest-adjust-section-title)
+;; )
+;; (add-hook 'text-mode-hook 'user-rst-mode-hook)
+;;
+;; Other specialized and more generic functions are also available.
+;; Note that C-= is a good binding, since it allows you to specify a negative
+;; arg easily with C-- C-= (easy to type), as well as ordinary prefix arg with
+;; C-u C-=.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Generic text functions that are more convenient than the defaults.
+;;
+
+(defun replace-lines (fromchar tochar)
+ "Replace flush-left lines, consisting of multiple FROMCHAR characters,
+with equal-length lines of TOCHAR."
+ (interactive "\
+cSearch for flush-left lines of char:
+cand replace with char: ")
+ (save-excursion
+ (let* ((fromstr (string fromchar))
+ (searchre (concat "^" (regexp-quote fromstr) "+ *$"))
+ (found 0))
+ (condition-case err
+ (while t
+ (search-forward-regexp searchre)
+ (setq found (1+ found))
+ (search-backward fromstr) ;; point will be *before* last char
+ (setq p (1+ (point)))
+ (beginning-of-line)
+ (setq l (- p (point)))
+ (kill-line)
+ (insert-char tochar l))
+ (search-failed
+ (message (format "%d lines replaced." found)))))))
+
+(defun join-paragraph ()
+ "Join lines in current paragraph into one line, removing end-of-lines."
+ (interactive)
+ (let ((fill-column 65000)) ; some big number
+ (call-interactively 'fill-paragraph)))
+
+(defun force-fill-paragraph ()
+ "Fill paragraph at point, first joining the paragraph's lines into one.
+This is useful for filling list item paragraphs."
+ (interactive)
+ (join-paragraph)
+ (fill-paragraph nil))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; The following functions implement a smart automatic title sectioning feature.
+;; The idea is that with the cursor sitting on a section title, we try to get as
+;; much information from context and do the best thing. This function can be
+;; invoked many time and/or with prefix argument to rotate between the various
+;; options.
+;;
+;; There are two styles of sectioning:
+;;
+;; 1. simple-underline, e.g. |Some Title
+;; |----------
+;;
+;; 2. overline-and-underline, e.g. |------------
+;; | Some Title
+;; |------------
+;;
+;; Some notes:
+;;
+;; - the underlining character that is used depends on context. The file is
+;; scanned to find other sections and an appropriate character is selected.
+;; If the function is invoked on a section that is complete, the character
+;; is rotated among the existing ones.
+;;
+;; Note that when rotating the underlining characters, if we come to the end
+;; of the hierarchy of characters, the variable rest-preferred-characters
+;; is consulted to propose a new underline char, and if continued, we cycle
+;; the underline characters all over again. Set this variable to nil if
+;; you want to limit the underlining character propositions to the existing
+;; underlines in the file.
+;;
+;; - prefix argument is used to alternate the sectioning style.
+;;
+;; Examples:
+;;
+;; |Some Title ---> |Some Title
+;; | |----------
+;;
+;; |Some Title ---> |Some Title
+;; |----- |----------
+;;
+;; | |------------
+;; | Some Title ---> | Some Title
+;; | |------------
+;;
+;; In overline-and-underline style, a variable is available to select how much
+;; space to leave before and after the title (it can be zero) when alternating
+;; the style. Note that if the title already has some whitespace in front of
+;; it, we don't adjust it to the variable setting, we use the whitespace that is
+;; already there for adjustment.
+
+(defun rest-line-single-char-p (&optional accept-special)
+ "Predicate return the unique char if the current line is
+ composed only of a single repeated non-whitespace
+ character. This returns the char even if there is whitespace at
+ the beginning of the line.
+
+ If ACCEPT-SPECIAL is specified we do not ignore special sequences
+ which normally we would ignore when doing a search on many lines.
+ For example, normally we have cases to ignore commonly occuring
+ patterns, such as :: or ...; with the flag do not ignore them."
+ (save-excursion
+ (back-to-indentation)
+ (if (not (looking-at "\n"))
+ (let ((c (thing-at-point 'char)))
+ (if (and (looking-at (format "[%s]+\\s-*$" c))
+ (or accept-special
+ (and
+ ;; common patterns
+ (not (looking-at "::\\s-*$"))
+ (not (looking-at "\\.\\.\\.\\s-*$"))
+ ;; discard one char line
+ (not (looking-at ".\\s-*$"))
+ )))
+ (string-to-char c))
+ ))
+ ))
+
+(defun rest-find-last-section-char ()
+ "Looks backward for the last section char found in the file."
+
+ (let (c)
+ (save-excursion
+ (while (and (not c) (not (bobp)))
+ (forward-line -1)
+ (setq c (rest-line-single-char-p))
+ ))
+ c))
+
+(defun rest-current-section-char (&optional point)
+ "Gets the section char around the current point."
+ (save-excursion
+ (if point (goto-char point))
+ (let ((offlist '(0 1 -2))
+ loff
+ rval
+ c)
+ (while offlist
+ (forward-line (car offlist))
+ (setq c (rest-line-single-char-p 1))
+ (if c
+ (progn (setq offlist nil
+ rval c))
+ (setq offlist (cdr offlist)))
+ )
+ rval
+ )))
+
+(defun rest-initial-sectioning-style (&optional point)
+ "Looks around point and attempts to determine the sectioning
+ style, between simple-underline and overline-and-underline. If
+ there aren't any existing over/underlines, return nil."
+ (save-excursion
+ (if point (goto-char point))
+ (let (ou)
+ (save-excursion
+ (setq ou (mapcar
+ (lambda (x)
+ (forward-line x)
+ (rest-line-single-char-p))
+ '(-1 2))))
+ (beginning-of-line)
+ (cond
+ ((equal ou '(nil nil)) nil)
+ ((car ou) 'over-and-under) ;; we only need check the overline
+ (t 'simple)
+ )
+ )))
+
+(defun rest-all-section-chars (&optional ignore-lines)
+ "Finds all the section chars in the entire file and orders them
+ hierarchically, removing duplicates. Basically, returns a list
+ of the section underlining characters.
+
+ Optional parameters IGNORE-AROUND can be a list of lines to
+ ignore."
+
+ (let (chars
+ c
+ (curline 1))
+ (save-excursion
+ (beginning-of-buffer)
+ (while (< (point) (buffer-end 1))
+ (if (not (memq curline ignore-lines))
+ (progn
+ (setq c (rest-line-single-char-p))
+ (if c
+ (progn
+ (add-to-list 'chars c t)
+ ))) )
+ (forward-line 1) (setq curline (+ curline 1))
+ ))
+ chars))
+
+(defun rest-suggest-new-char (allchars)
+ "Given the last char that has been seen, suggest a new,
+ different character, different from all that have been seen."
+ (let ((potentials (copy-sequence rest-preferred-characters)))
+ (dolist (x allchars)
+ (setq potentials (delq x potentials))
+ )
+ (car potentials)
+ ))
+
+(defun rest-update-section (underlinechar style &optional indent)
+ "Unconditionally updates the overline/underline of a section
+ title using the given character CHAR, with STYLE 'simple or
+ 'over-and-under, in which case with title whitespace separation
+ on each side with INDENT whitespaces. If the style is 'simple,
+ whitespace before the title is removed.
+
+ If there are existing overline and/or underline, they are
+ removed before adding the requested adornments."
+
+ (interactive)
+ (let (marker
+ len
+ ec
+ (c ?-))
+
+ (end-of-line)
+ (setq marker (point-marker))
+
+ ;; Fixup whitespace at the beginning and end of the line
+ (if (or (null indent) (eq style 'simple))
+ (setq indent 0))
+ (beginning-of-line)
+ (delete-horizontal-space)
+ (insert (make-string indent ? ))
+
+ (end-of-line)
+ (delete-horizontal-space)
+
+ ;; Set the current column, we're at the end of the title line
+ (setq len (+ (current-column) indent))
+
+ ;; Remove previous line if it consists only of a single repeated character
+ (save-excursion
+ (forward-line -1)
+ (and (rest-line-single-char-p 1)
+ (kill-line 1)))
+
+ ;; Remove following line if it consists only of a single repeated character
+ (save-excursion
+ (forward-line +1)
+ (and (rest-line-single-char-p 1)
+ (kill-line 1))
+ ;; Add a newline if we're at the end of the buffer, for the subsequence
+ ;; inserting of the underline
+ (if (= (point) (buffer-end 1))
+ (newline 1)))
+
+ ;; Insert overline
+ (if (eq style 'over-and-under)
+ (save-excursion
+ (beginning-of-line)
+ (open-line 1)
+ (insert (make-string len underlinechar))))
+
+ ;; Insert underline
+ (forward-line +1)
+ (open-line 1)
+ (insert (make-string len underlinechar))
+
+ (forward-line +1)
+ (goto-char marker)
+ ))
+
+(defvar rest-preferred-characters '(?= ?- ?~ ?+ ?` ?# ?@)
+ "Preferred ordering of underline characters. This sequence is
+ consulted to offer a new underline character when we rotate the
+ underlines at the end of the existing hierarchy of characters.")
+
+(defvar rest-default-under-and-over-indent 1
+ "Number of characters to indent the section title when toggling
+ sectioning styles. This is used when switching from a simple
+ section style to a over-and-under style.")
+
+(defun rest-adjust-section-title ()
+ "Adjust/rotate the section underlining for the section around
+ point.
+
+ This function is the main entry point of this module and is a
+ bit of a swiss knife. It is meant as the single function to
+ invoke to adjust the underlines (and possibly overlines) of a
+ section title in restructuredtext. The next action it takes
+ depends on context around the point, and it is meant to be
+ invoked possibly more than once. Basically, this function deals
+ with:
+
+ - underlining a title if it does not have an underline;
+ - adjusting the length of the underline characters to fit a
+ modified title;
+ - rotating the underlines/overlines in the set of already
+ existing underline chars used in the file;
+ - switching between simple underline and over-and-under style
+ sectioning (or box style).
+
+ Here are the gory details:
+
+ - If the current line has no underline character around it,
+ search backwards for a previously used underlining character,
+ and underline the current line as a section title (also see
+ prefix argument below).
+
+ If no pre-existing underlining character is found in the on
+ the line, we use the last seen underline char or consult the
+ first element of rest-preferred-characters if this is the
+ first title in the entire file.
+
+ - If the current line does have an underline or overline, and
+ if
+
+ - the underline do not extend to exactly the end of the
+ title line, this changes the length of the under(over)lines
+ to fit exactly the section title;
+
+ - the underline length is already adjusted to the end of the
+ title line, we search the file for the underline chars, and
+ we rotate the current title's underline character with that
+ list (going down the hierarchy that is present in the
+ file);
+
+ If there is a prefix argument, switch the style between the
+ initial sectioning style and the other sectioning style. The
+ two styles are overline-and-underline and simple-underline.
+
+ If however, you are on a complete section title and you
+ specify a negative argument, the effect of the prefix
+ argument is to change the direction of rotation of the
+ underline characters. Thus using a prefix argument and a
+ negative prefix argument achieves a different result in the
+ case of rotation.
+
+ Note that the initial style of underlining (simple underline
+ or box-style) depends on if there is whitespace at the start
+ of the line. If there are already underlines/overlines,
+ those are used to select the style, otherwise if there is
+ whitespace at the front of the title overline-and-underline
+ style is chosen, and otherwise simple underline.
+
+ Also, note that this should work on the section title line as
+ well as on a complete or incomplete underline for a
+ title (first thing we check for that case and move the cursor
+ up a line if needed)."
+
+ (interactive)
+
+ ;; check if we're on an underline under a title line, and move the cursor up
+ ;; if it is so.
+ (if (and (or (rest-line-single-char-p 1)
+ (looking-at "^\\s-*$"))
+ (save-excursion
+ (forward-line -1)
+ (beginning-of-line)
+ (looking-at "^.+$")))
+ (forward-line -1))
+
+ (let (
+ ;; find current sectioning character
+ (curchar (rest-current-section-char))
+ ;; find current sectioning style
+ (init-style (rest-initial-sectioning-style))
+ ;; find current indentation of title line
+ (curindent (save-excursion
+ (back-to-indentation)
+ (current-column)))
+
+ ;; ending column
+ (endcol (- (line-end-position) (line-beginning-position)))
+ )
+
+ ;; if there is no current style found...
+ (if (eq init-style nil)
+ ;; select based on the whitespace at the beginning of the line
+ (save-excursion
+ (beginning-of-line)
+ (setq init-style
+ (if (looking-at "^\\s-+") 'over-and-under 'simple))))
+
+ ;; if we're switching characters, we're going to simply change the
+ ;; sectioning style. this branch is also taken if there is no current
+ ;; sectioning around the title.
+ (if (or (and current-prefix-arg
+ (not (< (prefix-numeric-value current-prefix-arg) 0)))
+ (eq curchar nil))
+
+ ;; we're switching characters or there is currently no sectioning
+ (progn
+ (setq curchar
+ (or curchar
+ (rest-find-last-section-char)
+ (car (rest-all-section-chars))
+ (car rest-preferred-characters)
+ ?=))
+
+ ;; if there is a current indent, reuse it, otherwise use default
+ (if (= curindent 0)
+ (setq curindent rest-default-under-and-over-indent))
+
+ (rest-update-section
+ curchar
+ (if (and current-prefix-arg
+ (not (< (prefix-numeric-value current-prefix-arg) 0)))
+ (if (eq init-style 'over-and-under) 'simple 'over-and-under)
+ init-style)
+ curindent)
+ )
+
+ ;; else we're not switching characters, and there is some sectioning
+ ;; already present, so check if the current sectioning is complete and
+ ;; correct.
+ (let ((exps (concat "^"
+ (regexp-quote (make-string
+ (+ endcol curindent) curchar))
+ "$")))
+ (if (or
+ (not (save-excursion (forward-line +1)
+ (beginning-of-line)
+ (looking-at exps)))
+ (and (eq init-style 'over-and-under)
+ (not (save-excursion (forward-line -1)
+ (beginning-of-line)
+ (looking-at exps)))))
+
+ ;; the current sectioning needs to be fixed/updated!
+ (rest-update-section curchar init-style curindent)
+
+ ;; the current sectioning is complete, rotate characters
+ (let* ( (curline (+ (count-lines (point-min) (point))
+ (if (bolp) 1 0)))
+ (allchars (rest-all-section-chars
+ (list (- curline 1) curline (+ curline 1))))
+
+ (rotchars
+ (append allchars
+ (filter 'identity
+ (list
+ ;; suggest a new char
+ (rest-suggest-new-char allchars)
+ ;; rotate to first char
+ (car allchars)))))
+ (nextchar
+ (or (cadr (memq curchar
+ (if (< (prefix-numeric-value
+ current-prefix-arg) 0)
+ (reverse rotchars) rotchars)))
+ (car allchars)) ) )
+
+
+ (if nextchar
+ (rest-update-section nextchar init-style curindent))
+ )))
+ )))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Generic character repeater function.
+;;
+;; For sections, better to use the specialized function above, but this can
+;; be useful for creating separators.
+
+(defun repeat-last-character (&optional tofill)
+ "Fills the current line up to the length of the preceding line (if not
+empty), using the last character on the current line. If the preceding line is
+empty, we use the fill-column.
+
+If a prefix argument is provided, use the next line rather than the preceding
+line.
+
+If the current line is longer than the desired length, shave the characters off
+the current line to fit the desired length.
+
+As an added convenience, if the command is repeated immediately, the alternative
+column is used (fill-column vs. end of previous/next line)."
+ (interactive)
+ (let* ((curcol (current-column))
+ (curline (+ (count-lines (point-min) (point))
+ (if (eq curcol 0) 1 0)))
+ (lbp (line-beginning-position 0))
+ (prevcol (if (and (= curline 1) (not current-prefix-arg))
+ fill-column
+ (save-excursion
+ (forward-line (if current-prefix-arg 1 -1))
+ (end-of-line)
+ (skip-chars-backward " \t" lbp)
+ (let ((cc (current-column)))
+ (if (= cc 0) fill-column cc)))))
+ (rightmost-column
+ (cond (tofill fill-column)
+ ((equal last-command 'repeat-last-character)
+ (if (= curcol fill-column) prevcol fill-column))
+ (t (save-excursion
+ (if (= prevcol 0) fill-column prevcol)))
+ )) )
+ (end-of-line)
+ (if (> (current-column) rightmost-column)
+ ;; shave characters off the end
+ (delete-region (- (point)
+ (- (current-column) rightmost-column))
+ (point))
+ ;; fill with last characters
+ (insert-char (preceding-char)
+ (- rightmost-column (current-column))))
+ ))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Section movement commands.
+;;
+
+;; Note: this is not quite correct, the definition is any non alpha-numeric
+;; character.
+(defun rest-title-char-p (c)
+ "Returns true if the given character is a valid title char."
+ (and (string-match "[-=`:\\.'\"~^_*+#<>!$%&(),/;?@\\\|]"
+ (char-to-string c)) t))
+
+(defun rest-forward-section ()
+ "Skip to the next restructured text section title."
+ (interactive)
+ (let* ( (newpoint
+ (save-excursion
+ (forward-char) ;; in case we're right on a title
+ (while
+ (not
+ (and (re-search-forward "^[A-Za-z0-9].*[ \t]*$" nil t)
+ (reST-title-char-p (char-after (+ (point) 1)))
+ (looking-at (format "\n%c\\{%d,\\}[ \t]*$"
+ (char-after (+ (point) 1))
+ (current-column))))))
+ (beginning-of-line)
+ (point))) )
+ (if newpoint (goto-char newpoint)) ))
+
+(defun rest-backward-section ()
+ "Skip to the previous restructured text section title."
+ (interactive)
+ (let* ( (newpoint
+ (save-excursion
+ ;;(forward-char) ;; in case we're right on a title
+ (while
+ (not
+ (and (or (backward-char) t)
+ (re-search-backward "^[A-Za-z0-9].*[ \t]*$" nil t)
+ (or (end-of-line) t)
+ (reST-title-char-p (char-after (+ (point) 1)))
+ (looking-at (format "\n%c\\{%d,\\}[ \t]*$"
+ (char-after (+ (point) 1))
+ (current-column))))))
+ (beginning-of-line)
+ (point))) )
+ (if newpoint (goto-char newpoint)) ))
+
+
+;;------------------------------------------------------------------------------
+;; For backwards compatibility. Remove at some point.
+(defalias 'reST-title-char-p 'rest-title-char-p)
+(defalias 'reST-forward-title 'rest-forward-section)
+(defalias 'reST-backward-title 'rest-backward-section)
+
+
+(provide 'restructuredtext)
diff --git a/tools/editors/emacs/rst-html.el b/tools/editors/emacs/rst-html.el
new file mode 100644
index 000000000..c9ebf33ef
--- /dev/null
+++ b/tools/editors/emacs/rst-html.el
@@ -0,0 +1,129 @@
+;;; rst-mode.el --- Goodies to automate converting reST documents to HTML.
+
+;; Copyright 2003 Martin Blais <blais@iro.umontreal.ca>
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+;;; Commentary:
+
+;; This package provides a few functions and variables that can help in
+;; automating converting reST documents to HTML from within emacs. You could
+;; use a makefile to do this, of use the compile command that this package
+;; provides.
+
+;; You can also bind a command to automate converting to HTML:
+;; (defun user-rst-mode-hook ()
+;; (local-set-key [(control c)(?9)] 'rst-html-compile))
+;; (add-hook 'rst-mode-hook 'user-rst-mode-hook)
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Customization:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defgroup rst-html nil
+ "Settings for conversion to HTML available by \\[rst-html-compile]. Use of
+this functionality is discouraged. Get a proper `Makefile' instead."
+ :group 'rst
+ :version "21.1")
+
+(defcustom rst-html-command "docutils-html"
+ "Command to convert an reST file to HTML."
+ :group 'rst-html
+ :type '(string))
+
+(defcustom rst-html-stylesheet ""
+ "Stylesheet for reST to HTML conversion. Empty for no special stylesheet."
+ :group 'rst-html
+ :type '(string))
+
+(defcustom rst-html-options ""
+ "Local file options for reST to HTML conversion.
+Stylesheets are set by an own option."
+ :group 'rst-html
+ :type '(string))
+
+(defcustom rst-html-extension ".html"
+ "Extension for HTML output file."
+ :group 'rst-html
+ :type '(string))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Conversion to HTML
+
+(defun rst-html-compile ()
+ "Compile command to convert reST document into HTML."
+ (interactive)
+ (let* ((bufname (file-name-nondirectory buffer-file-name))
+ (outname (file-name-sans-extension bufname))
+ (ssheet
+ (or (and (not (zerop (length rst-html-stylesheet)))
+ (concat "--stylesheet=\"" rst-html-stylesheet "\""))
+ "")))
+ (set (make-local-variable 'compile-command)
+ (mapconcat 'identity
+ (list rst-html-command
+ ssheet rst-html-options
+ bufname (concat outname rst-html-extension))
+ " "))
+ (if (or compilation-read-command current-prefix-arg)
+ (call-interactively 'compile)
+ (compile compile-command))
+ ))
+
+(defun rst-html-compile-with-conf ()
+ "Compile command to convert reST document into HTML. Attempts to find
+configuration file, if it can, overrides the options."
+ (interactive)
+ (let ((conffile (rst-html-find-conf)))
+ (if conffile
+ (let* ((bufname (file-name-nondirectory buffer-file-name))
+ (outname (file-name-sans-extension bufname)))
+ (set (make-local-variable 'compile-command)
+ (mapconcat 'identity
+ (list rst-html-command
+ (concat "--config=\"" conffile "\"")
+ bufname (concat outname rst-html-extension))
+ " "))
+ (if (or compilation-read-command current-prefix-arg)
+ (call-interactively 'compile)
+ (compile compile-command)))
+ (call-interactively 'rst-html-compile)
+ )))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Find the configuration file in the parents.
+
+(defun rst-html-find-conf ()
+ "Look for the configuration file in the parents of the current path."
+ (interactive)
+ (let ((file-name "docutils.conf")
+ (buffer-file (buffer-file-name)))
+ ;; Move up in the dir hierarchy till we find a change log file.
+ (let ((dir (file-name-directory buffer-file)))
+ (while (and (or (not (string= "/" dir)) (setq dir nil) nil)
+ (not (file-exists-p (concat dir file-name))))
+ ;; Move up to the parent dir and try again.
+ (setq dir (expand-file-name (file-name-directory
+ (directory-file-name
+ (file-name-directory dir))))) )
+ (or (and dir (concat dir file-name)) nil)
+ )))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; rst-mode.el ends here
diff --git a/tools/editors/emacs/rst-mode.el b/tools/editors/emacs/rst-mode.el
new file mode 100644
index 000000000..8fc14e4a5
--- /dev/null
+++ b/tools/editors/emacs/rst-mode.el
@@ -0,0 +1,700 @@
+;;; rst-mode.el --- Mode for viewing and editing reStructuredText-documents.
+
+;; Copyright 2003 Stefan Merten <smerten@oekonux.de>
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+;;; Commentary:
+
+;; This package provides support for documents marked up using the
+;; reStructuredText format
+;; [http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html].
+;; Support includes font locking as well as some convenience functions
+;; for editing.
+
+;; The package is based on `text-mode' and inherits some things from it.
+;; Particularly `text-mode-hook' is run before `rst-mode-hook'.
+
+;; Add the following lines to your `.emacs' file:
+;;
+;; (autoload 'rst-mode "rst-mode" "mode for editing reStructuredText documents" t)
+;; (setq auto-mode-alist
+;; (append '(("\\.rst$" . rst-mode)
+;; ("\\.rest$" . rst-mode)) auto-mode-alist))
+;;
+;; If you are using `.txt' as a standard extension for reST files as
+;; http://docutils.sourceforge.net/FAQ.html#what-s-the-standard-filename-extension-for-a-restructuredtext-file
+;; suggests you may use one of the `Local Variables in Files' mechanism Emacs
+;; provides to set the major mode automatically. For instance you may use
+;;
+;; .. -*- mode: rst -*-
+;;
+;; in the very first line of your file. However, because this is a major
+;; security breach you or your administrator may have chosen to switch that
+;; feature off. See `Local Variables in Files' in the Emacs documentation for a
+;; more complete discussion.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; Customization:
+
+(defgroup rst nil "Support for reStructuredText documents"
+ :group 'wp
+ :version "21.1"
+ :link '(url-link "http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html"))
+
+(defcustom rst-mode-hook nil
+ "Hook run when Rst Mode is turned on. The hook for Text Mode is run before
+ this one."
+ :group 'rst
+ :type '(hook))
+
+(defcustom rst-mode-lazy t
+ "*If non-nil Rst Mode font-locks comment, literal blocks, and section titles
+correctly. Because this is really slow it switches on Lazy Lock Mode
+automatically. You may increase Lazy Lock Defer Time for reasonable results.
+
+If nil comments and literal blocks are font-locked only on the line they start.
+
+The value of this variable is used when Rst Mode is turned on."
+ :group 'rst
+ :type '(boolean))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defgroup rst-faces nil "Faces used in Rst Mode"
+ :group 'rst
+ :group 'faces
+ :version "21.1")
+
+(defcustom rst-block-face 'font-lock-keyword-face
+ "All syntax marking up a special block"
+ :group 'rst-faces
+ :type '(face))
+
+(defcustom rst-external-face 'font-lock-type-face
+ "Field names and interpreted text"
+ :group 'rst-faces
+ :type '(face))
+
+(defcustom rst-definition-face 'font-lock-function-name-face
+ "All other defining constructs"
+ :group 'rst-faces
+ :type '(face))
+
+(defcustom rst-directive-face
+ ;; XEmacs compatibility
+ (if (boundp 'font-lock-builtin-face)
+ 'font-lock-builtin-face
+ 'font-lock-preprocessor-face)
+ "Directives and roles"
+ :group 'rst-faces
+ :type '(face))
+
+(defcustom rst-comment-face 'font-lock-comment-face
+ "Comments"
+ :group 'rst-faces
+ :type '(face))
+
+(defcustom rst-emphasis1-face
+ ;; XEmacs compatibility
+ (if (facep 'italic)
+ ''italic
+ 'italic)
+ "Simple emphasis"
+ :group 'rst-faces
+ :type '(face))
+
+(defcustom rst-emphasis2-face
+ ;; XEmacs compatibility
+ (if (facep 'bold)
+ ''bold
+ 'bold)
+ "Double emphasis"
+ :group 'rst-faces
+ :type '(face))
+
+(defcustom rst-literal-face 'font-lock-string-face
+ "Literal text"
+ :group 'rst-faces
+ :type '(face))
+
+(defcustom rst-reference-face 'font-lock-variable-name-face
+ "References to a definition"
+ :group 'rst-faces
+ :type '(face))
+
+;; Faces for displaying items on several levels; these definitions define
+;; different shades of grey where the lightest one is used for level 1
+(defconst rst-level-face-max 6
+ "Maximum depth of level faces defined")
+(defconst rst-level-face-base-color "grey"
+ "The base color to be used for creating level faces")
+(defconst rst-level-face-base-light 85
+ "The lightness factor for the base color")
+(defconst rst-level-face-format-light "%2d"
+ "The format for the lightness factor for the base color")
+(defconst rst-level-face-step-light -7
+ "The step width to use for next color")
+
+;; Define the faces
+(let ((i 1))
+ (while (<= i rst-level-face-max)
+ (let ((sym (intern (format "rst-level-%d-face" i)))
+ (doc (format "Face for showing section title text at level %d" i))
+ (col (format (concat "%s" rst-level-face-format-light)
+ rst-level-face-base-color
+ (+ (* (1- i) rst-level-face-step-light)
+ rst-level-face-base-light))))
+ (make-empty-face sym)
+ (set-face-doc-string sym doc)
+ (set-face-background sym col)
+ (set sym sym)
+ (setq i (1+ i)))))
+
+(defcustom rst-adornment-faces-alist
+ '((1 . rst-level-1-face)
+ (2 . rst-level-2-face)
+ (3 . rst-level-3-face)
+ (4 . rst-level-4-face)
+ (5 . rst-level-5-face)
+ (6 . rst-level-6-face)
+ (t . font-lock-keyword-face)
+ (nil . font-lock-keyword-face))
+ "Provides faces for the various adornment types. Key is a number (for the
+section title text of that level), t (for transitions) or nil (for section
+title adornment)."
+ :group 'rst-faces
+ :type '(alist :key-type (choice (integer :tag "Section level")
+ (boolean :tag "transitions (on) / section title adornment (off)"))
+ :value-type (face)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; FIXME: Code from `restructuredtext.el' should be integrated
+
+(defvar rst-mode-syntax-table nil
+ "Syntax table used while in rst mode.")
+
+(unless rst-mode-syntax-table
+ (setq rst-mode-syntax-table (make-syntax-table text-mode-syntax-table))
+ (modify-syntax-entry ?$ "." rst-mode-syntax-table)
+ (modify-syntax-entry ?% "." rst-mode-syntax-table)
+ (modify-syntax-entry ?& "." rst-mode-syntax-table)
+ (modify-syntax-entry ?' "." rst-mode-syntax-table)
+ (modify-syntax-entry ?* "." rst-mode-syntax-table)
+ (modify-syntax-entry ?+ "." rst-mode-syntax-table)
+ (modify-syntax-entry ?. "_" rst-mode-syntax-table)
+ (modify-syntax-entry ?/ "." rst-mode-syntax-table)
+ (modify-syntax-entry ?< "." rst-mode-syntax-table)
+ (modify-syntax-entry ?= "." rst-mode-syntax-table)
+ (modify-syntax-entry ?> "." rst-mode-syntax-table)
+ (modify-syntax-entry ?\\ "\\" rst-mode-syntax-table)
+ (modify-syntax-entry ?| "." rst-mode-syntax-table)
+ (modify-syntax-entry ?_ "." rst-mode-syntax-table)
+ )
+
+(defvar rst-mode-abbrev-table nil
+ "Abbrev table used while in rst mode.")
+(define-abbrev-table 'rst-mode-abbrev-table ())
+
+;; FIXME: Movement keys to skip forward / backward over or mark an indented
+;; block could be defined; keys to markup section titles based on
+;; `rst-adornment-level-alist' would be useful
+(defvar rst-mode-map nil
+ "Keymap for rst mode. This inherits from Text mode.")
+
+(unless rst-mode-map
+ (setq rst-mode-map (copy-keymap text-mode-map)))
+
+(defun rst-mode ()
+ "Major mode for editing reStructuredText documents.
+
+You may customize `rst-mode-lazy' to switch font-locking of blocks.
+
+\\{rst-mode-map}
+Turning on `rst-mode' calls the normal hooks `text-mode-hook' and
+`rst-mode-hook'."
+ (interactive)
+ (kill-all-local-variables)
+
+ ;; Maps and tables
+ (use-local-map rst-mode-map)
+ (setq local-abbrev-table rst-mode-abbrev-table)
+ (set-syntax-table rst-mode-syntax-table)
+
+ ;; For editing text
+ ;;
+ ;; FIXME: It would be better if this matches more exactly the start of a reST
+ ;; paragraph; however, this not always possible with a simple regex because
+ ;; paragraphs are determined by indentation of the following line
+ (set (make-local-variable 'paragraph-start)
+ (concat page-delimiter "\\|[ \t]*$"))
+ (if (eq ?^ (aref paragraph-start 0))
+ (setq paragraph-start (substring paragraph-start 1)))
+ (set (make-local-variable 'paragraph-separate) paragraph-start)
+ (set (make-local-variable 'indent-line-function) 'indent-relative-maybe)
+ (set (make-local-variable 'adaptive-fill-mode) t)
+ (set (make-local-variable 'comment-start) ".. ")
+
+ ;; Special variables
+ (make-local-variable 'rst-adornment-level-alist)
+
+ ;; Font lock
+ (set (make-local-variable 'font-lock-defaults)
+ '(rst-font-lock-keywords-function
+ t nil nil nil
+ (font-lock-multiline . t)
+ (font-lock-mark-block-function . mark-paragraph)))
+ (when (boundp 'font-lock-support-mode)
+ ;; rst-mode has its own mind about font-lock-support-mode
+ (make-local-variable 'font-lock-support-mode)
+ (cond
+ ((and (not rst-mode-lazy) (not font-lock-support-mode)))
+ ;; No support mode set and none required - leave it alone
+ ((or (not font-lock-support-mode) ;; No support mode set (but required)
+ (symbolp font-lock-support-mode)) ;; or a fixed mode for all
+ (setq font-lock-support-mode
+ (list (cons 'rst-mode (and rst-mode-lazy 'lazy-lock-mode))
+ (cons t font-lock-support-mode))))
+ ((and (listp font-lock-support-mode)
+ (not (assoc 'rst-mode font-lock-support-mode)))
+ ;; A list of modes missing rst-mode
+ (setq font-lock-support-mode
+ (append '((cons 'rst-mode (and rst-mode-lazy 'lazy-lock-mode)))
+ font-lock-support-mode)))))
+
+ ;; Names and hooks
+ (setq mode-name "reST")
+ (setq major-mode 'rst-mode)
+ (run-hooks 'text-mode-hook)
+ (run-hooks 'rst-mode-hook))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Font lock
+
+(defun rst-font-lock-keywords-function ()
+ "Returns keywords to highlight in rst mode according to current settings."
+ ;; The reST-links in the comments below all relate to sections in
+ ;; http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html
+ (let* ( ;; This gets big - so let's define some abbreviations
+ ;; horizontal white space
+ (re-hws "[\t ]")
+ ;; beginning of line with possible indentation
+ (re-bol (concat "^" re-hws "*"))
+ ;; Separates block lead-ins from their content
+ (re-blksep1 (concat "\\(" re-hws "+\\|$\\)"))
+ ;; explicit markup tag
+ (re-emt "\\.\\.")
+ ;; explicit markup start
+ (re-ems (concat re-emt re-hws "+"))
+ ;; inline markup prefix
+ (re-imp1 (concat "\\(^\\|" re-hws "\\|[-'\"([{</:]\\)"))
+ ;; inline markup suffix
+ (re-ims1 (concat "\\(" re-hws "\\|[]-'\")}>/:.,;!?\\]\\|$\\)"))
+ ;; symbol character
+ (re-sym1 "\\(\\sw\\|\\s_\\)")
+ ;; inline markup content begin
+ (re-imbeg2 "\\(\\S \\|\\S \\([^")
+
+ ;; There seems to be a bug leading to error "Stack overflow in regexp
+ ;; matcher" when "|" or "\\*" are the characters searched for
+ (re-imendbeg
+ (if (< emacs-major-version 21)
+ "]"
+ "\\]\\|\\\\."))
+ ;; inline markup content end
+ (re-imend (concat re-imendbeg "\\)*[^\t \\\\]\\)"))
+ ;; inline markup content without asterisk
+ (re-ima2 (concat re-imbeg2 "*" re-imend))
+ ;; inline markup content without backquote
+ (re-imb2 (concat re-imbeg2 "`" re-imend))
+ ;; inline markup content without vertical bar
+ (re-imv2 (concat re-imbeg2 "|" re-imend))
+ ;; Supported URI schemes
+ (re-uris1 "\\(acap\\|cid\\|data\\|dav\\|fax\\|file\\|ftp\\|gopher\\|http\\|https\\|imap\\|ldap\\|mailto\\|mid\\|modem\\|news\\|nfs\\|nntp\\|pop\\|prospero\\|rtsp\\|service\\|sip\\|tel\\|telnet\\|tip\\|urn\\|vemmi\\|wais\\)")
+ ;; Line starting with adornment and optional whitespace; complete
+ ;; adornment is in (match-string 1); there must be at least 3
+ ;; characters because otherwise explicit markup start would be
+ ;; recognized
+ (re-ado2 (concat "^\\(\\(["
+ (if (or
+ (< emacs-major-version 21)
+ (save-match-data
+ (string-match "XEmacs\\|Lucid" emacs-version)))
+ "^a-zA-Z0-9 \t\x00-\x1F"
+ "^[:word:][:space:][:cntrl:]")
+ "]\\)\\2\\2+\\)" re-hws "*$"))
+ )
+ (list
+ ;; FIXME: Block markup is not recognized in blocks after explicit markup
+ ;; start
+
+ ;; Simple `Body Elements`_
+ ;; `Bullet Lists`_
+ (list
+ (concat re-bol "\\([-*+]" re-blksep1 "\\)")
+ 1 rst-block-face)
+ ;; `Enumerated Lists`_
+ (list
+ (concat re-bol "\\((?\\([0-9]+\\|[A-Za-z]\\|[IVXLCMivxlcm]+\\)[.)]" re-blksep1 "\\)")
+ 1 rst-block-face)
+ ;; `Definition Lists`_ FIXME: missing
+ ;; `Field Lists`_
+ (list
+ (concat re-bol "\\(:[^:]+:\\)" re-blksep1)
+ 1 rst-external-face)
+ ;; `Option Lists`_
+ (list
+ (concat re-bol "\\(\\(\\(\\([-+/]\\|--\\)\\sw\\(-\\|\\sw\\)*\\([ =]\\S +\\)?\\)\\(,[\t ]\\)?\\)+\\)\\($\\|[\t ]\\{2\\}\\)")
+ 1 rst-block-face)
+
+ ;; `Tables`_ FIXME: missing
+
+ ;; All the `Explicit Markup Blocks`_
+ ;; `Footnotes`_ / `Citations`_
+ (list
+ (concat re-bol "\\(" re-ems "\\[[^[]+\\]\\)" re-blksep1)
+ 1 rst-definition-face)
+ ;; `Directives`_ / `Substitution Definitions`_
+ (list
+ (concat re-bol "\\(" re-ems "\\)\\(\\(|[^|]+|[\t ]+\\)?\\)\\(" re-sym1 "+::\\)" re-blksep1)
+ (list 1 rst-directive-face)
+ (list 2 rst-definition-face)
+ (list 4 rst-directive-face))
+ ;; `Hyperlink Targets`_
+ (list
+ (concat re-bol "\\(" re-ems "_\\([^:\\`]\\|\\\\.\\|`[^`]+`\\)+:\\)" re-blksep1)
+ 1 rst-definition-face)
+ (list
+ (concat re-bol "\\(__\\)" re-blksep1)
+ 1 rst-definition-face)
+
+ ;; All `Inline Markup`_
+ ;; FIXME: Condition 5 preventing fontification of e.g. "*" not implemented
+ ;; `Strong Emphasis`_
+ (list
+ (concat re-imp1 "\\(\\*\\*" re-ima2 "\\*\\*\\)" re-ims1)
+ 2 rst-emphasis2-face)
+ ;; `Emphasis`_
+ (list
+ (concat re-imp1 "\\(\\*" re-ima2 "\\*\\)" re-ims1)
+ 2 rst-emphasis1-face)
+ ;; `Inline Literals`_
+ (list
+ (concat re-imp1 "\\(``" re-imb2 "``\\)" re-ims1)
+ 2 rst-literal-face)
+ ;; `Inline Internal Targets`_
+ (list
+ (concat re-imp1 "\\(_`" re-imb2 "`\\)" re-ims1)
+ 2 rst-definition-face)
+ ;; `Hyperlink References`_
+ ;; FIXME: `Embedded URIs`_ not considered
+ (list
+ (concat re-imp1 "\\(\\(`" re-imb2 "`\\|\\sw+\\)__?\\)" re-ims1)
+ 2 rst-reference-face)
+ ;; `Interpreted Text`_
+ (list
+ (concat re-imp1 "\\(\\(:" re-sym1 "+:\\)?\\)\\(`" re-imb2 "`\\)\\(\\(:" re-sym1 "+:\\)?\\)" re-ims1)
+ (list 2 rst-directive-face)
+ (list 5 rst-external-face)
+ (list 8 rst-directive-face))
+ ;; `Footnote References`_ / `Citation References`_
+ (list
+ (concat re-imp1 "\\(\\[[^]]+\\]_\\)" re-ims1)
+ 2 rst-reference-face)
+ ;; `Substitution References`_
+ (list
+ (concat re-imp1 "\\(|" re-imv2 "|\\)" re-ims1)
+ 2 rst-reference-face)
+ ;; `Standalone Hyperlinks`_
+ (list
+ ;; FIXME: This takes it easy by using a whitespace as delimiter
+ (concat re-imp1 "\\(" re-uris1 ":\\S +\\)" re-ims1)
+ 2 rst-definition-face)
+ (list
+ (concat re-imp1 "\\(" re-sym1 "+@" re-sym1 "+\\)" re-ims1)
+ 2 rst-definition-face)
+
+ ;; Do all block fontification as late as possible so 'append works
+
+ ;; Sections_ / Transitions_
+ (append
+ (list
+ re-ado2)
+ (if (not rst-mode-lazy)
+ (list 1 rst-block-face)
+ (list
+ (list 'rst-font-lock-handle-adornment
+ '(progn
+ (setq rst-font-lock-adornment-point (match-end 1))
+ (point-max))
+ nil
+ (list 1 '(cdr (assoc nil rst-adornment-faces-alist))
+ 'append t)
+ (list 2 '(cdr (assoc rst-font-lock-level rst-adornment-faces-alist))
+ 'append t)
+ (list 3 '(cdr (assoc nil rst-adornment-faces-alist))
+ 'append t)))))
+
+ ;; `Comments`_
+ (append
+ (list
+ (concat re-bol "\\(" re-ems "\\)\[^[|_]\\([^:]\\|:\\([^:]\\|$\\)\\)*$")
+ (list 1 rst-comment-face))
+ (if rst-mode-lazy
+ (list
+ (list 'rst-font-lock-find-unindented-line
+ '(progn
+ (setq rst-font-lock-indentation-point (match-end 1))
+ (point-max))
+ nil
+ (list 0 rst-comment-face 'append)))))
+ (append
+ (list
+ (concat re-bol "\\(" re-emt "\\)\\(\\s *\\)$")
+ (list 1 rst-comment-face)
+ (list 2 rst-comment-face))
+ (if rst-mode-lazy
+ (list
+ (list 'rst-font-lock-find-unindented-line
+ '(progn
+ (setq rst-font-lock-indentation-point 'next)
+ (point-max))
+ nil
+ (list 0 rst-comment-face 'append)))))
+
+ ;; `Literal Blocks`_
+ (append
+ (list
+ (concat re-bol "\\(\\([^.\n]\\|\\.[^.\n]\\).*\\)?\\(::\\)$")
+ (list 3 rst-block-face))
+ (if rst-mode-lazy
+ (list
+ (list 'rst-font-lock-find-unindented-line
+ '(progn
+ (setq rst-font-lock-indentation-point t)
+ (point-max))
+ nil
+ (list 0 rst-literal-face 'append)))))
+ )))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Indented blocks
+
+(defun rst-forward-indented-block (&optional column limit)
+ "Move forward across one indented block.
+Find the next non-empty line which is not indented at least to COLUMN (defaults
+to the column of the point). Moves point to first character of this line or the
+first empty line immediately before it and returns that position. If there is
+no such line before LIMIT (defaults to the end of the buffer) returns nil and
+point is not moved."
+ (interactive)
+ (let ((clm (or column (current-column)))
+ (start (point))
+ fnd beg cand)
+ (if (not limit)
+ (setq limit (point-max)))
+ (save-match-data
+ (while (and (not fnd) (< (point) limit))
+ (forward-line 1)
+ (when (< (point) limit)
+ (setq beg (point))
+ (if (looking-at "\\s *$")
+ (setq cand (or cand beg)) ; An empty line is a candidate
+ (move-to-column clm)
+ ;; FIXME: No indentation [(zerop clm)] must be handled in some
+ ;; useful way - though it is not clear what this should mean at all
+ (if (string-match
+ "^\\s *$" (buffer-substring-no-properties beg (point)))
+ (setq cand nil) ; An indented line resets a candidate
+ (setq fnd (or cand beg)))))))
+ (goto-char (or fnd start))
+ fnd))
+
+;; Stores the point where the current indentation ends if a number. If `next'
+;; indicates `rst-font-lock-find-unindented-line' shall take the indentation
+;; from the next line if this is not empty. If non-nil indicates
+;; `rst-font-lock-find-unindented-line' shall take the indentation from the
+;; next non-empty line. Also used as a trigger for
+;; `rst-font-lock-find-unindented-line'.
+(defvar rst-font-lock-indentation-point nil)
+
+(defun rst-font-lock-find-unindented-line (limit)
+ (let* ((ind-pnt rst-font-lock-indentation-point)
+ (beg-pnt ind-pnt))
+ ;; May run only once - enforce this
+ (setq rst-font-lock-indentation-point nil)
+ (when (and ind-pnt (not (numberp ind-pnt)))
+ ;; Find indentation point in next line if any
+ (setq ind-pnt
+ (save-excursion
+ (save-match-data
+ (if (eq ind-pnt 'next)
+ (when (and (zerop (forward-line 1)) (< (point) limit))
+ (setq beg-pnt (point))
+ (when (not (looking-at "\\s *$"))
+ (looking-at "\\s *")
+ (match-end 0)))
+ (while (and (zerop (forward-line 1)) (< (point) limit)
+ (looking-at "\\s *$")))
+ (when (< (point) limit)
+ (setq beg-pnt (point))
+ (looking-at "\\s *")
+ (match-end 0)))))))
+ (when ind-pnt
+ (goto-char ind-pnt)
+ ;; Always succeeds because the limit set by PRE-MATCH-FORM is the
+ ;; ultimate point to find
+ (goto-char (or (rst-forward-indented-block nil limit) limit))
+ (set-match-data (list beg-pnt (point)))
+ t)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Adornments
+
+;; Stores the point where the current adornment ends. Also used as a trigger
+;; for `rst-font-lock-handle-adornment'.
+(defvar rst-font-lock-adornment-point nil)
+
+;; Here `rst-font-lock-handle-adornment' stores the section level of the
+;; current adornment or t for a transition.
+(defvar rst-font-lock-level nil)
+
+;; FIXME: It would be good if this could be used to markup section titles of
+;; given level with a special key; it would be even better to be able to
+;; customize this so it can be used for a generally available personal style
+;;
+;; FIXME: There should be some way to reset and reload this variable - probably
+;; a special key
+;;
+;; FIXME: Some support for `outline-mode' would be nice which should be based
+;; on this information
+(defvar rst-adornment-level-alist nil
+ "Associates adornments with section levels.
+The key is a two character string. The first character is the adornment
+character. The second character distinguishes underline section titles (`u')
+from overline/underline section titles (`o'). The value is the section level.
+
+This is made buffer local on start and adornments found during font lock are
+entered.")
+
+;; Returns section level for adornment key KEY. Adds new section level if KEY
+;; is not found and ADD. If KEY is not a string it is simply returned.
+(defun rst-adornment-level (key &optional add)
+ (let ((fnd (assoc key rst-adornment-level-alist))
+ (new 1))
+ (cond
+ ((not (stringp key))
+ key)
+ (fnd
+ (cdr fnd))
+ (add
+ (while (rassoc new rst-adornment-level-alist)
+ (setq new (1+ new)))
+ (setq rst-adornment-level-alist
+ (append rst-adornment-level-alist (list (cons key new))))
+ new))))
+
+;; Classifies adornment for section titles and transitions. ADORNMENT is the
+;; complete adornment string as found in the buffer. END is the point after the
+;; last character of ADORNMENT. For overline section adornment LIMIT limits the
+;; search for the matching underline. Returns a list. The first entry is t for
+;; a transition, or a key string for `rst-adornment-level' for a section title.
+;; The following eight values forming four match groups as can be used for
+;; `set-match-data'. First match group contains the maximum points of the whole
+;; construct. Second and last match group matched pure section title adornment
+;; while third match group matched the section title text or the transition.
+;; Each group but the first may or may not exist.
+(defun rst-classify-adornment (adornment end limit)
+ (save-excursion
+ (save-match-data
+ (goto-char end)
+ (let ((ado-ch (aref adornment 0))
+ (ado-re (regexp-quote adornment))
+ (end-pnt (point))
+ (beg-pnt (progn
+ (forward-line 0)
+ (point)))
+ (nxt-emp
+ (save-excursion
+ (or (not (zerop (forward-line 1)))
+ (looking-at "\\s *$"))))
+ (prv-emp
+ (save-excursion
+ (or (not (zerop (forward-line -1)))
+ (looking-at "\\s *$"))))
+ key beg-ovr end-ovr beg-txt end-txt beg-und end-und)
+ (cond
+ ((and nxt-emp prv-emp)
+ ;; A transition
+ (setq key t)
+ (setq beg-txt beg-pnt)
+ (setq end-txt end-pnt))
+ (prv-emp
+ ;; An overline
+ (setq key (concat (list ado-ch) "o"))
+ (setq beg-ovr beg-pnt)
+ (setq end-ovr end-pnt)
+ (forward-line 1)
+ (setq beg-txt (point))
+ (while (and (< (point) limit) (not end-txt))
+ (if (looking-at "\\s *$")
+ ;; No underline found
+ (setq end-txt (1- (point)))
+ (when (looking-at (concat "\\(" ado-re "\\)\\s *$"))
+ (setq end-und (match-end 1))
+ (setq beg-und (point))
+ (setq end-txt (1- beg-und))))
+ (forward-line 1)))
+ (t
+ ;; An underline
+ (setq key (concat (list ado-ch) "u"))
+ (setq beg-und beg-pnt)
+ (setq end-und end-pnt)
+ (setq end-txt (1- beg-und))
+ (setq beg-txt (progn
+ (if (re-search-backward "^\\s *$" 1 'move)
+ (forward-line 1))
+ (point)))))
+ (list key
+ (or beg-ovr beg-txt beg-und)
+ (or end-und end-txt end-und)
+ beg-ovr end-ovr beg-txt end-txt beg-und end-und)))))
+
+;; Handles adornments for font-locking section titles and transitions. Returns
+;; three match groups. First and last match group matched pure overline /
+;; underline adornment while second group matched section title text. Each
+;; group may not exist.
+(defun rst-font-lock-handle-adornment (limit)
+ (let ((ado-pnt rst-font-lock-adornment-point))
+ ;; May run only once - enforce this
+ (setq rst-font-lock-adornment-point nil)
+ (if ado-pnt
+ (let* ((ado (rst-classify-adornment (match-string-no-properties 1)
+ ado-pnt limit))
+ (key (car ado))
+ (mtc (cdr ado)))
+ (setq rst-font-lock-level (rst-adornment-level key t))
+ (goto-char (nth 1 mtc))
+ (set-match-data mtc)
+ t))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(provide 'rst-mode)
+
+;;; rst-mode.el ends here
diff --git a/tools/editors/emacs/tests/tests-adjust-section.el b/tools/editors/emacs/tests/tests-adjust-section.el
new file mode 100644
index 000000000..43215fb98
--- /dev/null
+++ b/tools/editors/emacs/tests/tests-adjust-section.el
@@ -0,0 +1,240 @@
+;; Authors: Martin Blais <blais@furius.ca>
+;; Date: $Date: 2005/04/01 23:19:41 $
+;; Copyright: This module has been placed in the public domain.
+;;
+;; Regression tests for rest-adjust-section-title.
+;;
+
+(setq rest-adjust-section-tests
+ '(
+ (simple
+"
+Some Title@
+
+"
+"
+Some Title
+==========
+
+")
+
+ (simple-cursor-in-line
+"
+Some Tit@le
+
+"
+"
+Some Title
+==========
+
+")
+
+ (simple-cursor-beginning
+"
+@Some Title
+
+"
+"
+Some Title
+==========
+
+")
+
+ (simple-at-end-of-buffer
+"
+Some Title@"
+"
+Some Title
+==========
+")
+
+ (cursor-on-empty-line-under
+"
+Some Title
+@
+"
+"
+Some Title
+==========
+
+")
+
+
+
+ (partial
+"
+Some Title@
+---
+"
+"
+Some Title
+----------
+
+")
+
+ (cursor-on-underline
+"
+Some Title
+---@
+"
+"
+Some Title
+----------
+
+")
+
+ (cursor-on-underline-one-char
+"
+Some Title
+~@
+"
+"
+Some Title
+~~~~~~~~~~
+
+")
+
+ (with-previous-text
+"
+Some Title
+**********
+
+Subtitle@
+
+"
+"
+Some Title
+**********
+
+Subtitle
+********
+
+")
+
+ (with-suggested-new-text
+"
+Some Title
+==========
+
+Subtitle
+--------
+
+Subtitle2@
+
+"
+"
+Some Title
+==========
+
+Subtitle
+--------
+
+Subtitle2
+~~~~~~~~~
+
+"
+(nil nil))
+
+ (with-previous-text-rotating
+"
+Some Title
+==========
+
+Subtitle
+--------
+
+Subtitle2@
+
+"
+"
+Some Title
+==========
+
+Subtitle
+--------
+
+Subtitle2
+=========
+
+"
+(nil nil nil))
+
+ (start-indented
+"
+ Some Title@
+
+"
+"
+================
+ Some Title
+================
+
+")
+
+ (switch-from-nothing
+"
+Some Title@
+
+"
+"
+============
+ Some Title
+============
+
+" (t))
+
+ (switch-from-over-and-under
+"
+============
+ Some Title@
+============
+"
+"
+Some Title
+==========
+
+" (t))
+
+))
+
+ "A list of regression tests for the section update method.")
+
+
+
+(defun regression-test-compare-expect-buffer (testlist fun)
+ "Run the regression tests for the section adjusting method."
+
+ (let ((buf (get-buffer-create "restructuredtext-regression-tests"))
+ (specchar "@")
+ )
+ (dolist (curtest testlist)
+ ;; print current text
+ (message (format "========= %s" (prin1-to-string (car curtest))))
+
+ ;; prepare a buffer with the starting text, and move the cursor where
+ ;; the special character is located
+ (switch-to-buffer buf)
+ (erase-buffer)
+ (insert (cadr curtest))
+ (search-backward specchar)
+ (delete-char 1)
+
+ ;; run the section title update command n times
+ (dolist (x (or (cadddr curtest) (list nil)))
+ (let ((current-prefix-arg x))
+ (funcall fun)))
+
+ ;; compare the buffer output with the expected text
+ (or (string=
+ (buffer-string)
+ (caddr curtest))
+ (progn
+ (error "Test %s failed." (car curtest))))
+ )
+ ))
+
+;; evaluate this to run the tests, either interactively or in batch
+(regression-test-compare-expect-buffer
+ rest-adjust-section-tests
+ (lambda ()
+ (call-interactively 'rest-adjust-section-title)))
diff --git a/tools/pep-html-template b/tools/pep-html-template
new file mode 100644
index 000000000..94ecafb70
--- /dev/null
+++ b/tools/pep-html-template
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="%(encoding)s" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<!--
+This HTML is auto-generated. DO NOT EDIT THIS FILE! If you are writing a new
+PEP, see http://www.python.org/peps/pep-0001.html for instructions and links
+to templates. DO NOT USE THIS HTML FILE AS YOUR TEMPLATE!
+-->
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=%(encoding)s" />
+ <meta name="generator" content="Docutils %(version)s: http://docutils.sourceforge.net/" />
+ <title>PEP %(pep)s -- %(title)s</title>
+ %(stylesheet)s</head>
+<body bgcolor="white">
+<table class="navigation" cellpadding="0" cellspacing="0"
+ width="100%%" border="0">
+<tr><td class="navicon" width="150" height="35">
+<a href="%(pyhome)s/" title="Python Home Page">
+<img src="%(pyhome)s/pics/PyBanner%(banner)03d.gif" alt="[Python]"
+ border="0" width="150" height="35" /></a></td>
+<td class="textlinks" align="left">
+[<b><a href="%(pyhome)s/">Python Home</a></b>]
+[<b><a href="%(pepindex)s">PEP Index</a></b>]
+[<b><a href="%(pephome)s/pep-%(pepnum)s.txt">PEP Source</a></b>]
+</td></tr></table>
+%(body)s
+%(body_suffix)s
diff --git a/tools/pep.py b/tools/pep.py
new file mode 100755
index 000000000..5aa4b8afc
--- /dev/null
+++ b/tools/pep.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+A minimal front end to the Docutils Publisher, producing HTML from PEP
+(Python Enhancement Proposal) documents.
+"""
+
+try:
+ import locale
+ locale.setlocale(locale.LC_ALL, '')
+except:
+ pass
+
+from docutils.core import publish_cmdline, default_description
+
+
+description = ('Generates (X)HTML from reStructuredText-format PEP files. '
+ + default_description)
+
+publish_cmdline(reader_name='pep', writer_name='pep_html',
+ description=description)
diff --git a/tools/quicktest.py b/tools/quicktest.py
new file mode 100755
index 000000000..fbccb1aaa
--- /dev/null
+++ b/tools/quicktest.py
@@ -0,0 +1,211 @@
+#!/usr/bin/env python
+
+# Author: Garth Kidd
+# Contact: garth@deadlybloodyserious.com
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+try:
+ import locale
+ locale.setlocale(locale.LC_ALL, '')
+except:
+ pass
+
+import sys
+import os
+import getopt
+import docutils
+from docutils.frontend import OptionParser
+from docutils.utils import new_document
+from docutils.parsers.rst import Parser
+
+
+usage_header = """\
+quicktest.py: quickly test the restructuredtext parser.
+
+Usage::
+
+ quicktest.py [options] [<source> [<destination>]]
+
+``source`` is the name of the file to use as input (default is stdin).
+``destination`` is the name of the file to create as output (default is
+stdout).
+
+Options:
+"""
+
+options = [('pretty', 'p',
+ 'output pretty pseudo-xml: no "&abc;" entities (default)'),
+ ('test', 't', 'output test-ready data (input & expected output, '
+ 'ready to be copied to a parser test module)'),
+ ('rawxml', 'r', 'output raw XML'),
+ ('styledxml=', 's', 'output raw XML with XSL style sheet '
+ 'reference (filename supplied in the option argument)'),
+ ('xml', 'x', 'output pretty XML (indented)'),
+ ('attributes', 'A', 'dump document attributes after processing'),
+ ('debug', 'd', 'debug mode (lots of output)'),
+ ('version', 'V', 'show Docutils version then exit'),
+ ('help', 'h', 'show help text then exit')]
+"""See ``distutils.fancy_getopt.FancyGetopt.__init__`` for a description of
+the data structure: (long option, short option, description)."""
+
+def usage():
+ print usage_header
+ for longopt, shortopt, description in options:
+ if longopt[-1:] == '=':
+ opts = '-%s arg, --%sarg' % (shortopt, longopt)
+ else:
+ opts = '-%s, --%s' % (shortopt, longopt)
+ print '%-15s' % opts,
+ if len(opts) > 14:
+ print '%-16s' % '\n',
+ while len(description) > 60:
+ limit = description.rindex(' ', 0, 60)
+ print description[:limit].strip()
+ description = description[limit + 1:]
+ print '%-15s' % ' ',
+ print description
+
+def _pretty(input, document, optargs):
+ return document.pformat()
+
+def _rawxml(input, document, optargs):
+ return document.asdom().toxml()
+
+def _styledxml(input, document, optargs):
+ docnode = document.asdom().childNodes[0]
+ return '%s\n%s\n%s' % (
+ '<?xml version="1.0" encoding="ISO-8859-1"?>',
+ '<?xml-stylesheet type="text/xsl" href="%s"?>'
+ % optargs['styledxml'], docnode.toxml())
+
+def _prettyxml(input, document, optargs):
+ return document.asdom().toprettyxml(' ', '\n')
+
+def _test(input, document, optargs):
+ tq = '"""'
+ output = document.pformat() # same as _pretty()
+ return """\
+ totest['change_this_test_name'] = [
+[%s\\
+%s
+%s,
+%s\\
+%s
+%s],
+]
+""" % ( tq, escape(input.rstrip()), tq, tq, escape(output.rstrip()), tq )
+
+def escape(text):
+ """
+ Return `text` in triple-double-quoted Python string form.
+ """
+ text = text.replace('\\', '\\\\') # escape backslashes
+ text = text.replace('"""', '""\\"') # break up triple-double-quotes
+ text = text.replace(' \n', ' \\n\\\n') # protect trailing whitespace
+ return text
+
+_outputFormatters = {
+ 'rawxml': _rawxml,
+ 'styledxml': _styledxml,
+ 'xml': _prettyxml,
+ 'pretty' : _pretty,
+ 'test': _test
+ }
+
+def format(outputFormat, input, document, optargs):
+ formatter = _outputFormatters[outputFormat]
+ return formatter(input, document, optargs)
+
+def getArgs():
+ if os.name == 'mac' and len(sys.argv) <= 1:
+ return macGetArgs()
+ else:
+ return posixGetArgs(sys.argv[1:])
+
+def posixGetArgs(argv):
+ outputFormat = 'pretty'
+ # convert fancy_getopt style option list to getopt.getopt() arguments
+ shortopts = ''.join([option[1] + ':' * (option[0][-1:] == '=')
+ for option in options if option[1]])
+ longopts = [option[0] for option in options if option[0]]
+ try:
+ opts, args = getopt.getopt(argv, shortopts, longopts)
+ except getopt.GetoptError:
+ usage()
+ sys.exit(2)
+ optargs = {'debug': 0, 'attributes': 0}
+ for o, a in opts:
+ if o in ['-h', '--help']:
+ usage()
+ sys.exit()
+ elif o in ['-V', '--version']:
+ print >>sys.stderr, ('quicktest.py (Docutils %s)'
+ % docutils.__version__)
+ sys.exit()
+ elif o in ['-r', '--rawxml']:
+ outputFormat = 'rawxml'
+ elif o in ['-s', '--styledxml']:
+ outputFormat = 'styledxml'
+ optargs['styledxml'] = a
+ elif o in ['-x', '--xml']:
+ outputFormat = 'xml'
+ elif o in ['-p', '--pretty']:
+ outputFormat = 'pretty'
+ elif o in ['-t', '--test']:
+ outputFormat = 'test'
+ elif o in ['--attributes', '-A']:
+ optargs['attributes'] = 1
+ elif o in ['-d', '--debug']:
+ optargs['debug'] = 1
+ else:
+ raise getopt.GetoptError, "getopt should have saved us!"
+ if len(args) > 2:
+ print 'Maximum 2 arguments allowed.'
+ usage()
+ sys.exit(1)
+ inputFile = sys.stdin
+ outputFile = sys.stdout
+ if args:
+ inputFile = open(args.pop(0))
+ if args:
+ outputFile = open(args.pop(0), 'w')
+ return inputFile, outputFile, outputFormat, optargs
+
+def macGetArgs():
+ import EasyDialogs
+ EasyDialogs.Message("""\
+Use the next dialog to build a command line:
+
+1. Choose an output format from the [Option] list
+2. Click [Add]
+3. Choose an input file: [Add existing file...]
+4. Save the output: [Add new file...]
+5. [OK]""")
+ optionlist = [(longopt, description)
+ for (longopt, shortopt, description) in options]
+ argv = EasyDialogs.GetArgv(optionlist=optionlist, addfolder=0)
+ return posixGetArgs(argv)
+
+def main():
+ # process cmdline arguments:
+ inputFile, outputFile, outputFormat, optargs = getArgs()
+ settings = OptionParser(components=(Parser,)).get_default_values()
+ settings.debug = optargs['debug']
+ parser = Parser()
+ input = inputFile.read()
+ document = new_document(inputFile.name, settings)
+ parser.parse(input, document)
+ output = format(outputFormat, input, document, optargs)
+ outputFile.write(output)
+ if optargs['attributes']:
+ import pprint
+ pprint.pprint(document.__dict__)
+
+
+if __name__ == '__main__':
+ sys.stderr = sys.stdout
+ main()
diff --git a/tools/rst2html.py b/tools/rst2html.py
new file mode 100755
index 000000000..35e5558aa
--- /dev/null
+++ b/tools/rst2html.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@python.org
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+A minimal front end to the Docutils Publisher, producing HTML.
+"""
+
+try:
+ import locale
+ locale.setlocale(locale.LC_ALL, '')
+except:
+ pass
+
+from docutils.core import publish_cmdline, default_description
+
+
+description = ('Generates (X)HTML documents from standalone reStructuredText '
+ 'sources. ' + default_description)
+
+publish_cmdline(writer_name='html', description=description)
diff --git a/tools/rst2latex.py b/tools/rst2latex.py
new file mode 100755
index 000000000..5f51f34e2
--- /dev/null
+++ b/tools/rst2latex.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+A minimal front end to the Docutils Publisher, producing LaTeX.
+"""
+
+try:
+ import locale
+ locale.setlocale(locale.LC_ALL, '')
+except:
+ pass
+
+from docutils.core import publish_cmdline, default_description
+
+
+description = ('Generates LaTeX documents from standalone reStructuredText '
+ 'sources. ' + default_description)
+
+publish_cmdline(writer_name='latex', description=description)
diff --git a/tools/rst2newlatex.py b/tools/rst2newlatex.py
new file mode 100755
index 000000000..46524753f
--- /dev/null
+++ b/tools/rst2newlatex.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+A minimal front end to the Docutils Publisher, producing LaTeX using
+the new LaTeX writer.
+"""
+
+try:
+ import locale
+ locale.setlocale(locale.LC_ALL, '')
+except:
+ pass
+
+from docutils.core import publish_cmdline, default_description
+
+
+description = ('Generates LaTeX documents from standalone reStructuredText '
+ 'sources. This writer is EXPERIMENTAL and should not be used '
+ 'in a production environment. ' + default_description)
+
+publish_cmdline(writer_name='newlatex2e', description=description)
diff --git a/tools/rst2pseudoxml.py b/tools/rst2pseudoxml.py
new file mode 100755
index 000000000..627b3d198
--- /dev/null
+++ b/tools/rst2pseudoxml.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+A minimal front end to the Docutils Publisher, producing pseudo-XML.
+"""
+
+try:
+ import locale
+ locale.setlocale(locale.LC_ALL, '')
+except:
+ pass
+
+from docutils.core import publish_cmdline, default_description
+
+
+description = ('Generates pseudo-XML from standalone reStructuredText '
+ 'sources (for testing purposes). ' + default_description)
+
+publish_cmdline(description=description)
diff --git a/tools/rst2xml.py b/tools/rst2xml.py
new file mode 100755
index 000000000..8e2ad757f
--- /dev/null
+++ b/tools/rst2xml.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This module has been placed in the public domain.
+
+"""
+A minimal front end to the Docutils Publisher, producing Docutils XML.
+"""
+
+try:
+ import locale
+ locale.setlocale(locale.LC_ALL, '')
+except:
+ pass
+
+from docutils.core import publish_cmdline, default_description
+
+
+description = ('Generates Docutils-native XML from standalone '
+ 'reStructuredText sources. ' + default_description)
+
+publish_cmdline(writer_name='xml', description=description)
diff --git a/tools/stylesheets/default.css b/tools/stylesheets/default.css
new file mode 100644
index 000000000..608aad487
--- /dev/null
+++ b/tools/stylesheets/default.css
@@ -0,0 +1,263 @@
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Date: $Date$
+:Version: $Revision$
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+*/
+
+/* "! important" is used here to override other ``margin-top`` and
+ ``margin-bottom`` styles that are later in the stylesheet or
+ more specific. See http://www.w3.org/TR/CSS1#the-cascade */
+.first {
+ margin-top: 0 ! important }
+
+.last, .with-subtitle {
+ margin-bottom: 0 ! important }
+
+.hidden {
+ display: none }
+
+a.toc-backref {
+ text-decoration: none ;
+ color: black }
+
+blockquote.epigraph {
+ margin: 2em 5em ; }
+
+dl.docutils dd {
+ margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+ font-weight: bold }
+*/
+
+div.abstract {
+ margin: 2em 5em }
+
+div.abstract p.topic-title {
+ font-weight: bold ;
+ text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+ margin: 2em ;
+ border: medium outset ;
+ padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+ color: red ;
+ font-weight: bold ;
+ font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+ compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+ margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+ margin-top: 0.5em }
+*/
+
+div.dedication {
+ margin: 2em 5em ;
+ text-align: center ;
+ font-style: italic }
+
+div.dedication p.topic-title {
+ font-weight: bold ;
+ font-style: normal }
+
+div.figure {
+ margin-left: 2em }
+
+div.footer, div.header {
+ font-size: smaller }
+
+div.line-block {
+ display: block ;
+ margin-top: 1em ;
+ margin-bottom: 1em }
+
+div.line-block div.line-block {
+ margin-top: 0 ;
+ margin-bottom: 0 ;
+ margin-left: 1.5em }
+
+div.sidebar {
+ margin-left: 1em ;
+ border: medium outset ;
+ padding: 1em ;
+ background-color: #ffffee ;
+ width: 40% ;
+ float: right ;
+ clear: right }
+
+div.sidebar p.rubric {
+ font-family: sans-serif ;
+ font-size: medium }
+
+div.system-messages {
+ margin: 5em }
+
+div.system-messages h1 {
+ color: red }
+
+div.system-message {
+ border: medium outset ;
+ padding: 1em }
+
+div.system-message p.system-message-title {
+ color: red ;
+ font-weight: bold }
+
+div.topic {
+ margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+ margin-top: 0.4em }
+
+h1.title {
+ text-align: center }
+
+h2.subtitle {
+ text-align: center }
+
+hr.docutils {
+ width: 75% }
+
+ol.simple, ul.simple {
+ margin-bottom: 1em }
+
+ol.arabic {
+ list-style: decimal }
+
+ol.loweralpha {
+ list-style: lower-alpha }
+
+ol.upperalpha {
+ list-style: upper-alpha }
+
+ol.lowerroman {
+ list-style: lower-roman }
+
+ol.upperroman {
+ list-style: upper-roman }
+
+p.attribution {
+ text-align: right ;
+ margin-left: 50% }
+
+p.caption {
+ font-style: italic }
+
+p.credits {
+ font-style: italic ;
+ font-size: smaller }
+
+p.label {
+ white-space: nowrap }
+
+p.rubric {
+ font-weight: bold ;
+ font-size: larger ;
+ color: maroon ;
+ text-align: center }
+
+p.sidebar-title {
+ font-family: sans-serif ;
+ font-weight: bold ;
+ font-size: larger }
+
+p.sidebar-subtitle {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+p.topic-title {
+ font-weight: bold }
+
+pre.address {
+ margin-bottom: 0 ;
+ margin-top: 0 ;
+ font-family: serif ;
+ font-size: 100% }
+
+pre.line-block {
+ font-family: serif ;
+ font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+ margin-left: 2em ;
+ margin-right: 2em ;
+ background-color: #eeeeee }
+
+span.classifier {
+ font-family: sans-serif ;
+ font-style: oblique }
+
+span.classifier-delimiter {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+span.interpreted {
+ font-family: sans-serif }
+
+span.option {
+ white-space: nowrap }
+
+span.pre {
+ white-space: pre }
+
+span.problematic {
+ color: red }
+
+span.section-subtitle {
+ /* font-size relative to parent (<h#> element) */
+ font-size: 80% }
+
+table.citation {
+ border-left: solid thin gray }
+
+table.docinfo {
+ margin: 2em 4em }
+
+table.docutils {
+ margin-top: 0.5em ;
+ margin-bottom: 0.5em }
+
+table.footnote {
+ border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+ padding-left: 0.5em ;
+ padding-right: 0.5em ;
+ vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+ font-weight: bold ;
+ text-align: left ;
+ white-space: nowrap ;
+ padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+ font-size: 100% }
+
+tt.docutils {
+ background-color: #eeeeee }
+
+ul.auto-toc {
+ list-style-type: none }
diff --git a/tools/stylesheets/latex-notes.txt b/tools/stylesheets/latex-notes.txt
new file mode 100644
index 000000000..87e65abd2
--- /dev/null
+++ b/tools/stylesheets/latex-notes.txt
@@ -0,0 +1,40 @@
+Try the commands mentioned in
+<http://groups.google.de/groups?selm=c7opho%248ts%241%40wsc10.lrz-muenchen.de>.
+
+
+Regarding UTF-8:
+
+* Read <http://article.gmane.org/gmane.text.docutils.user/1863>.
+
+* From <http://article.gmane.org/gmane.text.docutils.user/1861>::
+
+ > The amssymb package and the postscript option were simply so that
+ > LaTeX could find the fonts and symbol definitions for the particular
+ > Unicode characters I used.
+ > However the DeclareUnicodeCharacter directive was to work around a
+ > missing or misnamed character in the UCS database.
+
+
+<http://www.tug.org/applications/pdftex/pdfTeX-FAQ.pdf>::
+
+ 3.1.6. How can I make a document portable to both latex and pdflatex
+ Contributed by: Christian Kumpf
+ Check for the existence of the variable \pdfoutput:
+ \newif\ifpdf
+ \ifx\pdfoutput\undefined
+ \pdffalse % we are not running PDFLaTeX
+ \else
+ \pdfoutput=1 % we are running PDFLaTeX
+ \pdftrue
+ \fi
+ Then use your new variable \ifpdf
+ \ifpdf
+ \usepackage[pdftex]{graphicx}
+ \pdfcompresslevel=9
+ \else
+ \usepackage{graphicx}
+ \fi
+
+Width of images needs cleanup, in the framework. Integers aren't
+sufficient (virtually unusable in typeset documents). Need to discuss
+on Docutils-develop and come up with a set of standard units.
diff --git a/tools/stylesheets/latex.tex b/tools/stylesheets/latex.tex
new file mode 100644
index 000000000..d9fc58348
--- /dev/null
+++ b/tools/stylesheets/latex.tex
@@ -0,0 +1,970 @@
+\makeatletter
+
+\providecommand{\DSpackages}{%
+ % All kinds of useful packages.
+ \usepackage{ifthen}
+}
+
+
+\providecommand{\DSfontencoding}{
+ % T1-emulation. Provides most characters and features we're used
+ % from T1-encoded fonts but doesn't use bitmap fonts.
+ \usepackage{ae}
+ % Provide the characters not contained in AE from EC bitmap fonts.
+ \usepackage{aecompl}
+ % Guillemets ("<<", ">>") in AE.
+ \usepackage{aeguill}
+}
+
+
+% Taken from
+% <http://groups.google.de/groups?selm=1i0n5tgtplti420e1omp4pctlv19jpuhbb%404ax.com>
+% and modified. Used with permission.
+\providecommand{\Dprovidelength}[2]{%
+ \begingroup%
+ \escapechar\m@ne%
+ \xdef\@gtempa{{\string#1}}%
+ \endgroup%
+ \expandafter\@ifundefined\@gtempa%
+ {\newlength{#1}\setlength{#1}{#2}}%
+ {}%
+}
+
+\providecommand{\Dprovidecounter}[1]{%
+ % Like \newcounter except that it doesn't crash if the counter
+ % already exists.
+ \@ifundefined{c@#1}{\newcounter{#1}}{}
+}
+
+\providecommand{\DSboxcommands}{
+ \Dprovidelength{\Dboxparindent}{\parindent}
+ \providecommand{\Dmakeboxminipage}[1]{%
+ % Make minipage for use in a box created by \Dmakefbox.
+ \begin{minipage}[t]{0.9\linewidth}%
+ \setlength{\parindent}{\Dboxparindent}%
+ ##1%
+ \end{minipage}%
+ }
+ \providecommand{\Dmakefbox}[1]{%
+ % Make a centered, framed box. Useful e.g. for admonitions.
+ \vspace{0.4\baselineskip}%
+ \begin{center}%
+ \fbox{\Dmakeboxminipage{##1}}%
+ \end{center}%
+ \vspace{0.4\baselineskip}%
+ }
+ \providecommand{\Dmakebox}[1]{%
+ % Make a centered, frameless box. Useful e.g. for block quotes.
+ % Do not use minipages here, but create pseudo-lists to allow
+ % page-breaking. (Don't uses KOMA-script's addmargin environment
+ % because it messes up bullet lists.)
+ \Dmakelistenvironment{}{}{%
+ \setlength{\parskip}{0pt}%
+ \setlength{\parindent}{\Dboxparindent}%
+ \item{##1}%
+ }%
+ }
+}
+
+
+\providecommand{\DSfrenchspacing}{
+ \frenchspacing
+}
+
+
+\providecommand{\DSauxiliaryspace}{
+ \Dprovidelength{\Dblocklevelvspace}{%
+ % Space between block-level elements other than paragraphs.
+ 0.7\baselineskip plus 0.3\baselineskip minus 0.2\baselineskip%
+ }
+ \providecommand{\Dauxiliaryspace}{%
+ \ifthenelse{\equal{\Dneedvspace}{true}}{\vspace{\Dblocklevelvspace}}{}%
+ \Dpar\noindent%
+ }
+ \providecommand{\Dauxiliaryparspace}{%
+ \ifthenelse{\equal{\Dneedvspace}{true}}{\vspace{\Dblocklevelvspace}}{}%
+ \Dpar%
+ }
+ \providecommand{\Dparagraphspace}{\Dpar}
+ \providecommand{\Dneedvspace}{true}
+}
+
+
+\providecommand{\DSparagraphs}{
+ \providecommand{\Dnextparindent}{}
+ \providecommand{\Dnextpar}{\par}
+ %\newcommand{\Dnextpar}{\par\Dnextparindent}
+ \providecommand{\Dpar}{%
+ \Dnextpar%
+ \Dnextparindent%
+ \protect\renewcommand{\Dnextpar}{\par}%
+ \protect\renewcommand{\Dnextparindent}{}%
+ }
+ \providecommand{\Dnopar}{%
+ \protect\renewcommand{\Dnextpar}{\par}%
+ \protect\renewcommand{\Dnextparindent}{}%
+ }
+}
+
+\providecommand{\DSlinks}{
+ % Targets and references.
+ \usepackage[colorlinks=false,pdfborder={0 0 0}]{hyperref}
+
+ \providecommand{\Draisedlink}[1]{\Hy@raisedlink{##1}}
+
+ % References.
+ % We're assuming here that the "refid" and "refuri" attributes occur
+ % only in inline context (in TextElements).
+ \providecommand{\DArefid}[5]{%
+ \ifthenelse{\equal{##4}{reference}}{%
+ \Dexplicitreference{\###3}{##5}%
+ }{%
+ % If this is not a target node (targets with refids are
+ % uninteresting and should be silently dropped).
+ \ifthenelse{\not\equal{##4}{target}}{%
+ % If this is a footnote reference, call special macro.
+ \ifthenelse{\equal{##4}{footnotereference}}{%
+ \Dimplicitfootnotereference{\###3}{##5}%
+ }{%
+ \ifthenelse{\equal{##4}{citationreference}}{%
+ \Dimplicitcitationreference{\###3}{##5}%
+ }{%
+ \Dimplicitreference{\###3}{##5}%
+ }%
+ }%
+ }{}%
+ }%
+ }
+ \providecommand{\DArefuri}[5]{%
+ \ifthenelse{\equal{##4}{target}}{%
+ % Hyperlink targets can (and should be) ignored because they are
+ % invisible.
+ }{%
+ % We only have explicit URI references, so one macro suffices.
+ \Durireference{##3}{##5}%
+ }%
+ }
+ % Targets.
+ \Dprovidelength{\Dorgbaselineskip}{0pt}
+ \providecommand{\DAids}[5]{%
+ \ifthenelse{\equal{##4}{footnotereference}}{%
+ {%
+ \renewcommand{\HyperRaiseLinkDefault}{%
+ % Dirty hack to make backrefs to footnote references work.
+ % For some reason, \baselineskip is 0pt in fn references.
+ 0.5\Dorgbaselineskip%
+ }%
+ \Draisedlink{\hypertarget{##3}{}}##5%
+ }%
+ }{%
+ \Draisedlink{\hypertarget{##3}{}}##5%
+ }%
+ }
+ % Color in references.
+ \usepackage{color}
+ \providecommand{\Dimplicitreference}[2]{%
+ % Create implicit reference to ID. Implicit references occur
+ % e.g. in TOC-backlinks of section titles. Parameters:
+ % 1. Target.
+ % 2. Link text.
+ \href{##1}{##2}%
+ }
+ \providecommand{\Dimplicitfootnotereference}[2]{%
+ % Ditto, but for the special case of footnotes.
+ % We want them to be rendered like explicit references.
+ \Dexplicitreference{##1}{##2}%
+ }
+ \providecommand{\Dimplicitcitationreference}[2]{%
+ % Ditto for citation references.
+ \Dimplicitfootnotereference{##1}{##2}%
+ }
+ \providecommand{\Dexplicitreference}[2]{%
+ % Create explicit reference to ID, e.g. created with "foo_".
+ % Parameters:
+ % 1. Target.
+ % 2. Link text.
+ \href{##1}{{\color{blue}##2}}%
+ }
+ \providecommand{\Durireference}[2]{%
+ % Create reference to URI. Parameters:
+ % 1. Target.
+ % 2. Link text.
+ \href{##1}{{\color{blue}##2}}%
+ }
+}
+
+
+\providecommand{\DSearly}{}
+\providecommand{\DSlate}{}
+
+\providecommand{\Ddocumentclass}{scrartcl}
+\providecommand{\Ddocumentoptions}{a4paper}
+
+\documentclass[\Ddocumentoptions]{\Ddocumentclass}
+
+\DSearly
+
+
+\providecommand{\DAclasses}[5]{%
+ \Difdefined{DN#4C#3}{%
+ % Pass only contents, nothing else!
+ \csname DN#4C#3\endcsname{#5}%
+ }{%
+ \Difdefined{DC#3}{%
+ \csname DC#3\endcsname{#5}%
+ }{%
+ #5%
+ }%
+ }%
+}
+
+\providecommand{\Difdefined}[3]{\@ifundefined{#1}{#3}{#2}}
+
+\providecommand{\Dattr}[5]{%
+ % Global attribute dispatcher.
+ % Parameters:
+ % 1. Attribute number.
+ % 2. Attribute name.
+ % 3. Attribute value.
+ % 4. Node name.
+ % 5. Node contents.
+ \Difdefined{DN#4A#2V#3}{%
+ \csname DN#4A#2V#3\endcsname{#1}{#2}{#3}{#4}{#5}%
+ }{\Difdefined{DN#4A#2}{%
+ \csname DN#4A#2\endcsname{#1}{#2}{#3}{#4}{#5}%
+ }{\Difdefined{DA#2V#3}{%
+ \csname DA#2V#3\endcsname{#1}{#2}{#3}{#4}{#5}%
+ }{\Difdefined{DA#2}{%
+ \csname DA#2\endcsname{#1}{#2}{#3}{#4}{#5}%
+ }{#5%
+ }}}}%
+}
+
+\providecommand{\DNparagraph}[1]{#1}
+\providecommand{\Dformatboxtitle}[1]{{\Large\textbf{#1}}}
+\providecommand{\Dformatboxsubtitle}[1]{{\large\textbf{#1}}}
+\providecommand{\Dtopictitle}[1]{%
+ \noindent\Dformatboxtitle{#1}%
+ \ifthenelse{\equal{\Dhassubtitle}{false}}{\vspace{1em}}{\vspace{0.5em}}%
+ \Dpar\noindent%
+}
+\providecommand{\Dtopicsubtitle}[1]{%
+ \Dformatboxsubtitle{#1}%
+ \vspace{1em}%
+ \Dpar\noindent%
+}
+\providecommand{\Dsidebartitle}[1]{\Dtopictitle{#1}}
+\providecommand{\Dsidebarsubtitle}[1]{\Dtopicsubtitle{#1}}
+\providecommand{\Ddocumenttitle}[1]{%
+ \begin{center}{\Huge#1}\end{center}%
+ \ifthenelse{\equal{\Dhassubtitle}{true}}{\vspace{0.1cm}}{\vspace{1cm}}%
+}
+\providecommand{\Ddocumentsubtitle}[1]{%
+ \begin{center}{\huge#1}\end{center}%
+ \vspace{1cm}%
+}
+% Can be overwritten by user stylesheet.
+\providecommand{\Dformatsectiontitle}[1]{#1}
+\providecommand{\Dformatsectionsubtitle}[1]{\Dformatsectiontitle{#1}}
+\providecommand{\Dbookmarksectiontitle}[1]{%
+ % Return text suitable for use in \section*, \subsection*, etc.,
+ % containing a PDF bookmark. Parameter: The title (as node tree).
+ \Draisedlink{\Dpdfbookmark{\Dtitleastext}}%
+ #1%
+}
+\providecommand{\Dsectiontitlehook}[1]{#1}
+\providecommand{\Dsectiontitle}[1]{%
+ \Dsectiontitlehook{%
+ \Ddispatchsectiontitle{\Dbookmarksectiontitle{\Dformatsectiontitle{#1}}}%
+ }%
+}
+\providecommand{\Ddispatchsectiontitle}[1]{%
+ \@ifundefined{Dsectiontitle\roman{Dsectionlevel}}{%
+ \Ddeepsectiontitle{#1}%
+ }{%
+ \csname Dsectiontitle\roman{Dsectionlevel}\endcsname{#1}%
+ }%
+}
+\providecommand{\Ddispatchsectionsubtitle}[1]{%
+ \Ddispatchsectiontitle{#1}%
+}
+\providecommand{\Dsectiontitlei}[1]{\section*{#1}}
+\providecommand{\Dsectiontitleii}[1]{\subsection*{#1}}
+\providecommand{\Ddeepsectiontitle}[1]{%
+ % Anything below \subsubsection (like \paragraph or \subparagraph)
+ % is useless because it uses the same font. The only way to
+ % (visually) distinguish such deeply nested sections is to use
+ % section numbering.
+ \subsubsection*{#1}%
+}
+\providecommand{\Dsectionsubtitlehook}[1]{#1}
+\Dprovidelength{\Dsectionsubtitleraisedistance}{0.7em}
+\providecommand{\Dsectionsubtitle}[1]{%
+ \Dsectionsubtitlehook{%
+ % Move the subtitle nearer to the title.
+ \vspace{-\Dsectionsubtitleraisedistance}%
+ % Don't create a PDF bookmark.
+ \Ddispatchsectionsubtitle{\Dformatsectionsubtitle{\scalebox{.8}{#1}}}%
+ }%
+}
+% Boolean variable.
+\providecommand{\Dhassubtitle}{false}
+\providecommand{\DNtitle}[1]{%
+ \csname D\Dparent title\endcsname{#1}%
+}
+\providecommand{\DNsubtitle}[1]{%
+ \csname D\Dparent subtitle\endcsname{#1}%
+}
+\newcounter{Dpdfbookmarkid}
+\setcounter{Dpdfbookmarkid}{0}
+\providecommand{\Dpdfbookmark}[1]{%
+ % Temporarily decrement Desctionlevel counter.
+ \addtocounter{Dsectionlevel}{-1}%
+ %\typeout{\arabic{Dsectionlevel}}%
+ %\typeout{#1}%
+ %\typeout{docutils\roman{Dpdfbookmarkid}}%
+ %\typeout{}%
+ \pdfbookmark[\arabic{Dsectionlevel}]{#1}{docutils\arabic{Dpdfbookmarkid}}%
+ \addtocounter{Dsectionlevel}{1}%
+ \addtocounter{Dpdfbookmarkid}{1}%
+}
+
+%\providecommand{\DNliteralblock}[1]{\begin{quote}\ttfamily\raggedright#1\end{quote}}
+\providecommand{\DNliteralblock}[1]{%
+ \Dmakelistenvironment{}{}{%
+ \raggedright\item\noindent\nohyphens{\textnhtt{#1}}%
+ }%
+}
+\providecommand{\DNdoctestblock}[1]{%
+ % Treat doctest blocks the same as literal blocks.
+ \DNliteralblock{#1}%
+}
+\usepackage{hyphenat}
+\providecommand{\DNliteral}[1]{\textnhtt{#1}}
+\providecommand{\DNemphasis}[1]{\emph{#1}}
+\providecommand{\DNstrong}[1]{\textbf{#1}}
+\providecommand{\Dvisitdocument}{\begin{document}\noindent}
+\providecommand{\Ddepartdocument}{\end{document}}
+\providecommand{\DNtopic}[1]{%
+ \par%
+ \Dmakebox{%
+ %% % Close with \par because otherwise LaTeX wouldn't notice the
+ %% % changed \baselineskip (due to the font size change).
+ %% {\small#1\par}%
+ #1%
+ }%
+}
+\providecommand{\Dformatrubric}[1]{\textbf{#1}}
+\Dprovidelength{\Dprerubricspace}{0.3em}
+\providecommand{\DNrubric}[1]{%
+ \vspace{\Dprerubricspace}\Dpar\noindent\Dformatrubric{#1}\Dpar\noindent%
+}
+
+\providecommand{\Dbullet}{}
+\providecommand{\Dsetbullet}[1]{\renewcommand{\Dbullet}{#1}}
+\providecommand{\DNbulletlist}[1]{\Dmakelistenvironment{\Dbullet}{}{#1}}
+
+\providecommand{\DNlistitem}[1]{\item{#1}}
+\providecommand{\DNenumeratedlist}[1]{#1}
+\newcounter{Dsectionlevel}
+\providecommand{\Dvisitsectionhook}{}
+\providecommand{\Ddepartsectionhook}{}
+\providecommand{\Dvisitsection}{%
+ \addtocounter{Dsectionlevel}{1}%
+ \Dvisitsectionhook%
+}
+\providecommand{\Ddepartsection}{%
+ \Ddepartsectionhook%
+ \addtocounter{Dsectionlevel}{-1}%
+}
+
+% Using \_ will cause hyphenation after _ even in \textnhtt-typewriter
+% because the hyphenat package redefines \_. So we use
+% \textunderscore here.
+\providecommand{\Dtextunderscore}{\textunderscore}
+
+\providecommand{\Dtextinlineliteralfirstspace}{{ }}
+\providecommand{\Dtextinlineliteralsecondspace}{{~}}
+
+\Dprovidelength{\Dlistspacing}{0.8\baselineskip}
+
+% Current hardcoded.
+\usepackage[latin1]{inputenc}
+
+\providecommand{\Dsetlistrightmargin}{%
+ \ifthenelse{\lengthtest{\linewidth>10em}}{%
+ % Equal margins.
+ \setlength{\rightmargin}{\leftmargin}%
+ }{%
+ % If the line is narrower than 10em, we don't remove any further
+ % space from the right.
+ \setlength{\rightmargin}{0pt}%
+ }%
+}
+\providecommand{\Dresetlistdepth}{false}
+\providecommand{\Dmakelistenvironment}[3]{%
+ % Make list environment with support for unlimited nesting and with
+ % reasonable default lengths. Parameters:
+ % 1. Label (same as in list environment).
+ % 2. Spacing (same as in list environment).
+ % 3. List contents (contents of list environment).
+ \ifthenelse{\equal{\Dinsidetabular}{true}}{%
+ % Unfortunately, vertical spacing doesn't work correctly when
+ % using lists inside tabular environments, so we use a minipage.
+ \begin{minipage}[t]{\linewidth}%
+ }{}%
+ {%
+ \renewcommand{\Dneedvspace}{false}%
+ % \parsep0.5\baselineskip
+ \renewcommand{\Dresetlistdepth}{false}%
+ \ifnum \@listdepth>5%
+ \protect\renewcommand{\Dresetlistdepth}{true}%
+ \@listdepth=5%
+ \fi%
+ \begin{list}{%
+ #1%
+ }{%
+ \setlength{\itemsep}{0pt}%
+ \setlength{\partopsep}{0pt}%
+ \setlength{\topsep}{0pt}%
+ % List should take 90% of total width.
+ \setlength{\leftmargin}{0.05\linewidth}%
+ \Dsetlistrightmargin%
+ #2%
+ }{%
+ #3%
+ }%
+ \end{list}%
+ \ifthenelse{\equal{\Dresetlistdepth}{true}}{\@listdepth=5}{}%
+ }%
+ \ifthenelse{\equal{\Dinsidetabular}{true}}{\end{minipage}}{}%
+}
+\providecommand{\DAlastitem}[5]{#5\@finalstrut\@arstrutbox}
+
+\Dprovidelength{\Ditemsep}{0pt}
+\providecommand{\Dmakeenumeratedlist}[6]{%
+ % Make enumerated list.
+ % Parameters:
+ % - prefix
+ % - type (\arabic, \roman, ...)
+ % - suffix
+ % - suggested counter name
+ % - start number - 1
+ % - list contents
+ \newcounter{#4}%
+ \Dmakelistenvironment{#1#2{#4}#3}{%
+ % Use as much space as needed for the label.
+ \setlength{\labelwidth}{10em}%
+ % Reserve enough space so that the label doesn't go beyond the
+ % left margin of preceding paragraphs. Like that:
+ %
+ % A paragraph.
+ %
+ % 1. First item.
+ \setlength{\leftmargin}{2.5em}%
+ \Dsetlistrightmargin%
+ \setlength{\itemsep}{\Ditemsep}%
+ % Use counter recommended by Python module.
+ \usecounter{#4}%
+ % Set start value.
+ \addtocounter{#4}{#5}%
+ }{%
+ % The list contents.
+ #6%
+ }%
+}
+
+
+\providecommand{\Dlanguage}{english}
+\usepackage[\Dlanguage]{babel}
+
+% Single quote in literal mode. \textquotesingle from package
+% textcomp has wrong width when using package ae, so we use a normal
+% single curly quote here.
+\providecommand{\Dtextliteralsinglequote}{'}
+
+
+% "Tabular lists" are field lists and options lists (not definition
+% lists because there the term always appears on its own line). We'll
+% use the terminology of field lists now ("field", "field name",
+% "field body"), but the same is also analogously applicable to option
+% lists.
+%
+% We want these lists to be breakable across pages. We cannot
+% automatically get the narrowest possible size for the left column
+% (i.e. the field names or option groups) because tabularx does not
+% support multi-page tables, ltxtable needs to have the table in an
+% external file and we don't want to clutter the user's directories
+% with auxiliary files created by the filecontents environment, and
+% ltablex is not included in teTeX.
+%
+% Thus we set a fixed length for the left column and use list
+% environments. This also has the nice side effect that breaking is
+% now possible anywhere, not just between fields.
+%
+% Note that we are creating a distinct list environment for each
+% field. There is no macro for a whole tabular list!
+\Dprovidelength{\Dtabularlistfieldnamewidth}{6em}
+\Dprovidelength{\Dtabularlistfieldnamesep}{0.5em}
+\providecommand{\Dinsidetabular}{false}
+\providecommand{\Dsavefieldname}{}
+\providecommand{\Dsavefieldbody}{}
+\Dprovidelength{\Dusedfieldnamewidth}{0pt}
+\Dprovidelength{\Drealfieldnamewidth}{0pt}
+\providecommand{\Dtabularlistfieldname}[1]{\renewcommand{\Dsavefieldname}{#1}}
+\providecommand{\Dtabularlistfieldbody}[1]{\renewcommand{\Dsavefieldbody}{#1}}
+\providecommand{\Dtabularlistfield}[1]{%
+ {%
+ % This only saves field name and field body in \Dsavefieldname and
+ % \Dsavefieldbody, resp. It does not insert any text into the
+ % document.
+ #1%
+ % Recalculate the real field name width everytime we encounter a
+ % tabular list field because it may have been changed using a
+ % "raw" node.
+ \setlength{\Drealfieldnamewidth}{\Dtabularlistfieldnamewidth}%
+ \addtolength{\Drealfieldnamewidth}{\Dtabularlistfieldnamesep}%
+ \Dmakelistenvironment{%
+ \makebox[\Drealfieldnamewidth][l]{\Dsavefieldname}%
+ }{%
+ \setlength{\labelwidth}{\Drealfieldnamewidth}%
+ \setlength{\leftmargin}{\Drealfieldnamewidth}%
+ \setlength{\rightmargin}{0pt}%
+ \setlength{\labelsep}{0pt}%
+ }{%
+ \item%
+ \settowidth{\Dusedfieldnamewidth}{\Dsavefieldname}%
+ \ifthenelse{%
+ \lengthtest{\Dusedfieldnamewidth>\Dtabularlistfieldnamewidth}%
+ }{~\newline}{}%
+ \Dsavefieldbody%
+ \@finalstrut\@arstrutbox%
+ }%
+ \par%
+ }%
+}
+
+\providecommand{\Dformatfieldname}[1]{\textbf{#1:}}
+\providecommand{\DNfieldlist}[1]{#1}
+\providecommand{\DNfield}[1]{\Dtabularlistfield{#1}}
+\providecommand{\DNfieldname}[1]{%
+ \Dtabularlistfieldname{%
+ \Dformatfieldname{#1}%
+ }%
+}
+\providecommand{\DNfieldbody}[1]{\Dtabularlistfieldbody{#1}}
+
+\providecommand{\Dformatoptiongroup}[1]{%
+ % Format option group, e.g. "-f file, --input file".
+ \texttt{#1}%
+}
+\providecommand{\Dformatoption}[1]{%
+ % Format option, e.g. "-f file".
+ % Put into mbox to avoid line-breaking at spaces.
+ \mbox{#1}%
+}
+\providecommand{\Dformatoptionstring}[1]{%
+ % Format option string, e.g. "-f".
+ #1%
+}
+\providecommand{\Dformatoptionargument}[1]{%
+ % Format option argument, e.g. "file".
+ \textsl{#1}%
+}
+\providecommand{\Dformatoptiondescription}[1]{%
+ % Format option description, e.g.
+ % "\DNparagraph{Read input data from file.}"
+ #1%
+}
+\providecommand{\DNoptionlist}[1]{#1}
+\providecommand{\Doptiongroupjoiner}{,{ }}
+\providecommand{\Disfirstoption}{%
+ % Auxiliary macro indicating if a given option is the first child
+ % of its option group (if it's not, it has to preceded by
+ % \Doptiongroupjoiner).
+ false%
+}
+\providecommand{\DNoptionlistitem}[1]{%
+ \Dtabularlistfield{#1}%
+}
+\providecommand{\DNoptiongroup}[1]{%
+ \renewcommand{\Disfirstoption}{true}%
+ \Dtabularlistfieldname{\Dformatoptiongroup{#1}}%
+}
+\providecommand{\DNoption}[1]{%
+ % If this is not the first option in this option group, add a
+ % joiner.
+ \ifthenelse{\equal{\Disfirstoption}{true}}{%
+ \renewcommand{\Disfirstoption}{false}%
+ }{%
+ \Doptiongroupjoiner%
+ }%
+ \Dformatoption{#1}%
+}
+\providecommand{\DNoptionstring}[1]{\Dformatoptionstring{#1}}
+\providecommand{\DNoptionargument}[1]{{ }\Dformatoptionargument{#1}}
+\providecommand{\DNdescription}[1]{%
+ \Dtabularlistfieldbody{\Dformatoptiondescription{#1}}%
+}
+
+\providecommand{\DNdefinitionlist}[1]{%
+ % XXX Replace with a generic list, so we don't have to hack around
+ % spacing problems with \vspace and \hspace.
+ \vspace{-2em}%
+ \begin{description}%
+ \parskip0pt%
+ #1%
+ \end{description}%
+}
+\providecommand{\DNdefinitionlistitem}[1]{%
+ % LaTeX expects the label in square brackets; we provide an empty
+ % label.
+ \item[]#1%
+}
+\providecommand{\Dformatterm}[1]{#1}
+\providecommand{\DNterm}[1]{\hspace{-5pt}\Dformatterm{#1}}
+% I'm still not sure what's the best rendering for classifiers. The
+% colon syntax is used by reStructuredText, so it's at least WYSIWYG.
+% Use slanted text because italic would cause too much emphasis.
+\providecommand{\Dformatclassifier}[1]{\textsl{#1}}
+\providecommand{\DNclassifier}[1]{~:~\Dformatclassifier{#1}}
+\providecommand{\Dformatdefinition}[1]{#1}
+\providecommand{\DNdefinition}[1]{\Dpar\Dformatdefinition{#1}}
+
+\providecommand{\Dlineblockindentation}{2.5em}
+\providecommand{\DNlineblock}[1]{%
+ \Dmakelistenvironment{}{%
+ \ifthenelse{\equal{\Dparent}{lineblock}}{%
+ % Parent is a line block, so indent.
+ \setlength{\leftmargin}{\Dlineblockindentation}%
+ }{%
+ % At top level; don't indent.
+ \setlength{\leftmargin}{0pt}%
+ }%
+ \setlength{\rightmargin}{0pt}%
+ \setlength{\parsep}{0pt}%
+ }{%
+ #1%
+ }%
+}
+\providecommand{\DNline}[1]{\item#1}
+
+
+\providecommand{\DNtransition}{%
+ \Dpar\noindent{}\hspace*{\fill}\hrulefill\hrulefill\hspace*{\fill}%
+}
+
+
+\providecommand{\Dformatblockquote}[1]{%
+ % Format contents of block quote.
+ % This occurs in block-level context, so we cannot use \textsl.
+ {\slshape#1}%
+}
+\providecommand{\Dformatattribution}[1]{---\textup{#1}}
+\providecommand{\DNblockquote}[1]{%
+ \renewcommand{\Dnextparindent}{\noindent}%
+ \renewcommand{\Dnextpar}{}%
+ \Dmakebox{%
+ \Dformatblockquote{#1}
+ }%
+}
+\providecommand{\DNattribution}[1]{%
+ \Dpar%
+ \begin{flushright}\Dformatattribution{#1}\end{flushright}%
+}
+
+
+% Sidebars:
+\usepackage{picins}
+% Vertical and horizontal margins.
+\Dprovidelength{\Dsidebarvmargin}{0.5em}
+\Dprovidelength{\Dsidebarhmargin}{1em}
+% Padding (space between contents and frame).
+\Dprovidelength{\Dsidebarpadding}{1em}
+% Frame width.
+\Dprovidelength{\Dsidebarframewidth}{2\fboxrule}
+% Position ("l" or "r").
+\providecommand{\Dsidebarposition}{r}
+% Width.
+\Dprovidelength{\Dsidebarwidth}{0.45\linewidth}
+\providecommand{\DNsidebar}[1]{
+ \parpic[\Dsidebarposition]{%
+ \Dpar%
+ \begin{minipage}[t]{\Dsidebarwidth}
+ % Doing this with nested minipages is ugly, but I haven't found
+ % another way to place vertical space before and after the fbox.
+ \vspace{\Dsidebarvmargin}
+ {%
+ \setlength{\fboxrule}{\Dsidebarframewidth}%
+ \setlength{\fboxsep}{\Dsidebarpadding}%
+ \fbox{%
+ \begin{minipage}[t]{\linewidth}%
+ \setlength{\parindent}{\Dboxparindent}%
+ #1%
+ \end{minipage}%
+ }%
+ }%
+ \vspace{\Dsidebarvmargin}
+ \end{minipage}%
+ }%
+}
+
+
+% Citations and footnotes.
+\providecommand{\Dformatfootnote}[1]{%
+ % Format footnote.
+ {%
+ \footnotesize#1%
+ % \par is necessary for LaTeX to adjust baselineskip to the
+ % changed font size.
+ \par%
+ }%
+}
+\providecommand{\Dformatcitation}[1]{\Dformatfootnote{#1}}
+\providecommand{\DNfootnotereference}[1]{%
+ {%
+ % \baselineskip is 0pt in \textsuperscript, so we save it here.
+ \setlength{\Dorgbaselineskip}{\baselineskip}%
+ \textsuperscript{#1}%
+ }%
+}
+\providecommand{\DNcitationreference}[1]{{[}#1{]}}
+\Dprovidelength{\Dfootnotesep}{5pt}
+\providecommand{\Dfootnotespacing}{%
+ % Spacing commands executed at the beginning of footnotes.
+ \setlength{\parindent}{0pt}%
+ \hspace{1em}%
+}
+\providecommand{\DNfootnote}[1]{%
+ % See ltfloat.dtx for details.
+ {%
+ \insert\footins{%
+ \Dnopar\vspace{\Dfootnotesep}\Dfootnotespacing%
+ \Dformatfootnote{#1}%
+ }%
+ }%
+}
+\providecommand{\DNcitation}[1]{\DNfootnote{#1}}
+\providecommand{\Dformatfootnotelabel}[1]{%
+ % Keep \footnotesize in footnote labels (\textsuperscript would
+ % reduce the font size even more).
+ \textsuperscript{\footnotesize#1{ }}%
+}
+\providecommand{\Dformatcitationlabel}[1]{{[}#1{]}{ }}
+\providecommand{\Dformatmultiplebackrefs}[1]{\textsl{#1}}
+\providecommand{\Dthislabel}{}
+\providecommand{\DNlabel}[1]{%
+ \renewcommand{\Dthislabel}{#1}
+ \ifthenelse{\not\equal{\Dsinglebackref}{}}{%
+ \let\Doriginallabel=\Dthislabel%
+ \def\Dthislabel{%
+ \Dsinglefootnotebacklink{\Dsinglebackref}{\Doriginallabel}%
+ }%
+ }{}%
+ \ifthenelse{\equal{\Dparent}{footnote}}{%
+ % Footnote label.
+ \Dformatfootnotelabel{\Dthislabel}%
+ }{%
+ \ifthenelse{\equal{\Dparent}{citation}}{%
+ % Citation label.
+ \Dformatcitationlabel{\Dthislabel}%
+ }{}%
+ }%
+ % If there are multiple backrefs, add them now.
+ \Dformatmultiplebackrefs{\Dmultiplebackrefs}%
+ % Supress next paragraph change.
+ \renewcommand{\Dnextpar}{}%
+}
+\providecommand{\Dsinglefootnotebacklink}[2]{%
+ % Create normal backlink of a footnote label. Parameters:
+ % 1. ID.
+ % 2. Link text.
+ % Treat like a footnote reference.
+ \Dimplicitfootnotereference{\##1}{#2}%
+}
+\providecommand{\Dmultifootnotebacklink}[2]{%
+ % Create generated backlink, as in (1, 2). Parameters:
+ % 1. ID.
+ % 2. Link text.
+ % Treat like a footnote reference.
+ \Dimplicitfootnotereference{\##1}{#2}%
+}
+\providecommand{\Dsinglecitationbacklink}[2]{\Dsinglefootnotebacklink{#1}{#2}}
+\providecommand{\Dmulticitationbacklink}[2]{\Dmultifootnotebacklink{#1}{#2}}
+
+
+\usepackage{longtable}
+\providecommand{\Dmaketable}[2]{%
+ % Make table. Parameters:
+ % 1. Table spec (like "|p|p|").
+ % 2. Table contents.
+ {%
+ \renewcommand{\Dinsidetabular}{true}%
+ \begin{longtable}{#1}%
+ \hline%
+ #2%
+ \end{longtable}%
+ }%
+}
+\providecommand{\DNthead}[1]{%
+ #1%
+ \endhead%
+}
+\providecommand{\DNrow}[1]{%
+ #1\tabularnewline%
+ \hline%
+}
+\providecommand{\Dcolspan}[2]{%
+ % Take care of the morecols attribute (but incremented by 1).
+ &\multicolumn{#1}{l|}{#2}%
+}
+\providecommand{\Dcolspanleft}[2]{%
+ % Like \Dmorecols, but called for the leftmost entries in a table
+ % row.
+ \multicolumn{#1}{|l|}{#2}%
+}
+\providecommand{\Dsubsequententry}[1]{%
+ &#1%
+}
+% \DNentry is not used because we set the ampersand ("&") in the
+% \DAcolspan... macros.
+\providecommand{\DAtableheaderentry}[5]{\Dformattableheaderentry{#5}}
+\providecommand{\Dformattableheaderentry}[1]{{\bfseries#1}}
+
+
+\providecommand{\DNsystemmessage}[1]{%
+ {%
+ \color{red}%
+ \bfseries%
+ #1%
+ }%
+}
+
+
+\providecommand{\Dinsidehalign}{false}
+\providecommand{\Dhalign}[2]{%
+ % Horizontally align the contents to the left or right so that the
+ % text flows around it.
+ % Parameters:
+ % 1. l or r
+ % 2. Contents.
+ \renewcommand{\Dinsidehalign}{true}%
+ % For some obscure reason \parpic consumes some vertical space.
+ \vspace{-3pt}%
+ \parpic[#1]{#2}%
+ \renewcommand{\Dinsidehalign}{false}%
+}
+
+
+\usepackage{graphicx}
+% Maximum width of an image.
+\providecommand{\Dimagemaxwidth}{\linewidth}
+\providecommand{\Dfloatimagemaxwidth}{0.5\linewidth}
+% Auxiliary variable.
+\Dprovidelength{\Dcurrentimagewidth}{0pt}
+\providecommand{\DNimageAalign}[5]{%
+ \ifthenelse{\equal{#3}{left}}{%
+ \Dhalign{l}{#5}%
+ }{%
+ \ifthenelse{\equal{#3}{right}}{%
+ \Dhalign{r}{#5}%
+ }{%
+ \ifthenelse{\equal{#3}{center}}{%
+ % Text floating around centered figures is brain damage.
+ % Thus we use a center environment. Note that no extra space
+ % is added by the writer, so the space added by the center
+ % environment is fine.
+ \begin{center}#5\end{center}%
+ }{%
+ #5%
+ }%
+ }%
+ }%
+}
+% Base path for images.
+\providecommand{\Dimagebase}{}
+% Auxiliary command. Current image path.
+\providecommand{\Dimagepath}{}
+\providecommand{\DNimageAuri}[5]{%
+ % Insert image. We treat the URI like a path here.
+ \renewcommand{\Dimagepath}{\Dimagebase#3}%
+ \Difdefined{DcurrentNimageAwidth}{%
+ \Dpercentwidthimage{\DcurrentNimageAwidth}{\Dimagepath}%
+ }{%
+ \Dsimpleimage{\Dimagepath}%
+ }%
+}
+\Dprovidelength{\Dfloatimagevmargin}{0pt}
+\providecommand{\Dfloatimagetopmargin}{\Dfloatimagevmargin}
+\providecommand{\Dfloatimagebottommargin}{\Dfloatimagevmargin}
+\providecommand{\Dwidthimage}[2]{%
+ % Image with specified width.
+ % Parameters:
+ % 1. Image width.
+ % 2. Image path.
+ % Need to make bottom-alignment dependent on align attribute (add
+ % functional test first).
+ \begin{minipage}[b]{#1}%
+ \ifthenelse{\equal{\Dinsidehalign}{true}}{
+ % Compensate for space previously added in \Dhalign, but not
+ % entirely.
+ \vspace*{2.5pt}%
+ \vspace*{\Dfloatimagetopmargin}%
+ }{}%
+ \includegraphics[width=\linewidth,height=\textheight,keepaspectratio]{#2}%
+ \ifthenelse{\equal{\Dinsidehalign}{true}}{%
+ \vspace*{1.5pt}%
+ \vspace*{\Dfloatimagebottommargin}%
+ }{}%
+ \end{minipage}%
+}
+\providecommand{\Dcurrentimagemaxwidth}{}
+\providecommand{\Dsimpleimage}[1]{%
+ % Insert image, without much parametrization.
+ \settowidth{\Dcurrentimagewidth}{\includegraphics{#1}}%
+ \ifthenelse{\equal{\Dinsidehalign}{true}}{%
+ \renewcommand{\Dcurrentimagemaxwidth}{\Dfloatimagemaxwidth}%
+ }{%
+ \renewcommand{\Dcurrentimagemaxwidth}{\Dimagemaxwidth}%
+ }%
+ \ifthenelse{\lengthtest{\Dcurrentimagewidth>\Dcurrentimagemaxwidth}}{%
+ \Dwidthimage{\Dcurrentimagemaxwidth}{#1}%
+ }{%
+ \Dwidthimage{\Dcurrentimagewidth}{#1}%
+ }%
+}
+% Auxiliary length. One percent of \linewidth.
+\Dprovidelength{\Dlinewidthpercent}{0pt}
+\providecommand{\Dpercentwidthimage}[2]{%
+ % Image with specified width.
+ % Parameters:
+ % 1. Image width in percent of \linewidth (1 to 100).
+ % 2. Image path.
+ \setlength{\Dlinewidthpercent}{0.01\linewidth}%
+ \Dwidthimage{#1\Dlinewidthpercent}{#2}%
+}
+
+
+\providecommand{\DCborder}[1]{\fbox{#1}}
+
+
+% Need to replace with language-specific stuff. Maybe look at
+% csquotes.sty and ask the author for permission to use parts of it.
+\providecommand{\Dtextleftdblquote}{``}
+\providecommand{\Dtextrightdblquote}{''}
+
+
+%\usepackage{fixmath}
+%\usepackage{amsmath}
+
+
+\DSpackages
+\DSfontencoding
+\DSboxcommands
+\DSfrenchspacing
+\DSauxiliaryspace
+\DSparagraphs
+\DSlinks
+\DSlate
+
+\makeatother
diff --git a/tools/stylesheets/pep.css b/tools/stylesheets/pep.css
new file mode 100644
index 000000000..a82045bc9
--- /dev/null
+++ b/tools/stylesheets/pep.css
@@ -0,0 +1,240 @@
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:date: $Date$
+:version: $Revision$
+:copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the PEP HTML output of Docutils.
+*/
+
+.first {
+ margin-top: 0 }
+
+.last {
+ margin-bottom: 0 }
+
+.navigation {
+ width: 100% ;
+ background: #99ccff ;
+ margin-top: 0px ;
+ margin-bottom: 0px }
+
+.navigation .navicon {
+ width: 150px ;
+ height: 35px }
+
+.navigation .textlinks {
+ padding-left: 1em ;
+ text-align: left }
+
+.navigation td, .navigation th {
+ padding-left: 0em ;
+ padding-right: 0em ;
+ vertical-align: middle }
+
+.rfc2822 {
+ margin-top: 0.5em ;
+ margin-left: 0.5em ;
+ margin-right: 0.5em ;
+ margin-bottom: 0em }
+
+.rfc2822 td {
+ text-align: left }
+
+.rfc2822 th.field-name {
+ text-align: right ;
+ font-family: sans-serif ;
+ padding-right: 0.5em ;
+ font-weight: bold ;
+ margin-bottom: 0em }
+
+a.toc-backref {
+ text-decoration: none ;
+ color: black }
+
+body {
+ margin: 0px ;
+ margin-bottom: 1em ;
+ padding: 0px }
+
+dd {
+ margin-bottom: 0.5em }
+
+div.section {
+ margin-left: 1em ;
+ margin-right: 1em ;
+ margin-bottom: 1.5em }
+
+div.section div.section {
+ margin-left: 0em ;
+ margin-right: 0em ;
+ margin-top: 1.5em }
+
+div.abstract {
+ margin: 2em 5em }
+
+div.abstract p.topic-title {
+ font-weight: bold ;
+ text-align: center }
+
+div.attention, div.caution, div.danger, div.error, div.hint,
+div.important, div.note, div.tip, div.warning {
+ margin: 2em ;
+ border: medium outset ;
+ padding: 1em }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+ color: red ;
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.hint p.admonition-title, div.important p.admonition-title,
+div.note p.admonition-title, div.tip p.admonition-title {
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.figure {
+ margin-left: 2em }
+
+div.footer, div.header {
+ font-size: smaller }
+
+div.footer {
+ margin-left: 1em ;
+ margin-right: 1em }
+
+div.system-messages {
+ margin: 5em }
+
+div.system-messages h1 {
+ color: red }
+
+div.system-message {
+ border: medium outset ;
+ padding: 1em }
+
+div.system-message p.system-message-title {
+ color: red ;
+ font-weight: bold }
+
+div.topic {
+ margin: 2em }
+
+h1 {
+ font-family: sans-serif ;
+ font-size: large }
+
+h2 {
+ font-family: sans-serif ;
+ font-size: medium }
+
+h3 {
+ font-family: sans-serif ;
+ font-size: small }
+
+h4 {
+ font-family: sans-serif ;
+ font-style: italic ;
+ font-size: small }
+
+h5 {
+ font-family: sans-serif;
+ font-size: x-small }
+
+h6 {
+ font-family: sans-serif;
+ font-style: italic ;
+ font-size: x-small }
+
+.section hr {
+ width: 75% }
+
+ol.simple, ul.simple {
+ margin-bottom: 1em }
+
+ol.arabic {
+ list-style: decimal }
+
+ol.loweralpha {
+ list-style: lower-alpha }
+
+ol.upperalpha {
+ list-style: upper-alpha }
+
+ol.lowerroman {
+ list-style: lower-roman }
+
+ol.upperroman {
+ list-style: upper-roman }
+
+p.caption {
+ font-style: italic }
+
+p.credits {
+ font-style: italic ;
+ font-size: smaller }
+
+p.label {
+ white-space: nowrap }
+
+p.topic-title {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+pre.line-block {
+ font-family: serif ;
+ font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+ margin-left: 2em ;
+ margin-right: 2em ;
+ background-color: #eeeeee }
+
+span.classifier {
+ font-family: sans-serif ;
+ font-style: oblique }
+
+span.classifier-delimiter {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+span.interpreted {
+ font-family: sans-serif }
+
+span.option-argument {
+ font-style: italic }
+
+span.pre {
+ white-space: pre }
+
+span.problematic {
+ color: red }
+
+table {
+ margin-top: 0.5em ;
+ margin-bottom: 0.5em }
+
+td, th {
+ padding-left: 0.5em ;
+ padding-right: 0.5em ;
+ vertical-align: top }
+
+td.num {
+ text-align: right }
+
+th.field-name {
+ font-weight: bold ;
+ text-align: left ;
+ white-space: nowrap }
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+ font-size: 100% }
+
+tt {
+ background-color: #eeeeee }
+
+ul.auto-toc {
+ list-style-type: none }
diff --git a/tools/stylesheets/style.tex b/tools/stylesheets/style.tex
new file mode 100644
index 000000000..6e041a14b
--- /dev/null
+++ b/tools/stylesheets/style.tex
@@ -0,0 +1,74 @@
+% latex include file for docutils latex writer
+% --------------------------------------------
+%
+% CVS: $Id$
+%
+% This is included at the end of the latex header in the generated file,
+% to allow overwriting defaults, although this could get hairy.
+% Generated files should process well standalone too, LaTeX might give a
+% message about a missing file.
+
+% donot indent first line of paragraph.
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{5pt plus 2pt minus 1pt}
+
+% sloppy
+% ------
+% Less strict (opposite to default fussy) space size between words. Therefore
+% less hyphenation.
+\sloppy
+
+% fonts
+% -----
+% times for pdf generation, gives smaller pdf files.
+%
+% But in standard postscript fonts: courier and times/helvetica do not fit.
+% Maybe use pslatex.
+\usepackage{times}
+
+% pagestyle
+% ---------
+% headings might put section titles in the page heading, but not if
+% the table of contents is done by docutils.
+% If pagestyle{headings} is used, \geometry{headheight=10pt,headsep=1pt}
+% should be set too.
+%\pagestyle{plain}
+%
+% or use fancyhdr (untested !)
+%\usepackage{fancyhdr}
+%\pagestyle{fancy}
+%\addtolength{\headheight}{\\baselineskip}
+%\renewcommand{\sectionmark}[1]{\markboth{#1}{}}
+%\renewcommand{\subsectionmark}[1]{\markright{#1}}
+%\fancyhf{}
+%\fancyhead[LE,RO]{\\bfseries\\textsf{\Large\\thepage}}
+%\fancyhead[LO]{\\textsf{\\footnotesize\\rightmark}}
+%\fancyhead[RE]{\\textsc{\\textsf{\\footnotesize\leftmark}}}
+%\\fancyfoot[LE,RO]{\\bfseries\\textsf{\scriptsize Docutils}}
+%\fancyfoot[RE,LO]{\\textsf{\scriptsize\\today}}
+
+% geometry
+% --------
+% = papersizes and margins
+%\geometry{a4paper,twoside,tmargin=1.5cm,
+% headheight=1cm,headsep=0.75cm}
+
+% Do section number display
+% -------------------------
+%\makeatletter
+%\def\@seccntformat#1{}
+%\makeatother
+% no numbers in toc
+%\renewcommand{\numberline}[1]{}
+
+
+% change maketitle
+% ----------------
+%\renewcommand{\maketitle}{
+% \begin{titlepage}
+% \begin{center}
+% \textsf{TITLE \@title} \\
+% Date: \today
+% \end{center}
+% \end{titlepage}
+%}
diff --git a/tools/unicode2rstsubs.py b/tools/unicode2rstsubs.py
new file mode 100755
index 000000000..d5e259863
--- /dev/null
+++ b/tools/unicode2rstsubs.py
@@ -0,0 +1,195 @@
+#! /usr/bin/env python
+
+# Author: David Goodger
+# Contact: goodger@users.sourceforge.net
+# Revision: $Revision$
+# Date: $Date$
+# Copyright: This program has been placed in the public domain.
+
+"""
+unicode2subfiles.py -- produce character entity files (reSructuredText
+substitutions) from the MathML master unicode.xml file.
+
+This program extracts character entity and entity set information from a
+unicode.xml file and produces multiple reStructuredText files (in the current
+directory) containing substitutions. Entity sets are from ISO 8879 & ISO
+9573-13 (combined), MathML, and HTML4. One or two files are produced for each
+entity set; a second file with a "-wide.txt" suffix is produced if there are
+wide-Unicode characters in the set.
+
+The input file, unicode.xml, is maintained as part of the MathML 2
+Recommentation XML source, and is available at
+<http://www.w3.org/Math/characters/unicode.xml> (as of 2003-06-22).
+"""
+
+import sys
+import os
+import optparse
+import re
+from xml.parsers.expat import ParserCreate
+
+
+usage_msg = """Usage: %s [unicode.xml]"""
+
+def usage(prog, status=0, msg=None):
+ print >>sys.stderr, usage_msg % prog
+ if msg:
+ print >>sys.stderr, msg
+ sys.exit(status)
+
+def main(argv=None):
+ if argv is None:
+ argv = sys.argv
+ if len(argv) == 2:
+ inpath = argv[1]
+ elif len(argv) > 2:
+ usage(argv[0], 2,
+ 'Too many arguments (%s): only 1 expected.' % (len(argv) - 1))
+ else:
+ inpath = 'unicode.xml'
+ if not os.path.isfile(inpath):
+ usage(argv[0], 1, 'No such file: "%s".' % inpath)
+ infile = open(inpath)
+ process(infile)
+
+def process(infile):
+ grouper = CharacterEntitySetExtractor(infile)
+ grouper.group()
+ grouper.write_sets()
+
+
+class CharacterEntitySetExtractor:
+
+ """
+ Extracts character entity information from unicode.xml file, groups it by
+ entity set, and writes out reStructuredText substitution files.
+ """
+
+ unwanted_entity_sets = ['stix', # unknown, buggy set
+ 'predefined']
+
+ def __init__(self, infile):
+ self.infile = infile
+ """Input unicode.xml file."""
+
+ self.parser = self.setup_parser()
+ """XML parser."""
+
+ self.elements = []
+ """Stack of element names. Last is current element."""
+
+ self.sets = {}
+ """Mapping of charent set name to set dict."""
+
+ self.charid = None
+ """Current character's "id" attribute value."""
+
+ self.descriptions = {}
+ """Mapping of character ID to description."""
+
+ def setup_parser(self):
+ parser = ParserCreate()
+ parser.StartElementHandler = self.StartElementHandler
+ parser.EndElementHandler = self.EndElementHandler
+ parser.CharacterDataHandler = self.CharacterDataHandler
+ return parser
+
+ def group(self):
+ self.parser.ParseFile(self.infile)
+
+ def StartElementHandler(self, name, attributes):
+ self.elements.append(name)
+ handler = name + '_start'
+ if hasattr(self, handler):
+ getattr(self, handler)(name, attributes)
+
+ def EndElementHandler(self, name):
+ assert self.elements[-1] == name, \
+ 'unknown end-tag %r (%r)' % (name, self.element)
+ self.elements.pop()
+ handler = name + '_end'
+ if hasattr(self, handler):
+ getattr(self, handler)(name)
+
+ def CharacterDataHandler(self, data):
+ handler = self.elements[-1] + '_data'
+ if hasattr(self, handler):
+ getattr(self, handler)(data)
+
+ def character_start(self, name, attributes):
+ self.charid = attributes['id']
+
+ def entity_start(self, name, attributes):
+ set = self.entity_set_name(attributes['set'])
+ if not set:
+ return
+ if not self.sets.has_key(set):
+ print 'bad set: %r' % set
+ return
+ entity = attributes['id']
+ assert (not self.sets[set].has_key(entity)
+ or self.sets[set][entity] == self.charid), \
+ ('sets[%r][%r] == %r (!= %r)'
+ % (set, entity, self.sets[set][entity], self.charid))
+ self.sets[set][entity] = self.charid
+
+ def description_data(self, data):
+ self.descriptions.setdefault(self.charid, '')
+ self.descriptions[self.charid] += data
+
+ entity_set_name_pat = re.compile(r'[0-9-]*(.+)$')
+ """Pattern to strip ISO numbers off the beginning of set names."""
+
+ def entity_set_name(self, name):
+ """
+ Return lowcased and standard-number-free entity set name.
+ Return ``None`` for unwanted entity sets.
+ """
+ match = self.entity_set_name_pat.match(name)
+ name = match.group(1).lower()
+ if name in self.unwanted_entity_sets:
+ return None
+ self.sets.setdefault(name, {})
+ return name
+
+ def write_sets(self):
+ sets = self.sets.keys()
+ sets.sort()
+ for set_name in sets:
+ self.write_set(set_name)
+
+ def write_set(self, set_name, wide=None):
+ if wide:
+ outname = set_name + '-wide.txt'
+ else:
+ outname = set_name + '.txt'
+ outfile = open(outname, 'w')
+ print 'writing file "%s"' % outname
+ set = self.sets[set_name]
+ entities = [(e.lower(), e) for e in set.keys()]
+ entities.sort()
+ longest = 0
+ for _, entity_name in entities:
+ longest = max(longest, len(entity_name))
+ has_wide = None
+ for _, entity_name in entities:
+ has_wide = self.write_entity(
+ set, set_name, entity_name, outfile, longest, wide) or has_wide
+ if has_wide and not wide:
+ self.write_set(set_name, 1)
+
+ def write_entity(self, set, set_name, entity_name, outfile, longest,
+ wide=None):
+ charid = set[entity_name]
+ if not wide:
+ for code in charid[1:].split('-'):
+ if int(code, 16) > 0xFFFF:
+ return 1 # wide-Unicode character
+ codes = ' '.join(['U+%s' % code for code in charid[1:].split('-')])
+ print >>outfile, ('.. %-*s unicode:: %s .. %s'
+ % (longest + 2, '|' + entity_name + '|',
+ codes, self.descriptions[charid]))
+
+
+if __name__ == '__main__':
+ sys.exit(main())