Skip to content

Commit 5980431

Browse files
committed
improvements to table functionality.
1 parent c10a8a8 commit 5980431

4 files changed

Lines changed: 238 additions & 158 deletions

File tree

textile/core.py

Lines changed: 7 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,14 @@
2121

2222
import uuid
2323
import six
24-
from xml.etree import ElementTree
2524

2625
from textile.tools import sanitizer, imagesize
2726
from textile.regex_strings import (align_re_s, cls_re_s, halign_re_s,
2827
pnct_re_s, regex_snippets, syms_re_s, table_span_re_s, valign_re_s)
2928
from textile.utils import (decode_high, encode_high, encode_html, generate_tag,
3029
has_raw_text, is_rel_url, is_valid_url, list_type, normalize_newlines,
3130
parse_attributes, pba)
32-
from textile.objects import Block
31+
from textile.objects import Block, Table
3332

3433

3534
try:
@@ -284,160 +283,12 @@ def table(self, text):
284283
pattern = re.compile(r'^(?:table(?P<tatts>_?{s}{a}{c})\.'
285284
r'(?P<summary>.*?)\n)?^(?P<rows>{a}{c}\.? ?\|.*\|)'
286285
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
441292

442293
def textileLists(self, text):
443294
pattern = re.compile(r'^((?:[*;:]+|[*;:#]*#(?:_|\d+)?){0}[ .].*)$'

textile/objects/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
from .block import Block
2+
from .table import Table
23

3-
__all__ = ['Block', ]
4+
__all__ = ['Block', 'Table']

0 commit comments

Comments
 (0)