Edgewall Software

Ticket #801: patch_779_780_and_more.diff

File patch_779_780_and_more.diff, 18.6 KB (added by tonib, 4 years ago)

Patch for the ticket

  • trac/util.py

     
    7272               .replace('"', '"') 
    7373    return text 
    7474 
     75def unescape(text): 
     76    """Reverses Escapes &, <, > and \"""" 
     77    if not text: 
     78        return '' 
     79    if type(text) is StringType: 
     80        text = text.replace('&#34;', '"') \ 
     81               .replace('&gt;', '>') \ 
     82               .replace('&lt;', '<') \ 
     83               .replace('&amp;', '&')  
     84    return text 
     85 
    7586def get_first_line(text, maxlen): 
    7687    """ 
    7788    returns the first line of text. If the line is longer then 
  • trac/wikimacros/rst.py

     
    4343    raise EnvironmentError, 'Docutils version >= %s required, %s found' % (docutils_required, __version__) 
    4444 
    4545from trac.Href import Href 
     46from trac.WikiFormatter import WikiProcessor 
    4647 
    4748__docformat__ = 'reStructuredText' 
    4849 
    49 WIKI_LINK = re.compile(r'(?:wiki:)?(?P<w>[A-Za-z][\w\#\?]*[^\w\#\?]*)') # Links must begin with Letters, \# ? so we can link inside pages. 
    50 #WIKI_LINK = re.compile(r'(?:wiki:)?(?P<w>(^|(?<=[^A-Za-z]))[!]?[A-Z][a-z/]+(?:[A-Z][a-z/]+)+)') 
     50WIKI_LINK = re.compile(r'(?:wiki:)?(.+)') 
     51#WIKI_LINK = re.compile(r'(?:wiki:)?(?P<wikilink>[A-Za-z][\w\-]*[^\w\#\?]*)') 
    5152TICKET_LINK = re.compile(r'(?:#(\d+))|(?:ticket:(\d+))') 
    5253REPORT_LINK = re.compile(r'(?:{(\d+)})|(?:report:(\d+))') 
    5354CHANGESET_LINK = re.compile(r'(?:\[(\d+)\])|(?:changeset:(\d+))') 
    5455FILE_LINK = re.compile(r'(?:browser|repos|source):([^#]+)#?(.*)') 
    5556 
     57#import trac.Logging 
     58#log = trac.Logging.logger_factory(logtype='file', logfile="/tmp/debug_rst.txt", level='ALL') 
     59 
    5660def _wikipage(href, args): 
    5761    return href.wiki(args[0]) 
    5862 
     
    7175    return href.browser(path, rev) 
    7276 
    7377# TracLink REs and callback functions 
    74 LINKS = [(WIKI_LINK, _wikipage), 
    75          (TICKET_LINK, _ticket), 
     78LINKS = [(TICKET_LINK, _ticket), 
    7679         (REPORT_LINK, _report), 
    7780         (CHANGESET_LINK, _changeset), 
    78          (FILE_LINK, _browser)] 
     81         (FILE_LINK, _browser), 
     82         (WIKI_LINK, _wikipage)] 
    7983 
    8084 
    81 def trac_get_reference(env, rawtext, text): 
     85def trac_get_reference(env, rawtext, link, text): 
     86 
    8287    for (pattern, function) in LINKS: 
    83         m = pattern.match(text) 
     88        m = pattern.match(link) 
    8489        if m: 
    8590            g = filter(None, m.groups()) 
    8691            missing = False 
     92            if not text: 
     93                text = g[0] 
    8794            if pattern == WIKI_LINK: 
    88                 if not (env._wiki_pages.has_key(g[0])): 
     95                pagename = re.search(r'^[^\#]+',g[0]) 
     96                if not (env._wiki_pages.has_key(pagename.group())): 
    8997                        missing = True 
    90                         text = text + "?" 
     98                        text = text + "?"             
    9199            uri = function(env.href, g) 
    92100            reference = nodes.reference(rawtext, text) 
    93101            reference['refuri']= uri 
    94102            if missing: 
    95103                reference.set_class('missing') 
    96104            return reference 
     105         
    97106    return None 
    98107 
    99108def trac(env, name, arguments, options, content, lineno, 
     
    119128 
    120129    .. _TracLink: http://projects.edgewall.com/trac/wiki/TracLinks 
    121130    """ 
    122     text = arguments[int(len(arguments) == 2)] 
    123     reference = trac_get_reference(env, block_text, text) 
     131    link = arguments[0] 
     132    if len(arguments) == 2: 
     133        text = arguments[1] 
     134    else: 
     135        text = None 
     136    reference = trac_get_reference(env, block_text, link, text) 
    124137    if reference: 
    125138        return reference 
    126139    # didn't find a match (invalid TracLink), 
     
    133146 
    134147 
    135148def trac_role(env, name, rawtext, text, lineno, inliner, options={}, content=[]): 
    136     reference = trac_get_reference(env, rawtext, text) 
     149    args  = text.split(" ",1) 
     150    link = args[0] 
     151    if len(args)==2: 
     152        text = args[1] 
     153    else: 
     154        text = None 
     155    reference = trac_get_reference(env, rawtext, link, text) 
    137156    if reference: 
    138157        return [reference], [] 
    139158    warning = nodes.warning(None, 
     
    159178    rst.roles.register_local_role('trac', do_trac_role) 
    160179 
    161180    # The code_block could is taken from the leo plugin rst2 
     181    def code_formatter(language, text): 
     182        #log.debug("language '%s' args '%s'", % (language, arguments)) 
     183        Format = WikiProcessor(env, language) 
     184        html = Format.process(hdf, text)         
     185        #log.debug("language '%s' htmltext '%s'" % (language, html)) 
     186        raw = nodes.raw('',html, format='html') #(self, rawsource='', text='', *children, **attributes): 
     187        return raw 
     188         
     189    def code_role(name, rawtext, text, lineno, inliner, options={}, content=[]): 
     190        args  = text.split(":",1) 
     191        language = args[0] 
     192        if len(args)==2: 
     193            text = args[1] 
     194        else: 
     195            text = "" 
     196        #log.debug("coderole '%s' text '%s'" % (language, text)) 
     197        reference = code_formatter(language, text) 
     198        return [reference], [] 
     199         
     200 
     201       
    162202    def code_block(name,arguments,options,content,lineno,content_offset,block_text,state,state_machine): 
    163203 
    164204        """Create a code-block directive for docutils. 
     
    166206        Usage: .. code-block:: language 
    167207 
    168208        If the language can be syntax highlighted it will be.""" 
    169  
    170  
    171          
    172         from trac.WikiFormatter import Formatter 
    173          
    174209        language = arguments[0] 
     210        text = '\n'.join(content)         
     211        reference = code_formatter(language, text) 
     212        return [reference] 
    175213 
    176         code_processor = None 
    177         if  Formatter.builtin_processors.has_key(language): 
    178             code_processor = Formatter.builtin_processors[language] 
    179         else: 
    180             code_processor = Formatter.builtin_processors['default'] 
    181  
    182  
    183         html = code_processor(hdf, '\n'.join(content), env)         
    184         raw = nodes.raw('',html, format='html') #(self, rawsource='', text='', *children, **attributes): 
    185         return [raw] 
    186  
    187214    # These are documented at http://docutils.sourceforge.net/spec/howto/rst-directives.html. 
    188215    code_block.arguments = ( 
    189216        1, # Number of required arguments. 
     
    199226    code_block.content = 1 # True if content is allowed. 
    200227    # Register the directive with docutils. 
    201228    rst.directives.register_directive('code-block',code_block) 
     229    rst.roles.register_local_role('code-block', code_role) 
    202230     
    203231     
    204232 
  • trac/Mimeview.py

     
    5151    'make':'text/x-makefile', 'mk':'text/x-makefile', 'Makefile':'text/x-makefile', 
    5252    'mail':'text/x-mail', 
    5353    'pas':'text/x-pascal', 
    54     'pl':'text/x-perl', 'pm':'text/x-perl', 'PL':'text/x-perl', 
     54    'pl':'text/x-perl', 'pm':'text/x-perl', 'PL':'text/x-perl', 'perl':'text/x-perl', 
    5555    'php':'text/x-php', 'php4':'text/x-php', 'php3':'text/x-php', 
    5656    'ps':'application/postscript', 
    5757    'psp':'text/x-psp', 
    58     'py':'text/x-python', 
     58    'py':'text/x-python', 'python':'text/x-python', 
    5959    'pyx':'text/x-pyrex', 
    6060    'nroff':'application/x-troff', 'roff':'application/x-troff', 'troff':'application/x-troff', 
    6161 
    62     'rb':'text/x-ruby', 
     62    'rb':'text/x-ruby', 'ruby':'text/x-ruby', 
    6363    'rfc':'text/x-rfc', 
    6464    'scm':'text/x-scheme', 
    6565    'sh':'application/x-sh', 
     
    6868    'tex':'text/x-tex', 
    6969    'vba':'text/x-vba', 
    7070    'bas':'text/x-vba', 
    71     'v':'text/x-verilog', 
     71    'v':'text/x-verilog', 'verilog':'text/x-verilog', 
    7272    'vhd':'text/x-vhdl', 
    7373    'vrml':'model/vrml', 
    7474    'wrl':'model/vrml', 
  • trac/WikiFormatter.py

     
    2727import StringIO 
    2828 
    2929import util 
     30import Mimeview 
    3031 
    31 __all__ = ['Formatter', 'OneLinerFormatter', 'wiki_to_html', 'wiki_to_oneliner'] 
     32__all__ = ['Formatter', 'OneLinerFormatter', 'wiki_to_html', 'wiki_to_oneliner', 'WikiProcessor'] 
    3233 
    3334 
     35class WikiProcessor: 
     36 
     37    mime_type = "" 
     38 
     39    def __init__(self, env, name): 
     40        self.env = env 
     41        self.error = self.set_code_processor(name) 
     42     
     43    def default_processor(hdf, text, env): 
     44        return '<pre class="wiki">' + util.escape(text) + '</pre>' 
     45     
     46    def html_processor(hdf, text, env): 
     47        if Formatter._htmlproc_disallow_rule.search(text): 
     48            err = """\ 
     49<div class="system-message">Error: HTML block contains disallowed tags. 
     50<pre> 
     51%s</pre> 
     52</div>""" % util.escape(text) 
     53            env.log.error(err) 
     54            return err 
     55        return text 
     56 
     57    def mime_processor(self, hdf, text, env): 
     58        return env.mimeview.display(text, self.mime_type) 
     59     
     60    builtin_processors = { 'html': html_processor, 
     61                           'default': default_processor} 
     62 
     63    def process(self, hdf, text, inline=False): 
     64        text = self.code_processor(hdf, text, self.env) 
     65        if inline: 
     66            code_block_start = re.compile('^<div class="code-block">') 
     67            code_block_end = re.compile('</div>$') 
     68            text, nr = code_block_start.subn('<span class="code-block">', text, 1 ) 
     69            if nr: 
     70                text, nr = code_block_end.subn('</span>', text, 1 ) 
     71            return text 
     72        else: 
     73            return text 
     74     
     75 
     76    def set_code_processor(self, name): 
     77        if  self.builtin_processors.has_key(name): 
     78            self.code_processor = self.builtin_processors[name] 
     79        else: 
     80            try: 
     81                self.code_processor = self.load_macro(name) 
     82            except Exception, e: 
     83                if Mimeview.MIME_MAP.has_key(name): 
     84                    name = Mimeview.MIME_MAP[name] 
     85                mimeviewer, exists = self.env.mimeview.get_viewer(name) 
     86                if exists != -1: 
     87                    self.mime_type = name 
     88                    self.code_processor = self.mime_processor 
     89                else: 
     90                    self.code_processor = self.builtin_processors['default'] 
     91                    return 1 
     92        return 0 
     93     
     94    def load_macro(self, name): 
     95        # Look in envdir/wiki-macros/ first 
     96        try: 
     97            module = imp.load_source(name, os.path.join(self.env.path, 'wiki-macros', name+'.py')) 
     98        except IOError: 
     99            # fall back to site-wide macros 
     100            macros = __import__('wikimacros.' + name, globals(),  locals(), []) 
     101            module = getattr(macros, name) 
     102        return module.execute 
     103 
     104 
    34105class CommonFormatter: 
    35106    """This class contains the patterns common to both Formatter and 
    36107    OneLinerFormatter""" 
     
    240311    """ 
    241312    _rules = [r"""(?P<svnimg>(source|repos):([^ ]+)\.(PNG|png|JPG|jpg|JPEG|jpeg|GIF|gif))"""] + \ 
    242313             CommonFormatter._rules + \ 
    243              [r"""(?P<macro>!?\[\[(?P<macroname>[a-zA-Z]+)(\((?P<macroargs>[^\)]*)\))?\]\])""", 
     314             [r"""(?P<macro>!?\[\[(?P<macroname>[\w/+-]+)(\]\]|\((?P<macroargs>.*?)\)\]\]))""", 
    244315              r"""(?P<heading>^\s*(?P<hdepth>=+)\s.*\s(?P=hdepth)\s*$)""", 
    245316              r"""(?P<list>^(?P<ldepth>\s+)(?:\*|[0-9]+\.) )""", 
    246317              r"""(?P<indent>^(?P<idepth>\s+)(?=\S))""", 
     
    250321              r"""(?P<table_cell>\|\|)"""] 
    251322 
    252323    _compiled_rules = re.compile('(?:' + string.join(_rules, '|') + ')') 
    253     _processor_re = re.compile('#\!([a-zA-Z0-9/+-]+)') 
    254     mime_type = "" 
     324    _processor_re = re.compile('#\!([\w/+-]+)') 
    255325     
    256326 
    257327    # RE patterns used by other patterna 
     
    261331 
    262332    _htmlproc_disallow_rule = re.compile('(?i)<(script|noscript|embed|object|iframe|frame|frameset|link|style|meta|param|doctype)') 
    263333 
    264     def default_processor(hdf, text, env): 
    265         return '<pre class="wiki">' + util.escape(text) + '</pre>' 
    266     def asp_processor(hdf, text, env): 
    267         return env.mimeview.display(text, 'text/x-asp') 
    268     def c_processor(hdf, text, env): 
    269         return env.mimeview.display(text, 'text/x-csrc') 
    270     def css_processor(hdf, text, env): 
    271         return env.mimeview.display(text, 'text/css') 
    272     def java_processor(hdf, text, env): 
    273         return env.mimeview.display(text, 'text/x-java') 
    274     def cpp_processor(hdf, text, env): 
    275         return env.mimeview.display(text, 'text/x-c++src') 
    276     def perl_processor(hdf, text, env): 
    277         return env.mimeview.display(text, 'text/x-perl') 
    278     def php_processor(hdf, text, env): 
    279         return env.mimeview.display(text, 'text/x-php') 
    280     def python_processor(hdf, text, env): 
    281         return env.mimeview.display(text, 'text/x-python') 
    282     def ruby_processor(hdf, text, env): 
    283         return env.mimeview.display(text, 'text/x-ruby') 
    284     def sql_processor(hdf, text, env): 
    285         return env.mimeview.display(text, 'text/x-sql') 
    286     def xml_processor(hdf, text, env): 
    287         return env.mimeview.display(text, 'text/xml') 
    288     def verilog_processor(hdf, text, env): 
    289         return env.mimeview.display(text, 'text/x-verilog') 
    290     def html_processor(hdf, text, env): 
    291         if Formatter._htmlproc_disallow_rule.search(text): 
    292             err = """\ 
    293 <div class="system-message">Error: HTML block contains disallowed tags. 
    294 <pre> 
    295 %s</pre> 
    296 </div>""" % util.escape(text) 
    297             env.log.error(err) 
    298             return err 
    299         return text 
    300     def mime_processor(self, hdf, text, env): 
    301         return env.mimeview.display(text, self.mime_type) 
    302  
    303     builtin_processors = { 'html': html_processor, 
    304                            'asp': asp_processor, 
    305                            'c': c_processor, 
    306                            'css': css_processor, 
    307                            'cpp': cpp_processor, 
    308                            'java': java_processor, 
    309                            'php': php_processor, 
    310                            'perl': perl_processor, 
    311                            'python': python_processor, 
    312                            'ruby': ruby_processor, 
    313                            'sql': sql_processor, 
    314                            'xml': xml_processor, 
    315                            'verilog': verilog_processor, 
    316                            'default': default_processor} 
    317  
    318     def load_macro(self, name): 
    319         # Look in envdir/wiki-macros/ first 
    320         try: 
    321             module = imp.load_source(name, os.path.join(self.env.path, 'wiki-macros', name+'.py')) 
    322         except IOError: 
    323             # fall back to site-wide macros 
    324             macros = __import__('wikimacros.' + name, globals(),  locals(), []) 
    325             module = getattr(macros, name) 
    326         return module.execute 
    327  
    328334    def _macro_formatter(self, match, fullmatch): 
    329335        name = fullmatch.group('macroname') 
    330336        if name in ['br', 'BR']: 
    331337            return '<br />' 
    332338        args = fullmatch.group('macroargs') 
     339        args = util.unescape(args) 
    333340        try: 
    334             macro = self.load_macro(name) 
    335             return macro(self.hdf, args, self.env) 
     341            macro = WikiProcessor(self.env, name) 
     342            return macro.process(self.hdf, args, True) 
    336343        except Exception, e: 
    337344            return '<div class="system-message">Macro %s(%s) failed: %s</div>' \ 
    338345                   % (name, args, e) 
     
    474481            else: 
    475482                self.code_text += line + os.linesep 
    476483                if not self.code_processor: 
    477                     self.code_processor = Formatter.builtin_processors['default'] 
     484                    self.code_processor =  WikiProcessor(self.env, 'default') 
    478485        elif line.strip() == '}}}': 
    479486            self.in_code_block -= 1 
    480487            if self.in_code_block == 0 and self.code_processor: 
    481488                self.close_paragraph() 
    482489                self.close_table() 
    483                 self.out.write(self.code_processor(self.hdf, self.code_text, self.env)) 
     490                self.out.write(self.code_processor.process(self.hdf, self.code_text)) 
    484491            else: 
    485492                self.code_text += line + os.linesep 
    486493        elif not self.code_processor: 
    487494            match = Formatter._processor_re.search(line) 
    488495            if match: 
    489496                name = match.group(1) 
    490                 if  Formatter.builtin_processors.has_key(name): 
    491                     self.code_processor = Formatter.builtin_processors[name] 
    492                 else: 
    493                     try: 
    494                         self.code_processor = self.load_macro(name) 
    495                     except Exception, e: 
    496                         mimeviewer, exists = self.env.mimeview.get_viewer(name) 
    497                         if exists != -1: 
    498                             self.mime_type = name 
    499                             self.code_processor = self.mime_processor 
    500                         else: 
    501                             self.code_text += line + os.linesep 
    502                             self.code_processor = Formatter.builtin_processors['default'] 
    503                             self.out.write('<div class="system-message">Failed to load processor macro %s: %s t %s</div>' % (name, line, e)) 
     497                self.code_processor = WikiProcessor(self.env, name) 
     498                if self.code_processor.error: 
     499                    self.out.write("<div class='system-message'>Failed to load processor macro '%s': '%s' '%s'</div>" % (name, line, e)) 
     500                    self.code_text += line + os.linesep 
    504501            else: 
    505502                self.code_text += line + os.linesep  
    506                 self.code_processor = Formatter.builtin_processors['default'] 
     503                self.code_processor =  WikiProcessor(self.env, 'default')            
    507504        else: 
    508505            self.code_text += line + os.linesep 
    509506 
     507 
    510508    def format(self, text, out): 
    511509        self.out = out 
    512510        self._open_tags = [] 
  • trac/tests/wiki.py

     
    44 
    55from Wiki import Formatter 
    66 
     7 
    78class WikiTestCase(unittest.TestCase): 
    89    def __init__(self, input, correct): 
    910        unittest.TestCase.__init__(self, 'test') 
     
    1314    def test(self): 
    1415        """Testing WikiFormatter""" 
    1516        import Href 
     17        import Mimeview 
    1618        class Environment: 
    1719            def __init__(self): 
    1820                self.href = Href.Href('/') 
    1921                self._wiki_pages = {} 
     22                self.mimeview = Mimeview.Mimeview(self) 
    2023        class Cursor: 
    2124            def execute(self, *kwargs): pass 
    2225            def fetchone(self): return [] 
     
    2831        out = StringIO.StringIO() 
    2932        Formatter(None, Environment(), Connection()).format(self.input, out) 
    3033        if out.getvalue() != self.correct: 
    31             print "'%s' != '%s'" % (out.getvalue(), self.correct) 
     34            print "\n'%s' != \n'%s'" % (out.getvalue(), self.correct) 
    3235            assert self.correct == out.getvalue() 
    3336 
    3437def suite():