1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - ImprovedMoinSearch library 4 5 @copyright: 2010 Paul Boddie <paul@boddie.org.uk> 6 @license: GNU GPL (v2 or later), see COPYING.txt for details. 7 """ 8 9 from MoinMoin.search import searchPages 10 from MoinMoin.Page import Page 11 from MoinMoin import wikiutil 12 import re 13 14 heading_regexp = re.compile(r"^(?P<level>=+)(?P<heading>.*?)(?P=level)$", re.UNICODE | re.MULTILINE) 15 paragraph_regexp = re.compile(r"(?P<paragraph>(?:^[^#=\s].*$\n)+)", re.UNICODE | re.MULTILINE) 16 17 def range_groups(min_name, max_name): 18 return r"(?P<%s>\d+)?(?:\s*-\s*(?P<%s>\d+))?" % (min_name, max_name) 19 20 format_options_regexp = re.compile(r"(" 21 "(?P<heading>(heading|title|h)\s*" + range_groups("min_heading", "max_heading") + ")" 22 "|(?P<paragraph>(paragraph|para|p)\s*(?P<paragraph_number>\d+)?)" 23 ")", re.UNICODE) 24 25 def getSearchResultPages(request, query, **kw): 26 27 """ 28 Return matching pages using the given 'request' and search 'query'. Optional 29 keyword arguments are passed to the underlying search infrastructure. 30 """ 31 32 results = searchPages(request, query, **kw) 33 return results.hits 34 35 def getFirstPageHeading(request, page, min_level=None, max_level=None): 36 37 """ 38 Using the given 'request', return the first heading in the given 'page' 39 having a heading level of at least 'min_level' (which is undefined if not 40 specified) and at most 'max_level' (which is undefined if not specified). 41 """ 42 43 full_page = Page(request, page.page_name) 44 body = full_page.get_raw_body() 45 46 for match in heading_regexp.finditer(body): 47 level = len(match.group("level")) 48 49 if (min_level is None or level >= min_level) and \ 50 (max_level is None or level <= max_level): 51 52 return match.group("heading") 53 54 return None 55 56 def getParagraph(request, page, number=None): 57 58 full_page = Page(request, page.page_name) 59 body = full_page.get_raw_body() 60 61 for i, match in enumerate(paragraph_regexp.finditer(body)): 62 if number is None or i == number: 63 return match.group("paragraph") 64 65 return None 66 67 def getPageName(request, page): 68 return page.page_name 69 70 def formatResultPages(request, formatter, pages, paging, format, page_from=0): 71 72 """ 73 Using the given 'request' and 'formatter', return a formatted string showing 74 the result 'pages', providing paging controls when 'paging' is set to a true 75 value, and providing page details according to the given 'format'. 76 77 If the optional 'pages_from' parameter is set, the result pages from the 78 given result (specified within a range from 0 to the length of the 'pages' 79 collection) will be shown. 80 """ 81 82 actions = [] 83 84 if format: 85 for match in format_options_regexp.finditer(format): 86 if match.group("heading"): 87 actions.append((getFirstPageHeading, map(int_or_none, (match.group("min_heading"), match.group("max_heading"))))) 88 elif match.group("paragraph"): 89 actions.append((getParagraph, map(int_or_none, (match.group("paragraph_number"),)))) 90 else: 91 actions.append((getPageName, ())) 92 93 # Use paging only when there are enough results. 94 95 results_per_page = request.cfg.search_results_per_page 96 paging = paging and len(pages) > results_per_page 97 98 if paging: 99 pages_to_show = pages[page_from:page_from + results_per_page] 100 else: 101 pages_to_show = pages 102 103 # Prepare the output. 104 105 output = [] 106 output.append(formatter.number_list(on=1, start=page_from + 1)) 107 108 for page in pages_to_show: 109 output.append(formatter.listitem(on=1)) 110 111 first = 1 112 for action, args in actions: 113 if first: 114 output.append(formatter.pagelink(on=1, pagename=page.page_name)) 115 else: 116 output.append(" ") 117 118 text = action(request, page, *args) 119 output.append(formatter.text(text)) 120 121 if first: 122 output.append(formatter.pagelink(on=0)) 123 first = 0 124 125 output.append(formatter.listitem(on=0)) 126 127 output.append(formatter.number_list(on=0)) 128 129 # Show paging navigation. 130 131 if paging: 132 output.append(formatPagingNavigation(request, formatter, pages, page_from)) 133 134 return "".join(output) 135 136 def formatPagingNavigation(request, formatter, pages, page_from=0): 137 138 """ 139 Using the given 'request' and 'formatter', return a formatted string showing 140 the paging navigation for the result 'pages', according to the 'page_from' 141 indicator which provides the current position in the result set. 142 """ 143 144 page = formatter.page 145 pagename = page.page_name 146 _ = request.getText 147 148 output = [] 149 150 results_per_page = request.cfg.search_results_per_page 151 number_of_results = len(pages) 152 153 pages_total = number_of_results / results_per_page 154 pages_before = page_from / results_per_page 155 pages_after = ((number_of_results - page_from) / results_per_page) - 1 156 157 querydict = wikiutil.parseQueryString(request.query_string) 158 159 output.append(formatter.paragraph(on=1)) 160 output.append(formatter.text(_("Result pages:"))) 161 output.append(formatter.text(" ")) 162 163 n = 0 164 while n < pages_before: 165 output.append(formatter.pagelink(on=1, pagename=pagename, querystr=getPagingQueryString(querydict, n * results_per_page))) 166 output.append(formatter.text(str(n + 1))) 167 output.append(formatter.pagelink(on=0)) 168 output.append(formatter.text(" ")) 169 n += 1 170 171 output.append(formatter.text(str(n + 1))) 172 output.append(formatter.text(" ")) 173 n += 1 174 175 while n <= pages_total: 176 output.append(formatter.pagelink(on=1, pagename=pagename, querystr=getPagingQueryString(querydict, n * results_per_page))) 177 output.append(formatter.text(str(n + 1))) 178 output.append(formatter.pagelink(on=0)) 179 output.append(formatter.text(" ")) 180 n += 1 181 182 output.append(formatter.paragraph(on=0)) 183 184 return "".join(output) 185 186 def getPagingQueryString(querydict, page_from): 187 querydict["from"] = page_from 188 return wikiutil.makeQueryString(querydict) 189 190 def int_or_none(x): 191 if x is None: 192 return x 193 else: 194 return int(x) 195 196 # vim: tabstop=4 expandtab shiftwidth=4