Attachment 'multisearch.diff'
Download 1 diff -Nur trunk-orig/moin/MoinMoin/Page.py test/moin/MoinMoin/Page.py
2 --- trunk-orig/moin/MoinMoin/Page.py Sun Mar 16 22:17:53 2003
3 +++ test/moin/MoinMoin/Page.py Sun Apr 13 21:55:02 2003
4 @@ -234,6 +234,7 @@
5 print_mode = request.form.has_key('action') and request.form['action'].value == 'print'
6 content_only = keywords.get('content_only', 0)
7 self.hilite_re = keywords.get('hilite_re', None)
8 + self.hilite_words_re = keywords.get('hilite_words_re', None)
9 if msg is None: msg = ""
10
11 # count hit?
12 diff -Nur trunk-orig/moin/MoinMoin/macro/MultiSearch.py test/moin/MoinMoin/macro/MultiSearch.py
13 --- trunk-orig/moin/MoinMoin/macro/MultiSearch.py Thu Jan 1 01:00:00 1970
14 +++ test/moin/MoinMoin/macro/MultiSearch.py Mon Apr 14 03:01:03 2003
15 @@ -0,0 +1,61 @@
16 +"""
17 + MoinMoin - MultiSearch Macro
18 +
19 + Copyright (c) 2003 Ronny Buchmann <ronny-vlug@vlugnet.org>
20 + Modified by ThomasWaldmann
21 + All rights reserved, see COPYING for details.
22 +
23 + based on FullSearch.py
24 + Copyright (c) 2000, 2001, 2002 by Jürgen Hermann <jh@web.de>
25 +
26 + [[MultiSearch]]
27 + displays a search dialog, as it always did
28 +
29 + [[MultiSearch('HelpContents')]]
30 + embeds a search result into a page, as if you entered
31 + "HelpContents" into the search dialog
32 +
33 + $Id: $
34 +"""
35 +
36 +# Imports
37 +import re, urllib
38 +from MoinMoin import config, user, wikiutil
39 +
40 +_args_re_pattern = r'((?P<hquote>[\'"])(?P<htext>.+?)(?P=hquote))|'
41 +
42 +
43 +def execute(macro, text, args_re=re.compile(_args_re_pattern)):
44 + _ = macro.request.getText
45 +
46 + # if no args given, invoke "classic" behavior
47 + if text is None:
48 + return macro._m_search("multisearch")
49 +
50 + # parse and check arguments
51 + args = args_re.match(text)
52 + if not args:
53 + return '<p><strong class="error">Invalid MultiSearch arguments "%s"!</strong></p>' % (text,)
54 +
55 + needle = args.group('htext')
56 + if not needle:
57 + return '<p><strong class="error">No argument given for MultiSearch!</strong></p>' % (text,)
58 +
59 + # do the search
60 + pagecount, hits = wikiutil.multisearchPages(needle, context=0)
61 +
62 + # generate the result
63 + result = macro.formatter.number_list(1)
64 + for (count, pagename, dummy) in hits:
65 + result = result + macro.formatter.listitem(1)
66 + result = result + wikiutil.link_tag('%s?action=highlight&value=%s&words=1' %
67 + (wikiutil.quoteWikiname(pagename), urllib.quote_plus(needle)),
68 + pagename)
69 + result = result + ' . . . . ' + `count` + [
70 + _(' match'),
71 + _(' matches')][count != 1]
72 + result = result + macro.formatter.listitem(0)
73 + result = result + macro.formatter.number_list(0)
74 +
75 + return result
76 +
77 diff -Nur trunk-orig/moin/MoinMoin/parser/wiki.py test/moin/MoinMoin/parser/wiki.py
78 --- trunk-orig/moin/MoinMoin/parser/wiki.py Sat Mar 22 12:16:20 2003
79 +++ test/moin/MoinMoin/parser/wiki.py Sun Apr 13 22:26:50 2003
80 @@ -763,7 +763,42 @@
81
82 def highlight_text(self, text, **kw):
83 if kw.get('flow', 1): self._check_p()
84 - if not self.hilite_re: return self.formatter.text(text)
85 + if not self.hilite_re:
86 + if not self.hilite_words_re:
87 + return self.formatter.text(text)
88 + else: # hilite_words_re
89 + result = []
90 + matches = []
91 + # find matches of all words and sort them
92 + for word_re in self.hilite_words_re:
93 + lastpos = 0
94 + match = word_re.search(text)
95 + while 1:
96 + match = word_re.search(text, lastpos)
97 + if not match: break
98 + lastpos = match.end()+1
99 + matches.append((match.start(), match.end()))
100 + matches.sort()
101 + # actually output it
102 + lastpos = 0
103 + hilite_open = 0
104 + for (start, end) in matches:
105 + if start <= lastpos: # overlapping match
106 + result.append(self.formatter.text(text[lastpos:end]))
107 + lastpos = end
108 + else: # new match
109 + if hilite_open:
110 + result.append(self.formatter.highlight(0))
111 + hilite_open = 0
112 + result.append(self.formatter.text(text[lastpos:start-1]))
113 + result.append(self.formatter.highlight(1))
114 + result.append(self.formatter.text(text[start:end]))
115 + lastpos = end
116 + hilite_open = 1
117 + if lastpos < len(text):
118 + result.append(self.formatter.highlight(0))
119 + result.append(self.formatter.text(text[lastpos:]))
120 + return string.join(result, '')
121
122 result = []
123 lastpos = 0
124 @@ -823,6 +858,7 @@
125 """
126 self.formatter = formatter
127 self.hilite_re = self.formatter.page.hilite_re
128 + self.hilite_words_re = self.formatter.page.hilite_words_re
129
130 # prepare regex patterns
131 rules = string.replace(self.formatting_rules, '\n', '|')
132 @@ -926,7 +962,7 @@
133 self.in_table = 0
134
135 # convert line from wiki markup to HTML and print it
136 - if self.hilite_re:
137 + if self.hilite_re or self.hilite_words_re:
138 self.request.write(self.highlight_scan(scan_re, line + " "))
139 else:
140 line, count = re.subn(scan_re, self.replace, line + " ")
141 diff -Nur trunk-orig/moin/MoinMoin/wikiaction.py test/moin/MoinMoin/wikiaction.py
142 --- trunk-orig/moin/MoinMoin/wikiaction.py Thu Mar 13 09:13:11 2003
143 +++ test/moin/MoinMoin/wikiaction.py Mon Apr 14 03:16:43 2003
144 @@ -86,6 +86,54 @@
145 print_search_stats(request, len(hits), pagecount, start)
146 wikiutil.send_footer(request, pagename, editable=0, showactions=0, form=request.form)
147
148 +def do_multisearch(pagename, request, fieldname='value'):
149 + _ = request.getText
150 + start = time.clock()
151 +
152 + # send http headers
153 + webapi.http_headers(request)
154 +
155 + # get parameters
156 + if request.form.has_key(fieldname):
157 + needle = request.form[fieldname].value
158 + else:
159 + needle = ''
160 + try:
161 + context = int(request.form['context'].value)
162 + except (KeyError, ValueError):
163 + context = 0
164 + max_context = 10 # only show first `max_context` contexts
165 +
166 + # check for sensible search term
167 + #if len(needle) < 3:
168 + # Page(pagename).send_page(request,
169 + # msg=_("<b>Please use a more selective search term instead of '%(needle)s'!</b>") % locals())
170 + # return
171 +
172 + # send title
173 + wikiutil.send_title(request, _('Full text search for "%s"') % (needle,))
174 +
175 + # search the pages
176 + pagecount, hits = wikiutil.multisearchPages(needle, context=context)
177 +
178 + # print the result
179 + print "<UL>"
180 + for (count, page_name, fragments) in hits:
181 + print '<LI>' + Page(page_name).link_to(querystr=
182 + 'action=highlight&value=%s&words=1' % urllib.quote_plus(needle))
183 + print ' . . . . ' + `count`
184 + print (_(' match'), _(' matches'))[count != 1]
185 + if context:
186 + for hit in fragments[:max_context]:
187 + print '<br>', ' '*8, '<font color="#808080">...%s<b>%s</b>%s...</font>' \
188 + % tuple(map(cgi.escape, hit))
189 + if len(fragments) > max_context:
190 + print '<br>', ' '*8, '<font color="#808080">...</font>'
191 + print "</UL>"
192 +
193 + print_search_stats(request, len(hits), pagecount, start)
194 + wikiutil.send_footer(request, pagename, editable=0, showactions=0, form=request.form)
195 +
196
197 def do_titlesearch(pagename, request, fieldname='value'):
198 _ = request.getText
199 @@ -146,14 +194,24 @@
200 needle = request.form["value"].value
201 else:
202 needle = ''
203 + if request.form.has_key('words'):
204 + words = request.form["words"].value
205 + else:
206 + words = 0
207
208 - try:
209 - needle_re = re.compile(needle, re.IGNORECASE)
210 - except re.error:
211 - needle = re.escape(needle)
212 - needle_re = re.compile(needle, re.IGNORECASE)
213 -
214 - Page(pagename).send_page(request, hilite_re=needle_re)
215 + if words:
216 + needle_words = string.split(needle)
217 + words_re = []
218 + for needle_word in needle_words:
219 + words_re.append(re.compile(re.escape(needle_word), re.IGNORECASE))
220 + Page(pagename).send_page(request, hilite_words_re=words_re)
221 + else:
222 + try:
223 + needle_re = re.compile(needle, re.IGNORECASE)
224 + except re.error:
225 + needle = re.escape(needle)
226 + needle_re = re.compile(needle, re.IGNORECASE)
227 + Page(pagename).send_page(request, hilite_re=needle_re)
228
229
230 #############################################################################
231 diff -Nur trunk-orig/moin/MoinMoin/wikimacro.py test/moin/MoinMoin/wikimacro.py
232 --- trunk-orig/moin/MoinMoin/wikimacro.py Thu Mar 13 09:13:11 2003
233 +++ test/moin/MoinMoin/wikimacro.py Mon Apr 14 02:58:21 2003
234 @@ -119,6 +119,11 @@
235 + '<br><input type="checkbox" name="case" value="1">'
236 + self._('Case-sensitive searching')
237 )
238 + if type == "multisearch":
239 + boxes = (
240 + '<br><input type="checkbox" name="context" value="40" checked>'
241 + + self._('Display context of search results')
242 + )
243 return self.formatter.rawHTML((
244 '<form method="GET">'
245 '<input type="hidden" name="action" value="%s">'
246 diff -Nur trunk-orig/moin/MoinMoin/wikiutil.py test/moin/MoinMoin/wikiutil.py
247 --- trunk-orig/moin/MoinMoin/wikiutil.py Wed Apr 9 21:02:41 2003
248 +++ test/moin/MoinMoin/wikiutil.py Mon Apr 14 04:04:25 2003
249 @@ -393,6 +393,97 @@
250
251 return (len(all_pages), hits)
252
253 +def multisearchPages(needle, **kw):
254 + """ Search the text of all pages for "needle", and return a tuple of
255 + (number of pages, hits).
256 +
257 + "needle" is a google style search pattern, we do an AND search in
258 + any case (doing OR searches is pointless as this can be done via
259 + multiple search calls).
260 +
261 + words are searched case-insensitive. If you want to search for a
262 + case-sensitive match, use +searchword.
263 + Use -excludeword to exclude pages containing excludeword.
264 +
265 + `hits` is a list of tuples containing the number of hits on a page
266 + and the pagename. When context>0, a list of triples with the text of
267 + the hit and the text on each side of it is added; otherwise, the
268 + third element is None.
269 +
270 + context != 0: Provide `context` chars of text on each side of a hit
271 + """
272 + from MoinMoin.Page import Page
273 +
274 + context = int(kw.get('context', 0))
275 +
276 + needle_words = needle.split()
277 + needle_res = []
278 + for word in needle_words:
279 + re_mode = re.IGNORECASE
280 + exclude = 0
281 + if word.startswith("-"): # -exclude
282 + exclude = 1
283 + word = word[1:]
284 + elif word.startswith("+"): # +CaseSensitive
285 + re_mode = 0
286 + word = word[1:]
287 + if word.startswith("/") and word.endswith("/"): # /regex/
288 + word = word[1:-1]
289 + else:
290 + word = re.escape(word)
291 + c_re = re.compile(word, re_mode)
292 + needle_res.append((exclude, c_re))
293 +
294 + hits = []
295 + all_pages = getPageList(config.text_dir)
296 + for page_name in all_pages:
297 + # we also search the title by faking it into the "body":
298 + body = "****** %s ******\n" % page_name + Page(page_name).get_raw_body()
299 + count = 0
300 + hit = 0
301 + matches = []
302 + # search every pre-compiled re
303 + for (exclude, needle_re) in needle_res:
304 + if exclude:
305 + hit = (needle_re.search(body) == None)
306 + else:
307 + if context:
308 + pos = 0
309 + while 1:
310 + match = needle_re.search(body, pos)
311 + if not match: break
312 + pos = match.end()+1
313 + matches.append((match.start(), match.end()))
314 + hit = pos # if pos > 0: we have a hit
315 + else:
316 + hit = len(needle_re.findall(body))
317 + count = count + hit
318 + if not hit: break
319 + if not hit: continue
320 + # now output all hits in correct order
321 + if context:
322 + matches.sort()
323 + fragments = []
324 + # at the moment fragments can be listed several times
325 + # if more than one needle_word appears within
326 + for (start, end) in matches:
327 + fragments.append((
328 + body[start-context:start],
329 + body[start:end],
330 + body[end:end+context],
331 + ))
332 + if fragments:
333 + hits.append((len(fragments), page_name, fragments))
334 + else:
335 + if count:
336 + hits.append((count, page_name, None))
337 +
338 + # The default comparison for tuples compares elements in order,
339 + # so this sorts by number of hits
340 + hits.sort()
341 + hits.reverse()
342 +
343 + return (len(all_pages), hits)
344
345 #############################################################################
346 ### Misc
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.