Attachment 'slideshow_wiki-1.0.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3 MoinMoin - slideshow_wiki parser, Version 1.0, 05.12.2012
   4 
   5 A slide parser for SlideShow action, which by default behaves as the in-built
   6 parser, that can be additionally controlled by #pragma processing instructions
   7 to give alternative functionality. 
   8 
   9 See http://rileylink.net/moin.cgi/slideshow_wiki.py for more information.
  10 
  11 @copyright: 2012 Ian Riley <ian.riley@internode.on.net>
  12             
  13 Developed with inspiration and code from SlideShow action:
  14 
  15 @copyright: 2005 Jim Clark,
  16             2005 Nir Soffer,
  17             2008 ThomasWaldmann, 2009 ReimarBauer
  18             
  19 License: GNU GPL, see COPYING for details.
  20 """
  21 
  22 import re
  23 from MoinMoin.parser import text_moin_wiki as wiki
  24 
  25 class Parser:
  26     """ Warning parser to keep wikiutil.py happy.
  27     
  28     SlideShow action expects to find plugin parser in wiki/data/plugin/parser
  29     with class SlidePaser.
  30     
  31     Module wikiutil.py imports all parsers from wiki/data/plugin/paser expecting
  32     class Paser and looks for parsername. So this parser is to keep wikiutil
  33     on track and to provide a warning if direct use of slideparser_wiki is
  34     attempted.
  35     """        
  36     parsername = 'slideshow_wiki'
  37 
  38     def __init__(self, raw, request, **kw):
  39         self.raw = raw
  40         self.request = request
  41         self.form = request.form
  42         self._ = request.getText
  43 
  44     def format(self, formatter):
  45 
  46         warning = """
  47 {{{#!wiki red/solid
  48  /!\ '''Warning''': slideshow_wiki parser is for !SlideShow action only.       
  49 }}}
  50 """
  51         wikiizer = wiki.Parser(warning, self.request)
  52         wikiizer.format(formatter)
  53 
  54 class SlideParser(object):
  55     """ Parse slides using wiki format
  56 
  57     Imported by SlideShow action from wiki/data/plugin/paser and
  58     used effectively as:
  59         for title, start, end in SlideParser().parse(text):
  60             slides.append((title, start, end))
  61     """        
  62     
  63     _skip_pattern = r'(?P<skip>({{{(?:.*\n)+?}}})|(`.*`))'
  64     
  65     _heading_pattern = r"""
  66         (?P<heading>
  67         ^(?P<hmarker>=+)\s+
  68         (?P<text>.*?)\s+
  69         (?P=hmarker)$)
  70         """
  71 
  72     _pi_pattern = r'(?P<pi>)'
  73 
  74     # this pattern will find #pragma, #pragma key and #pragma key val,
  75     # which allows valueless keys to be detected.
  76     _pragma_pattern = r"""
  77         (?P<pragma>^\#pragma
  78         (?P<key>[ \t]?\S+)?
  79         (?P<val>[ \t]?.+)?)\n
  80         """     
  81     _compiled_heading_pattern = re.compile(
  82         _skip_pattern + "|" + _heading_pattern,
  83         re.MULTILINE | re.UNICODE | re.VERBOSE)
  84 
  85     _compiled_pragma_pattern = re.compile(
  86         _skip_pattern + "|" + _pragma_pattern, 
  87         re.MULTILINE | re.UNICODE | re.VERBOSE)
  88 
  89     #_slide_pattern_template = r'^(?P<slide>%s)((?P<extra>[ \t]?.+)?)\n'
  90     #_notes_pattern_template = r'^(?P<notes>%s)'
  91     # the above forces the token to be at the beginning of a line
  92     _slide_pattern_template = r'(?P<slide>%s)((?P<extra>[ \t]?.+)?)\n'
  93     _notes_pattern_template = r'(?P<notes>%s)'
  94     
  95     _compiled_token_pattern = '' #to be set by settings()
  96     _compiled_notes_pattern = ''
  97 
  98     slidesOn = True
  99     slidesToken = True
 100     slidesHeading = None
 101     slideToken = '##slide'
 102 
 103     notesOn = True
 104     notesToken = '##notes'
 105 
 106     tokens = {}
 107  
 108     def pi(self, text):
 109         """Return processing instruction lines from top of text
 110         """
 111         piText = ''
 112         while text and text[0] == '#':
 113             piLine, text = text.split('\n',1)
 114             piText = '\n'.join([piText, piLine])
 115         return piText
 116  
 117     def settings(self, text):
 118     
 119         # set defaults to give behaviour as the in-built parser
 120         self.tokens = {'slides': '1', 'notes': 'off'}
 121   
 122         matches = [match for match in self._compiled_pragma_pattern.finditer(self.pi(text))]
 123                
 124         for i in range(len(matches)):
 125             key = (matches[i].group('key') or '').strip()
 126             val = (matches[i].group('val') or '').strip()
 127             if key in ['slides', 'notes']:
 128                 self.tokens[key] = val
 129 
 130         if self.tokens['slides'] in ['', 'on']:
 131             self.tokens['slides'] = self.slideToken
 132         elif self.tokens['slides'] == 'off':
 133             self.slidesOn = False
 134         elif self.tokens['slides'] in str(range(1, 5)):
 135             self.slidesToken = False
 136             self.slidesHeading = int(self.tokens['slides'])
 137         
 138         if self.tokens['notes'] in ['', 'on']:
 139             self.tokens['notes'] = self.notesToken
 140         elif self.tokens['notes'] == 'off':
 141             self.notesOn = False
 142             
 143         if self.slidesOn:
 144             _slide_pattern = self._slide_pattern_template % (re.escape(self.tokens['slides']))
 145             _notes_pattern = self._notes_pattern_template % (re.escape(self.tokens['notes']))
 146             _token_pattern = ''
 147             if self.slidesToken:
 148                 _token_pattern = _slide_pattern
 149                 if self.notesOn:
 150                     _token_pattern += '|'
 151             if self.notesOn:
 152                 _token_pattern += _notes_pattern 
 153 
 154             self._compiled_token_pattern = re.compile(
 155                 self._skip_pattern + '|' +
 156                 _token_pattern,
 157                 re.MULTILINE | re.UNICODE | re.VERBOSE)
 158                 
 159     def headings(self, text):
 160         """ Get wiki headings and return a lis of
 161             [heading, headingStart, headingEnd, headingLevel]
 162             with headingLevel as interger between 1 and 5.
 163         """
 164         matches = [match for match in 
 165                        self._compiled_heading_pattern.finditer(text)
 166                        if match.start('skip') == -1]
 167         headings = []
 168         for i in range(len(matches)):
 169             heading = matches[i].group('text').strip()
 170             headingStart = matches[i].start('heading')
 171             headingEnd  = matches[i].end('heading')
 172             headingLevel = matches[i].group('hmarker').strip()
 173             headings.append([heading, headingStart, headingEnd, len(headingLevel)])
 174         return headings
 175     
 176     def parse(self, text):
 177         """ Parse text for slide data.
 178 
 179         Slides are defined by slide tokens or headings of a specified
 180         level, ignoring the text before the first token/heading. Where 
 181         a token is used the slide heading is taken from any heading found
 182         on the next content line.
 183         
 184         A notes token indicates content to be ignored between slide tokens
 185         or slide headings.
 186         
 187         Content with parser sections is ignored when searching for tokens or
 188         slide headings.
 189 
 190         Returns an iterator of (title, bodyStart, bodyEnd) for each slide,
 191         with bodyStart and bodyEnd as indexes to the text provided.
 192         """
 193 
 194         self.settings(text)
 195         
 196         if self.slidesOn:
 197         
 198             headings = self.headings(text)
 199             
 200             slideNum = 0
 201             slides = []
 202 
 203             if self.slidesToken:
 204                 matches = [match for match in
 205                            self._compiled_token_pattern.finditer(text)
 206                            if match.start('skip') == -1]
 207                 matchCount = len(matches)
 208                 for i in range(matchCount):
 209                     title = ''
 210                     slideTokenStart = matches[i].start('slide')
 211                     slideTokenEnd = matches[i].end('slide')
 212                     slideTokenExtra = (matches[i].group('extra') or '')
 213                     slideTokenHeadings = self.headings(slideTokenExtra.strip())
 214                     if slideTokenHeadings:
 215                         title = slideTokenHeadings[0][0]
 216                         slideTokenEnd = matches[i].end('extra')
 217                     elif slideTokenExtra:
 218                         if slideTokenExtra[0] in [' ', '\t']:
 219                             slideTokenEnd += 1
 220                     if self.notesOn:
 221                         notesTokenStart = matches[i].start('notes')
 222                     if slideTokenStart != -1:
 223                         slideNum += 1
 224                         slideStart = slideTokenEnd
 225                         if i + 1 < matchCount:
 226                             if self.notesOn:
 227                                 slideEnd = matches[i + 1].start('notes')
 228                             if (not self.notesOn) or slideEnd == -1:
 229                                 slideEnd = matches[i + 1].start('slide')
 230                         else:
 231                             slideEnd = len(text) 
 232                         slides.append([title, slideStart, slideEnd])
 233 
 234                 slidesWithHeadings = []
 235                 for slide in slides:
 236                     modified = False
 237                     for heading in headings:
 238                         if not slide[0] and slide[1] + 1 == heading[1]:
 239                             slidesWithHeadings.append([heading[0], heading[2], slide[2]])
 240                             modified = True
 241                     if not modified:
 242                         slidesWithHeadings.append(slide)
 243                 slides = slidesWithHeadings                
 244             else:
 245                 if self.notesOn:
 246                     notes = []
 247                     matches = [match for match in 
 248                                self._compiled_token_pattern.finditer(text)
 249                                if match.start('skip') == -1]
 250                     for match in matches:
 251                         notesStart = match.start('notes')
 252                         notes.append(notesStart)
 253 
 254                 headingsToUse = []
 255                 for heading in headings:
 256                     if self.slidesHeading == heading[3]:
 257                         headingsToUse.append(heading)
 258                 headings = headingsToUse
 259                 matchCount = len(headings)
 260                 if matchCount:
 261                     for i in range(matchCount):
 262                         title = headings[i][0]
 263                         slideStart = headings[i][2]
 264                         if i + 1 < matchCount:
 265                             slideEnd = headings[i + 1][1]
 266                         else:
 267                             slideEnd = len(text)
 268                         if self.notesOn:
 269                             for end in notes:
 270                                 if (slideStart < end) and (end < slideEnd):
 271                                     slideEnd = end
 272                                     notes.remove(end)
 273                                     break
 274                         slides.append([title, slideStart, slideEnd])
 275                         
 276             for slide in slides:
 277                 yield slide               
 278 
 279 def main():
 280 
 281     dummyPage = '''
 282 #format wiki
 283 ## test empty pragma
 284 ##pragma
 285 ## test valueless pragma
 286 #pragma slides
 287 #pragma notes
 288 ## test set value
 289 #pragma slides ##slide
 290 #pragma notes ##notes
 291 ## test value overide
 292 ##pragma slides off
 293 ##pragma notes off
 294 ## test headings
 295 ##pragma slides 2
 296 
 297 <<Action(SlideShow)>>
 298 
 299 ##slide
 300 = Slide 1 =
 301 slide 1 content
 302 ##notes
 303 notes for slide 1
 304 
 305 ##slide
 306 == Slide 2 ==
 307 slide 2 content
 308 ##notes
 309 notes for slide 2
 310 
 311 ##slide = Slide 3 =
 312 === subheading ===
 313 slide 3 content
 314 '''
 315 
 316     P = SlideParser()
 317     for finds in P.parse(dummyPage):
 318         print finds
 319 
 320 if __name__=="__main__":
 321     main()

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