1.1 --- a/moinformat/__init__.py Sat Apr 29 18:20:55 2017 +0200
1.2 +++ b/moinformat/__init__.py Sat Apr 29 23:04:30 2017 +0200
1.3 @@ -19,31 +19,39 @@
1.4 this program. If not, see <http://www.gnu.org/licenses/>.
1.5 """
1.6
1.7 -from moinformat.tree import Block, ListItem, Region, Rule, Text
1.8 +from moinformat.tree import Block, Heading, ListItem, Region, Rule, Text
1.9 import re
1.10
1.11 # Regular expressions.
1.12
1.13 syntax = {
1.14 # Page regions:
1.15 - "regionstart" : (r"((^\s*)([{]{3,}))", re.MULTILINE | re.DOTALL), # {{{...
1.16 - "regionend" : (r"^\s*([}]{3,})", re.MULTILINE | re.DOTALL), # }}}...
1.17 - "header" : (r"#!(.*?)\n", 0), # #! char-excl-nl
1.18 + "regionstart" : r"((^\s*)([{]{3,}))", # {{{...
1.19 + "regionend" : r"^\s*([}]{3,})", # }}}...
1.20 + "header" : r"#!(.*?)\n", # #! char-excl-nl
1.21
1.22 # Region contents:
1.23 - "break" : (r"^(\s*?)\n", re.MULTILINE), # blank line
1.24 - "listitem" : (r"^((\s+)([*]|\d+[.]))", re.MULTILINE), # indent (list-item or number-item)
1.25 - "rule" : (r"(-----*)", 0), # ----...
1.26 + # Line-oriented patterns:
1.27 + "break" : r"^(\s*?)\n", # blank line
1.28 + "heading" : r"^(\s*)(?P<x>=+)(\s+)(?=.*?\s+(?P=x)\s*\n)", # [ws...] =... ws... expecting headingend
1.29 + "listitem" : r"^((\s+)([*]|\d+[.]))", # indent (list-item or number-item)
1.30 +
1.31 + # Region contents:
1.32 + # Inline patterns:
1.33 + "rule" : r"(-----*)", # ----...
1.34 +
1.35 + # Heading contents:
1.36 + "headingend" : r"(\s+)(=+)(\s*\n)", # ws... =... [ws...] nl
1.37
1.38 # List contents:
1.39 - "listitemend" : (r"^", re.MULTILINE), # next line
1.40 + "listitemend" : r"^", # next line
1.41 }
1.42
1.43 # Define patterns for the regular expressions.
1.44
1.45 patterns = {}
1.46 -for name, (value, flags) in syntax.items():
1.47 - patterns[name] = re.compile(value, re.UNICODE | flags)
1.48 +for name, value in syntax.items():
1.49 + patterns[name] = re.compile(value, re.UNICODE | re.MULTILINE)
1.50
1.51
1.52
1.53 @@ -156,7 +164,7 @@
1.54 "Parse the data provided by 'items' to populate a wiki 'region'."
1.55
1.56 new_block(region)
1.57 - parse_region_details(items, region, ["break", "listitem", "regionstart", "regionend", "rule"])
1.58 + parse_region_details(items, region, ["break", "heading", "listitem", "regionstart", "regionend", "rule"])
1.59
1.60 def parse_region_opaque(items, region):
1.61
1.62 @@ -215,11 +223,27 @@
1.63 block.final = False
1.64 new_block(region)
1.65
1.66 -def parse_listitem_end(items, region):
1.67 +def parse_heading(items, region):
1.68 +
1.69 + "Handle a heading."
1.70
1.71 - "Handle the end of a list."
1.72 + start_extra = items.read_match(1)
1.73 + level = len(items.read_match(2))
1.74 + start_pad = items.read_match(3)
1.75 + heading = Heading([], level, start_extra, start_pad)
1.76 + parse_region_details(items, heading, ["headingend"])
1.77 + region.append(heading)
1.78 + new_block(region)
1.79
1.80 - raise StopIteration
1.81 +def parse_heading_end(items, heading):
1.82 +
1.83 + "Handle the end of a heading."
1.84 +
1.85 + level = len(items.read_match(2))
1.86 + if heading.level == level:
1.87 + heading.end_pad = items.read_match(1)
1.88 + heading.end_extra = items.read_match(3)
1.89 + raise StopIteration
1.90
1.91 def parse_listitem(items, region):
1.92
1.93 @@ -230,6 +254,12 @@
1.94 region.append(item)
1.95 new_block(region)
1.96
1.97 +def parse_listitem_end(items, item):
1.98 +
1.99 + "Handle the end of a list."
1.100 +
1.101 + raise StopIteration
1.102 +
1.103 def parse_rule(items, region):
1.104
1.105 "Handle a horizontal rule within 'region'."
1.106 @@ -265,6 +295,8 @@
1.107 handlers = {
1.108 None : end_region,
1.109 "break" : parse_break,
1.110 + "heading" : parse_heading,
1.111 + "headingend" : parse_heading_end,
1.112 "listitemend" : parse_listitem_end,
1.113 "listitem" : parse_listitem,
1.114 "regionstart" : parse_section,