1.1 --- a/moinformat/macros/toc.py Mon Aug 13 17:55:16 2018 +0200
1.2 +++ b/moinformat/macros/toc.py Mon Aug 13 22:52:54 2018 +0200
1.3 @@ -20,7 +20,28 @@
1.4 """
1.5
1.6 from moinformat.macros.common import Macro
1.7 -from moinformat.tree.moin import Container, Heading, Link, List, ListItem, Text
1.8 +from moinformat.tree.moin import Block, Container, Heading, Link, List, \
1.9 + ListItem, Text
1.10 +
1.11 +def in_range(min_level, level, max_level):
1.12 +
1.13 + """
1.14 + Test that 'min_level' <= 'level' <= 'max_level', only imposing tests
1.15 + involving limits not set to None.
1.16 + """
1.17 +
1.18 + return (min_level is None or min_level <= level) and \
1.19 + (max_level is None or level <= max_level)
1.20 +
1.21 +def above_minimum(min_level, level, max_level):
1.22 +
1.23 + """
1.24 + Test that 'min_level' < 'level' <= 'max_level', only imposing tests
1.25 + involving limits not set to None.
1.26 + """
1.27 +
1.28 + return (min_level is None or min_level < level) and \
1.29 + (max_level is None or level <= max_level)
1.30
1.31 class TableOfContents(Macro):
1.32
1.33 @@ -81,7 +102,7 @@
1.34
1.35 # Ignore levels outside the range of interest.
1.36
1.37 - if not (min_level <= level <= max_level):
1.38 + if not in_range(min_level, level, max_level):
1.39 continue
1.40
1.41 # Determine whether the heading should be generated at this
1.42 @@ -133,7 +154,7 @@
1.43
1.44 # Retain a list at the minimum level.
1.45
1.46 - if min_level < level <= max_level:
1.47 + if above_minimum(min_level, level, max_level):
1.48 lists.pop()
1.49
1.50 level -= 1
1.51 @@ -145,17 +166,52 @@
1.52
1.53 # Add the heading as an item.
1.54
1.55 - if min_level <= level <= max_level:
1.56 + if in_range(min_level, level, max_level):
1.57 +
1.58 indent = level - 1
1.59 nodes = self.get_entry(heading)
1.60
1.61 item = ListItem(nodes, indent, marker, space, None)
1.62 items.append(item)
1.63
1.64 - # Replace the macro node's children with the top-level list.
1.65 - # The macro cannot be replaced because it will be appearing inline.
1.66 + # Replace the macro node with the top-level list.
1.67 +
1.68 + self.insert_table(lists[0])
1.69 +
1.70 + def insert_table(self, content):
1.71 +
1.72 + "Insert the given 'content' into the document."
1.73 +
1.74 + macro = self.node
1.75 + parent = macro.parent
1.76 + region = macro.region
1.77 +
1.78 + # Replace the macro if it is not inside a block.
1.79 + # NOTE: This attempts to avoid blocks being used in inline-only contexts
1.80 + # NOTE: but may not be successful in every case.
1.81 +
1.82 + if not isinstance(parent, Block) or parent is region:
1.83 + parent.replace(macro, content)
1.84
1.85 - self.node.nodes = lists and [lists[0]] or []
1.86 + # Split any block containing the macro into preceding and following
1.87 + # parts.
1.88 +
1.89 + else:
1.90 + following = parent.split_at(macro)
1.91 +
1.92 + # Insert any non-empty following block.
1.93 +
1.94 + if not following.whitespace_only():
1.95 + region.insert_after(parent, following)
1.96 +
1.97 + # Insert the new content.
1.98 +
1.99 + region.insert_after(parent, content)
1.100 +
1.101 + # Remove any empty preceding block.
1.102 +
1.103 + if parent.whitespace_only():
1.104 + region.remove(parent)
1.105
1.106 def find_headings(self, node, headings):
1.107