summaryrefslogtreecommitdiff
path: root/sandbox/rstdiff/rstdiff.py
diff options
context:
space:
mode:
authorsmerten <smerten@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2010-08-08 12:29:52 +0000
committersmerten <smerten@929543f6-e4f2-0310-98a6-ba3bd3dd1d04>2010-08-08 12:29:52 +0000
commitba4faf80bd15cd44a9ed6640baca351abe2b8b71 (patch)
tree0ef71dbdfeddfef105d072fffb942f3b0578c464 /sandbox/rstdiff/rstdiff.py
parente0e71bacc99f67b84839bd544747acb660fce4ce (diff)
downloaddocutils-ba4faf80bd15cd44a9ed6640baca351abe2b8b71.tar.gz
Once only elements no longer propagate their changes up. Though this
is correct this leads to sections not being replaced as a whole any more. git-svn-id: http://svn.code.sf.net/p/docutils/code/trunk@6384 929543f6-e4f2-0310-98a6-ba3bd3dd1d04
Diffstat (limited to 'sandbox/rstdiff/rstdiff.py')
-rwxr-xr-xsandbox/rstdiff/rstdiff.py115
1 files changed, 87 insertions, 28 deletions
diff --git a/sandbox/rstdiff/rstdiff.py b/sandbox/rstdiff/rstdiff.py
index 835d33ada..61b6c4f5a 100755
--- a/sandbox/rstdiff/rstdiff.py
+++ b/sandbox/rstdiff/rstdiff.py
@@ -484,6 +484,10 @@ class DocutilsDispatcher(HashableNodeImpl):
for newChild in self.copyRange(srcRoot, srcRange, newType):
self.addChild(diffRoot, newChild)
elif command == Opcode.Replace:
+ # TODO Replacement doubles elements. This needs to be
+ # reflected by creation of unique @ids for replaced
+ # elements. This needs to be reflected in referring @refid
+ # and @backrefs.
for newChild in self.copyRange(oldRoot, oldRange,
self.NewReplaced):
self.addChild(diffRoot, newChild)
@@ -613,7 +617,7 @@ class DocutilsDispatcher(HashableNodeImpl):
def rootEq_enumerated_list(self, node, other):
return self.attributeEq_enumerated_list(node, other)
- def childEq_option_argument(self, node, other):
+ def childEq_enumerated_list(self, node, other):
return (self.attributeEq_enumerated_list(node, other)
and self.childrenEq(node, other))
@@ -695,26 +699,49 @@ class DocutilsDispatcher(HashableNodeImpl):
and self.childrenEq(node, other))
###########################################################################
+ # A change in certain elements must propagate the change up since
+ # they may occur only once. Must be done by parents.
- # TODO A change in certain elements must propagate the change up
- # or down since they may occur only once. These elements are
- # <title> (down), <subtitle> (down), <decoration> (down),
- # <docinfo> (down), <transition>, <header> (down), <footer>
- # (down), <info>, <term> (down), <definition> (down), <field_name>
- # (down), <field_body> (down), <option_group> (down),
- # <description> (down), <option_string> (up), <attribution>
- # (down), <label> (up), <caption> (down), <legend> (down),
- # <thead>, <tbody>, <entry> (down) (because otherwise the column
- # count is wrong)
- #
- # However, only those need to be considered which may have
- # replacing changes at all. Typically not the case for container
- # elements.
+ # Checks whether `node` and `other` have both a node of type
+ # `childClass` and whether the first of thosee are equal.
+ def rootEqWithChild(self, node, other, childClass):
+ if node.__class__ != other.__class__:
+ return False
+
+ nodeFound = None
+ for nodeChild in self.getChildren(node):
+ if isinstance(nodeChild, childClass):
+ nodeFound = nodeChild
+ break
+
+ otherFound = None
+ for otherChild in self.getChildren(other):
+ if isinstance(otherChild, childClass):
+ otherFound = otherChild
+ break
+
+ if nodeFound is None or otherFound is None:
+ return True
+
+ return self.childEq(nodeFound, otherFound)
+
+ ###########################################################################
+ # footnote
+
+ def rootEq_footnote(self, node, other):
+ return self.rootEqWithChild(node, other, nodes.label)
+
+ ###########################################################################
+ # citation
+
+ def rootEq_citation(self, node, other):
+ return self.rootEqWithChild(node, other, nodes.label)
+
+ ###########################################################################
+ # option
- # TODO Why are changes in text are propagated up? For instance
- # <entry><paragraph>+</paragraph></entry> =>
- # <entry><paragraph>++</paragraph></entry> becomes a change in the
- # <entry>!
+ def rootEq_option(self, node, other):
+ return self.rootEqWithChild(node, other, nodes.option_string)
###############################################################################
###############################################################################
@@ -791,16 +818,33 @@ def buildTree(dispatcher, diffRoot, opcodes, oldRoot, newRoot):
dispatcher.mergeChildren(diffRoot, oldRoot, newRoot,
command, oldRange, newRange)
-def cleanOpcodes(opcodes):
- """Replace some nasty results in `opcodes` by cleaner versions."""
+# A change in certain elements must not be propagated up since they
+# may occur only once
+replaceNotUp = ( nodes.title, nodes.subtitle, nodes.term, nodes.field_name,
+ nodes.attribution, nodes.caption, # (%text.model)
+ nodes.header, nodes.footer, nodes.definition,
+ nodes.field_body, nodes.description, nodes.legend,
+ nodes.entry, # (%body.elements;+) or (%body.elements;*)
+ nodes.decoration, nodes.docinfo, nodes.transition,
+ nodes.option_group, nodes.thead,
+ nodes.tbody, # different content model
+ )
+
+def cleanOpcodes(opcodes, dispatcher, oldList, newList):
+ """Replace some nasty results in `opcodes` by cleaner versions. Opcodes
+ create `newList` from `oldList`."""
for i in range(len(opcodes)):
opcode = Opcode(opcodes[i])
- subOpcodes = opcode.getSubOpcodes()
+ ( command, oldRange, newRange, subOpcodes,
+ ) = opcode.resolveOpcode(oldList, newList)
if not subOpcodes:
- # Nothing to clean for flat opcodes
+ # Nothing to clean for flat or empty opcodes
continue
- cleanOpcodes(subOpcodes)
+ oldNode = oldRange[0]
+ newNode = newRange[0]
+ cleanOpcodes(subOpcodes, dispatcher, dispatcher.getChildren(oldNode),
+ dispatcher.getChildren(newNode))
j = 1
while j < len(subOpcodes):
prev = Opcode(subOpcodes[j - 1])
@@ -820,9 +864,24 @@ def cleanOpcodes(opcodes):
opcode.setSubOpcodes(subOpcodes)
if len(subOpcodes) == 1:
subOpcode = Opcode(subOpcodes[0])
- if subOpcode.getCommand() != Opcode.Descend:
- # Propagate 1-element sequences up
- opcode.setCommand(subOpcode.getCommand())
+ if (subOpcode.getCommand() != Opcode.Replace
+ or not reduce(lambda last, cls:
+ last or isinstance(oldNode, cls),
+ replaceNotUp, False)):
+ # TODO If a section/title would propagate up the
+ # propagation needs to be done if all siblings would
+ # propagate, too; this way a section replacement
+ # should work again
+ #
+ # This applies to section/title, section/subtitle,
+ # definition_list_item/term, field/field_name,
+ # block_quote/attribution, figure/caption,
+ # definition_list_item/definition, field/field_body,
+ # option_list_item/description, figure/legend,
+ # option_list_item/option_group
+ if subOpcode.getCommand() != Opcode.Descend:
+ # Propagate 1-element sequences up
+ opcode.setCommand(subOpcode.getCommand())
opcodes[i] = opcode.asTuple()
def createDiff(oldTree, newTree):
@@ -836,7 +895,7 @@ def createDiff(oldTree, newTree):
print(newTree.asdom().toprettyxml())
pprint(opcodes, sys.stdout, 2, 40, None)
print("^^^ Before cleaning vvv After cleaning")
- cleanOpcodes(opcodes)
+ cleanOpcodes(opcodes, dispatcher, [ oldTree ], [ newTree ])
if dispatcher.debug:
from pprint import pprint
pprint(opcodes, sys.stdout, 2, 40, None)