Attachment 'wiki_word.py'
Download 1 # -*- coding: iso-8859-1 -*-
2
3 """
4 MoinMoin - MoinMoin Wiki Markup Parser (for Word Dump)
5
6 Copyright (c) 2000, 2001, 2002 by Jürgen Hermann <jh@web.de>
7 All rights reserved, see COPYING for details.
8
9 $Id: wiki.py,v 1.88 2002/05/09 21:09:37 jhermann Exp $
10 ORS modifications:
11 08.01.04 RS inline parser fix, makes inline extensions configurable
12 08.01.04 RS colorizer, makes colorizer extensions configurable
13 09.01.04 RS ignore character formatting inside DT
14 09.01.04 RS upgrade to 1.1. using wiki.py
15 12.01.04 RS set proper encoding of this file
16 1.3.3 re-migration of patches started 31.01.05
17 * page variables in interwiki
18 1.3.3 re-migration of patches started 01.09.05
19 * cleaned some obsolete 1.1. deltas
20
21 """
22
23 import os, re
24 from MoinMoin import config, wikimacro, wikiutil
25 from MoinMoin.Page import Page
26 from MoinMoin.util import web
27
28 Dependencies = []
29
30 _debug=1
31
32 _max_lineno=-40 #limit number of lines in source, -1 = all
33
34 class Parser:
35 """
36 Object that turns Wiki markup into HTML.
37
38 All formatting commands can be parsed one line at a time, though
39 some state is carried over between lines.
40
41 Methods named like _*_repl() are responsible to handle the named regex
42 patterns defined in print_html().
43 """
44
45 # allow caching
46 caching = 1
47 Dependencies = []
48
49 # some common strings
50 PARENT_PREFIX = wikiutil.PARENT_PREFIX
51 attachment_schemas = ["attachment", "inline", "drawing"]
52 punct_pattern = re.escape(u'''"\'}]|:,.)?!''')
53 url_pattern = (u'http|https|ftp|nntp|news|mailto|telnet|wiki|file|' +
54 u'|'.join(attachment_schemas) +
55 (config.url_schemas and u'|' + u'|'.join(config.url_schemas) or ''))
56
57 # some common rules
58 word_rule = ur'(?:(?<![%(l)s])|^)%(parent)s(?:%(subpages)s(?:[%(u)s][%(l)s]+){2,})+(?![%(u)s%(l)s]+)' % {
59 'u': config.chars_upper,
60 'l': config.chars_lower,
61 'subpages': config.allow_subpages and (wikiutil.CHILD_PREFIX + '?') or '',
62 'parent': config.allow_subpages and (ur'(?:%s)?' % re.escape(PARENT_PREFIX)) or '',
63 }
64 #RS end
65 #RS Word version
66 punct_pattern_red = re.escape(u',.?')
67 textword_rule = ur'(?:[%(l)s|%(u)s][%(l)s]*)' % {
68 'u': config.chars_upper,
69 'l': config.chars_lower,
70 # 'punctr': punct_pattern_red,
71 }
72 #RS stop
73 url_rule = ur'%(url_guard)s(%(url)s)\:([^\s\<%(punct)s]|([%(punct)s][^\s\<%(punct)s]))+' % {
74 'url_guard': u'(^|(?<!\w))',
75 'url': url_pattern,
76 'punct': punct_pattern,
77 }
78
79 ol_rule = ur"^\s+(?:[0-9]+|[aAiI])\.(?:#\d+)?\s"
80 dl_rule = ur"^\s+.*?::\s"
81
82 # the big, fat, ugly one ;)
83 #RS word
84 #Patterns that have been replaced inside the formatting_rules:
85 #<textword> inserted before <ent>
86 #(?P<textword>%(textword_rule)s)
87 #<eoln> and <char> inserted after <ent>
88 #(?P<eoln> $)
89 #(?P<char>.)
90 #RS end
91
92 formatting_rules = ur"""(?:(?P<emph_ibb>'''''(?=[^']+'''))
93 (?P<emph_ibi>'''''(?=[^']+''))
94 (?P<emph_ib_or_bi>'{5}(?=[^']))
95 (?P<emph>'{2,3})
96 (?P<u>__)
97 (?P<sup>\^.*?\^)
98 (?P<sub>,,[^,]{1,40},,)
99 (?P<tt>\{\{\{.*?\}\}\})
100 (?P<processor>(\{\{\{(#!.*|\s*$)))
101 (?P<pre>(\{\{\{ ?|\}\}\}))
102 (?P<small>(\~- ?|-\~))
103 (?P<big>(\~\+ ?|\+\~))
104 (?P<rule>-{4,})
105 (?P<comment>^\#\#.*$)
106 (?P<macro>\[\[(%%(macronames)s)(?:\(.*?\))?\]\]))
107 (?P<ol>%(ol_rule)s)
108 (?P<dl>%(dl_rule)s)
109 (?P<li>^\s+\*?)
110 (?P<tableZ>\|\| $)
111 (?P<table>(?:\|\|)+(?:<[^>]*?>)?(?!\|? $))
112 (?P<heading>^\s*(?P<hmarker>=+)\s.*\s(?P=hmarker) $)
113 (?P<interwiki>[A-Z][a-zA-Z]+\:[^\s'\"\:\<\|]([^\s%(punct)s]|([%(punct)s][^\s%(punct)s]))+)
114 (?P<word>%(word_rule)s)
115 (?P<url_bracket>\[\^?((%(url)s)\:|#|\:)[^\s\]]+(\s[^\]]+)?\])
116 (?P<url>%(url_rule)s)
117 (?P<email>[-\w._+]+\@[\w-]+(\.[\w-]+)+)
118 (?P<smiley>(?<=\s)(%(smiley)s)(?=\s))
119 (?P<smileyA>^(%(smiley)s)(?=\s))
120 (?P<textword>%(textword_rule)s)
121 (?P<ent>[<>&])
122 (?P<eoln> $)
123 (?P<char>[^`])""" % {
124 'url': url_pattern,
125 'punct': punct_pattern,
126 #RS 1.3?
127 # 'macronames': '|'.join(wikimacro.names),
128 #RS end
129 'ol_rule': ol_rule,
130 'dl_rule': dl_rule,
131 'url_rule': url_rule,
132 'word_rule': word_rule,
133 #RS word
134 'textword_rule': textword_rule,
135 #RS end
136 'smiley': u'|'.join(map(re.escape, config.smileys.keys()))}
137
138 # Don't start p before these
139 #RS word
140 # no_new_p_before = ("heading rule table tableZ tr td ul ol dl dt dd li "
141 # "processor macro pre")
142 no_new_p_before = ("heading rule table tableZ tr td ul ol dl dt dd li "
143 "processor macro pre textword char")
144 #RS end
145 no_new_p_before = dict(zip(no_new_p_before.split(), [1] * len(no_new_p_before)))
146
147 def __init__(self, raw, request, **kw):
148 self.raw = raw
149 self.request = request
150 self.form = request.form
151 self._ = request.getText
152 self.cfg = request.cfg
153
154 self.macro = None
155
156 self.is_em = 0
157 self.is_b = 0
158 self.is_u = 0
159 self.lineno = 0
160 self.in_li = 0
161 self.in_dd = 0
162 self.in_pre = 0
163 self.in_table = 0
164 self.is_big = False
165 self.is_small = False
166 self.inhibit_p = 0 # if set, do not auto-create a <p>aragraph
167 self.titles = request._page_headings
168 # abp add for pdf
169 self.is_sub = 0
170 self.is_sup = 0
171 self.is_tt = 0
172
173 # holds the nesting level (in chars) of open lists
174 self.list_indents = []
175 self.list_types = []
176
177 self.formatting_rules = self.formatting_rules % {'macronames': u'|'.join(wikimacro.getNames(self.cfg))}
178
179 #RS obsolete in 1.3?
180 def _check_p(self):
181 pass
182 # if not (self.formatter.in_p or self.in_pre):
183 # self.request.write(self.formatter.paragraph(1))
184
185
186 def _close_item(self, result):
187 result.append("<!-- close item begin -->\n")
188 if self.in_table:
189 result.append(self.formatter.table(0))
190 self.in_table = 0
191 if self.in_li:
192 self.in_li = 0
193 if self.formatter.in_p:
194 result.append(self.formatter.paragraph(0))
195 result.append(self.formatter.listitem(0))
196 if self.in_dd:
197 self.in_dd = 0
198 if self.formatter.in_p:
199 result.append(self.formatter.paragraph(0))
200 result.append(self.formatter.definition_desc(0))
201 result.append("<!-- close item end -->\n")
202
203
204 def interwiki(self, url_and_text, **kw):
205 # TODO: maybe support [wiki:Page http://wherever/image.png] ?
206 self._check_p()
207
208 if len(url_and_text) == 1:
209 url = url_and_text[0]
210 text = None
211 else:
212 url, text = url_and_text
213
214 url = url[5:] # remove "wiki:"
215 if text is None:
216 tag, tail = wikiutil.split_wiki(url)
217 if tag:
218 text = tail
219 else:
220 text = url
221 url = ""
222 elif config.allow_subpages and url.startswith(wikiutil.CHILD_PREFIX):
223 # fancy link to subpage [wiki:/SubPage text]
224 return self._word_repl(url, text)
225 elif Page(self.request, url).exists():
226 # fancy link to local page [wiki:LocalPage text]
227 return self._word_repl(url, text)
228
229 wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, url)
230 #RS evaluate some keywords that can be set by pragmas
231 for key in self.request.pagevars:
232 value=self.request.getPragma("var_%s" % key, "")
233 wikiurl=wikiurl.replace("$var_%s" % key, value)
234 #RS
235 wikiurl = wikiutil.mapURL(self.request,wikiurl)
236 href = wikiutil.join_wiki(wikiurl, wikitail)
237
238 # check for image URL, and possibly return IMG tag
239 if not kw.get('pretty_url', 0) and wikiutil.isPicture(wikitail):
240 return self.formatter.image(src=href)
241
242 # link to self?
243 if wikitag is None:
244 return self._word_repl(wikitail)
245
246 ## # return InterWiki hyperlink
247 ## prefix = config.url_prefix
248 ## badwiki = wikitag == "BadWikiTag"
249 #RS changed for Word
250 ## text = self.highlight_text(text) # also wikiutil.escapes if necessary
251 #RS stop
252 ## icon = ''
253 ## if self.request.user.show_fancy_links:
254 #RS continue
255 ## self.formatter.image(width=16, height=16, hspace=2,
256 ## border=badwiki,
257 ## src=prefix+"/img/moin-inter.gif",
258 ## alt="[%s]" % wikitag)
259 #RS end
260 ## return self.formatter.url(href, icon + text,
261 ## title=wikitag, unescaped=1, pretty_url=kw.get('pretty_url', 0), target=target)
262 #RS end
263 return (self.formatter.interwikilink(1, wikitag, wikitail) +
264 self.formatter.text(text) +
265 self.formatter.interwikilink(0))
266
267
268 def attachment(self, url_and_text, **kw):
269 """ This gets called on attachment URLs.
270 """
271 import urllib
272 _ = self._
273
274 self._check_p()
275
276 if len(url_and_text) == 1:
277 url = url_and_text[0]
278 text = None
279 else:
280 url, text = url_and_text
281
282 inline = url[0] == 'i'
283 drawing = url[0] == 'd'
284 url = url.split(":", 1)[1]
285 url = urllib.unquote(url)
286 text = text or url
287
288 pagename = self.formatter.page.page_name
289 parts = url.split('/')
290 if len(parts) > 1:
291 # get attachment from other page
292 pagename = '/'.join(parts[:-1])
293 url = parts[-1]
294
295 import urllib
296 from MoinMoin.action import AttachFile
297 fname = wikiutil.taintfilename(url)
298 if drawing:
299 drawing = fname
300 fname = fname + ".png"
301 url = url + ".png"
302 # fallback for old gif drawings (1.1 -> 1.2)
303 fpath = AttachFile.getFilename(self.request, pagename, fname)
304 if not os.path.exists(fpath):
305 gfname = fname[:-4] + ".gif"
306 gurl = url[:-4] + ".gif"
307 gfpath = AttachFile.getFilename(self.request, pagename, gfname)
308 if os.path.exists(gfpath):
309 fname, url, fpath = gfname, gurl, gfpath
310 else:
311 fpath = AttachFile.getFilename(self.request, pagename, fname)
312
313 # check whether attachment exists, possibly point to upload form
314 if not os.path.exists(fpath):
315 if drawing:
316 linktext = _('Create new drawing "%(filename)s"')
317 else:
318 linktext = _('Upload new attachment "%(filename)s"')
319 return wikiutil.link_tag(self.request,
320 self.formatter.text('%s?action=AttachFile&rename=%s%s' % (
321 wikiutil.quoteWikinameURL(pagename),
322 urllib.quote_plus(fname.encode(config.charset)),
323 drawing and ('&drawing=%s' % urllib.quote(drawing.encode(config.charset))) or '')),
324 linktext % {'filename': self.formatter.text(fname)})
325
326 # check for image URL, and possibly return IMG tag
327 # (images are always inlined, just like for other URLs)
328 if not kw.get('pretty_url', 0) and wikiutil.isPicture(url):
329 if drawing:
330 # check for map file
331 mappath = AttachFile.getFilename(self.request, pagename, drawing + '.map')
332 edit_link = self.formatter.text('%s?action=AttachFile&rename=%s&drawing=%s' % (wikiutil.quoteWikinameURL(pagename), urllib.quote_plus(fname.encode(config.charset)), urllib.quote(drawing.encode(config.charset))))
333 if os.path.exists(mappath):
334 # we have a image map. inline it and add a map ref
335 # to the img tag
336 try:
337 map = open(mappath,'r').read()
338 except IOError:
339 pass
340 except OSError:
341 pass
342 else:
343 mapid = 'ImageMapOf'+drawing
344 # replace MAPNAME
345 map = map.replace('%MAPNAME%', mapid)
346 # add alt and title tags to areas
347 map = re.sub('href\s*=\s*"((?!%TWIKIDRAW%).+?)"',r'href="\1" alt="\1" title="\1"',map)
348 # add in edit links plus alt and title attributes
349 map = map.replace('%TWIKIDRAW%"', edit_link + '" alt="' + _('Edit drawing %(filename)s') % {'filename': self.formatter.text(fname)} + '" title="' + _('Edit drawing %(filename)s') % {'filename': self.formatter.text(fname)} + '"')
350 # unxml, because 4.01 concrete will not validate />
351 map = map.replace('/>','>')
352 return map + self.formatter.image(alt=drawing,
353 src=AttachFile.getAttachUrl(pagename, url, self.request, addts=1), usemap='#'+mapid, html_class="drawing")
354 else:
355 return wikiutil.link_tag(self.request,
356 edit_link,
357 self.formatter.image(alt=url,
358 src=AttachFile.getAttachUrl(pagename, url, self.request, addts=1), html_class="drawing"),
359 attrs='title="%s"' % (_('Edit drawing %(filename)s') % {'filename': self.formatter.text(fname)}))
360 else:
361 return self.formatter.image(alt=url,
362 src=AttachFile.getAttachUrl(pagename, url, self.request, addts=1))
363
364 # print "image<P>"
365 form = self.request.form
366
367 # determine modes
368 #RS handle attachments as path url when printmode
369 print_mode = form.has_key('action') and form['action'].value == 'print'
370 if print_mode:
371 # print "printed:"
372 attsrc=AttachFile.getAttachPathUrl(pagename, url, addts=1)
373 return self.formatter.image(border=0, alt=url,
374 src=attsrc)
375 else:
376 return self.formatter.image(border=0, alt=url,
377 src=AttachFile.getAttachUrl(pagename, url, addts=1))
378 #RS end
379
380 # try to inline the attachment (parser know what they
381 # can handle)
382 base, ext = os.path.splitext(url)
383 if inline:
384 Parser = wikiutil.getParserForExtension(self.cfg, ext)
385 if Parser is not None:
386 content = file(fpath, 'r').read()
387 # Try to decode text. It might return junk, but we don't
388 # have enough information with attachments.
389 content = wikiutil.decodeUnknownInput(content)
390 colorizer = Parser(content, self.request)
391 colorizer.format(self.formatter)
392
393 url = AttachFile.getAttachUrl(pagename, url, self.request)
394
395 if not kw.get('pretty_url', 0) and wikiutil.isPicture(url):
396 return self.formatter.image(src=url)
397 else:
398 return (self.formatter.url(1, url) +
399 self.formatter.text(text) +
400 self.formatter.url(0))
401
402 def _u_repl(self, word):
403 """Handle underline."""
404 self._check_p()
405 self.is_u = not self.is_u
406 return self.formatter.underline(self.is_u)
407
408 def _small_repl(self, word):
409 """Handle small."""
410 if word.strip() == '~-' and self.is_small: return word
411 if word.strip() == '-~' and not self.is_small: return word
412 self.is_small = not self.is_small
413 return self.formatter.small(self.is_small)
414
415 def _big_repl(self, word):
416 """Handle big."""
417 if word.strip() == '~+' and self.is_big: return word
418 if word.strip() == '+~' and not self.is_big: return word
419 self.is_big = not self.is_big
420 return self.formatter.big(self.is_big)
421
422 def _emph_repl(self, word):
423 """Handle emphasis, i.e. '' and '''."""
424 self._check_p()
425 ##print "#", self.is_b, self.is_em, "#"
426 if len(word) == 3:
427 self.is_b = not self.is_b
428 if self.is_em and self.is_b: self.is_b = 2
429 return self.formatter.strong(self.is_b)
430 else:
431 self.is_em = not self.is_em
432 if self.is_em and self.is_b: self.is_em = 2
433 return self.formatter.emphasis(self.is_em)
434
435 def _emph_ibb_repl(self, word):
436 """Handle mixed emphasis, i.e. ''''' followed by '''."""
437 self._check_p()
438 self.is_b = not self.is_b
439 self.is_em = not self.is_em
440 if self.is_em and self.is_b: self.is_b = 2
441 return self.formatter.emphasis(self.is_em) + self.formatter.strong(self.is_b)
442
443 def _emph_ibi_repl(self, word):
444 """Handle mixed emphasis, i.e. ''''' followed by ''."""
445 self._check_p()
446 self.is_b = not self.is_b
447 self.is_em = not self.is_em
448 if self.is_em and self.is_b: self.is_em = 2
449 return self.formatter.strong(self.is_b) + self.formatter.emphasis(self.is_em)
450
451 def _emph_ib_or_bi_repl(self, word):
452 """Handle mixed emphasis, exactly five '''''."""
453 self._check_p()
454 ##print "*", self.is_b, self.is_em, "*"
455 b_before_em = self.is_b > self.is_em > 0
456 self.is_b = not self.is_b
457 self.is_em = not self.is_em
458 if b_before_em:
459 return self.formatter.strong(self.is_b) + self.formatter.emphasis(self.is_em)
460 else:
461 return self.formatter.emphasis(self.is_em) + self.formatter.strong(self.is_b)
462
463
464 def _sup_repl(self, word):
465 """Handle superscript."""
466 self._check_p()
467 return self.formatter.sup(1) + \
468 self.formatter.text(word[1:-1]) + \
469 self.formatter.sup(0)
470
471 def _sub_repl(self, word):
472 """Handle subscript."""
473 self._check_p()
474 return self.formatter.sub(1) + \
475 self.formatter.text(word[2:-2]) + \
476 self.formatter.sub(0)
477
478 def _rule_repl(self, word):
479 """Handle sequences of dashes."""
480 ##self.inhibit_p = 1
481 result = self._undent() + self._closeP()
482 if len(word) <= 4:
483 result = result + self.formatter.rule()
484 else:
485 # Create variable rule size 1 - 6. Actual size defined in css.
486 size = min(len(word), 10) - 4
487 result = result + self.formatter.rule(size)
488 return result
489
490 def _word_repl(self, word, text=None):
491
492 """Handle WikiNames."""
493 self._check_p()
494 # check for parent links
495 # !!! should use wikiutil.AbsPageName here, but setting `text`
496 # correctly prevents us from doing this for now
497 if config.allow_subpages and word.startswith(wikiutil.PARENT_PREFIX):
498 if not text: text = word
499 word = '/'.join(filter(None, self.formatter.page.page_name.split('/')[:-1] + [word[wikiutil.PARENT_PREFIX_LEN:]]))
500
501 if not text:
502 # if a simple, self-referencing link, emit it as plain text
503 if word == self.formatter.page.page_name:
504 return self.formatter.text(word)
505 text = word
506 if config.allow_subpages and word.startswith(wikiutil.CHILD_PREFIX):
507 word = self.formatter.page.page_name + '/' + word[wikiutil.CHILD_PREFIX_LEN:]
508 return (self.formatter.pagelink(1, word) +
509 self.formatter.text(text) +
510 self.formatter.pagelink(0, word))
511
512 #RS word
513 def _textword_repl(self, word):
514 """Handle simple text word."""
515 self._check_p()
516 return self.formatter.pure(word)
517
518 def _punct1_repl(self, word):
519 """Handle simple text word."""
520 self._check_p()
521 return self.formatter.pure('*'+word)
522
523 def _char_repl(self, word):
524 """Handle single chars."""
525 return self.formatter.pure(word)
526
527 def _eoln_repl(self, word):
528 """final space at eoln"""
529 return self.formatter.pure('')
530
531 def _punct2_repl(self, word):
532 """Handle simple text word."""
533 self._check_p()
534 return self.formatter.pure('*'+word)
535
536 def _punct3_repl(self, word):
537 """Handle simple text word."""
538 self._check_p()
539 return self.formatter.pure('*'+word)
540
541 def _punctr_repl(self, word):
542 """Handle simple text word."""
543 self._check_p()
544 return self.formatter.pure('^'+word)
545 #RS end
546
547 def _notword_repl(self, word):
548 """Handle !NotWikiNames."""
549 self._check_p()
550 return self.formatter.text(word[1:])
551
552
553 def _interwiki_repl(self, word):
554 """Handle InterWiki links."""
555 self._check_p()
556 return self.interwiki(["wiki:" + word])
557
558
559 def _url_repl(self, word):
560 """Handle literal URLs including inline images."""
561 self._check_p()
562 scheme = word.split(":", 1)[0]
563
564 if scheme == "wiki": return self.interwiki([word])
565 if scheme in self.attachment_schemas:
566 return self.attachment([word])
567
568 #RS word
569 # return self.formatter.url(word, text=word)
570 #RS end
571 if wikiutil.isPicture(word):
572 word = wikiutil.mapURL(self.request, word)
573 # Get image name http://here.com/dir/image.gif -> image
574 name = word.split('/')[-1]
575 name = ''.join(name.split('.')[:-1])
576 return self.formatter.image(src=word, alt=name)
577 else:
578 return (self.formatter.url(1, word, type='www') +
579 self.formatter.text(word) +
580 self.formatter.url(0))
581
582 def _wikiname_bracket_repl(self, word):
583 """Handle special-char wikinames."""
584 wikiname = word[2:-2]
585 if wikiname:
586 return self._word_repl(wikiname)
587 else:
588 return word
589
590
591 def _url_bracket_repl(self, word):
592 """Handle bracketed URLs."""
593 self._check_p()
594
595 # Local extended link?
596 if word[1] == ':':
597 words = word[2:-1].split(':', 1)
598 if len(words) == 1:
599 words = words * 2
600 words[0] = 'wiki:Self:%s' % words[0]
601 return self.interwiki(words, pretty_url=1)
602 #return self._word_repl(words[0], words[1])
603
604 # Traditional split on space
605 words = word[1:-1].split(None, 1)
606 if len(words) == 1: words = words * 2
607
608 if words[0][0] == '#':
609 # anchor link
610 return (self.formatter.url(1, words[0]) +
611 self.formatter.text(words[1]) +
612 self.formatter.url(0))
613 scheme = words[0].split(":", 1)[0]
614 if scheme == "wiki": return self.interwiki(words, pretty_url=1)
615 if scheme in self.attachment_schemas:
616 return self.attachment(words, pretty_url=1)
617
618 if wikiutil.isPicture(words[1]) and re.match(self.url_rule, words[1]):
619 return (self.formatter.url(1, words[0], 'external', unescaped=1) +
620 self.formatter.image(title=words[0], alt=words[0], src=words[1]) +
621 self.formatter.url(0))
622 else:
623 return (self.formatter.url(1, words[0], 'external',
624 type='www', unescaped=1) +
625 self.formatter.text(words[1]) +
626 self.formatter.url(0))
627
628
629
630 def _email_repl(self, word):
631 """Handle email addresses (without a leading mailto:)."""
632 self._check_p()
633 return (self.formatter.url(1, "mailto:" + word, type='mailto') +
634 self.formatter.text(word) +
635 self.formatter.url(0))
636
637
638 def _ent_repl(self, word):
639 """Handle SGML entities."""
640 self._check_p()
641 return self.formatter.text(word)
642 #return {'&': '&',
643 # '<': '<',
644 # '>': '>'}[word]
645
646
647 def _ent_numeric_repl(self, word):
648 """Handle numeric SGML entities."""
649 self._check_p()
650 return self.formatter.rawHTML(word)
651
652
653 def _li_repl(self, match):
654 """Handle bullet lists."""
655 result = []
656 indented_only = (match == (" " * len(match)))
657 if indented_only and self.in_li: return ''
658
659 self._close_item(result)
660 #self.inhibit_p = 1
661 self.in_li = 1
662 css_class = ''
663 if self.line_was_empty and not self.first_list_item:
664 css_class = 'gap'
665 if indented_only:
666 result.append(self.formatter.listitem(1, css_class=css_class,
667 style="list-style-type:none"))
668 else:
669 result.append(self.formatter.listitem(1, css_class=css_class))
670 # Suspected p!
671 ## result.append(self.formatter.paragraph(1))
672 return ''.join(result)
673
674
675 def _ol_repl(self, match):
676 """Handle numbered lists."""
677 return self._li_repl(match)
678
679
680 def _dl_repl(self, match):
681 """Handle definition lists."""
682 result = []
683 self._close_item(result)
684 #self.inhibit_p = 1
685 self.in_dd = 1
686 result.extend([
687 self.formatter.definition_term(1),
688 #RS ignore character formatting inside DT
689 # self.formatter.text(match[1:-3]),
690 self.formatter.text(match[1:-3].replace("'","")),
691 #RS end
692 self.formatter.definition_term(0),
693 self.formatter.definition_desc(1),
694 ## CHANGE: no automatic paragraph
695 ##self.formatter.paragraph(1)
696 ])
697 return ''.join(result)
698
699
700 def _indent_level(self):
701 """Return current char-wise indent level."""
702 return len(self.list_indents) and self.list_indents[-1]
703
704
705 def _indent_to(self, new_level, list_type, numtype, numstart):
706 """Close and open lists."""
707 open = [] # don't make one out of these two statements!
708 close = []
709
710
711 if self._indent_level() != new_level and self.in_table:
712 tag=self.formatter.table(0)
713 if tag:
714 close.append(tag)
715 self.in_table = 0
716 # #self._close_item(close)
717 #else:
718 # if not self.line_was_empty:
719 # self.inhibit_p = 1
720
721 # Close lists while char-wise indent is greater than the current one
722 while ((self._indent_level() > new_level) or
723 ( new_level and
724 (self._indent_level() == new_level) and
725 (self.list_types[-1]) != list_type)):
726 self._close_item(close)
727 if self.list_types[-1] == 'ol':
728 tag = self.formatter.number_list(0)
729 elif self.list_types[-1] == 'dl':
730 tag = self.formatter.definition_list(0)
731 else:
732 tag = self.formatter.bullet_list(0)
733 if tag:
734 close.append(tag)
735
736 del(self.list_indents[-1])
737 del(self.list_types[-1])
738
739 #if new_level:
740 # self.inhibit_p = 1
741 #else:
742 # self.inhibit_p = 0
743
744 if self.list_types: # we are still in a list
745 if self.list_types[-1] == 'dl':
746 self.in_dd = 1
747 else:
748 self.in_li = 1
749
750 # Open new list, if necessary
751 if self._indent_level() < new_level:
752
753 self.list_indents.append(new_level)
754 self.list_types.append(list_type)
755
756 if self.formatter.in_p:
757 tag=self.formatter.paragraph(0)
758 if tag:
759 close.append(tag)
760
761 if list_type == 'ol':
762 tag = self.formatter.number_list(1, numtype, numstart)
763 elif list_type == 'dl':
764 tag = self.formatter.definition_list(1)
765 else:
766 tag = self.formatter.bullet_list(1)
767 if tag:
768 open.append(tag)
769
770 self.first_list_item = 1
771 ## Maybe this prevent p creation in lists?
772 ##self.inhibit_p = 1
773 self.in_li = 0
774 self.in_dd = 0
775 # If list level changes, close an open table
776 if self.in_table and (open or close):
777 tag=self.formatter.table(0)
778 if tag:
779 close[0:0] = []
780 self.in_table = 0
781
782 ## Maybe this prevent p creation in lists?
783 ##self.inhibit_p = bool(self.list_types)
784
785 return ''.join(close) + ''.join(open)
786
787
788 def _undent(self):
789 """Close all open lists."""
790 result = []
791 #result.append("<!-- _undent start -->\n")
792 self._close_item(result)
793 for type in self.list_types:
794 if type == 'ol':
795 result.append(self.formatter.number_list(0))
796 elif type == 'dl':
797 result.append(self.formatter.definition_list(0))
798 else:
799 result.append(self.formatter.bullet_list(0))
800 #result.append("<!-- _undent end -->\n")
801 self.list_indents = []
802 self.list_types = []
803 return ''.join(result)
804
805
806 def _tt_repl(self, word):
807 """Handle inline code."""
808 self._check_p()
809
810 return self.formatter.code(1) + \
811 self.formatter.text(word[3:-3]) + \
812 self.formatter.code(0)
813
814
815 def _tt_bt_repl(self, word):
816 """Handle backticked inline code."""
817 if len(word) == 2: return ""
818 self._check_p()
819 #RS word
820 # self.highlight_text(word[1:-1],pure=1) + \
821 return self.formatter.code(1) + \
822 self.formatter.text(word[1:-1]) + \
823 self.formatter.code(0)
824 #RS end
825
826
827 def _getTableAttrs(self, attrdef):
828 # skip "|" and initial "<"
829 while attrdef and attrdef[0] == "|":
830 attrdef = attrdef[1:]
831 if not attrdef or attrdef[0] != "<":
832 return {}, ''
833 attrdef = attrdef[1:]
834
835 # extension for special table markup
836 def table_extension(key, parser, attrs, wiki_parser=self):
837 _ = wiki_parser._
838 msg = ''
839 if key[0] in "0123456789":
840 token = parser.get_token()
841 if token != '%':
842 wanted = '%'
843 msg = _('Expected "%(wanted)s" after "%(key)s", got "%(token)s"') % {
844 'wanted': wanted, 'key': key, 'token': token}
845 else:
846 try:
847 dummy = int(key)
848 except ValueError:
849 msg = _('Expected an integer "%(key)s" before "%(token)s"') % {
850 'key': key, 'token': token}
851 else:
852 attrs['width'] = '"%s%%"' % key
853 elif key == '-':
854 arg = parser.get_token()
855 try:
856 dummy = int(arg)
857 except ValueError:
858 msg = _('Expected an integer "%(arg)s" after "%(key)s"') % {
859 'arg': arg, 'key': key}
860 else:
861 attrs['colspan'] = '"%s"' % arg
862 elif key == '|':
863 arg = parser.get_token()
864 try:
865 dummy = int(arg)
866 except ValueError:
867 msg = _('Expected an integer "%(arg)s" after "%(key)s"') % {
868 'arg': arg, 'key': key}
869 else:
870 attrs['rowspan'] = '"%s"' % arg
871 elif key == '(':
872 attrs['align'] = '"left"'
873 elif key == ':':
874 attrs['align'] = '"center"'
875 elif key == ')':
876 attrs['align'] = '"right"'
877 elif key == '^':
878 attrs['valign'] = '"top"'
879 elif key == 'v':
880 attrs['valign'] = '"bottom"'
881 elif key == '#':
882 arg = parser.get_token()
883 try:
884 if len(arg) != 6: raise ValueError
885 dummy = int(arg, 16)
886 except ValueError:
887 msg = _('Expected a color value "%(arg)s" after "%(key)s"') % {
888 'arg': arg, 'key': key}
889 else:
890 attrs['bgcolor'] = '"#%s"' % arg
891 else:
892 msg = None
893 #print "key: %s\nattrs: %s" % (key, str(attrs))
894 return msg
895
896 # scan attributes
897 attr, msg = wikiutil.parseAttributes(self.request, attrdef, '>', table_extension)
898 if msg: msg = '<strong class="highlight">%s</strong>' % msg
899 #print attr
900 return attr, msg
901
902 def _tableZ_repl(self, word):
903 """Handle table row end."""
904 if self.in_table:
905 result = ''
906 # REMOVED: check for self.in_li, p should always close
907 if self.formatter.in_p:
908 result = self.formatter.paragraph(0)
909 result += self.formatter.table_cell(0) + self.formatter.table_row(0)
910 return result
911 else:
912 return word
913
914
915 def _table_repl(self, word):
916 """Handle table cell separator."""
917 if self.in_table:
918 result = []
919 # check for attributes
920 attrs, attrerr = self._getTableAttrs(word)
921
922 # start the table row?
923 if self.table_rowstart:
924 self.table_rowstart = 0
925 result.append(self.formatter.table_row(1, attrs))
926 else:
927 # Close table cell, first closing open p
928 # REMOVED check for self.in_li, paragraph should close always!
929 if self.formatter.in_p:
930 result.append(self.formatter.paragraph(0))
931 result.append(self.formatter.table_cell(0))
932
933 # check for adjacent cell markers
934 if word.count("|") > 2:
935 if not attrs.has_key('align'):
936 attrs['align'] = '"center"'
937 if not attrs.has_key('colspan'):
938 attrs['colspan'] = '"%d"' % (word.count("|")/2)
939
940 # return the complete cell markup
941 result.append(self.formatter.table_cell(1, attrs) + attrerr)
942 return ''.join(result)
943 else:
944 return word
945
946
947 def _heading_repl(self, word):
948 """Handle section headings."""
949 import sha
950
951 ##self.inhibit_p = 1
952
953 h = word.strip()
954 level = 1
955 while h[level:level+1] == '=':
956 level = level+1
957 depth = min(5,level)
958
959 # this is needed for Included pages
960 # TODO but it might still result in unpredictable results
961 # when included the same page multiple times
962 title_text = h[level:-level].strip()
963 pntt = self.formatter.page.page_name + title_text
964 self.titles.setdefault(pntt, 0)
965 self.titles[pntt] += 1
966
967 unique_id = ''
968 if self.titles[pntt] > 1:
969 unique_id = '-%d' % self.titles[pntt]
970 result = self._closeP()
971 result += self.formatter.heading(1, depth, id="head-"+sha.new(pntt.encode(config.charset)).hexdigest()+unique_id)
972
973 return (result + self.formatter.text(title_text) +
974 self.formatter.heading(0, depth))
975
976 def _processor_repl(self, word):
977 """Handle processed code displays."""
978 #RS debug
979 if _debug:
980 print "request processor",word
981 #RS end
982 if word[:3] == '{{{': word = word[3:]
983
984 self.processor = None
985 self.processor_name = None
986 self.processor_is_parser = 0
987 s_word = word.strip()
988 if s_word == '#!':
989 # empty bang paths lead to a normal code display
990 # can be used to escape real, non-empty bang paths
991 word = ''
992 self.in_pre = 3
993 return self._closeP() + self.formatter.preformatted(1)
994 elif s_word[:2] == '#!':
995 # first try to find a processor for this (will go away in 1.4)
996 processor_name = s_word[2:].split()[0]
997 self.processor = wikiutil.importPlugin(
998 self.request.cfg, "processor", processor_name, "process")
999 # now look for a parser with that name
1000 if self.processor is None:
1001 self.processor = wikiutil.importPlugin(
1002 self.request.cfg, "parser", processor_name, "Parser")
1003 if self.processor:
1004 self.processor_is_parser = 1
1005
1006 if self.processor:
1007 self.processor_name = processor_name
1008 self.in_pre = 2
1009 self.colorize_lines = [word]
1010 return ''
1011 elif s_word:
1012 self.in_pre = 3
1013 return self._closeP() + self.formatter.preformatted(1) + \
1014 self.formatter.text(s_word + ' (-)')
1015 else:
1016 self._check_p()
1017 #RS 1.1
1018 self.in_pre = 1
1019 # self.in_pre = word and 1 or 3
1020 return ''
1021 #RS end
1022
1023 def _pre_repl(self, word):
1024 """Handle code displays."""
1025 word = word.strip()
1026 if word == '{{{' and not self.in_pre:
1027 self.in_pre = 3
1028 ##self.inhibit_p = 1
1029 return self._closeP() + self.formatter.preformatted(self.in_pre)
1030 elif word == '}}}' and self.in_pre:
1031 self.in_pre = 0
1032 self.inhibit_p = 0
1033 return self.formatter.preformatted(self.in_pre)
1034
1035 #RS word
1036 ## return word
1037 return self.formatter.pure(word)
1038 #RS end
1039
1040
1041 def _smiley_repl(self, word):
1042 """Handle smileys."""
1043 self._check_p()
1044 return self.formatter.smiley(word)
1045
1046 _smileyA_repl = _smiley_repl
1047
1048
1049 def _comment_repl(self, word):
1050 return ''
1051
1052 def _closeP(self):
1053 if self.formatter.in_p:
1054 return self.formatter.paragraph(0)
1055 return ''
1056
1057 def _macro_repl(self, word):
1058 """Handle macros ([[macroname]])."""
1059 self._check_p()
1060 macro_name = word[2:-2]
1061 #self.inhibit_p = 1 # fixes UserPreferences, but makes new trouble!
1062
1063 # check for arguments
1064 args = None
1065 if macro_name.count("("):
1066 macro_name, args = macro_name.split('(', 1)
1067 args = args[:-1]
1068
1069 # create macro instance
1070 if self.macro is None:
1071 self.macro = wikimacro.Macro(self)
1072
1073 # call the macro
1074 #RS word
1075 self.oldformatter=self.formatter
1076 # print "Before Macro: %s" % (str(vars(self)))
1077
1078 ## return self.formatter.macro(self.macro, macro_name, args)
1079 try:
1080 result=self.formatter.macro(self.macro, macro_name, args)
1081 except:
1082 result='<error executing macro %s>' % macro_name
1083 raise
1084 # print "After Macro: %s" % (str(vars(self)))
1085 self.formatter=self.oldformatter
1086 return result
1087
1088 return self.formatter.macro(self.macro, macro_name, args)
1089 #RS end
1090
1091 def scan(self, scan_re, line):
1092 """ Scans one line
1093
1094 Append text before match, invoke replace() with match, and
1095 add text after match.
1096 """
1097 result = []
1098 lastpos = 0
1099
1100 ###result.append(u'<span class="info">[scan: <tt>"%s"</tt>]</span>' % line)
1101 if _debug:
1102 try:
1103 print "\n SCAN BEGIN :%s:" % line
1104 except UnicodeEncodeError,e:
1105 print "\n SCAN BEGIN, line has unicode problem: %s" % e
1106 old_lastpos=lastpos-1
1107 for match in scan_re.finditer(line):
1108 if old_lastpos==lastpos:
1109 #emergency break?
1110 break
1111 # Add text before the match
1112 if lastpos < match.start():
1113
1114 ###result.append(u'<span class="info">[add text before match: <tt>"%s"</tt>]</span>' % line[lastpos:match.start()])
1115
1116 if not (self.inhibit_p or self.in_pre or self.formatter.in_p):
1117 result.append(self.formatter.paragraph(1))
1118 result.append(self.formatter.text(line[lastpos:match.start()]))
1119
1120 # Replace match with markup
1121 result.append(self.replace(match))
1122 old_lastpos=lastpos
1123 lastpos = match.end()
1124 if _debug:
1125 try:
1126 print "\n SCAN END :%s:" % line
1127 except UnicodeEncodeError,e:
1128 print "\n SCAN END, line has unicode problem: %s" % e
1129
1130 ###result.append('<span class="info">[no match, add rest: <tt>"%s"<tt>]</span>' % line[lastpos:])
1131
1132 # No match: Add paragraph with the text of the line
1133 if not (self.in_pre or self.inhibit_p or
1134 self.formatter.in_p) and lastpos < len(line):
1135 result.append(self.formatter.paragraph(1))
1136 result.append(self.formatter.text(line[lastpos:]))
1137 if _debug:
1138 print "\n SCAN result :%s:" % result
1139
1140 return u''.join(result)
1141
1142 def highlight_text(self, text, **kw):
1143 #RS obsolete
1144 return ''
1145 if kw.get('flow', 1): self._check_p()
1146 #RS word
1147 ## if not self.hilite_re: return self.formatter.text(text)
1148 if not self.hilite_re:
1149 if kw.get('pure', 0):
1150 return self.formatter.pure(text)
1151 else:
1152 return self.formatter.text(text)
1153 return "$HI"+text+"$"
1154 #RS end
1155 result = []
1156 lastpos = 0
1157 match = self.hilite_re.search(text)
1158 while match and lastpos < len(text):
1159 # add the match we found
1160 result.append(self.formatter.text(text[lastpos:match.start()]))
1161 result.append(self.formatter.highlight(1))
1162 result.append(self.formatter.text(match.group(0)))
1163 result.append(self.formatter.highlight(0))
1164
1165 # search for the next one
1166 lastpos = match.end() + (match.end() == lastpos)
1167 match = self.hilite_re.search(text, lastpos)
1168
1169 result.append(self.formatter.text(text[lastpos:]))
1170 return string.join(result, '')
1171
1172 def highlight_scan(self, scan_re, line):
1173 #RS obsolete
1174 return ''
1175 result = []
1176 lastpos = 0
1177 match = scan_re.search(line)
1178 while match and lastpos < len(line):
1179 # add the match we found
1180 #RS word
1181 ## result.append(self.highlight_text(line[lastpos:match.start()]))
1182 result.append(self.highlight_text(line[lastpos:match.start()],pure=0))
1183 #RS end
1184 result.append(self.replace(match))
1185
1186 # search for the next one
1187 lastpos = match.end() + (match.end() == lastpos)
1188 match = scan_re.search(line, lastpos)
1189
1190 result.append(self.highlight_text(line[lastpos:]))
1191 return string.join(result, '')
1192
1193
1194 def replace(self, match):
1195 """ Replace match using type name """
1196 result = []
1197 #RS debug
1198 # if _debug:
1199 # print "\n REPLACE: match groups Xx%sxX\n" % (str(match.groupdict()))
1200 #RS end
1201 for type, hit in match.groupdict().items():
1202 if hit is not None and type != "hmarker":
1203 #RS debug
1204 if _debug:
1205 print "\n ###", wikiutil.escape(`type`)," # ", wikiutil.escape(`hit`), "###"
1206 #RS end
1207 if self.in_pre and type not in ['pre', 'ent']:
1208 return self.formatter.text(hit)
1209 #RS end
1210 else:
1211 # Open p for certain types
1212 if not (self.inhibit_p or self.formatter.in_p
1213 or self.in_pre or (type in self.no_new_p_before)):
1214 result.append(self.formatter.paragraph(1))
1215 # Get replace method and replece hit
1216 replace = getattr(self, '_' + type + '_repl')
1217 result.append(replace(hit))
1218 return ''.join(result)
1219
1220 else:
1221 # We should never get here
1222 import pprint
1223 raise Exception("Can't handle match " + `match`
1224 + "\n" + pprint.pformat(match.groupdict())
1225 + "\n" + pprint.pformat(match.groups()) )
1226 #RS word
1227 ## return ""
1228 return u"§NOREP§"
1229 #RS end
1230
1231
1232 def format(self, formatter):
1233 """ For each line, scan through looking for magic
1234 strings, outputting verbatim any intervening text.
1235 """
1236 self.formatter = formatter
1237 self.hilite_re = self.formatter.page.hilite_re
1238
1239 # prepare regex patterns
1240 rules = self.formatting_rules.replace('\n', '|')
1241 if self.cfg.allow_extended_names:
1242 #RS word
1243 # rules = rules + ur'|(?P<wikiname_bracket>\[".*?"\])'
1244 rules = ur'(?P<wikiname_bracket>\[".*?"\])|' + rules
1245 #RS stop
1246 if self.cfg.bang_meta:
1247 rules = ur'(?P<notword>!%(word_rule)s)|%(rules)s' % {
1248 'word_rule': self.word_rule,
1249 'rules': rules,
1250 }
1251 if self.cfg.backtick_meta:
1252 rules = rules + ur'|(?P<tt_bt>`.*?`)'
1253 if self.cfg.allow_numeric_entities:
1254 rules = ur'(?P<ent_numeric>&#\d{1,5};)|' + rules
1255
1256 #RS debug
1257 # if _debug:
1258 # print u"\nRULE:%s:" % str(rules)
1259 #RS end
1260
1261 self.request.clock.start('compile_huge_and_ugly')
1262 scan_re = re.compile(rules, re.UNICODE)
1263 number_re = re.compile(self.ol_rule, re.UNICODE)
1264 term_re = re.compile(self.dl_rule, re.UNICODE)
1265 indent_re = re.compile("^\s*", re.UNICODE)
1266 eol_re = re.compile(r'\r?\n', re.UNICODE)
1267 self.request.clock.stop('compile_huge_and_ugly')
1268
1269 # get text and replace TABs
1270 rawtext = self.raw.expandtabs()
1271
1272 # go through the lines
1273 self.lineno = 0
1274 self.lines = eol_re.split(rawtext)
1275 self.line_is_empty = 0
1276
1277 # Main loop
1278 for line in self.lines:
1279 self.lineno = self.lineno + 1
1280 if _max_lineno>=0 and self.lineno>_max_lineno:
1281 break
1282 self.table_rowstart = 1
1283 self.line_was_empty = self.line_is_empty
1284 self.line_is_empty = 0
1285 self.first_list_item = 0
1286 self.inhibit_p = 0
1287
1288 if self.in_pre:
1289 # TODO: move this into function
1290 # still looking for processing instructions
1291 # TODO: use strings for pre state, not numbers
1292 if self.in_pre == 1:
1293 self.processor = None
1294 self.processor_is_parser = 0
1295 processor_name = ''
1296 if (line.strip()[:2] == "#!"):
1297 processor_name = line.strip()[2:].split()[0]
1298 self.processor = wikiutil.importPlugin(
1299 self.request.cfg, "processor", processor_name, "process")
1300
1301 # now look for a parser with that name
1302 if self.processor is None:
1303 self.processor = wikiutil.importPlugin(
1304 self.request.cfg, "parser", processor_name, "Parser")
1305 if self.processor:
1306 self.processor_is_parser = 1
1307 if self.processor:
1308 self.in_pre = 2
1309 self.colorize_lines = [line]
1310 self.processor_name = processor_name
1311 continue
1312 else:
1313 self.request.write(self._closeP() +
1314 self.formatter.preformatted(1))
1315 self.in_pre = 3
1316 if self.in_pre == 2:
1317 # processing mode
1318 endpos = line.find("}}}")
1319 if endpos == -1:
1320 self.colorize_lines.append(line)
1321 continue
1322 if line[:endpos]:
1323 self.colorize_lines.append(line[:endpos])
1324
1325 # Close p before calling processor
1326 # TODO: do we really need this?
1327 self.request.write(self._closeP())
1328 #RS debug
1329 if _debug:
1330 print "\n PROCESSOR :%s:\n" % self.processor_name
1331 #RS end
1332 res = self.formatter.processor(self.processor_name,
1333 self.colorize_lines,
1334 self.processor_is_parser)
1335 self.request.write(res)
1336 del self.colorize_lines
1337 self.in_pre = 0
1338 self.processor = None
1339
1340 # send rest of line through regex machinery
1341 line = line[endpos+3:]
1342 else:
1343 # we don't have \n as whitespace any more
1344 # This is the space between lines we join to one paragraph
1345 line = line + ' '
1346
1347 # Paragraph break on empty lines
1348 if not line.strip():
1349 if self.in_table:
1350 #RS debug
1351 if _debug:
1352 print "\n TABLE OFF\n"
1353 #RS end
1354 self.request.write(self.formatter.table(0))
1355 self.in_table = 0
1356 # CHANGE: removed check for not self.list_types
1357 # p should close on every empty line
1358 if (self.formatter.in_p):
1359 #RS debug
1360 if _debug:
1361 print "\n PARAGRAPH OFF (A)\n"
1362 #RS end
1363 self.request.write(self.formatter.paragraph(0))
1364 self.line_is_empty = 1
1365 continue
1366
1367 # Check indent level
1368 indent = indent_re.match(line)
1369 indlen = len(indent.group(0))
1370 indtype = "ul"
1371 numtype = None
1372 numstart = None
1373 #RS debug
1374 # if _debug:
1375 # print "\n INDENT:%s:" % (str(indent))
1376 #RS end
1377 if indlen:
1378 match = number_re.match(line)
1379 if match:
1380 numtype, numstart = match.group(0).strip().split('.')
1381 numtype = numtype[0]
1382
1383 if numstart and numstart[0] == "#":
1384 numstart = int(numstart[1:])
1385 else:
1386 numstart = None
1387
1388 indtype = "ol"
1389 else:
1390 match = term_re.match(line)
1391 if match:
1392 indtype = "dl"
1393
1394 # output proper indentation tags
1395 self.request.write(self._indent_to(indlen, indtype, numtype,
1396 numstart))
1397
1398 # Table mode
1399 # TODO: move into function?
1400 if (not self.in_table and line[indlen:indlen + 2] == "||"
1401 and line[-3:] == "|| " and len(line) >= 5 + indlen):
1402 # Start table
1403 if self.list_types and not self.in_li:
1404 #RS debug
1405 if _debug:
1406 print "\n LISTITEM ON\n"
1407 #RS end
1408 self.request.write(self.formatter.listitem
1409 (1, style="list-style-type:none"))
1410 ## CHANGE: no automatic p on li
1411 ##self.request.write(self.formatter.paragraph(1))
1412 self.in_li = 1
1413
1414 # CHANGE: removed check for self.in_li
1415 # paragraph should end before table, always!
1416 if self.formatter.in_p:
1417 #RS debug
1418 if _debug:
1419 print "\n PARAGRAPH OFF (B)\n"
1420 #RS end
1421 self.request.write(self.formatter.paragraph(0))
1422 attrs, attrerr = self._getTableAttrs(line[indlen+2:])
1423 #RS debug
1424 if _debug:
1425 print "\n TABLE ON (B)\n"
1426 #RS end
1427 self.request.write(self.formatter.table(1, attrs) + attrerr)
1428 self.in_table = True # self.lineno
1429 elif (self.in_table and not
1430 # intra-table comments should not break a table
1431 (line[:2]=="##" or
1432 line[indlen:indlen + 2] == "||" and
1433 line[-3:] == "|| " and
1434 len(line) >= 5 + indlen)):
1435
1436 # Close table
1437 #RS debug
1438 if _debug:
1439 print "\n TABLE OFF (B)\n"
1440 #RS end
1441 self.request.write(self.formatter.table(0))
1442 self.in_table = 0
1443
1444 # Scan line, format and write
1445 formatted_line = self.scan(scan_re, line)
1446 self.request.write(formatted_line)
1447
1448 if self.in_pre:
1449 #RS debug
1450 if _debug:
1451 print "\n LINEBREAK in_pre\n"
1452 #RS end
1453 self.request.write(self.formatter.linebreak())
1454
1455 # Close code displays, paragraphs, tables and open lists
1456 self.request.write(self._undent())
1457 if self.in_pre:
1458 #RS debug
1459 if _debug:
1460 print "\n PRE OFF (C)\n"
1461 #RS end
1462 self.request.write(self.formatter.preformatted(0))
1463 if self.formatter.in_p:
1464 #RS debug
1465 if _debug:
1466 print "\n PARAGRAPH OFF (C)\n"
1467 #RS end
1468 self.request.write(self.formatter.paragraph(0))
1469 if self.in_table:
1470 #RS debug
1471 if _debug:
1472 print "\n TABLE OFF (C)\n"
1473 #RS end
1474 self.request.write(self.formatter.table(0))
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.