The initial patches of the formatter.text_plain rewrite request.

   1 # -*- coding: iso-8859-1 -*-
   2 # MoinMoin/formatter/
   3 """
   4     MoinMoin - "text/plain" Formatter
   5 
   6     @copyright: 2000, 2001, 2002 by Jürgen Hermann <jh@web.de>
   7                 2007 by Timo Sirainen <tss@iki.fi>
   8     @license: GNU GPL, see COPYING for details.
   9 """
  10 
  11 from MoinMoin.formatter import FormatterBase
  12 
  13 class Formatter(FormatterBase):
  14     """
  15         Send plain text data.
  16     """
  17 
  18     hardspace = u' '
  19 
  20     def __init__(self, request, **kw):
  21         apply(FormatterBase.__init__, (self, request), kw)
  22         self._in_code_area = 0
  23         self._in_code_line = 0
  24         self._code_area_state = [0, -1, -1, 0]
  25         self._lists = []
  26         self._url = None
  27         self._text = None # XXX does not work with links in headings!!!!!
  28         self._text_stack = []
  29         self._skip_text = False
  30         self._wrap_skip_text = False
  31         self._textbuf = ''
  32         self._indent = 0
  33         self._listitem_on = []
  34         self._empty_line_count = 2
  35         self._paragraph_ended = False
  36         self._paragraph_skip_begin = True
  37 
  38     def startDocument(self, pagename):
  39         line = u"*" * (len(pagename) + 2) + u'\n'
  40         return self.wrap(u"%s %s \n%s" % (line, pagename, line))
  41 
  42     def endContent(self):
  43         return self.flush(True)
  44 
  45     def sysmsg(self, on, **kw):
  46         return self.wrap((u'\n\n*** ', u' ***\n\n')[not on])
  47 
  48     def pagelink(self, on, pagename='', page=None, **kw):
  49         apply(FormatterBase.pagelink, (self, on, pagename, page), kw)
  50         if on:
  51             result = self.wrap(u"<")
  52             self.text_on(True)
  53             self.add_missing_space()
  54             return result
  55         else:
  56             linktext = self._text
  57             self.text_off()
  58             orig_pagename = pagename
  59             if pagename.find('/'):
  60                 pagename = pagename.replace('/', '.')
  61             pagename += '.txt'
  62             if linktext == orig_pagename:
  63                 return self.wrap(pagename + u">")
  64             else:
  65                 return self.wrap(linktext + u"> [%s]" % (pagename))
  66 
  67     def interwikilink(self, on, interwiki='', pagename='', **kw):
  68         if on:
  69             self.add_missing_space()
  70             self._url = u"%s:%s" % (interwiki, pagename)
  71             self.text_on()
  72             return u''
  73         else:
  74             text = self._text
  75             self.text_off()
  76             if text == self._url:
  77                 result = ''
  78             else:
  79                 result = self.wrap(u' [%s]' % (self._url))
  80             self._url = None
  81             return result
  82 
  83     def url(self, on, url='', css=None, **kw):
  84         if on:
  85             self.add_missing_space()
  86             self._url = url
  87             self.text_on()
  88             return u''
  89         else:
  90             text = self._text
  91             self.text_off()
  92             if text == self._url or 'mailto:' + text == self._url:
  93                 result = ''
  94             else:
  95                 result = self.wrap(u' [%s]' % (self._url))
  96             self._url = None
  97             return result
  98 
  99     def attachment_link(self, on, url=None, **kw):
 100         if on:
 101             return '[' + url + ']'
 102         else:
 103             return ''
 104 
 105     def attachment_image(self, url, **kw):
 106         title = ''
 107         for a in (u'title', u'html__title', u'alt', u'html_alt'):
 108             if kw.has_key(a):
 109                 title = ':' + kw[a]
 110         return self.wrap("[image:%s%s]" % (url, title))
 111 
 112     def attachment_drawing(self, url, text, **kw):
 113         return self.wrap("[drawing:%s]" % text)
 114 
 115     def text(self, text, **kw):
 116         if self._text is not None:
 117             self._text += text
 118         if self._wrap_skip_text:
 119             return ''
 120         return self.wrap(text)
 121 
 122     def rule(self, size=0, **kw):
 123         size = min(size, 10)
 124         ch = u"---~=*+#####"[size]
 125         self.paragraph_begin()
 126         result = self.wrap((ch * (79 - self._indent)))
 127         self.paragraph_end()
 128         return result
 129 
 130     def strong(self, on, **kw):
 131         if on:
 132             self.add_missing_space()
 133         return self.wrap(u'*')
 134 
 135     def emphasis(self, on, **kw):
 136         if on:
 137             self.add_missing_space()
 138         return self.wrap(u'/')
 139 
 140     def highlight(self, on, **kw):
 141         return u''
 142 
 143     def number_list(self, on, type=None, start=None, **kw):
 144         if on:
 145             if len(self._lists) > 0:
 146                 # No empty lines between sublists
 147                 self._paragraph_ended = False
 148             self.paragraph_begin()
 149             self._lists.append(0)
 150             self._listitem_on.append(False)
 151         elif len(self._lists) > 0:
 152             self.paragraph_end()
 153             num = self._lists.pop(-1)
 154             listitem_on = self._listitem_on.pop(-1)
 155             if listitem_on:
 156                 prefix = ' %d. ' % (num)
 157                 self._indent -= len(prefix)
 158         return ''
 159 
 160     def bullet_list(self, on, **kw):
 161         if on:
 162             if len(self._lists) > 0:
 163                 # No empty lines between sublists
 164                 self._paragraph_ended = False
 165             self.paragraph_begin()
 166             self._lists.append(-1)
 167             self._listitem_on.append(False)
 168         else:
 169             self.paragraph_end()
 170             self._lists.pop(-1)
 171             listitem_on = self._listitem_on.pop(-1)
 172             if listitem_on:
 173                 self._indent -= 3
 174         return ''
 175 
 176     def listitem(self, on, **kw):
 177         self._paragraph_ended = False
 178         if not on:
 179             # we can't rely on this
 180             self.paragraph_end()
 181             return ''
 182 
 183         result = ''
 184         num = self._lists.pop(-1)
 185         listitem_on = self._listitem_on.pop(-1)
 186         if listitem_on and on:
 187             # we didn't receive on=False for previous listitem
 188             self.paragraph_end()
 189             if num >= 0:
 190                 prefix = ' %d. ' % (num)
 191                 self._indent -= len(prefix)
 192             else:
 193                 self._indent -= 3
 194 
 195         if num >= 0:
 196             num += 1
 197             prefix = ' %d. ' % (num)
 198         else:
 199             prefix = ' * '
 200         self._lists.append(num)
 201         self._listitem_on.append(on)
 202 
 203         result += self.wrap(prefix)
 204         self._indent += len(prefix)
 205         self._paragraph_skip_begin = True
 206         return result;
 207 
 208     def sup(self, on, **kw):
 209         if on:
 210             return self.wrap(u'^')
 211         else:
 212             return ''
 213 
 214     def sub(self, on, **kw):
 215         return self.wrap(u'_')
 216 
 217     def strike(self, on, **kw):
 218         if on:
 219             self.add_missing_space()
 220         return self.wrap(u'__')
 221 
 222     def code(self, on, **kw):
 223         if on:
 224             self.add_missing_space()
 225         return self.wrap(u"'")
 226 
 227     def preformatted(self, on, **kw):
 228         FormatterBase.preformatted(self, on)
 229         snip = u'---%<'
 230         snip = snip + (u'-' * (78 - self._indent - len(snip)))
 231         if on:
 232             self.paragraph_begin()
 233             return self.wrap(snip + u'\n')
 234         else:
 235             if len(self._textbuf) > 0 and self._textbuf[-1] != '\n':
 236                 self._textbuf += '\n'
 237             result = self.wrap(snip + u'\n')
 238             self.paragraph_end()
 239             return result
 240 
 241     def small(self, on, **kw):
 242         if on:
 243             self.add_missing_space()
 244         return u''
 245 
 246     def big(self, on, **kw):
 247         if on:
 248             self.add_missing_space()
 249         return u''
 250 
 251     def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1, msg=None):
 252         snip = u'---CodeArea'
 253         snip = snip + (u'-' * (78 - self._indent - len(snip)))
 254         if on:
 255             self.paragraph_begin()
 256             self._in_code_area = 1
 257             self._in_code_line = 0
 258             self._code_area_state = [show, start, step, start]
 259             return self.wrap(snip + u'\n')
 260         else:
 261             if self._in_code_line:
 262                 return self.wrap(self.code_line(0) + snip + u'\n')
 263             result = self.wrap(snip + u'\n')
 264             self.paragraph_end()
 265             return result
 266 
 267     def code_line(self, on):
 268         res = u''
 269         if not on or (on and self._in_code_line):
 270             res += u'\n'
 271         if on:
 272             if self._code_area_state[0] > 0:
 273                 res += u' %4d  ' % self._code_area_state[3]
 274                 self._code_area_state[3] += self._code_area_state[2]
 275         self._in_code_line = on != 0
 276         return self.wrap(res)
 277 
 278     def code_token(self, on, tok_type):
 279         return ""
 280 
 281     def add_missing_space(self):
 282         if len(self._textbuf) > 0 and self._textbuf[-1].isalnum():
 283             self._textbuf += ' '
 284 
 285     def paragraph(self, on, **kw):
 286         FormatterBase.paragraph(self, on)
 287         if on:
 288             self.paragraph_begin()
 289         else:
 290             self.paragraph_end()
 291         return ''
 292 
 293     def linebreak(self, preformatted=1):
 294         return self.wrap(u'\n')
 295 
 296     def smiley(self, text):
 297         return self.wrap(text)
 298 
 299     def heading(self, on, depth, **kw):
 300         if on:
 301             self.paragraph_begin()
 302             self.text_on()
 303             result = ''
 304         else:
 305             if depth == 1:
 306                 chr = u'='
 307             else:
 308                 chr = u'-'
 309 
 310             result =  u'\n%s\n' % (chr * len(self._text))
 311             self.text_off()
 312             result = self.wrap(result)
 313             self.paragraph_end()
 314         return result;
 315 
 316     def get_table_sep(self, col_widths):
 317         result = ''
 318         for width in col_widths:
 319             result += '+' + ('-' * width)
 320         return result + '+\n'
 321 
 322     def fix_col_widths(self):
 323         min_widths = self._table_column_min_len
 324         max_widths = self._table_column_max_len
 325         max_len = 0
 326         for col in max_widths:
 327             max_len += col
 328         # take the needed space equally from all columns
 329         count = len(max_widths)
 330         i = 0
 331         skip = 0
 332         available_len = 79 - count - 1
 333         while max_len > available_len:
 334             if max_widths[i] > min_widths[i]:
 335                 max_widths[i] -= 1
 336                 max_len -= 1
 337                 skip = 0
 338             else:
 339                 skip += 1
 340                 if skip == count:
 341                      # there are only too wide columns
 342                      break
 343             if i == count-1:
 344                 i = 0
 345             else:
 346                 i += 1
 347         return max_widths
 348 
 349     def table(self, on, attrs={}, **kw):
 350         if on:
 351             self._table = []
 352             self._table_column_min_len = []
 353             self._table_column_max_len = []
 354             result = self.flush(True)
 355         else:
 356             result = u''
 357             col_widths = self.fix_col_widths()
 358             for row in self._table:
 359                 result += self.get_table_sep(col_widths)
 360                 more = True
 361                 while more:
 362                     more = False
 363                     num = 0
 364                     result += '|'
 365                     for col in row:
 366                         # break at next LF
 367                         lf_idx = col.find('\n')
 368                         if lf_idx != -1:
 369                             more = True
 370                             col_len = lf_idx
 371                             next_idx = lf_idx + 1
 372                         else:
 373                             col_len = len(col)
 374                             next_idx = col_len
 375                         # possibly break earlier if we need to wrap
 376                         if col_len > col_widths[num]:
 377                             idx = col.rfind(' ', 0, col_widths[num])
 378                             if idx == -1:
 379                                 idx = col.find(' ', col_widths[num])
 380                             if idx != -1:
 381                                 col_len = idx
 382                                 next_idx = idx + 1
 383                             more = True
 384                         result += ' ' + col[:col_len]
 385                         result += (' ' * (col_widths[num] - col_len - 1)) + '|'
 386                         row[num] = col[next_idx:]
 387                         num += 1
 388                     result += '\n'
 389             result += self.get_table_sep(col_widths)
 390             self._table = None
 391             self._table_column_min_len = None
 392             self._table_column_max_len = None
 393             self._empty_line_count = 0
 394             self.paragraph_end()
 395         return result
 396 
 397     def table_row(self, on, attrs={}, **kw):
 398         if on:
 399             self._table.append([])
 400         return u''
 401 
 402     def table_cell(self, on, attrs={}, **kw):
 403         if on:
 404             self.text_on()
 405             self._wrap_skip_text = True
 406         else:
 407             # keep track of the longest word and the longest line in the cell
 408             self._text = self._text.strip()
 409             max_line_len = 0
 410             max_word_len = 0
 411             for line in self._text.split('\n'):
 412                 if len(line) > max_line_len:
 413                     max_line_len = len(line)
 414             for word in self._text.split(' '):
 415                 if len(word) > max_word_len:
 416                     max_word_len = len(word)
 417             # one preceding and trailing cell whitespace
 418             max_word_len += 2
 419             max_line_len += 2
 420 
 421             rownum = len(self._table) - 1
 422             colnum = len(self._table[rownum])
 423             if len(self._table_column_max_len) <= colnum:
 424                 self._table_column_min_len.append(max_word_len)
 425                 self._table_column_max_len.append(max_line_len)
 426             else:
 427                 if max_word_len > self._table_column_min_len[colnum]:
 428                     self._table_column_min_len[colnum] = max_word_len
 429                 if self._table_column_max_len[colnum] < max_line_len:
 430                     self._table_column_max_len[colnum] = max_line_len
 431             self._table[rownum].append(self._text)
 432             self.text_off()
 433         return u''
 434 
 435     def underline(self, on, **kw):
 436         return self.wrap(u'_')
 437 
 438     def definition_list(self, on, **kw):
 439         if on:
 440             self.paragraph_begin()
 441         else:
 442             self.paragraph_end()
 443         return u''
 444 
 445     def definition_term(self, on, compact=0, **kw):
 446         result = u''
 447         #if not compact:
 448         #    result = result + u'\n'
 449         if not on:
 450             result = result + u':'
 451         return self.wrap(result)
 452 
 453     def definition_desc(self, on, **kw):
 454         if on:
 455             self._indent += 2
 456             self.paragraph_begin()
 457         else:
 458             self.paragraph_end()
 459             self._textbuf += '\n'
 460             self._indent -= 2
 461         return ''
 462 
 463     def image(self, src=None, **kw):
 464         for a in (u'title', u'html__title', u'alt', u'html_alt'):
 465             if kw.has_key(a):
 466                 return self.wrap(kw[a] + ' [' + src + ']')
 467         return self.wrap('[' + src + ']')
 468 
 469     def lang(self, on, lang_name):
 470         return ''
 471 
 472     def paragraph_begin(self):
 473         if self._paragraph_ended:
 474             self._textbuf += '\n'
 475         elif not self._paragraph_skip_begin:
 476             if len(self._textbuf) > 0 and self._textbuf[-1] != '\n':
 477                 self._textbuf += '\n'
 478         self._paragraph_ended = False
 479         self._paragraph_skip_begin = False
 480 
 481     def paragraph_end(self):
 482         if len(self._textbuf) > 0 and self._textbuf[-1] != '\n':
 483             self._textbuf += '\n'
 484         self._paragraph_ended = True
 485 
 486     def wrap(self, text):
 487         if len(text) == 0:
 488             return ''
 489         if self._wrap_skip_text:
 490             # we're inside table
 491             #self._text += 'w{' + text + '}'
 492             self._text += text
 493             return ''
 494 
 495         self._paragraph_ended = False
 496         self._paragraph_skip_begin = False
 497 
 498         # add indents after all LFs. kind of dirty to split twice though..
 499         lines = text.split('\n')
 500         text = lines.pop(0)
 501         while len(lines) > 0:
 502             text += '\n' + (' ' * self._indent) + lines.pop(0)
 503 
 504         prefix = ''
 505         if len(self._textbuf) == 0 or self._textbuf[-1] == '\n':
 506             self._textbuf += ' ' * self._indent
 507         self._textbuf += text
 508         lines = self._textbuf.split('\n')
 509 
 510         self._textbuf = ''
 511         text = ''
 512         while len(lines) > 0:
 513             self._textbuf += lines.pop(0)
 514             if len(lines) > 0:
 515                 # LFs found
 516                 text += self.flush(True)
 517             if len(self._textbuf) > 80 and self._textbuf.find(' ', self._indent) != -1:
 518                 # wrap time
 519                 text += self.flush(False)
 520         return text
 521 
 522     def flush(self, addlf):
 523         result = ''
 524 
 525         while len(self._textbuf) >= 80:
 526             # need to wrap
 527             last_space = self._textbuf.rfind(' ', self._indent, 80)
 528             if last_space == -1:
 529                 # a long line. split at the next possible space
 530                 last_space = self._textbuf.find(' ', self._indent)
 531                 if last_space == -1:
 532                     break
 533             result += self._textbuf[:last_space] + '\n'
 534             self._empty_line_count = 0
 535             self._textbuf = ' ' * self._indent + self._textbuf[last_space+1:]
 536 
 537         # strip trailing whitespace
 538         while len(self._textbuf) > 0 and self._textbuf[-1] == ' ':
 539             self._textbuf = self._textbuf[:-1]
 540 
 541         if len(self._textbuf) == 0:
 542             if not addlf:
 543                 return result
 544             self._empty_line_count += 1
 545             if self._empty_line_count >= 2:
 546                 return result
 547         else:
 548             self._empty_line_count = 0
 549 
 550         if addlf:
 551             result += self._textbuf + '\n'
 552             self._textbuf = ''
 553         return result
 554 
 555     def text_on(self, skip_text=False):
 556         if self._text is None:
 557             self._text_stack.append(None)
 558         else:
 559             self._text_stack.append(self._text)
 560             #self._text_stack.append('[' + self._text + ']')
 561         self._text_stack.append(self._skip_text)
 562         self._text_stack.append(self._wrap_skip_text)
 563         self._text = ""
 564         self._skip_text = skip_text
 565         if skip_text:
 566             self._wrap_skip_text = True
 567 
 568     def text_off(self):
 569         prev_skip_text = self._skip_text
 570         self._wrap_skip_text = self._text_stack.pop(-1)
 571         self._skip_text = self._text_stack.pop(-1)
 572         old_text = self._text_stack.pop(-1)
 573         if old_text is None:
 574             self._text = None
 575         else:
 576             if not prev_skip_text:
 577                 #self._text = 'o#' + old_text + '#|#' + self._text + '#'
 578                 self._text = old_text + self._text
 579             else:
 580                 self._text = old_text

Patch:

   1 --- text_plain.py.old   2010-03-08 14:13:16.590262402 +0200
   2 +++ text_plain.py       2010-03-08 14:11:29.355621185 +0200
   3 @@ -1,8 +1,10 @@
   4  # -*- coding: iso-8859-1 -*-
   5 +# MoinMoin/formatter/
   6  """
   7      MoinMoin - "text/plain" Formatter
   8 
   9 -    @copyright: 2000-2002 Juergen Hermann <jh@web.de>
  10 +    @copyright: 2000, 2001, 2002 by Jürgen Hermann <jh@web.de>
  11 +               2007 by Timo Sirainen <tss@iki.fi>
  12      @license: GNU GPL, see COPYING for details.
  13  """
  14 
  15 @@ -16,172 +18,251 @@
  16      hardspace = u' '
  17 
  18      def __init__(self, request, **kw):
  19 -        FormatterBase.__init__(self, request, **kw)
  20 +        apply(FormatterBase.__init__, (self, request), kw)
  21          self._in_code_area = 0
  22          self._in_code_line = 0
  23          self._code_area_state = [0, -1, -1, 0]
  24 -        self._in_list = 0
  25 -        self._did_para = 0
  26 +        self._lists = []
  27          self._url = None
  28          self._text = None # XXX does not work with links in headings!!!!!
  29 +       self._text_stack = []
  30 +       self._skip_text = False
  31 +       self._wrap_skip_text = False
  32 +       self._textbuf = ''
  33 +       self._indent = 0
  34 +       self._listitem_on = []
  35 +       self._empty_line_count = 2
  36 +       self._paragraph_ended = False
  37 +       self._paragraph_skip_begin = True
  38 
  39      def startDocument(self, pagename):
  40          line = u"*" * (len(pagename) + 2) + u'\n'
  41 -        return u"%s %s \n%s" % (line, pagename, line)
  42 +       return self.wrap(u"%s %s \n%s" % (line, pagename, line))
  43 
  44 -    def endDocument(self):
  45 -        return u'\n'
  46 +    def endContent(self):
  47 +        return self.flush(True)
  48 
  49      def sysmsg(self, on, **kw):
  50 -        return (u'\n\n*** ', u' ***\n\n')[not on]
  51 +        return self.wrap((u'\n\n*** ', u' ***\n\n')[not on])
  52 
  53      def pagelink(self, on, pagename='', page=None, **kw):
  54 -        FormatterBase.pagelink(self, on, pagename, page, **kw)
  55 -        return (u">>", u"<<") [not on]
  56 +        apply(FormatterBase.pagelink, (self, on, pagename, page), kw)
  57 +       if on:
  58 +           result = self.wrap(u"<")
  59 +           self.text_on(True)
  60 +           self.add_missing_space()
  61 +           return result
  62 +       else:
  63 +           linktext = self._text
  64 +           self.text_off()
  65 +           orig_pagename = pagename
  66 +           if pagename.find('/'):
  67 +               pagename = pagename.replace('/', '.')
  68 +           pagename += '.txt'
  69 +           if linktext == orig_pagename:
  70 +               return self.wrap(pagename + u">")
  71 +           else:
  72 +               return self.wrap(linktext + u"> [%s]" % (pagename))
  73 
  74      def interwikilink(self, on, interwiki='', pagename='', **kw):
  75          if on:
  76 +            self.add_missing_space()
  77              self._url = u"%s:%s" % (interwiki, pagename)
  78 -            self._text = []
  79 +           self.text_on()
  80              return u''
  81          else:
  82 -            if "".join(self._text) == self._url:
  83 -                self._url = None
  84 -                self._text = None
  85 -                return ''
  86 +           text = self._text
  87 +           self.text_off()
  88 +           if text == self._url:
  89 +                result = ''
  90              else:
  91 +                result = self.wrap(u' [%s]' % (self._url))
  92                  self._url = None
  93 -                self._text = None
  94 -                return u' [%s]' % (self._url)
  95 +           return result
  96 
  97      def url(self, on, url='', css=None, **kw):
  98          if on:
  99 +            self.add_missing_space()
 100              self._url = url
 101 -            self._text = []
 102 +           self.text_on()
 103              return u''
 104          else:
 105 -            if "".join(self._text) == self._url:
 106 -                self._url = None
 107 -                self._text = None
 108 -                return ''
 109 +           text = self._text
 110 +           self.text_off()
 111 +           if text == self._url or 'mailto:' + text == self._url:
 112 +                result = ''
 113              else:
 114 +                result = self.wrap(u' [%s]' % (self._url))
 115                  self._url = None
 116 -                self._text = None
 117 -                return u' [%s]' % (self._url)
 118 +           return result
 119 
 120      def attachment_link(self, on, url=None, **kw):
 121          if on:
 122 -            return "["
 123 +            return '[' + url + ']'
 124          else:
 125 -            return "]"
 126 +            return ''
 127 
 128      def attachment_image(self, url, **kw):
 129          title = ''
 130          for a in (u'title', u'html__title', u'alt', u'html_alt'):
 131 -            if a in kw:
 132 +            if kw.has_key(a):
 133                  title = ':' + kw[a]
 134 -        return "[image:%s%s]" % (url, title)
 135 +        return self.wrap("[image:%s%s]" % (url, title))
 136 
 137      def attachment_drawing(self, url, text, **kw):
 138 -        return "[drawing:%s]" % text
 139 +        return self.wrap("[drawing:%s]" % text)
 140 
 141      def text(self, text, **kw):
 142 -        self._did_para = 0
 143          if self._text is not None:
 144 -            self._text.append(text)
 145 -        return text
 146 +            self._text += text
 147 +       if self._wrap_skip_text:
 148 +           return ''
 149 +       return self.wrap(text)
 150 
 151      def rule(self, size=0, **kw):
 152          size = min(size, 10)
 153          ch = u"---~=*+#####"[size]
 154 -        return (ch * 79) + u'\n'
 155 +       self.paragraph_begin()
 156 +       result = self.wrap((ch * (79 - self._indent)))
 157 +       self.paragraph_end()
 158 +       return result
 159 
 160      def strong(self, on, **kw):
 161 -        return u'*'
 162 +       if on:
 163 +            self.add_missing_space()
 164 +       return self.wrap(u'*')
 165 
 166      def emphasis(self, on, **kw):
 167 -        return u'/'
 168 +       if on:
 169 +            self.add_missing_space()
 170 +        return self.wrap(u'/')
 171 
 172      def highlight(self, on, **kw):
 173          return u''
 174 
 175      def number_list(self, on, type=None, start=None, **kw):
 176          if on:
 177 -            self._in_list = 1
 178 -            return [u'\n', u'\n\n'][not self._did_para]
 179 -        else:
 180 -            self._in_list = 0
 181 -            if not self._did_para:
 182 -                self._did_para = 1
 183 -                return u'\n'
 184 -        return u''
 185 +           if len(self._lists) > 0:
 186 +               # No empty lines between sublists
 187 +               self._paragraph_ended = False
 188 +           self.paragraph_begin()
 189 +           self._lists.append(0)
 190 +           self._listitem_on.append(False)
 191 +        elif len(self._lists) > 0:
 192 +           self.paragraph_end()
 193 +           num = self._lists.pop(-1)
 194 +           listitem_on = self._listitem_on.pop(-1)
 195 +           if listitem_on:
 196 +               prefix = ' %d. ' % (num)
 197 +               self._indent -= len(prefix)
 198 +        return ''
 199 
 200      def bullet_list(self, on, **kw):
 201          if on:
 202 -            self._in_list = -1
 203 -            return [u'\n', u'\n\n'][not self._did_para]
 204 -        else:
 205 -            self._in_list = 0
 206 -            if not self._did_para:
 207 -                self._did_para = 1
 208 -                return u'\n'
 209 -        return u''
 210 +           if len(self._lists) > 0:
 211 +               # No empty lines between sublists
 212 +               self._paragraph_ended = False
 213 +           self.paragraph_begin()
 214 +           self._lists.append(-1)
 215 +           self._listitem_on.append(False)
 216 +        else:
 217 +           self.paragraph_end()
 218 +           self._lists.pop(-1)
 219 +           listitem_on = self._listitem_on.pop(-1)
 220 +           if listitem_on:
 221 +               self._indent -= 3
 222 +        return ''
 223 
 224      def listitem(self, on, **kw):
 225 -        if on:
 226 -            if self._in_list > 0:
 227 -                self._in_list += 1
 228 -                self._did_para = 1
 229 -                return ' %d. ' % (self._in_list-1, )
 230 -            elif self._in_list < 0:
 231 -                self._did_para = 1
 232 -                return u' * '
 233 -            else:
 234 -                return u' * '
 235 -        else:
 236 -            self._did_para = 1
 237 -            return u'\n'
 238 +       self._paragraph_ended = False
 239 +       if not on:
 240 +           # we can't rely on this
 241 +           self.paragraph_end()
 242 +           return ''
 243 +
 244 +       result = ''
 245 +       num = self._lists.pop(-1)
 246 +       listitem_on = self._listitem_on.pop(-1)
 247 +       if listitem_on and on:
 248 +           # we didn't receive on=False for previous listitem
 249 +           self.paragraph_end()
 250 +           if num >= 0:
 251 +               prefix = ' %d. ' % (num)
 252 +               self._indent -= len(prefix)
 253 +           else:
 254 +               self._indent -= 3
 255 +
 256 +       if num >= 0:
 257 +           num += 1
 258 +           prefix = ' %d. ' % (num)
 259 +       else:
 260 +           prefix = ' * '
 261 +       self._lists.append(num)
 262 +       self._listitem_on.append(on)
 263 +
 264 +       result += self.wrap(prefix)
 265 +       self._indent += len(prefix)
 266 +       self._paragraph_skip_begin = True
 267 +        return result;
 268 
 269      def sup(self, on, **kw):
 270 -        return u'^'
 271 +       if on:
 272 +           return self.wrap(u'^')
 273 +       else:
 274 +           return ''
 275 
 276      def sub(self, on, **kw):
 277 -        return u'_'
 278 +        return self.wrap(u'_')
 279 
 280      def strike(self, on, **kw):
 281 -        return u'__'
 282 +       if on:
 283 +            self.add_missing_space()
 284 +        return self.wrap(u'__')
 285 
 286      def code(self, on, **kw):
 287 -        #return [unichr(0x60), unichr(0xb4)][not on]
 288 -        return u"'" # avoid high-ascii
 289 +       if on:
 290 +            self.add_missing_space()
 291 +        return self.wrap(u"'")
 292 
 293      def preformatted(self, on, **kw):
 294          FormatterBase.preformatted(self, on)
 295          snip = u'---%<'
 296 -        snip = snip + (u'-' * (78 - len(snip)))
 297 +        snip = snip + (u'-' * (78 - self._indent - len(snip)))
 298          if on:
 299 -            return u'\n' + snip + u'\n'
 300 +           self.paragraph_begin()
 301 +           return self.wrap(snip + u'\n')
 302          else:
 303 -            return snip + u'\n'
 304 +           if len(self._textbuf) > 0 and self._textbuf[-1] != '\n':
 305 +               self._textbuf += '\n'
 306 +           result = self.wrap(snip + u'\n')
 307 +           self.paragraph_end()
 308 +           return result
 309 
 310      def small(self, on, **kw):
 311 +       if on:
 312 +            self.add_missing_space()
 313          return u''
 314 
 315      def big(self, on, **kw):
 316 +       if on:
 317 +            self.add_missing_space()
 318          return u''
 319 
 320      def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1, msg=None):
 321          snip = u'---CodeArea'
 322 -        snip = snip + (u'-' * (78 - len(snip)))
 323 +        snip = snip + (u'-' * (78 - self._indent - len(snip)))
 324          if on:
 325 +           self.paragraph_begin()
 326              self._in_code_area = 1
 327              self._in_code_line = 0
 328              self._code_area_state = [show, start, step, start]
 329 -            return u'\n' + snip + u'\n'
 330 +            return self.wrap(snip + u'\n')
 331          else:
 332              if self._in_code_line:
 333 -                return self.code_line(0) + snip + u'\n'
 334 -            return snip + u'\n'
 335 +                return self.wrap(self.code_line(0) + snip + u'\n')
 336 +            result = self.wrap(snip + u'\n')
 337 +           self.paragraph_end()
 338 +           return result
 339 
 340      def code_line(self, on):
 341          res = u''
 342 @@ -192,70 +273,308 @@
 343                  res += u' %4d  ' % self._code_area_state[3]
 344                  self._code_area_state[3] += self._code_area_state[2]
 345          self._in_code_line = on != 0
 346 -        return res
 347 +        return self.wrap(res)
 348 
 349      def code_token(self, on, tok_type):
 350          return ""
 351 
 352 +    def add_missing_space(self):
 353 +       if len(self._textbuf) > 0 and self._textbuf[-1].isalnum():
 354 +           self._textbuf += ' '
 355 +
 356      def paragraph(self, on, **kw):
 357          FormatterBase.paragraph(self, on)
 358 -        if self._did_para:
 359 -            on = 0
 360 -        return [u'\n', u''][not on]
 361 +       if on:
 362 +           self.paragraph_begin()
 363 +       else:
 364 +           self.paragraph_end()
 365 +       return ''
 366 
 367      def linebreak(self, preformatted=1):
 368 -        return u'\n'
 369 +        return self.wrap(u'\n')
 370 
 371      def smiley(self, text):
 372 -        return text
 373 +        return self.wrap(text)
 374 
 375      def heading(self, on, depth, **kw):
 376          if on:
 377 -            self._text = []
 378 -            return '\n\n'
 379 +           self.paragraph_begin()
 380 +           self.text_on()
 381 +           result = ''
 382 +        else:
 383 +           if depth == 1:
 384 +               chr = u'='
 385 +           else:
 386 +               chr = u'-'
 387 +
 388 +           result =  u'\n%s\n' % (chr * len(self._text))
 389 +           self.text_off()
 390 +           result = self.wrap(result)
 391 +           self.paragraph_end()
 392 +       return result;
 393 +
 394 +    def get_table_sep(self, col_widths):
 395 +       result = ''
 396 +       for width in col_widths:
 397 +           result += '+' + ('-' * width)
 398 +       return result + '+\n'
 399 +
 400 +    def fix_col_widths(self):
 401 +       min_widths = self._table_column_min_len
 402 +       max_widths = self._table_column_max_len
 403 +       max_len = 0
 404 +       for col in max_widths:
 405 +           max_len += col
 406 +       # take the needed space equally from all columns
 407 +       count = len(max_widths)
 408 +       i = 0
 409 +       skip = 0
 410 +       available_len = 79 - count - 1
 411 +       while max_len > available_len:
 412 +           if max_widths[i] > min_widths[i]:
 413 +               max_widths[i] -= 1
 414 +               max_len -= 1
 415 +               skip = 0
 416 +           else:
 417 +               skip += 1
 418 +               if skip == count:
 419 +                    # there are only too wide columns
 420 +                    break
 421 +           if i == count-1:
 422 +               i = 0
 423          else:
 424 -            result = u'\n%s\n\n' % (u'=' * len("".join(self._text)))
 425 -            self._text = None
 426 -            return result
 427 +               i += 1
 428 +       return max_widths
 429 
 430      def table(self, on, attrs={}, **kw):
 431 -        return u''
 432 +       if on:
 433 +           self._table = []
 434 +           self._table_column_min_len = []
 435 +           self._table_column_max_len = []
 436 +           result = self.flush(True)
 437 +       else:
 438 +           result = u''
 439 +           col_widths = self.fix_col_widths()
 440 +           for row in self._table:
 441 +               result += self.get_table_sep(col_widths)
 442 +               more = True
 443 +               while more:
 444 +                   more = False
 445 +                   num = 0
 446 +                   result += '|'
 447 +                   for col in row:
 448 +                       # break at next LF
 449 +                       lf_idx = col.find('\n')
 450 +                       if lf_idx != -1:
 451 +                           more = True
 452 +                           col_len = lf_idx
 453 +                           next_idx = lf_idx + 1
 454 +                       else:
 455 +                           col_len = len(col)
 456 +                           next_idx = col_len
 457 +                       # possibly break earlier if we need to wrap
 458 +                       if col_len > col_widths[num]:
 459 +                           idx = col.rfind(' ', 0, col_widths[num])
 460 +                           if idx == -1:
 461 +                               idx = col.find(' ', col_widths[num])
 462 +                           if idx != -1:
 463 +                               col_len = idx
 464 +                               next_idx = idx + 1
 465 +                           more = True
 466 +                       result += ' ' + col[:col_len]
 467 +                       result += (' ' * (col_widths[num] - col_len - 1)) + '|'
 468 +                       row[num] = col[next_idx:]
 469 +                       num += 1
 470 +                   result += '\n'
 471 +           result += self.get_table_sep(col_widths)
 472 +           self._table = None
 473 +           self._table_column_min_len = None
 474 +           self._table_column_max_len = None
 475 +           self._empty_line_count = 0
 476 +           self.paragraph_end()
 477 +       return result
 478 
 479      def table_row(self, on, attrs={}, **kw):
 480 +       if on:
 481 +           self._table.append([])
 482          return u''
 483 
 484      def table_cell(self, on, attrs={}, **kw):
 485 +       if on:
 486 +           self.text_on()
 487 +           self._wrap_skip_text = True
 488 +       else:
 489 +           # keep track of the longest word and the longest line in the cell
 490 +           self._text = self._text.strip()
 491 +           max_line_len = 0
 492 +           max_word_len = 0
 493 +           for line in self._text.split('\n'):
 494 +               if len(line) > max_line_len:
 495 +                   max_line_len = len(line)
 496 +           for word in self._text.split(' '):
 497 +               if len(word) > max_word_len:
 498 +                   max_word_len = len(word)
 499 +           # one preceding and trailing cell whitespace
 500 +           max_word_len += 2
 501 +           max_line_len += 2
 502 +
 503 +           rownum = len(self._table) - 1
 504 +           colnum = len(self._table[rownum])
 505 +           if len(self._table_column_max_len) <= colnum:
 506 +               self._table_column_min_len.append(max_word_len)
 507 +               self._table_column_max_len.append(max_line_len)
 508 +           else:
 509 +               if max_word_len > self._table_column_min_len[colnum]:
 510 +                   self._table_column_min_len[colnum] = max_word_len
 511 +               if self._table_column_max_len[colnum] < max_line_len:
 512 +                   self._table_column_max_len[colnum] = max_line_len
 513 +           self._table[rownum].append(self._text)
 514 +           self.text_off()
 515          return u''
 516 
 517      def underline(self, on, **kw):
 518 -        return u'_'
 519 +        return self.wrap(u'_')
 520 
 521      def definition_list(self, on, **kw):
 522 +       if on:
 523 +           self.paragraph_begin()
 524 +       else:
 525 +           self.paragraph_end()
 526          return u''
 527 
 528      def definition_term(self, on, compact=0, **kw):
 529          result = u''
 530 -        if not compact:
 531 -            result = result + u'\n'
 532 +       #if not compact:
 533 +        #    result = result + u'\n'
 534          if not on:
 535 -            result = result + u':\n'
 536 -        return result
 537 +            result = result + u':'
 538 +        return self.wrap(result)
 539 
 540      def definition_desc(self, on, **kw):
 541 -        return [u'    ', u'\n'][not on]
 542 +       if on:
 543 +           self._indent += 2
 544 +           self.paragraph_begin()
 545 +       else:
 546 +           self.paragraph_end()
 547 +           self._textbuf += '\n'
 548 +           self._indent -= 2
 549 +       return ''
 550 
 551      def image(self, src=None, **kw):
 552          for a in (u'title', u'html__title', u'alt', u'html_alt'):
 553 -            if a in kw:
 554 -                return kw[a]
 555 -        return u''
 556 +            if kw.has_key(a):
 557 +                return self.wrap(kw[a] + ' [' + src + ']')
 558 +        return self.wrap('[' + src + ']')
 559 
 560 -    def transclusion(self, on, **kw):
 561 -        return u''
 562 +    def lang(self, on, lang_name):
 563 +        return ''
 564 
 565 -    def transclusion_param(self, **kw):
 566 -        return u''
 567 +    def paragraph_begin(self):
 568 +       if self._paragraph_ended:
 569 +           self._textbuf += '\n'
 570 +       elif not self._paragraph_skip_begin:
 571 +           if len(self._textbuf) > 0 and self._textbuf[-1] != '\n':
 572 +               self._textbuf += '\n'
 573 +       self._paragraph_ended = False
 574 +       self._paragraph_skip_begin = False
 575 +
 576 +    def paragraph_end(self):
 577 +       if len(self._textbuf) > 0 and self._textbuf[-1] != '\n':
 578 +           self._textbuf += '\n'
 579 +       self._paragraph_ended = True
 580 
 581 -    def lang(self, on, lang_name):
 582 +    def wrap(self, text):
 583 +       if len(text) == 0:
 584          return ''
 585 +       if self._wrap_skip_text:
 586 +           # we're inside table
 587 +           #self._text += 'w{' + text + '}'
 588 +           self._text += text
 589 +           return ''
 590 +
 591 +       self._paragraph_ended = False
 592 +       self._paragraph_skip_begin = False
 593 +
 594 +       # add indents after all LFs. kind of dirty to split twice though..
 595 +       lines = text.split('\n')
 596 +       text = lines.pop(0)
 597 +       while len(lines) > 0:
 598 +           text += '\n' + (' ' * self._indent) + lines.pop(0)
 599 +
 600 +       prefix = ''
 601 +       if len(self._textbuf) == 0 or self._textbuf[-1] == '\n':
 602 +           self._textbuf += ' ' * self._indent
 603 +       self._textbuf += text
 604 +       lines = self._textbuf.split('\n')
 605 +
 606 +       self._textbuf = ''
 607 +       text = ''
 608 +       while len(lines) > 0:
 609 +           self._textbuf += lines.pop(0)
 610 +           if len(lines) > 0:
 611 +               # LFs found
 612 +               text += self.flush(True)
 613 +           if len(self._textbuf) > 80 and self._textbuf.find(' ', self._indent) != -1:
 614 +               # wrap time
 615 +               text += self.flush(False)
 616 +       return text
 617 +
 618 +    def flush(self, addlf):
 619 +       result = ''
 620 
 621 +       while len(self._textbuf) >= 80:
 622 +           # need to wrap
 623 +           last_space = self._textbuf.rfind(' ', self._indent, 80)
 624 +           if last_space == -1:
 625 +               # a long line. split at the next possible space
 626 +               last_space = self._textbuf.find(' ', self._indent)
 627 +               if last_space == -1:
 628 +                   break
 629 +           result += self._textbuf[:last_space] + '\n'
 630 +           self._empty_line_count = 0
 631 +           self._textbuf = ' ' * self._indent + self._textbuf[last_space+1:]
 632 +
 633 +       # strip trailing whitespace
 634 +       while len(self._textbuf) > 0 and self._textbuf[-1] == ' ':
 635 +           self._textbuf = self._textbuf[:-1]
 636 +
 637 +       if len(self._textbuf) == 0:
 638 +           if not addlf:
 639 +               return result
 640 +           self._empty_line_count += 1
 641 +           if self._empty_line_count >= 2:
 642 +               return result
 643 +       else:
 644 +           self._empty_line_count = 0
 645 +
 646 +       if addlf:
 647 +           result += self._textbuf + '\n'
 648 +           self._textbuf = ''
 649 +       return result
 650 +
 651 +    def text_on(self, skip_text=False):
 652 +       if self._text is None:
 653 +           self._text_stack.append(None)
 654 +       else:
 655 +           self._text_stack.append(self._text)
 656 +           #self._text_stack.append('[' + self._text + ']')
 657 +       self._text_stack.append(self._skip_text)
 658 +       self._text_stack.append(self._wrap_skip_text)
 659 +       self._text = ""
 660 +       self._skip_text = skip_text
 661 +       if skip_text:
 662 +           self._wrap_skip_text = True
 663 +
 664 +    def text_off(self):
 665 +       prev_skip_text = self._skip_text
 666 +       self._wrap_skip_text = self._text_stack.pop(-1)
 667 +       self._skip_text = self._text_stack.pop(-1)
 668 +       old_text = self._text_stack.pop(-1)
 669 +       if old_text is None:
 670 +           self._text = None
 671 +       else:
 672 +           if not prev_skip_text:
 673 +               #self._text = 'o#' + old_text + '#|#' + self._text + '#'
 674 +               self._text = old_text + self._text
 675 +           else:
 676 +               self._text = old_text
 677 


CategoryFeaturePatched

MoinMoin: FeatureRequests/TextPlainFormatterRewrite/OldPatches (last edited 2010-05-03 08:47:40 by PascalVolk)