|
21 | 21 |
|
22 | 22 | import uuid |
23 | 23 | import six |
24 | | -from xml.etree import ElementTree |
25 | 24 |
|
26 | 25 | from textile.tools import sanitizer, imagesize |
27 | 26 | from textile.regex_strings import (align_re_s, cls_re_s, halign_re_s, |
28 | 27 | pnct_re_s, regex_snippets, syms_re_s, table_span_re_s, valign_re_s) |
29 | 28 | from textile.utils import (decode_high, encode_high, encode_html, generate_tag, |
30 | 29 | has_raw_text, is_rel_url, is_valid_url, list_type, normalize_newlines, |
31 | 30 | parse_attributes, pba) |
32 | | -from textile.objects import Block |
| 31 | +from textile.objects import Block, Table |
33 | 32 |
|
34 | 33 |
|
35 | 34 | try: |
@@ -284,160 +283,12 @@ def table(self, text): |
284 | 283 | pattern = re.compile(r'^(?:table(?P<tatts>_?{s}{a}{c})\.' |
285 | 284 | r'(?P<summary>.*?)\n)?^(?P<rows>{a}{c}\.? ?\|.*\|)' |
286 | 285 | r'[\s]*\n\n'.format(**{'s': table_span_re_s, 'a': align_re_s, |
287 | | - 'c': cls_re_s}), |
288 | | - flags=re.S | re.M | re.U) |
289 | | - return pattern.sub(self.fTable, text) |
290 | | - |
291 | | - def fTable(self, match): |
292 | | - table_attributes = parse_attributes(match.group('tatts'), 'table') |
293 | | - |
294 | | - summ = match.group('summary') |
295 | | - if summ: |
296 | | - table_attributes.update(summary=summ.strip()) |
297 | | - cap = '' |
298 | | - colgrp, last_rgrp = '', '' |
299 | | - c_row = 1 |
300 | | - rows = [] |
301 | | - groups = [] |
302 | | - enc = 'unicode' |
303 | | - if six.PY2: # pragma: no branch |
304 | | - enc = 'UTF-8' |
305 | | - split = re.split(r'\|\s*?$', match.group('rows'), flags=re.M) |
306 | | - for row in [x for x in split if x]: |
307 | | - row = row.lstrip() |
308 | | - |
309 | | - # Caption -- only occurs on row 1, otherwise treat '|=. foo |...' |
310 | | - # as a normal center-aligned cell. |
311 | | - captionpattern = (r"^\|\=(?P<capts>{s}{a}{c})\. (?P<cap>[^\n]*)" |
312 | | - r"(?P<row>.*)".format(**{'s': table_span_re_s, 'a': |
313 | | - align_re_s, 'c': cls_re_s})) |
314 | | - caption_re = re.compile(captionpattern, re.S) |
315 | | - cmtch = caption_re.match(row) |
316 | | - if c_row == 1 and cmtch: |
317 | | - caption_atts = parse_attributes(cmtch.group('capts')) |
318 | | - cap = '\t{0}\n\t'.format(generate_tag('caption', |
319 | | - cmtch.group('cap').strip(), caption_atts)) |
320 | | - row = cmtch.group('row').lstrip() |
321 | | - if row == '': |
322 | | - continue |
323 | | - |
324 | | - c_row = c_row + 1 |
325 | | - |
326 | | - # Colgroup |
327 | | - grppattern = r"^\|:(?P<cols>{s}{a}{c}\. .*)".format(**{'s': |
328 | | - table_span_re_s, 'a': align_re_s, 'c': cls_re_s}) |
329 | | - grp_re = re.compile(grppattern, re.M) |
330 | | - gmtch = grp_re.match(row.lstrip()) |
331 | | - if gmtch: |
332 | | - has_newline = "\n" in row |
333 | | - match_cols = gmtch.group('cols').replace('.', '').split('|') |
334 | | - group_atts = parse_attributes(match_cols[0].strip(), 'col') |
335 | | - colgroup = ElementTree.Element('colgroup', attrib=group_atts) |
336 | | - colgroup.text = '\n\t' |
337 | | - # colgroup is the first item in match_cols, the remaining items |
338 | | - # are cols. |
339 | | - for idx, col in enumerate(match_cols[1:]): |
340 | | - col_atts = parse_attributes(col.strip(), 'col') |
341 | | - ElementTree.SubElement(colgroup, 'col', col_atts) |
342 | | - colgrp = ElementTree.tostring(colgroup, encoding=enc) |
343 | | - # cleanup the extra xml declaration if it exists, (python |
344 | | - # versions differ) and then format the resulting string |
345 | | - # accordingly: newline and tab between cols and a newline at |
346 | | - # the end |
347 | | - colgrp = colgrp.replace("<?xml version='1.0' " |
348 | | - "encoding='UTF-8'?>\n", '') |
349 | | - colgrp = '{0}\n'.format(colgrp.replace('><', '>\n\t<')) |
350 | | - |
351 | | - # If the row has a newline in it, account for the missing |
352 | | - # closing pipe and process the rest of the line |
353 | | - if not has_newline: |
354 | | - continue |
355 | | - else: |
356 | | - row = row[row.index('\n'):].lstrip() |
357 | | - |
358 | | - grpmatchpattern = (r"(:?^\|(?P<part>{v})(?P<rgrpatts>{s}{a}{c})" |
359 | | - r"\.\s*$\n)?^(?P<row>.*)").format(**{'v': valign_re_s, 's': |
360 | | - table_span_re_s, 'a': align_re_s, 'c': cls_re_s}) |
361 | | - grpmatch_re = re.compile(grpmatchpattern, re.S | re.M) |
362 | | - grpmatch = grpmatch_re.match(row.lstrip()) |
363 | | - |
364 | | - # Row group |
365 | | - rgrp_atts = parse_attributes(grpmatch.group('rgrpatts')) |
366 | | - rgrp = '' |
367 | | - rgrptypes = {'^': 'thead', '~': 'tfoot', '-': 'tbody'} |
368 | | - if grpmatch.group('part'): |
369 | | - rgrp = rgrptypes[grpmatch.group('part')] |
370 | | - rgrp_tag = generate_tag(rgrp, '\n', rgrp_atts) |
371 | | - row = grpmatch.group('row') |
372 | | - |
373 | | - rmtch = re.search(r'^(?P<ratts>{0}{1}\. )(?P<row>.*)'.format( |
374 | | - align_re_s, cls_re_s), row.lstrip()) |
375 | | - if rmtch: |
376 | | - row_atts = parse_attributes(rmtch.group('ratts'), 'tr') |
377 | | - row = rmtch.group('row') |
378 | | - else: |
379 | | - row_atts = {} |
380 | | - |
381 | | - cells = [] |
382 | | - for cellctr, cell in enumerate(row.split('|')): |
383 | | - ctag = 'td' |
384 | | - if cell.startswith('_'): |
385 | | - ctag = 'th' |
386 | | - cmtch = re.search(r'^(?P<catts>_?{0}{1}{2}\. )(?P<cell>.*)'.format( |
387 | | - table_span_re_s, align_re_s, cls_re_s), cell, flags=re.S) |
388 | | - if cmtch: |
389 | | - cell_atts = parse_attributes(cmtch.group('catts'), 'td') |
390 | | - cell = cmtch.group('cell') |
391 | | - else: |
392 | | - cell_atts = {} |
393 | | - |
394 | | - if not self.lite: |
395 | | - a_pattern = r'(?P<space>{0}*)(?P<cell>.*)'.format( |
396 | | - regex_snippets['space']) |
397 | | - a = re.search(a_pattern, cell, flags=re.S) |
398 | | - cell = self.redcloth_list(a.group('cell')) |
399 | | - cell = self.textileLists(cell) |
400 | | - cell = '{0}{1}'.format(a.group('space'), cell) |
401 | | - |
402 | | - # row.split() gives us ['', 'cell 1 contents', '...'] |
403 | | - # so we ignore the first cell. |
404 | | - if cellctr > 0: |
405 | | - cline_tag = generate_tag(ctag, cell, cell_atts) |
406 | | - cells.append(self.doTagBr(ctag, cline_tag)) |
407 | | - |
408 | | - cell_tag_string = '\n\t\t\t{0}\n\t\t'.format('\n\t\t\t'.join( |
409 | | - cells)) |
410 | | - |
411 | | - row_tag = generate_tag('tr', cell_tag_string, row_atts) |
412 | | - rows.append(row_tag) |
413 | | - |
414 | | - # if rgrp and last_rgrp are set, it means the group has changed. |
415 | | - # That also means the closing group tag has already been set |
416 | | - if rgrp and last_rgrp: |
417 | | - groups.append(group_close) |
418 | | - |
419 | | - # if we see a new rgrp, start the group, and throw in all the |
420 | | - # current rows. |
421 | | - if rgrp: |
422 | | - group_open, group_close = rgrp_tag.split('\n') |
423 | | - groups.append('{0}\n\t\t{1}'.format(group_open, |
424 | | - '\n\t\t'.join(rows))) |
425 | | - |
426 | | - last_rgrp = rgrp if rgrp else last_rgrp |
427 | | - |
428 | | - # if no group was specified, just join the rows |
429 | | - if not rgrp: |
430 | | - groups.append('\t{0}'.format('\n\t\t'.join(rows))) |
431 | | - cells = [] |
432 | | - rows = [] |
433 | | - |
434 | | - if last_rgrp: |
435 | | - c = rgrp_tag.split('\n')[1] |
436 | | - groups.append(c) |
437 | | - |
438 | | - content = '\n{0}{1}\t{2}\n\t'.format(cap, colgrp, '\n\t'.join(groups)) |
439 | | - tbl = generate_tag('table', content, table_attributes) |
440 | | - return '\t{0}\n\n'.format(tbl) |
| 286 | + 'c': cls_re_s}), flags=re.S | re.M | re.U) |
| 287 | + match = pattern.search(text) |
| 288 | + if match: |
| 289 | + table = Table(self, **match.groupdict()) |
| 290 | + return table.process() |
| 291 | + return text |
441 | 292 |
|
442 | 293 | def textileLists(self, text): |
443 | 294 | pattern = re.compile(r'^((?:[*;:]+|[*;:#]*#(?:_|\d+)?){0}[ .].*)$' |
|
0 commit comments