1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - MoinContentSupport library 4 5 @copyright: 2008, 2009, 2010, 2011 by Paul Boddie <paul@boddie.org.uk> 6 @copyright: 2000-2004 Juergen Hermann <jh@web.de>, 7 2005-2008 MoinMoin:ThomasWaldmann. 8 @license: GNU GPL (v2 or later), see COPYING.txt for details. 9 """ 10 11 from MoinMoin.wikiutil import escape 12 import re 13 14 __version__ = "0.1" 15 16 # Regular expressions. 17 # NOTE: These overlap with ImprovedMoinSearch and EventAggregator. 18 19 heading_regexp_str = r"^(?P<level>=+)\s*(?P<heading>.*?)\s*(?P=level)$" 20 hrule_regexp_str = r"^----$" 21 include_regexp_str = r"^\s*<<Include.*?>>$" 22 section_regexp_str = "(" + heading_regexp_str + "|" + hrule_regexp_str + "|" + include_regexp_str + ")" 23 section_regexp = re.compile(section_regexp_str, re.UNICODE | re.MULTILINE) 24 25 category_membership_str = ur"^\s*(?:(Category\S+)(?:\s+(Category\S+))*)\s*$" 26 category_membership_regexp = re.compile(category_membership_str, re.MULTILINE | re.UNICODE) 27 category_declarations_regexp = re.compile("^----$\s*" + category_membership_str, re.MULTILINE | re.UNICODE) 28 29 def getSectionDetails(body, min_level=None, max_level=None): 30 31 """ 32 Return section details from the given 'body' for headings with the given 33 'min_level' to 'max_level' range. Specifying None or omitting 'max_level' or 34 'min_level' removes the appropriate constraint on the range. 35 36 A list of tuples is returned for each section divider. For headings, the 37 heading text and level number are returned as the first and second elements 38 of each tuple, whereas other section dividers (typically indicating the end 39 of a section) employ None as the first and second elements. The span (start 40 offset and end offset of the divider) is provided as a tuple in the third 41 element of each result tuple. 42 """ 43 44 headings = [] 45 46 for match in section_regexp.finditer(body): 47 level = match.group("level") 48 level = level and len(match.group("level")) 49 50 if (min_level is None or min_level <= level) and \ 51 (max_level is None or level <= max_level) or \ 52 level is None: 53 54 headings.append((match.group("heading"), level, match.span())) 55 56 return headings 57 58 def getCategoryMembership(body): 59 60 "From the given 'body', return the categories the page belongs to." 61 62 match = category_membership_regexp.search(body) 63 if match: 64 return [x for x in match.groups() if x] 65 else: 66 return [] 67 68 def getCategoryDeclarations(body): 69 70 """ 71 From the given 'body', return the category declaration sections in the page 72 in the form of a list of tuples, each containing a list of categories, the 73 start of the declaration region and the end of the region. 74 """ 75 76 return [([x for x in match.groups() if x], match.span()) for match in category_declarations_regexp.finditer(body)] 77 78 def makeCategoryDeclaration(categories): 79 80 "Return a category declaration string for the given 'categories'." 81 82 return "\n----\n%s\n" % " ".join(categories) 83 84 # Utility classes and associated functions. 85 # NOTE: These are a subset of EventAggregatorSupport. 86 87 class Form: 88 89 """ 90 A wrapper preserving MoinMoin 1.8.x (and earlier) behaviour in a 1.9.x 91 environment. 92 """ 93 94 def __init__(self, form): 95 self.form = form 96 97 def get(self, name, default=None): 98 values = self.form.getlist(name) 99 if not values: 100 return default 101 else: 102 return values 103 104 def __getitem__(self, name): 105 return self.form.getlist(name) 106 107 class ActionSupport: 108 109 """ 110 Work around disruptive MoinMoin changes in 1.9, and also provide useful 111 convenience methods. 112 """ 113 114 def get_form(self): 115 return get_form(self.request) 116 117 def get_form(request): 118 119 "Work around disruptive MoinMoin changes in 1.9." 120 121 if hasattr(request, "values"): 122 return Form(request.values) 123 else: 124 return request.form 125 126 class send_headers: 127 128 """ 129 A wrapper to preserve MoinMoin 1.8.x (and earlier) request behaviour in a 130 1.9.x environment. 131 """ 132 133 def __init__(self, request): 134 self.request = request 135 136 def __call__(self, headers): 137 for header in headers: 138 parts = header.split(":") 139 self.request.headers.add(parts[0], ":".join(parts[1:])) 140 141 def escattr(s): 142 return escape(s, 1) 143 144 # vim: tabstop=4 expandtab shiftwidth=4