diff options
Diffstat (limited to 'tools')
| -rwxr-xr-x | tools/buildhtml.py | 226 | ||||
| -rw-r--r-- | tools/docutils.conf | 16 | ||||
| -rw-r--r-- | tools/editors/README.txt | 19 | ||||
| -rw-r--r-- | tools/editors/emacs/README.txt | 91 | ||||
| -rw-r--r-- | tools/editors/emacs/docutils.conf | 2 | ||||
| -rw-r--r-- | tools/editors/emacs/restructuredtext.el | 596 | ||||
| -rw-r--r-- | tools/editors/emacs/rst-html.el | 129 | ||||
| -rw-r--r-- | tools/editors/emacs/rst-mode.el | 700 | ||||
| -rw-r--r-- | tools/editors/emacs/tests/tests-adjust-section.el | 240 | ||||
| -rw-r--r-- | tools/pep-html-template | 27 | ||||
| -rwxr-xr-x | tools/pep.py | 27 | ||||
| -rwxr-xr-x | tools/quicktest.py | 211 | ||||
| -rwxr-xr-x | tools/rst2html.py | 25 | ||||
| -rwxr-xr-x | tools/rst2latex.py | 25 | ||||
| -rwxr-xr-x | tools/rst2newlatex.py | 27 | ||||
| -rwxr-xr-x | tools/rst2pseudoxml.py | 25 | ||||
| -rwxr-xr-x | tools/rst2xml.py | 25 | ||||
| -rw-r--r-- | tools/stylesheets/default.css | 263 | ||||
| -rw-r--r-- | tools/stylesheets/latex-notes.txt | 40 | ||||
| -rw-r--r-- | tools/stylesheets/latex.tex | 970 | ||||
| -rw-r--r-- | tools/stylesheets/pep.css | 240 | ||||
| -rw-r--r-- | tools/stylesheets/style.tex | 74 | ||||
| -rwxr-xr-x | tools/unicode2rstsubs.py | 195 |
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]{% + % +} +% \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()) |
