Edgewall Software

Ticket #124: robust_lists_r3271.diff

File robust_lists_r3271.diff, 5.4 KB (added by cboos, 3 years ago)

Refactor the list formatter

  • trac/wiki/formatter.py

     
    193193         r"(\]\]|\((?P<macroargs>.*?)\)\]\]))"), 
    194194        # heading, list, definition, indent, table... 
    195195        r"(?P<heading>^\s*(?P<hdepth>=+)\s.*\s(?P=hdepth)\s*$)", 
    196         r"(?P<list>^(?P<ldepth>\s+)(?:\*|\d+\.|[a-zA-Z]\.|[ivxIVX]{1,5}\.) )", 
     196        r"(?P<list>^(?P<ldepth>\s+)(?:[-*]|\d+\.|[a-zA-Z]\.|[ivxIVX]{1,5}\.) )", 
    197197        r"(?P<definition>^\s+((?:%s.*?%s|%s.*?%s|[^%s%s])+?::)(?:\s+|$))" 
    198198        % (INLINE_TOKEN, INLINE_TOKEN, STARTBLOCK_TOKEN, ENDBLOCK_TOKEN, 
    199199           INLINE_TOKEN, STARTBLOCK[0]), 
     
    456456     
    457457    def _list_formatter(self, match, fullmatch): 
    458458        ldepth = len(fullmatch.group('ldepth')) 
    459         depth = int((len(fullmatch.group('ldepth')) + 1) / 2) 
    460459        listid = match[ldepth] 
    461         self.in_list_item = depth > 0 
     460        self.in_list_item = True 
    462461        class_ = start = None 
    463         if listid == '*': 
     462        if listid in '-*': 
    464463            type_ = 'ul' 
    465464        else: 
    466465            type_ = 'ol' 
     
    473472                class_ = 'loweralpha' 
    474473            elif listid.isupper(): 
    475474                class_ = 'upperalpha' 
    476         self._set_list_depth(depth, type_, class_, start) 
     475        self._set_list_depth(ldepth, type_, class_, start) 
    477476        return '' 
    478477 
    479     def _set_list_depth(self, depth, type_, class_, start): 
    480         current_depth = len(self._list_stack) 
    481         diff = depth - current_depth 
     478    def _get_list_depth(self): 
     479        """Return the space offset associated to the deepest opened list.""" 
     480        return self._list_stack and self._list_stack[-1][1] or 0 
     481         
     482    def _set_list_depth(self, depth, new_type, class_, start): 
    482483        self.close_table() 
    483484        self.close_paragraph() 
    484485        self.close_indentation() 
    485         begin_list = type_ 
    486         if class_: 
    487             begin_list += ' class="%s"' % class_ 
    488         if start: 
    489             begin_list += start and ' start="%s"' % start 
    490         if diff > 0: 
    491             for i in range(diff): 
    492                 self._list_stack.append(type_) 
    493                 self.out.write('<%s><li>' % begin_list) 
    494         elif diff < 0: 
    495             for i in range(-diff): 
    496                 tmp = self._list_stack.pop() 
    497                 self.out.write('</li></%s>' % tmp) 
    498             if self._list_stack != [] and type_ != self._list_stack[-1]: 
    499                 tmp = self._list_stack.pop() 
    500                 self._list_stack.append(type_) 
    501                 self.out.write('</li></%s><%s><li>' % (tmp, begin_list)) 
     486        def open_list(): 
     487            self._list_stack.append((new_type, depth)) 
     488            self.out.write('<%s%s%s><li>' % 
     489                           (new_type, class_ and ' class="%s"' % class_ or '', 
     490                            start and ' start="%s"' % start or '')) 
     491        def close_list(tp): 
     492            self._list_stack.pop() 
     493            self.out.write('</li></%s>' % tp) 
     494 
     495        # depending on the indent/dedent, open or close lists 
     496        if depth > self._get_list_depth(): 
     497            open_list() 
     498        else: 
     499            while self._list_stack: 
     500                deepest_type, deepest_offset = self._list_stack[-1] 
     501                if depth >= deepest_offset: 
     502                    break 
     503                close_list(deepest_type) 
    502504            if depth > 0: 
    503                 self.out.write('</li><li>') 
    504         # diff == 0 
    505         elif self._list_stack != [] and type_ != self._list_stack[-1]: 
    506             tmp = self._list_stack.pop() 
    507             self._list_stack.append(type_) 
    508             self.out.write('</li></%s><%s><li>' % (tmp, begin_list)) 
    509         elif depth > 0: 
    510             self.out.write('</li><li>') 
     505                if self._list_stack: 
     506                    old_type, old_offset = self._list_stack[-1] 
     507                    if old_type != new_type: 
     508                        close_list(old_type) 
     509                        open_list() 
     510                    else: 
     511                        if old_offset != depth: # adjust last depth 
     512                            self._list_stack[-1] = (old_type, depth) 
     513                        self.out.write('</li><li>') 
     514                else: 
     515                    open_list() 
    511516 
    512517    def close_list(self): 
    513518        if self._list_stack != []: 
     
    536541        self.indent_level = 0 
    537542 
    538543    def open_indentation(self, depth): 
     544        # transform number of space characters into indent level 
     545        depth = (depth+1)/2 
    539546        if self.in_def_list: 
    540547            return 
    541548        diff = depth - self.indent_level 
     
    545552            self.close_indentation() 
    546553            self.close_list() 
    547554            self.indent_level = depth 
    548             self.out.write(('<blockquote>' + os.linesep) * depth) 
     555            self.out.write(('<blockquote>' + os.linesep) * self.indent_level) 
    549556 
    550557    def _indent_formatter(self, match, fullmatch): 
    551         depth = int((len(fullmatch.group('idepth')) + 1) / 2) 
    552         list_depth = len(self._list_stack) 
    553         if list_depth > 0 and depth == list_depth + 1: 
    554             self.in_list_item = 1 
     558        idepth = len(fullmatch.group('idepth')) 
     559        ldepth = self._get_list_depth() 
     560        if ldepth > 0 and 0 <= (idepth - ldepth) <= 2: 
     561            self.in_list_item = True 
    555562        else: 
    556             self.open_indentation(depth) 
     563            self.open_indentation(idepth) 
    557564        return '' 
    558565 
    559566    # Table