Attachment 'moin-2.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 
   3 import re
   4 from MoinMoin import config
   5 from MoinMoin import wikiutil
   6 from emitter import DocEmitter
   7 from document import DocNode
   8 
   9 Dependencies = []
  10 
  11 class Parser:
  12     """
  13     The class to glue the DocParser and DocEmitter with the
  14     MoinMoin current API.
  15     """
  16     # Enable caching
  17     caching = 1
  18     Dependencies = []
  19 
  20     def __init__(self, raw, request, **kw):
  21         """Create a minimal Parser object with required attributes."""
  22         self.request = request
  23         self.form = request.form
  24         self.raw = raw
  25         
  26     def format(self, formatter):
  27         """Create and call the true parser and emitter."""
  28         document = DocParser(self.raw, self.request).parse()
  29         result = DocEmitter(document, formatter, self.request).emit()
  30         self.request.write(result)
  31 
  32 class DocParser:
  33     """
  34     Parse the raw text and create a document object
  35     that can be converted into output using DocEmitter.
  36     """
  37 
  38     # Table of character sequences to replace with entities:
  39 
  40     # The parsing rules
  41 
  42     wiki_word = r'[A-Z]\w+[A-Z]\w+'
  43 
  44     # For the inline elements
  45     smiley_rule = r'''(?P<smiley>
  46         (?<=[\n\s]) %s (?=[\s),;.?!\n])
  47     )''' % u'|'.join([re.escape(t) for t in config.smileys.keys()])
  48     wikiword_rule = r'''(?P<wikiword>
  49         (\/|(\.\.\/)+|^|(?<=[^!])) \b%s\b (\/%s)*
  50     )'''%(wiki_word, wiki_word)
  51     interwiki_rule = r'''\b(?P<interwiki>
  52         \w+:[^/][\w\/]+
  53     )\b'''
  54     interwiki2_rule = r'\[(?P<interwiki2>\w+:[^/]\S+)(\s+(?P<interwiki2_text>.+?))?\s*\]'
  55     attach_rule = r'\b(attachment|inline|drawing):(?P<attach>\S+?)\b'
  56     attach2_rule = r'\[(attachment|inline|drawing):(?P<attach2>\S+?)\s*(?P<attach2_text>.+?)\s*\]'
  57     anchor_rule = r'\[(?P<anchor>[#]\S+?)\s+(?P<anchor_text>.*?)\s*\]'
  58     url_rule = r'(?P<url>\[(?P<url_addr>(http|https|ftp|nntp|news|mailto|telnet|file|irc):[^\s\]]*)\s*(?P<url_text>.*?)\s*\])'
  59     link_rule = r'(?P<link>\["(?P<link_addr>.+?)"\s*(?P<link_text>.+?)?\s*\])'
  60     macro_rule = r'\[\[(?P<macro>.+?)(\((?P<macro_arg>.*?)\))?\]\]'
  61 
  62     char_rule = r'(?P<char>.)'
  63     code_rule = r'(?P<code>{{{(?P<code_text>.*?)}}})'
  64     code2_rule = r'(?P<code2>`(?P<code2_text>.*?)`)'
  65     emph_rule = r'''(?P<emph>'')'''
  66     strong_rule = r"(?P<strong>''')"
  67     
  68     # For the block elements
  69     rule_rule = r'(?P<rule>^----+$)'
  70     line_rule = r'(?P<line>^\s*$)'
  71     head_rule = r'(?P<head>^(?P<head_head>=+)\s*(?P<head_text>[^*].*?)\s*(?P=head_head)\s*$)'
  72     text_rule = r'(?P<text>.+)'
  73     ulist_rule = r'(?P<ulist>^(?P<ulist_head>\s+[\*])\s+(?P<ulist_text>.*?)$)'
  74     olist_rule = r'(?P<olist>^(?P<olist_head>\s+[0-9a-zA-Z#][\.\)])\s+(?P<olist_text>.*?)$)'
  75     dlist_rule = r'(?P<dlist>^\s+(?P<dlist_term>.+?)\s*::\s*)'
  76     table_rule = r'^\s*(?P<table>(\|\|.+?)+)\|\|\s*$'
  77     pre_rule = r'(?P<pre>^\s*{{{\s*(\n+\s*)?(?P<pre_text>([\#]!(?P<pre_kind>\S*).*$)?(.|\n)+?)(\n)?}}}\s*$)'
  78 
  79     def __init__(self, raw, request):
  80         self.request = request
  81         self._ = request.getText
  82         self.raw = raw
  83         self.root = DocNode("document", None)
  84         self.cur = self.root        # The most recent document node
  85         self.text = None            # The node to add inline characters to
  86         
  87         self.block_rules = '|'.join([
  88                 self.line_rule,
  89                 self.head_rule,
  90                 self.rule_rule,
  91                 self.pre_rule,
  92                 self.ulist_rule,
  93                 self.dlist_rule,
  94                 self.olist_rule,
  95                 self.table_rule,
  96                 self.text_rule,
  97         ])
  98         self.block_re = re.compile(self.block_rules, re.X|re.U|re.M)
  99         self.abbr_rule = self.get_abbr_rule()
 100         self.inline_rules = '|'.join([
 101                 self.link_rule,
 102                 self.anchor_rule,
 103                 self.url_rule,
 104                 self.macro_rule,
 105                 self.attach_rule,
 106                 self.attach2_rule,
 107                 self.wikiword_rule,
 108                 self.interwiki_rule,
 109                 self.interwiki2_rule,
 110                 self.code_rule,
 111                 self.code2_rule,
 112                 self.strong_rule,
 113                 self.emph_rule,
 114                 self.abbr_rule,
 115                 self.smiley_rule,
 116                 self.char_rule,
 117         ])
 118         self.inline_re = re.compile(self.inline_rules, re.X|re.U)
 119 
 120     def get_abbr_rule(self):
 121         abbr_dict_page = 'AbbreviationDict'
 122         if self.request.dicts.has_dict(abbr_dict_page):
 123             self.abbr_dict = self.request.dicts.dict(abbr_dict_page)
 124         else:
 125             self.abbr_dict = {}
 126         return r'''(^|<|(?<=[\s()'`"\[\]&-]))(?P<abbr>%s)(>|$|(?=[\s,.!?()'`":;\[\]&-]))'''%'|'.join([re.escape(k.strip()) for k in self.abbr_dict.keys()+['XXX']])
 127 
 128     # copied from wiki.py
 129     def _getTableAttrs(self, attrdef):
 130         # skip "|" and initial "<"
 131         while attrdef and attrdef[0] == "|":
 132             attrdef = attrdef[1:]
 133         if not attrdef or attrdef[0] != "<":
 134             return {}, ''
 135         attrdef = attrdef[1:]
 136 
 137         # extension for special table markup
 138         def table_extension(key, parser, attrs, wiki_parser=self):
 139             _ = wiki_parser._
 140             msg = ''
 141             if key[0] in "0123456789":
 142                 token = parser.get_token()
 143                 if token != '%':
 144                     wanted = '%'
 145                     msg = _('Expected "%(wanted)s" after "%(key)s", got "%(token)s"') % {
 146                         'wanted': wanted, 'key': key, 'token': token}
 147                 else:
 148                     try:
 149                         dummy = int(key)
 150                     except ValueError:
 151                         msg = _('Expected an integer "%(key)s" before "%(token)s"') % {
 152                             'key': key, 'token': token}
 153                     else:
 154                         attrs['width'] = '"%s%%"' % key
 155             elif key == '-':
 156                 arg = parser.get_token()
 157                 try:
 158                     dummy = int(arg)
 159                 except ValueError:
 160                     msg = _('Expected an integer "%(arg)s" after "%(key)s"') % {
 161                         'arg': arg, 'key': key}
 162                 else:
 163                     attrs['colspan'] = '"%s"' % arg
 164             elif key == '|':
 165                 arg = parser.get_token()
 166                 try:
 167                     dummy = int(arg)
 168                 except ValueError:
 169                     msg = _('Expected an integer "%(arg)s" after "%(key)s"') % {
 170                         'arg': arg, 'key': key}
 171                 else:
 172                     attrs['rowspan'] = '"%s"' % arg
 173             elif key == '(':
 174                 attrs['align'] = '"left"'
 175             elif key == ':':
 176                 attrs['align'] = '"center"'
 177             elif key == ')':
 178                 attrs['align'] = '"right"'
 179             elif key == '^':
 180                 attrs['valign'] = '"top"'
 181             elif key == 'v':
 182                 attrs['valign'] = '"bottom"'
 183             elif key == '#':
 184                 arg = parser.get_token()
 185                 try:
 186                     if len(arg) != 6: raise ValueError
 187                     dummy = int(arg, 16)
 188                 except ValueError:
 189                     msg = _('Expected a color value "%(arg)s" after "%(key)s"') % {
 190                         'arg': arg, 'key': key}
 191                 else:
 192                     attrs['bgcolor'] = '"#%s"' % arg
 193             elif key == '=':
 194                 arg = parser.get_token()
 195                 this_key = attrdef.split('=')[0]
 196                 attrs[this_key] = arg
 197             else:
 198                 msg = ""
 199             #print "key: %s\nattrs: %s" % (key, str(attrs))
 200             return msg
 201 
 202         # scan attributes
 203         attr, msg = wikiutil.parseAttributes(self.request, attrdef, '>', table_extension)
 204         if msg: msg = '<strong class="highlight">%s</strong>' % msg
 205         #print attr
 206         return attr, msg
 207     def _upto(self, node, kinds):
 208         """
 209         Look up the tree to the first occurence 
 210         of one of the listed kinds of nodes or root.
 211         Start at the node node.
 212         """
 213         if not node:
 214             return None
 215         while node.parent is not None and not node.kind in kinds:
 216             node = node.parent
 217         return node
 218 
 219     # The _*_repl methods called for matches in regexps
 220 
 221     def _macro_repl(self, groups):
 222         node = DocNode('macro', self.cur, groups.get('macro'))
 223         node.args = groups.get('macro_arg', None)
 224         self.text = None
 225     _macro_arg_repl = _macro_repl
 226 
 227     def _wikiword_repl(self, groups):
 228         page = groups.get('wikiword', '')
 229         node = DocNode('page_link', self.cur)
 230         node.content = page
 231         DocNode('text', node, page)
 232         self.text = None
 233         
 234     def _interwiki_repl(self, groups):
 235         page = groups.get('interwiki', 'self:') or groups.get('interwiki2', 'self:')
 236         text = groups.get('interwiki2_text')
 237         node = DocNode('interwiki_link', self.cur)
 238         node.content = page
 239         DocNode('text', node, text or page.split(':')[1])
 240         self.text = None
 241     _interwiki2_repl = _interwiki_repl
 242     _interwiki2_text_repl = _interwiki_repl
 243 
 244 
 245     def _anchor_repl(self, groups):
 246         addr = groups.get('anchor')
 247         text = groups.get('anchor_text', '') or addr
 248         node = DocNode('anchor_link', self.cur, addr)
 249         DocNode('text', node, text)
 250         self.text = None
 251     _anchor_text_repl = _anchor_repl
 252 
 253     def _url_repl(self, groups):
 254         addr = groups.get('url_addr', ':')
 255         proto = addr.split(':')[0]
 256         text = groups.get('url_text', '') or addr
 257         node = DocNode('external_link', self.cur)
 258         node.content = addr
 259         node.proto = proto
 260         DocNode('text', node, text)
 261         self.text = None
 262     _url_text_repl = _url_repl
 263     _url_addr_repl = _url_repl
 264 
 265     def _attach_repl(self, groups):
 266         addr = groups.get('attach') or groups.get('attach2') or ':'
 267         text = groups.get('attach2_text', ':')
 268         scheme, name = addr.split(':')
 269         if scheme=='inline':
 270             scheme='inlined_attachment'
 271         node = DocNode(scheme, self.cur, name)
 272         DocNode('text', node, text or addr)
 273         self.text = None
 274     _attach2_repl = _attach_repl
 275     _attach2_text_repl = _attach_repl
 276         
 277     def _link_repl(self, groups):
 278         """Handle all kinds of links, including macros."""
 279         addr = groups.get('link_addr', '')
 280         text = (groups.get('link_text', '') or '').strip()
 281         node = DocNode('page_link', self.cur, addr)
 282         DocNode('text', node, text or node.content)
 283         self.text = None
 284     _link_addr_repl = _link_repl
 285     _link_text_repl = _link_repl
 286 
 287     def _rule_repl(self, groups):
 288         self.cur = self._upto(self.cur, ('document','section','blockquote'))
 289         DocNode('rule', self.cur)
 290 
 291     def _table_repl(self, groups):
 292         row = groups.get('table', '||')
 293         attrs, attrerr = self._getTableAttrs(row)
 294         self.cur = self._upto(self.cur, ('table', 'document', 'section', 'blockquote'))
 295         if self.cur.kind!='table':
 296             self.cur = DocNode('table', self.cur)
 297             self.cur.attrs = attrs
 298         tb = self.cur
 299         tr = DocNode('table_row', tb)
 300         tr.attrs = attrs
 301         for cell in row.split('||')[1:]:
 302             if cell and cell[0]=='<':
 303                 attrs, attrerr = self._getTableAttrs(cell)
 304                 parts = cell[1:].split('>')
 305                 args = parts[0]
 306                 cell = '>'.join(parts[1:])
 307             else:
 308                 args = None
 309                 attrs = {}
 310                 attrerr =''
 311             self.cur = DocNode('table_cell', tr)
 312             self.cur.attrs = attrs
 313             self.text = None
 314             self.parse_inline(cell)
 315         self.cur = tb
 316         self.text = None
 317 
 318     def _dlist_repl(self, groups):
 319         self.cur = self._upto(self.cur, ('definition_list', 'document', 'section', 'blockquote'))
 320         if self.cur.kind!='definition_list':
 321             self.cur = DocNode('definition_list', self.cur)
 322         dl = self.cur
 323         self.cur = DocNode('term', dl)
 324         self.text = None
 325         self.parse_inline(groups.get('dlist_term', u''))
 326         self.cur = DocNode('definition', dl)
 327         self.text = None
 328     _dlist_term_repl = _dlist_repl
 329         
 330     def _ulist_repl(self, groups):
 331         bullet = groups.get('ulist_head', '')
 332         # Find a list with the same bullet up the tree
 333         lst = self.cur
 334         while ( lst and 
 335                 not (lst.kind == 'bullet_list' and 
 336                 lst.bullet==bullet) and 
 337                 not lst.kind in ('document','section','blockquote')
 338             ):
 339             lst = lst.parent
 340         if lst and lst.kind=='bullet_list':
 341             self.cur = lst
 342         else:
 343             # Create a new level of list
 344             self.cur = self._upto(self.cur, ('list_item', 'document', 'section', 'blockquote'))
 345             self.cur = DocNode('bullet_list', self.cur)
 346             self.cur.bullet = bullet
 347         self.cur = DocNode('list_item', self.cur)
 348         self.parse_inline(groups.get('ulist_text', ''))
 349         self.text = None
 350     _ulist_text_repl=_ulist_repl
 351     _ulist_head_repl=_ulist_repl
 352 
 353     def _olist_repl(self, groups):
 354         bullet = groups.get('olist_head', '')
 355         # Normalize the list number
 356         bullet = re.sub(r'[0-9]', '0', bullet)
 357         bullet = re.sub(r'[a-z]', 'a', bullet)
 358         bullet = re.sub(r'[A-Z]', 'A', bullet)
 359         # Find a list with the same bullet up the tree
 360         lst = self.cur
 361         while lst and not (lst.kind == 'number_list' and lst.bullet==bullet) and not lst.kind in ('document','section','blockquote'):
 362             lst = lst.parent
 363         if lst and lst.kind=='number_list':
 364             self.cur = lst
 365         else:
 366             # Create a new level of list
 367             self.cur = self._upto(self.cur, ('list_item', 'document', 'section', 'blockquote'))
 368             self.cur = DocNode('number_list', self.cur)
 369             self.cur.bullet = bullet
 370         self.cur = DocNode('list_item', self.cur)
 371         self.parse_inline(groups.get('olist_text', ''))
 372         self.text = None
 373     _olist_text_repl=_olist_repl
 374     _olist_head_repl=_olist_repl
 375 
 376     def _head_repl(self, groups):
 377         self.cur = self._upto(self.cur, ('document','section', 'blockquote'))
 378         node = DocNode('header', self.cur, groups.get('head_text', '').strip())
 379         node.level = len(groups.get('head_head', ' '))
 380     _head_head_repl = _head_repl
 381     _head_text_repl = _head_repl
 382    
 383     def _text_repl(self, groups):
 384         # No text allowed in those nodes
 385         if self.cur.kind in ('number_list', 'bullet_list', 'definition_list', 'table', 'table_row'):
 386             self.cur = self._upto(self.cur, ('document','section', 'blockquote'))
 387         # Those nodes can have text, but only in paragraphs
 388         if self.cur.kind in ('document','section','blockquote'):
 389             self.cur = DocNode('paragraph', self.cur)
 390         self.parse_inline(groups.get('text', '')+' ')
 391         self.text = None
 392 
 393     def _pre_repl(self, groups):
 394         self.cur = self._upto(self.cur, ('document','section','blockquote'))
 395         kind = groups.get('pre_kind', None)
 396         node = DocNode('preformatted', self.cur, groups.get('pre_text', u''))
 397         node.sect = kind or ''
 398         self.text = None
 399     _pre_text_repl = _pre_repl
 400     _pre_head_repl = _pre_repl
 401     _pre_kind_repl = _pre_repl
 402     
 403     def _line_repl(self, groups):
 404         self.cur = self._upto(self.cur, ('document','section','blockquote'))
 405 
 406     def _code_repl(self, groups):
 407         text = groups.get('code_text', u'') or groups.get('code2_text', u'')
 408         DocNode('code', self.cur, text)
 409         self.text = None
 410     _code_text_repl = _code_repl
 411     _code2_text_repl = _code_repl
 412     _code2_repl = _code_repl
 413 
 414     def _emph_repl(self, groups):
 415         last = self._upto(self.cur, ('emphasis','document'))
 416         if last.kind=='emphasis':
 417             self.cur = last.parent or self.root
 418         else:
 419             self.cur = DocNode('emphasis', self.cur)
 420         self.text = None
 421     _emph_open_repl = _emph_repl
 422     _emph_close_repl = _emph_repl
 423   
 424     def _strong_repl(self, groups):
 425         last = self._upto(self.cur, ('strong','document'))
 426         if last.kind=='strong':
 427             self.cur = last.parent or self.root
 428         else:
 429             self.cur = DocNode('strong', self.cur)
 430         self.text = None
 431     _strong_open_repl = _strong_repl
 432     _strong_close_repl = _strong_repl
 433   
 434     def _smiley_repl(self, groups):
 435         word = groups.get('smiley', '')
 436         DocNode('smiley', self.cur, word)
 437         
 438     def _abbr_repl(self, groups):
 439         abbr = groups.get('abbr', '')
 440         node = DocNode('abbr', self.cur, abbr)
 441         node.title = self.abbr_dict.get(abbr, '???')
 442         self.text = None
 443   
 444     def _char_repl(self, groups):
 445         if self.text is None:
 446             self.text = DocNode('text', self.cur, u'')
 447         self.text.content += groups.get('char', u'')
 448  
 449     def _replace(self, match):
 450         """Invoke appropriate _*_repl method. Called for every matched group."""
 451         groups = match.groupdict()
 452         for name,text in groups.iteritems():
 453             if text is not None:
 454                 replace = getattr(self, '_%s_repl'%name)
 455                 replace(groups)
 456                 return
 457 
 458     def parse_inline(self, raw):
 459         """Recognize inline elements inside blocks."""
 460         re.sub(self.inline_re, self._replace, raw)
 461     
 462     def parse_block(self, raw):
 463         """Recognize block elements."""
 464         re.sub(self.block_re, self._replace, raw)
 465     
 466     def parse(self):
 467         self.parse_block(self.raw)
 468         return self.root

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.
  • [get | view] (2006-06-01 08:42:20, 0.2 KB) [[attachment:document.py]]
  • [get | view] (2006-06-01 08:54:54, 10.5 KB) [[attachment:emitter-2.py]]
  • [get | view] (2006-06-01 08:55:10, 17.3 KB) [[attachment:moin-2.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.