You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
4.8 KiB
144 lines
4.8 KiB
# $Id: misc.py 6314 2010-04-26 10:04:17Z milde $ |
|
# Author: David Goodger <goodger@python.org> |
|
# Copyright: This module has been placed in the public domain. |
|
|
|
""" |
|
Miscellaneous transforms. |
|
""" |
|
|
|
__docformat__ = 'reStructuredText' |
|
|
|
from docutils import nodes |
|
from docutils.transforms import Transform, TransformError |
|
|
|
|
|
class CallBack(Transform): |
|
|
|
""" |
|
Inserts a callback into a document. The callback is called when the |
|
transform is applied, which is determined by its priority. |
|
|
|
For use with `nodes.pending` elements. Requires a ``details['callback']`` |
|
entry, a bound method or function which takes one parameter: the pending |
|
node. Other data can be stored in the ``details`` attribute or in the |
|
object hosting the callback method. |
|
""" |
|
|
|
default_priority = 990 |
|
|
|
def apply(self): |
|
pending = self.startnode |
|
pending.details['callback'](pending) |
|
pending.parent.remove(pending) |
|
|
|
|
|
class ClassAttribute(Transform): |
|
|
|
""" |
|
Move the "class" attribute specified in the "pending" node into the |
|
immediately following non-comment element. |
|
""" |
|
|
|
default_priority = 210 |
|
|
|
def apply(self): |
|
pending = self.startnode |
|
parent = pending.parent |
|
child = pending |
|
while parent: |
|
# Check for appropriate following siblings: |
|
for index in range(parent.index(child) + 1, len(parent)): |
|
element = parent[index] |
|
if (isinstance(element, nodes.Invisible) or |
|
isinstance(element, nodes.system_message)): |
|
continue |
|
element['classes'] += pending.details['class'] |
|
pending.parent.remove(pending) |
|
return |
|
else: |
|
# At end of section or container; apply to sibling |
|
child = parent |
|
parent = parent.parent |
|
error = self.document.reporter.error( |
|
'No suitable element following "%s" directive' |
|
% pending.details['directive'], |
|
nodes.literal_block(pending.rawsource, pending.rawsource), |
|
line=pending.line) |
|
pending.replace_self(error) |
|
|
|
|
|
class Transitions(Transform): |
|
|
|
""" |
|
Move transitions at the end of sections up the tree. Complain |
|
on transitions after a title, at the beginning or end of the |
|
document, and after another transition. |
|
|
|
For example, transform this:: |
|
|
|
<section> |
|
... |
|
<transition> |
|
<section> |
|
... |
|
|
|
into this:: |
|
|
|
<section> |
|
... |
|
<transition> |
|
<section> |
|
... |
|
""" |
|
|
|
default_priority = 830 |
|
|
|
def apply(self): |
|
for node in self.document.traverse(nodes.transition): |
|
self.visit_transition(node) |
|
|
|
def visit_transition(self, node): |
|
index = node.parent.index(node) |
|
error = None |
|
if (index == 0 or |
|
isinstance(node.parent[0], nodes.title) and |
|
(index == 1 or |
|
isinstance(node.parent[1], nodes.subtitle) and |
|
index == 2)): |
|
assert (isinstance(node.parent, nodes.document) or |
|
isinstance(node.parent, nodes.section)) |
|
error = self.document.reporter.error( |
|
'Document or section may not begin with a transition.', |
|
source=node.source, line=node.line) |
|
elif isinstance(node.parent[index - 1], nodes.transition): |
|
error = self.document.reporter.error( |
|
'At least one body element must separate transitions; ' |
|
'adjacent transitions are not allowed.', |
|
source=node.source, line=node.line) |
|
if error: |
|
# Insert before node and update index. |
|
node.parent.insert(index, error) |
|
index += 1 |
|
assert index < len(node.parent) |
|
if index != len(node.parent) - 1: |
|
# No need to move the node. |
|
return |
|
# Node behind which the transition is to be moved. |
|
sibling = node |
|
# While sibling is the last node of its parent. |
|
while index == len(sibling.parent) - 1: |
|
sibling = sibling.parent |
|
# If sibling is the whole document (i.e. it has no parent). |
|
if sibling.parent is None: |
|
# Transition at the end of document. Do not move the |
|
# transition up, and place an error behind. |
|
error = self.document.reporter.error( |
|
'Document may not end with a transition.', |
|
line=node.line) |
|
node.parent.insert(node.parent.index(node) + 1, error) |
|
return |
|
index = sibling.parent.index(sibling) |
|
# Remove the original transition node. |
|
node.parent.remove(node) |
|
# Insert the transition after the sibling. |
|
sibling.parent.insert(index + 1, node)
|
|
|