1 """
   2     MoinMoin - MoinMoin Wiki Markup Parser
   3 
   4     Copyright (c) 2000, 2001, 2002 by Jürgen Hermann <jh@web.de>
   5     All rights reserved, see COPYING for details.
   6 
   7     $Id: FabianFranz_2fwiki_2epy,v 1.1 2002/06/19 01:43:05 linuxwiki Exp $
   8 """
   9 
  10 # Imports
  11 import cgi, os, re, sys
  12 from MoinMoin import config, user, wikimacro, wikiutil, util
  13 from MoinMoin.Page import Page
  14 from MoinMoin.i18n import _
  15 
  16 
  17 #############################################################################
  18 ### MoinMoin Wiki Markup Parser
  19 #############################################################################
  20 
  21 class Parser:
  22     """
  23         Object that turns Wiki markup into HTML.
  24 
  25         All formatting commands can be parsed one line at a time, though
  26         some state is carried over between lines.
  27 
  28         Methods named like _*_repl() are responsible to handle the named regex
  29         patterns defined in print_html().
  30     """
  31 
  32     # some common strings
  33     
  34     #added mybuffer for buffering writes 
  35     
  36     mybuffer = [""]
  37     
  38     attachment_schemas = ["attachment", "inline", "drawing"]
  39     punct_pattern = re.escape('''"'}]|:,.)?!''')
  40     url_pattern = ('http|https|ftp|nntp|news|mailto|telnet|wiki|file|' +
  41             '|'.join(attachment_schemas) + 
  42             (config.url_schemas and '|' + '|'.join(config.url_schemas) or ''))
  43 
  44     # some common rules
  45     word_rule = r'(?:%(subpages)s(?:[%(u)s][%(l)s]+){2,})+' % {
  46         'u': config.upperletters,
  47         'l': config.lowerletters,
  48         'subpages': config.allow_subpages and '/?' or '',
  49     }
  50     url_rule = r'%(url_guard)s(%(url)s)\:([^\s\<%(punct)s]|([%(punct)s][^\s\<%(punct)s]))+' % {
  51         'url_guard': ('(^|(?<!\w))', '')[sys.version < "2"],
  52         'url': url_pattern,
  53         'punct': punct_pattern,
  54     }
  55 
  56     ol_rule = r"^\s+(?:[0-9]+|[aAiI])\.(?:#\d+)?\s"
  57     dl_rule = r"^\s+.*?::\s"
  58 
  59     # the big, fat, ugly one ;)
  60     formatting_rules = r"""(?:(?P<emph_ibb>'''''(?=[^']+'''))
  61 (?P<emph_ibi>'''''(?=[^']+''))
  62 (?P<emph_ib_or_bi>'{5}(?=[^']))
  63 (?P<emph>'{2,3})
  64 (?P<sup>\^.*?\^)
  65 (?P<tt>\{\{\{.*?\}\}\})
  66 (?P<processor>(\{\{\{#!.*))
  67 (?P<pre>(\{\{\{ ?|\}\}\}))
  68 (?P<rule>-{4,})
  69 (?P<comment>^\#\#.*$)
  70 (?P<macro>\[\[(%(macronames)s)(?:\(.*?\))?\]\]))
  71 (?P<li>^\s+\*)
  72 (?P<ol>%(ol_rule)s)
  73 (?P<dl>%(dl_rule)s)
  74 (?P<tableZ>\|\| $)
  75 (?P<table>(?:\|\|)+(?:<[^>]*?>)?(?=.))
  76 (?P<heading>^\s*(?P<hmarker>=+)\s.*\s(?P=hmarker) $)
  77 (?P<interwiki>[A-Z][a-zA-Z]+\:[^\s'\"\:\<]([^\s%(punct)s]|([%(punct)s][^\s%(punct)s]))+)
  78 (?P<word>%(word_rule)s)
  79 (?P<url_bracket>\[((%(url)s)\:|#)[^\s\]]+(\s[^\]]+)?\])
  80 (?P<url>%(url_rule)s)
  81 (?P<email>[-\w._+]+\@[\w-]+\.[\w.-]+)
  82 (?P<smiley>\s(%(smiley)s)\s)
  83 (?P<smileyA>^(%(smiley)s)\s)
  84 (?P<ent>[<>&])"""  % {
  85         'url': url_pattern,
  86         'punct': punct_pattern,
  87         'macronames': '|'.join(wikimacro.names),
  88         'ol_rule': ol_rule,
  89         'dl_rule': dl_rule,
  90         'url_rule': url_rule,
  91         'word_rule': word_rule,
  92         'smiley': '|'.join(map(re.escape, wikiutil.smileys.keys()))}
  93 
  94     def __init__(self, raw, request, **kw):
  95         self.raw = raw
  96         self.request = request
  97 
  98         self.macro = None
  99 
 100         self.is_em = 0
 101         self.is_b = 0
 102         self.lineno = 0
 103         self.in_li = 0
 104         self.in_dd = 0
 105         self.in_pre = 0
 106         self.in_table = 0
 107 
 108         # holds the nesting level (in chars) of open lists
 109         self.list_indents = []
 110         self.list_types = []
 111 
 112 
 113     ### New Functions for Buffered writing and returning what was written instead writing to stdout
 114     def mywrite(self, line):
 115         self.mybuffer.append(line)
 116         #sys.stdout.write(line)
 117     
 118     def myflush(self):
 119         sys.stdout.write(''.join(self.mybuffer))
 120         self.mybuffer=[""]
 121     
 122     def myread(self):
 123         return ''.join(self.mybuffer)
 124 
 125     def _check_p(self):
 126         if not (self.formatter.in_p or self.in_pre):
 127             self.mywrite(self.formatter.paragraph(1))
 128 
 129 
 130     def _close_item(self, result):
 131         if self.formatter.in_p:
 132             result.append(self.formatter.paragraph(0))
 133         if self.in_li:
 134             self.in_li = 0
 135             result.append(self.formatter.listitem(0))
 136         if self.in_dd:
 137             self.in_dd = 0
 138             result.append(self.formatter.definition_desc(0))
 139 
 140 
 141     def interwiki(self, url_and_text, **kw):
 142         self._check_p()
 143 
 144         if len(url_and_text) == 1:
 145             url = url_and_text[0]
 146             text = None
 147         else:
 148             url, text = url_and_text
 149 
 150         url = url[5:] # remove "wiki:"
 151         if text is None:
 152             tag, tail = wikiutil.split_wiki(url)
 153             if tag:
 154                 text = tail
 155             else:
 156                 text = url
 157                 url = ""
 158         elif config.allow_subpages and url[0] == '/':
 159             # fancy link to subpage [wiki:/SubPage text]
 160             return self._word_repl(url, text)
 161         elif Page(url).exists():
 162             # fancy link to local page [wiki:LocalPage text]
 163             return self._word_repl(url, text)
 164 
 165         import urllib
 166         wikitag, wikiurl, wikitail = wikiutil.resolve_wiki(url)
 167         wikiurl = wikiutil.mapURL(wikiurl)
 168         href = wikiutil.join_wiki(wikiurl, wikitail)
 169 
 170         # check for image URL, and possibly return IMG tag
 171         if not kw.get('pretty_url') and wikiutil.isPicture(wikitail):
 172             return self.formatter.image(border=0, src=href)
 173 
 174         # link to self?
 175         if wikitag is None:
 176             return self._word_repl(wikitail)
 177               
 178         # return InterWiki hyperlink
 179         prefix = config.url_prefix
 180         badwiki = wikitag == "BadWikiTag"
 181         text = self.highlight_text(text) # also cgi.escapes if necessary
 182 
 183         icon = ''
 184         if self.request.user.show_fancy_links:
 185             icon = self.formatter.image(width=16, height=16, hspace=2,
 186                 border=badwiki,
 187                 src=prefix+"/img/moin-inter.gif",
 188                 alt="[%s]" % wikitag)
 189         return self.formatter.url(href, icon + text,
 190             title=wikitag, unescaped=1, pretty_url=kw.get('pretty_url', 0))
 191 
 192 
 193     def attachment(self, url_and_text, **kw):
 194         """ This gets called on attachment URLs.
 195         """
 196         self._check_p()
 197 
 198         if len(url_and_text) == 1:
 199             url = url_and_text[0]
 200             text = None
 201         else:
 202             url, text = url_and_text
 203 
 204         inline = url[0] == 'i'
 205         drawing = url[0] == 'd'
 206         url = url.split(":", 1)[1]
 207         text = text or url
 208 
 209         pagename = self.formatter.page.page_name
 210         parts = url.split('/')
 211         if len(parts) > 1:
 212             # get attachment from other page
 213             pagename = '/'.join(parts[:-1])
 214             url = parts[-1]
 215 
 216         import urllib
 217         from MoinMoin.action import AttachFile
 218         fname = wikiutil.taintfilename(url)
 219         if drawing:
 220             drawing = fname
 221             fname += ".gif"
 222             url += ".gif"
 223         fpath = os.path.join(AttachFile.getAttachDir(pagename), fname)
 224 
 225         # check whether attachment exists, possibly point to upload form
 226         if not os.path.exists(fpath):
 227             if drawing:
 228                 linktext = _('Create new drawing "%(filename)s"')
 229             else:
 230                 linktext = _('Upload new attachment "%(filename)s"')
 231             return wikiutil.link_tag(
 232                 '%s?action=AttachFile&rename=%s%s' % (
 233                     wikiutil.quoteWikiname(pagename),
 234                     urllib.quote_plus(fname),
 235                     drawing and ('&drawing=%s' % urllib.quote(drawing)) or ''),
 236                 linktext % {'filename': fname})
 237 
 238         # check for image URL, and possibly return IMG tag
 239         # (images are always inlined, just like for other URLs)
 240         if not kw.get('pretty_url') and wikiutil.isPicture(url):
 241             return self.formatter.image(border=0, alt=url,
 242                 src=AttachFile.getAttachUrl(pagename, url, addts=1))
 243 
 244         # try to inline the attachment (we only accept a list
 245         # of known extensions)
 246         base, ext = os.path.splitext(url)
 247         if inline and ext in ['.py']:
 248             if ext == '.py':
 249                 import cStringIO
 250                 from MoinMoin.parser import python
 251 
 252                 buff = cStringIO.StringIO()
 253                 colorizer = python.Parser(open(fpath, 'r').read(), self.request, out = buff)
 254                 colorizer.format(self.formatter, self.form)
 255                 return self.formatter.preformatted(1) + \
 256                     self.formatter.rawHTML(buff.getvalue()) + \
 257                     self.formatter.preformatted(0)
 258 
 259         return self.formatter.url(
 260             AttachFile.getAttachUrl(pagename, url),
 261             text, pretty_url=kw.get('pretty_url', 0))
 262 
 263 
 264     def _emph_repl(self, word):
 265         """Handle emphasis, i.e. '' and '''."""
 266         self._check_p()
 267         ##print "#", self.is_b, self.is_em, "#"
 268         if len(word) == 3:
 269             self.is_b = not self.is_b
 270             if self.is_em and self.is_b: self.is_b = 2
 271             return self.formatter.strong(self.is_b)
 272         else:
 273             self.is_em = not self.is_em
 274             if self.is_em and self.is_b: self.is_em = 2
 275             return self.formatter.emphasis(self.is_em)
 276 
 277     def _emph_ibb_repl(self, word):
 278         """Handle mixed emphasis, i.e. ''''' followed by '''."""
 279         self._check_p()
 280         self.is_b = not self.is_b
 281         self.is_em = not self.is_em
 282         if self.is_em and self.is_b: self.is_b = 2
 283         return self.formatter.emphasis(self.is_em) + self.formatter.strong(self.is_b)
 284 
 285     def _emph_ibi_repl(self, word):
 286         """Handle mixed emphasis, i.e. ''''' followed by ''."""
 287         self._check_p()
 288         self.is_b = not self.is_b
 289         self.is_em = not self.is_em
 290         if self.is_em and self.is_b: self.is_em = 2
 291         return self.formatter.strong(self.is_b) + self.formatter.emphasis(self.is_em)
 292 
 293     def _emph_ib_or_bi_repl(self, word):
 294         """Handle mixed emphasis, exactly five '''''."""
 295         self._check_p()
 296         ##print "*", self.is_b, self.is_em, "*"
 297         b_before_em = self.is_b > self.is_em > 0
 298         self.is_b = not self.is_b
 299         self.is_em = not self.is_em
 300         if b_before_em:
 301             return self.formatter.strong(self.is_b) + self.formatter.emphasis(self.is_em)
 302         else:
 303             return self.formatter.emphasis(self.is_em) + self.formatter.strong(self.is_b)
 304 
 305 
 306     def _sup_repl(self, word):
 307         """Handle superscript."""
 308         self._check_p()
 309         return self.formatter.sup(1) + \
 310             self.highlight_text(word[1:-1]) + \
 311             self.formatter.sup(0)
 312 
 313 
 314     def _rule_repl(self, word):
 315         """Handle sequences of dashes."""
 316         result = self._undent()
 317         if len(word) <= 4:
 318             result += self.formatter.rule()
 319         else:
 320             result += self.formatter.rule(min(len(word), 10) - 2)
 321         return result
 322 
 323 
 324     def _word_repl(self, word, text=None):
 325         """Handle WikiNames."""
 326         self._check_p()
 327         if not text: text = word
 328         if config.allow_subpages and word[0] == '/':
 329             word = self.formatter.page.page_name + word
 330         text = self.highlight_text(text)
 331         if word == text:
 332             return self.formatter.pagelink(word)
 333         else:
 334             return self.formatter.pagelink(word, text)
 335 
 336     def _notword_repl(self, word):
 337         """Handle !NotWikiNames."""
 338         self._check_p()
 339         return self.highlight_text(word[1:])
 340 
 341 
 342     def _interwiki_repl(self, word):
 343         """Handle InterWiki links."""
 344         self._check_p()
 345         return self.interwiki(["wiki:" + word])
 346 
 347 
 348     def _url_repl(self, word):
 349         """Handle literal URLs including inline images."""
 350         self._check_p()
 351         scheme = word.split(":", 1)[0]
 352 
 353         if scheme == "wiki": return self.interwiki([word])
 354         if scheme in self.attachment_schemas:
 355             return self.attachment([word])
 356 
 357         return self.formatter.url(word, text=self.highlight_text(word))
 358 
 359 
 360     def _wikiname_bracket_repl(self, word):
 361         """Handle special-char wikinames."""
 362         return self._word_repl(word[2:-2])
 363 
 364 
 365     def _url_bracket_repl(self, word):
 366         """Handle bracketed URLs."""
 367         self._check_p()
 368         words = word[1:-1].split(None, 1)
 369         if len(words) == 1: words = words * 2
 370 
 371         if words[0][0] == '#':
 372             # anchor link
 373             return self.formatter.url(words[0], self.highlight_text(words[1]))
 374 
 375         scheme = words[0].split(":", 1)[0]
 376         if scheme == "wiki": return self.interwiki(words, pretty_url=1)
 377         if scheme in self.attachment_schemas:
 378             return self.attachment(words, pretty_url=1)
 379 
 380         icon = ("www", 11, 11)
 381         if scheme == "mailto": icon = ("email", 14, 10)
 382         if scheme == "news": icon = ("news", 10, 11)
 383         if scheme == "telnet": icon = ("telnet", 10, 11)
 384         if scheme == "ftp": icon = ("ftp", 11, 11)
 385         if scheme == "file": icon = ("ftp", 11, 11)
 386         #!!! use a map?
 387         # http|https|ftp|nntp|news|mailto|wiki|file
 388 
 389         text = ''
 390         if self.request.user.show_fancy_links:
 391             text += self.formatter.image(
 392                 src="%s/img/moin-%s.gif" % (config.url_prefix, icon[0]),
 393                 width=icon[1], height=icon[2], border=0, hspace=4,
 394                 alt="[%s]" % icon[0].upper()
 395                 )
 396         text += self.highlight_text(words[1])
 397         return self.formatter.url(words[0], text, 'external', pretty_url=1, unescaped=1)
 398 
 399 
 400     def _email_repl(self, word):
 401         """Handle email addresses (without a leading mailto:)."""
 402         self._check_p()
 403         return self.formatter.url("mailto:" + word, self.highlight_text(word))
 404 
 405 
 406     def _ent_repl(self, word):
 407         """Handle SGML entities."""
 408         self._check_p()
 409         return self.formatter.text(word)
 410         #return {'&': '&amp;',
 411         #        '<': '&lt;',
 412         #        '>': '&gt;'}[word]
 413 
 414 
 415     def _ent_numeric_repl(self, word):
 416         """Handle numeric SGML entities."""
 417         self._check_p()
 418         return self.formatter.rawHTML(word)
 419 
 420 
 421     def _li_repl(self, match):
 422         """Handle bullet lists."""
 423         result = []
 424         self._close_item(result)
 425         self.in_li = 1
 426         result.append(self.formatter.listitem(1))
 427         result.append(self.formatter.paragraph(1))
 428         return ''.join(result)
 429 
 430 
 431     def _ol_repl(self, match):
 432         """Handle numbered lists."""
 433         return self._li_repl(match)
 434 
 435 
 436     def _dl_repl(self, match):
 437         """Handle definition lists."""
 438         result = []
 439         self._close_item(result)
 440         self.in_dd = 1
 441         result.extend([
 442             self.formatter.definition_term(1),
 443             match[:-3],
 444             self.formatter.definition_term(0),
 445             self.formatter.definition_desc(1)
 446         ])
 447         return ''.join(result)
 448 
 449 
 450     def _tt_repl(self, word):
 451         """Handle inline code."""
 452         self._check_p()
 453         return self.formatter.code(1) + \
 454             self.highlight_text(word[3:-3]) + \
 455             self.formatter.code(0)
 456 
 457 
 458     def _tt_bt_repl(self, word):
 459         """Handle backticked inline code."""
 460         if len(word) == 2: return ""
 461         self._check_p()
 462         return self.formatter.code(1) + \
 463             self.highlight_text(word[1:-1]) + \
 464             self.formatter.code(0)
 465 
 466 
 467     def _getTableAttrs(self, attrdef):
 468         # skip "|" and initial "<"
 469         while attrdef and attrdef[0] == "|":
 470             attrdef = attrdef[1:]
 471         if not attrdef or attrdef[0] != "<":
 472             return {}, ''
 473         attrdef = attrdef[1:]
 474 
 475         # extension for special table markup
 476         def table_extension(key, parser, attrs):
 477             msg = ''
 478             if key[0].isdigit():
 479                 token = parser.get_token()
 480                 if token != '%':
 481                     wanted = '%'
 482                     msg = _('Expected "%(wanted)s" after "%(key)s", got "%(token)s"') % locals()
 483                 else:
 484                     try:
 485                         dummy = int(key)
 486                     except ValueError:
 487                         msg = _('Expected an integer "%(key)s" before "%(token)s"') % locals()
 488                     else:
 489                         attrs['width'] = '"%s"' % key
 490             elif key == '-':
 491                 arg = parser.get_token()
 492                 try:
 493                     dummy = int(arg)
 494                 except ValueError:
 495                     msg = _('Expected an integer "%(arg)s" after "%(key)s"') % locals()
 496                 else:
 497                     attrs['colspan'] = '"%s"' % arg
 498             elif key == '|':
 499                 arg = parser.get_token()
 500                 try:
 501                     dummy = int(arg)
 502                 except ValueError:
 503                     msg = _('Expected an integer "%(arg)s" after "%(key)s"') % locals()
 504                 else:
 505                     attrs['rowspan'] = '"%s"' % arg
 506             elif key == '(':
 507                 attrs['align'] = '"left"'
 508             elif key == ':':
 509                 attrs['align'] = '"center"'
 510             elif key == ')':
 511                 attrs['align'] = '"right"'
 512             elif key == '^':
 513                 attrs['valign'] = '"top"'
 514             elif key == 'v':
 515                 attrs['valign'] = '"bottom"'
 516             elif key == '#':
 517                 arg = parser.get_token()
 518                 try:
 519                     if len(arg) != 6: raise ValueError
 520                     dummy = int(arg, 16)
 521                 except ValueError:
 522                     msg = _('Expected a color value "%(arg)s" after "%(key)s"' % locals())
 523                 else:
 524                     attrs['bgcolor'] = '"%s"' % arg
 525             else:
 526                 msg = None
 527             return msg
 528 
 529         # scan attributes
 530         attr, msg = wikiutil.parseAttributes(attrdef, '>', table_extension)
 531         if msg: msg = '<strong class="highlight">%s</strong>' % msg
 532         return attr, msg
 533 
 534     def _tableZ_repl(self, word):
 535         """Handle table row end."""
 536         if self.in_table:
 537             return self.formatter.table_cell(0) + self.formatter.table_row(0)
 538         else:
 539             return word
 540 
 541 
 542     def _table_repl(self, word):
 543         """Handle table cell separator."""
 544         if self.in_table:
 545             # check for attributes
 546             attrs, attrerr = self._getTableAttrs(word)
 547 
 548             # start the table row?
 549             if self.table_rowstart:
 550                 self.table_rowstart = 0
 551                 leader = self.formatter.table_row(1, attrs)
 552             else:
 553                 leader = self.formatter.table_cell(0)
 554 
 555             # check for adjacent cell markers
 556             if word.count("|") > 2:
 557                 if 'align' not in attrs:
 558                     attrs['align'] = '"center"'
 559                 if 'colspan' not in attrs:
 560                     attrs['colspan'] = '"%d"' % (word.count("|")/2)
 561 
 562             # return the complete cell markup           
 563             return leader + self.formatter.table_cell(1, attrs) + attrerr
 564         else:
 565             return word
 566 
 567 
 568     def _heading_repl(self, word):
 569         """Handle section headings."""
 570         import sha
 571 
 572         icons = ''
 573         if self.request.user.show_topbottom:
 574             bottom = self.formatter.image(width=14, height=10, hspace=2, vspace=6, align="right",
 575                 border=0, src=config.url_prefix+"/img/moin-bottom.gif", alt="[BOTTOM]")
 576             icons += self.formatter.url("#bottom", bottom, unescaped=1)
 577             top = self.formatter.image(width=14, height=10, hspace=2, vspace=6, align="right",
 578                 border=0, src=config.url_prefix+"/img/moin-top.gif", alt="[TOP]")
 579             icons += self.formatter.url("#top", top, unescaped=1)
 580 
 581         h = word.strip()
 582         level = 1
 583         while h[level] == '=': level += 1
 584         depth = min(5,level)
 585         headline = h[level:-level].strip()
 586         return \
 587             self.formatter.anchordef("head-"+sha.new(headline).hexdigest()) + \
 588             self.formatter.heading(depth, self.highlight_text(headline, flow=0), icons=icons)
 589 
 590 
 591     def _processor_repl(self, word):
 592         """Handle processed code displays."""
 593         if word[:3] == '{{{': word = word[3:]
 594 
 595         from MoinMoin.processor import processors
 596         self.processor = None
 597         processor_name = word[2:].split()[0]
 598         if processor_name in processors:
 599             self.processor = util.importName("MoinMoin.processor." +
 600                 processor_name, "process")
 601 
 602         if self.processor:
 603             self.in_pre = 2
 604             self.colorize_lines = [word]
 605             return ''
 606         else:
 607             self._check_p()
 608             self.in_pre = 1
 609             return self.formatter.preformatted(self.in_pre) + \
 610                 self.formatter.text(word)
 611 
 612 
 613     def _pre_repl(self, word):
 614         """Handle code displays."""
 615         word = word.strip()
 616         if word == '{{{' and not self.in_pre:
 617             self._check_p()
 618             self.in_pre = 1
 619             return self.formatter.preformatted(self.in_pre)
 620         elif word == '}}}' and self.in_pre:
 621             self.in_pre = 0
 622             return self.formatter.preformatted(self.in_pre)
 623 
 624         return word
 625 
 626 
 627     def _smiley_repl(self, word):
 628         """Handle smileys."""
 629         self._check_p()
 630         return wikiutil.getSmiley(word, self.formatter)
 631 
 632     _smileyA_repl = _smiley_repl
 633 
 634 
 635     def _comment_repl(self, word):
 636         return ''
 637 
 638 
 639     def _macro_repl(self, word):
 640         """Handle macros ([[macroname]])."""
 641         self._check_p()
 642         macro_name = word[2:-2]
 643 
 644         # check for arguments
 645         args = None
 646         if macro_name.count("("):
 647             macro_name, args = macro_name.split('(', 1)
 648             args = args[:-1]
 649 
 650         # create macro instance
 651         if self.macro is None:
 652             self.macro = wikimacro.Macro(self)
 653 
 654         # call the macro
 655         return self.macro.execute(macro_name, args)
 656 
 657 
 658     def _indent_level(self):
 659         """Return current char-wise indent level."""
 660         return len(self.list_indents) and self.list_indents[-1]
 661 
 662 
 663     def _indent_to(self, new_level, list_type, numtype, numstart):
 664         """Close and open lists."""
 665         close = []
 666         open = ''
 667 
 668         # Close open paragraphs and list items
 669         if self._indent_level() != new_level:
 670             self._close_item(close)
 671 
 672         # Close lists while char-wise indent is greater than the current one
 673         while self._indent_level() > new_level:
 674             if self.list_types[-1] == 'ol':
 675                 close.append(self.formatter.number_list(0))
 676             elif self.list_types[-1] == 'dl':
 677                 close.append(self.formatter.definition_list(0))
 678             else:
 679                 close.append(self.formatter.bullet_list(0))
 680 
 681             del(self.list_indents[-1])
 682             del(self.list_types[-1])
 683 
 684         # Open new list, if necessary
 685         if self._indent_level() < new_level:
 686             self.list_indents.append(new_level)
 687             self.list_types.append(list_type)
 688             if list_type == 'ol':
 689                 open += self.formatter.number_list(1, numtype, numstart)
 690             elif list_type == 'dl':
 691                 open += self.formatter.definition_list(1)
 692             else:
 693                 open += self.formatter.bullet_list(1)
 694 
 695         # If list level changes, close an open table
 696         if self.in_table and (open or close):
 697             close.insert(0, self.formatter.table(0))
 698             self.in_table = 0
 699 
 700         return ''.join(close) + open
 701 
 702 
 703     def _undent(self):
 704         """Close all open lists."""
 705         result = []
 706         self._close_item(result)
 707         for type in self.list_types:
 708             if type == 'ol':
 709                 result.append(self.formatter.number_list(0))
 710             elif type == 'dl':
 711                 result.append(self.formatter.definition_list(0))
 712             else:
 713                 result.append(self.formatter.bullet_list(0))
 714         self.list_indents = []
 715         self.list_types = []
 716         return ''.join(result)
 717 
 718 
 719     def highlight_text(self, text, **kw):
 720         if kw.get('flow', 1): self._check_p()
 721         if not self.hilite_re: return self.formatter.text(text)
 722 
 723         result = []
 724         lastpos = 0
 725         match = self.hilite_re.search(text)
 726         while match and lastpos < len(text):
 727             # add the match we found
 728             result.append(self.formatter.text(text[lastpos:match.start()]))
 729             result.append(self.formatter.highlight(1))
 730             result.append(self.formatter.text(match.group(0)))
 731             result.append(self.formatter.highlight(0))
 732 
 733             # search for the next one
 734             lastpos = match.end() + (match.end() == lastpos)
 735             match = self.hilite_re.search(text, lastpos)
 736 
 737         result.append(self.formatter.text(text[lastpos:]))
 738         return ''.join(result)
 739 
 740     def highlight_scan(self, scan_re, line):
 741         result = []
 742         lastpos = 0
 743         match = scan_re.search(line)
 744         while match and lastpos < len(line):
 745             # add the match we found
 746             result.append(self.highlight_text(line[lastpos:match.start()]))
 747             result.append(self.replace(match))
 748 
 749             # search for the next one
 750             lastpos = match.end() + (match.end() == lastpos)
 751             match = scan_re.search(line, lastpos)
 752 
 753         result.append(self.highlight_text(line[lastpos:]))
 754         return ''.join(result)
 755 
 756 
 757     def replace(self, match):
 758         #hit = filter(lambda g: g[1], match.groupdict().items())
 759         for type, hit in match.groupdict().items():
 760             if hit is not None and type != "hmarker":
 761                 ##print "###", cgi.escape(`type`), cgi.escape(`hit`), "###"
 762                 if self.in_pre and type not in ['pre', 'ent']:
 763                     return self.highlight_text(hit)
 764                 else:
 765                     return getattr(self, '_' + type + '_repl')(hit)
 766         else:
 767             import pprint
 768             raise Exception("Can't handle match " + `match`
 769                 + "\n" + pprint.pformat(match.groupdict())
 770                 + "\n" + pprint.pformat(match.groups()) )
 771 
 772         return ""
 773 
 774 
 775     # needed new variable printing which decides if printing to stdout or buffer
 776     def format(self, formatter, form, printing=1):
 777         """ For each line, scan through looking for magic
 778             strings, outputting verbatim any intervening text.
 779         """
 780         self.formatter = formatter
 781         self.form = form
 782         self.hilite_re = self.formatter.page.hilite_re
 783 	self.mybuffer = ['']
 784 
 785         # prepare regex patterns
 786         rules = self.formatting_rules.replace('\n', '|')
 787         if config.allow_extended_names:
 788             rules = rules + r'|(?P<wikiname_bracket>\[".*?"\])'
 789         if config.bang_meta:
 790             rules = r'(?P<notword>!%(word_rule)s)|%(rules)s' % {
 791                 'word_rule': self.word_rule,
 792                 'rules': rules,
 793             }
 794         if config.backtick_meta:
 795             rules = rules + r'|(?P<tt_bt>`.*?`)'
 796         if config.allow_numeric_entities:
 797             rules = r'(?P<ent_numeric>&#\d{1,5};)|' + rules
 798 
 799         scan_re = re.compile(rules)
 800         number_re = re.compile(self.ol_rule)
 801         term_re = re.compile(self.dl_rule)
 802         indent_re = re.compile("^\s*")
 803         eol_re = re.compile(r'\r?\n')
 804 
 805         # get text and replace TABs
 806         rawtext = self.raw.expandtabs()
 807 
 808         # go through the lines
 809         self.lineno = 0
 810         self.lines = eol_re.split(rawtext)
 811         for line in self.lines:
 812             self.lineno = self.lineno + 1
 813             self.table_rowstart = 1
 814 
 815             if self.in_pre:
 816                 if self.in_pre == 2:
 817                     # processing mode
 818                     endpos = line.find("}}}")
 819                     if endpos == -1:
 820                         self.colorize_lines.append(line)
 821                         continue
 822 
 823                     self.processor(self.request, self.formatter, self.colorize_lines)
 824                     del self.colorize_lines
 825                     self.in_pre = 0
 826 
 827                     # send rest of line through regex machinery
 828                     line = line[endpos+3:]                    
 829                 elif line.strip()[:2] == "#!" and line.find('python') > 0:
 830                     from MoinMoin.processor.Colorize import process
 831                     self.processor = process
 832                     self.in_pre = 2
 833                     self.colorize_lines = [line]
 834                     continue
 835             else:
 836                 # paragraph break on empty lines
 837                 if not line.strip():
 838                     if self.formatter.in_p:
 839                         self.mywrite(self.formatter.paragraph(0))
 840                     if self.in_table:
 841                         self.mywrite(self.formatter.table(0))
 842                         self.in_table = 0
 843                     continue
 844 
 845                 # check indent level
 846                 indent = indent_re.match(line)
 847                 indlen = len(indent.group(0))
 848                 indtype = "ul"
 849                 numtype = None
 850                 numstart = None
 851                 if indlen:
 852                     match = number_re.match(line)
 853                     if match:
 854                         numtype, numstart = match.group(0).strip().split('.')
 855                         numtype = numtype[0]
 856 
 857                         if numstart and numstart[0] == "#":
 858                             numstart = int(numstart[1:])
 859                         else:
 860                             numstart = None
 861 
 862                         indtype = "ol"
 863                     else:
 864                         match = term_re.match(line)
 865                         if match:
 866                             indtype = "dl"
 867 
 868                 # output proper indentation tags
 869                 print self._indent_to(indlen, indtype, numtype, numstart)
 870 
 871                 # start or end table mode
 872                 if not self.in_table and line[indlen:indlen+2] == "||" and line[-2:] == "||":
 873                     attrs, attrerr = self._getTableAttrs(line[indlen+2:])
 874                     self.mywrite(self.formatter.table(1, attrs) + attrerr)
 875                     self.in_table = self.lineno
 876                 elif self.in_table and not(line[indlen:indlen+2] == "||" and line[-2:] == "||"):
 877                     self.mywrite(self.formatter.table(0))
 878                     self.in_table = 0
 879 
 880             # convert line from wiki markup to HTML and print it
 881             if self.hilite_re:
 882                 self.mywrite(self.highlight_scan(scan_re, line + " "))
 883             else:
 884                 line, count = re.subn(scan_re, self.replace, line + " ")
 885                 ##if not count: self._check_p()
 886                 self._check_p()
 887                 self.mywrite(line)
 888 
 889             if self.in_pre:
 890                 self.mywrite(self.formatter.linebreak())
 891             #if self.in_li:
 892             #    self.in_li = 0
 893             #    self.mywrite(self.formatter.listitem(0))
 894 
 895         # close code displays, paragraphs, tables and open lists
 896         if self.in_pre: self.mywrite(self.formatter.preformatted(0))
 897         if self.formatter.in_p: self.mywrite(self.formatter.paragraph(0))
 898         if self.in_table: self.mywrite(self.formatter.table(0))
 899         self.mywrite(self._undent())
 900         if printing==1: # flush buffer to stdout or
 901             self.myflush()
 902         else:
 903             return self.myread() # return buffer

FabianFranz/wiki.py (zuletzt geändert am 2010-03-06 06:15:49 durch s235-148)