The initial patches of the formatter.text_plain rewrite request.
Toggle line numbers
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:
Toggle line numbers
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