Skip to content

Commit fd3129b

Browse files
committed
rework block function.
this will likely benefit from a bit of cleanup.
1 parent 565316e commit fd3129b

4 files changed

Lines changed: 77 additions & 64 deletions

File tree

tests/test_block.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
from __future__ import unicode_literals
12
from textile import Textile
3+
from collections import OrderedDict
24

35
def test_block():
46
t = Textile()
@@ -7,25 +9,26 @@ def test_block():
79
assert result == expect
810

911
result = t.fBlock("bq", "", None, "", "Hello BlockQuote")
10-
expect = ('\t<blockquote>\n', '\t\t<p>', 'Hello BlockQuote', '</p>',
11-
'\n\t</blockquote>', False)
12+
expect = ('blockquote', OrderedDict(), 'p', OrderedDict(),
13+
'Hello BlockQuote', False)
1214
assert result == expect
1315

1416
result = t.fBlock("bq", "", None, "http://google.com", "Hello BlockQuote")
1517
citation = '{0}1:url'.format(t.uid)
16-
expect = ('\t<blockquote cite="{0}">\n'.format(citation), '\t\t<p>',
17-
'Hello BlockQuote', '</p>', '\n\t</blockquote>', False)
18+
expect = ('blockquote', OrderedDict([('cite',
19+
'{0.uid}{0.refIndex}:url'.format(t))]), 'p', OrderedDict(),
20+
'Hello BlockQuote', False)
1821
assert result == expect
1922

2023
result = t.fBlock("bc", "", None, "", 'printf "Hello, World";')
2124
# the content of text will be turned shelved, so we'll asert only the
2225
# deterministic portions of the expected values, below
23-
expect = ('<pre>', '<code>', 'printf "Hello, World";', '</code>', '</pre>', False)
24-
assert result[0:2] == expect[0:2]
25-
assert result[3:] == expect[3:]
26+
expect = ('pre', OrderedDict(), 'code', OrderedDict(), 'shelve', False)
27+
assert result[0:3] == expect[0:3]
28+
assert result[-1] == expect[-1]
2629

2730
result = t.fBlock("h1", "", None, "", "foobar")
28-
expect = ('', '\t<h1>', 'foobar', '</h1>', '', False)
31+
expect = ('h1', OrderedDict(), '', OrderedDict(), 'foobar', False)
2932
assert result == expect
3033

3134
def test_block_tags_false():

tests/test_values.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989

9090
('h2()>. Bingo.', '\t<h2 style="padding-left:1em; padding-right:1em; text-align:right;">Bingo.</h2>'),
9191

92-
('h3()>[no]{color:red}. Bingo', '\t<h3 style="color:red; padding-left:1em; padding-right:1em; text-align:right;" lang="no">Bingo</h3>'),
92+
('h3()>[no]{color:red}. Bingo', '\t<h3 lang="no" style="color:red; padding-left:1em; padding-right:1em; text-align:right;">Bingo</h3>'),
9393

9494
('<pre>\n<code>\na.gsub!( /</, "" )\n</code>\n</pre>',
9595
'<pre>\n<code>\na.gsub!( /&lt;/, "" )\n</code>\n</pre>'),

textile/core.py

Lines changed: 63 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -569,8 +569,6 @@ def block(self, text):
569569

570570
tag = 'p'
571571
atts = cite = graf = ext = ''
572-
c1 = ''
573-
eat = False
574572

575573
out = []
576574

@@ -581,38 +579,43 @@ def block(self, text):
581579
align_re_s, cls_re_s))
582580
match = re.search(pattern, line, flags=re.S | re.U)
583581
if match:
584-
if ext:
585-
out.append('{0}{1}'.format(out.pop(), c1))
586-
587582
tag, atts, ext, cite, content = match.groups()
588-
o1, o2, content, c2, c1, eat = self.fBlock(**match.groupdict())
583+
(outer_tag, outer_atts, inner_tag, inner_atts, content,
584+
eat) = self.fBlock(**match.groupdict())
589585
# leave off c1 if this block is extended,
590586
# we'll close it at the start of the next block
587+
inner_block = generate_tag(inner_tag, content, inner_atts)
588+
if inner_tag != 'code' and not has_raw_text(inner_block):
589+
inner_block = "\n\t\t{0}\n\t".format(inner_block)
591590
if ext:
592-
line = "{0}{1}{2}{3}".format(o1, o2, content, c2)
591+
line = content
593592
else:
594-
line = "{0}{1}{2}{3}{4}".format(o1, o2, content, c2, c1)
593+
line = generate_tag(outer_tag, inner_block, outer_atts)
594+
if outer_tag != 'pre' and not has_raw_text(line):
595+
line = "\t{0}".format(line)
595596

596597
else:
598+
if ext:
599+
line = '{0}\n{1}'.format(out.pop(), line)
597600
anon = True
598601
if ext or not re.search(r'^\s', line):
599-
o1, o2, content, c2, c1, eat = self.fBlock(tag, atts, ext,
600-
cite, line)
601-
# skip $o1/$c1 because this is part of a continuing
602-
# extended block
602+
(outer_tag, outer_atts, inner_tag, inner_atts, content,
603+
eat) = self.fBlock(tag, atts, ext, cite, line)
604+
# skip o1/c1 because this is part of a continuing extended
605+
# block
603606
if tag == 'p' and not has_raw_text(content):
604607
line = content
605608
else:
606-
line = "{0}{1}{2}".format(o2, content, c2)
609+
line = generate_tag(outer_tag, content, outer_atts)
610+
if outer_tag != 'pre' and not has_raw_text(line):
611+
line = "\t{0}".format(line)
607612
else:
608613
line = self.graf(line)
609614

610615
line = self.doPBr(line)
611616
line = re.sub(r'<br>', '<br />', line)
612617

613-
if ext and anon:
614-
out.append("{0}\n{1}".format(out.pop(), line))
615-
elif not eat and line:
618+
if not eat and line:
616619
out.append(line)
617620

618621
if not ext:
@@ -622,14 +625,15 @@ def block(self, text):
622625
graf = ''
623626

624627
if ext:
625-
out.append('{0}{1}'.format(out.pop(), c1))
628+
out.append(generate_tag(outer_tag, out.pop(), outer_atts))
626629
return '\n\n'.join(out)
627630

628631
def fBlock(self, tag, atts, ext, cite, content):
629632
att = atts
630633
atts = pba(atts, include_id=not self.restricted)
631-
o1 = o2 = c2 = c1 = ''
632-
eat = False
634+
attributes = parse_attributes(att)
635+
output = {'outer_tag': '', 'inner_tag': '', 'outer_atts': OrderedDict(),
636+
'inner_atts': OrderedDict(), 'content': content, 'eat': False}
633637

634638
if tag == 'p':
635639
# is this an anonymous block with a note definition?
@@ -643,11 +647,14 @@ def fBlock(self, tag, atts, ext, cite, content):
643647
(?P<content>.*)$ # content""".format(
644648
space=regex_snippets['space'], cls=cls_re_s),
645649
flags=re.X | re.U)
646-
notedef = notedef_re.sub(self.fParseNoteDefs, content)
650+
notedef = notedef_re.sub(self.fParseNoteDefs, output['content'])
647651

648652
# It will be empty if the regex matched and ate it.
649653
if '' == notedef:
650-
return o1, o2, notedef, c2, c1, True
654+
output['content'] = notedef
655+
return (output['outer_tag'], output['outer_atts'],
656+
output['inner_tag'], output['inner_atts'],
657+
output['content'], output['eat'])
651658

652659
fns = re.search(r'fn(?P<fnid>{0}+)'.format(regex_snippets['digit']),
653660
tag, flags=re.U)
@@ -660,65 +667,66 @@ def fBlock(self, tag, atts, ext, cite, content):
660667

661668
# If there is an author-specified ID goes on the wrapper & the
662669
# auto-id gets pushed to the <sup>
663-
supp_id = ''
670+
supp_id = OrderedDict()
664671

665672
# if class has not been previously specified, set it to "footnote"
666-
if atts.find('class=') < 0:
667-
atts = '{0} class="footnote"'.format(atts)
673+
if 'class' not in attributes:
674+
attributes.update({'class': 'footnote'})
668675

669676
# if there's no specified id, use the generated one.
670-
if atts.find('id=') < 0:
671-
atts = '{0} id="fn{1}"'.format(atts, fnid)
677+
if 'id' not in attributes:
678+
attributes.update({'id': 'fn{0}'.format(fnid)})
672679
else:
673-
supp_id = ' id="fn{0}"'.format(fnid)
680+
supp_id = parse_attributes('(#fn{0})'.format(fnid))
681+
674682

675-
if att.find('^') < 0:
676-
sup = self.formatFootnote(fns.group('fnid'), supp_id)
683+
if '^' not in att:
684+
sup = generate_tag('sup', fns.group('fnid'), supp_id)
677685
else:
678-
fnrev = '<a href="#fnrev{0}">{1}</a>'.format(fnid,
679-
fns.group('fnid'))
680-
sup = self.formatFootnote(fnrev, supp_id)
686+
fnrev = generate_tag('a', fns.group('fnid'), {'href':
687+
'#fnrev{0}'.format(fnid)})
688+
sup = generate_tag('sup', fnrev, supp_id)
681689

682-
content = '{0} {1}'.format(sup, content)
690+
output['content'] = '{0} {1}'.format(sup, output['content'])
683691

684692
if tag == 'bq':
685693
if cite:
686694
cite = self.shelveURL(cite)
695+
cite_att = OrderedDict(cite=cite)
687696
cite = ' cite="{0}"'.format(cite)
688697
else:
689698
cite = ''
690-
o1 = "\t<blockquote{0}{1}>\n".format(cite, atts)
691-
o2 = "\t\t<p{0}>".format(atts)
692-
c2 = "</p>"
693-
c1 = "\n\t</blockquote>"
699+
cite_att = OrderedDict()
700+
cite_att.update(attributes)
701+
output.update({'outer_tag': 'blockquote', 'outer_atts': cite_att,
702+
'inner_tag': 'p', 'inner_atts': attributes, 'eat': False})
694703

695704
elif tag == 'bc' or tag == 'pre':
696-
o1 = "<pre{0}>".format(atts)
697-
o2 = c2 = ''
705+
i_tag = ''
698706
if tag == 'bc':
699-
o2 = "<code{0}>".format(atts)
700-
c2 = "</code>"
701-
c1 = "</pre>"
702-
content = self.shelve(encode_html('{0}\n'.format(
703-
content.rstrip("\n"))))
707+
i_tag = 'code'
708+
content = self.shelve(encode_html('{0}\n'.format( output[
709+
'content'].rstrip("\n"))))
710+
output = {'outer_tag': 'pre', 'outer_atts': attributes,
711+
'inner_tag': i_tag, 'inner_atts': attributes, 'content':
712+
content, 'eat': False}
704713

705714
elif tag == 'notextile':
706-
content = self.shelve(content)
707-
o1 = o2 = ''
708-
c1 = c2 = ''
715+
output['content'] = self.shelve(output['content'])
709716

710717
elif tag == '###':
711-
eat = True
718+
output['eat'] = True
712719

713720
else:
714-
o2 = "\t<{0}{1}>".format(tag, atts)
715-
c2 = "</{0}>".format(tag)
721+
output['outer_tag'] = tag
722+
output['outer_atts'] = attributes
716723

717-
if not eat:
718-
content = self.graf(content)
724+
if not output['eat']:
725+
output['content'] = self.graf(output['content'])
719726
else:
720-
content = ''
721-
return o1, o2, content, c2, c1, eat
727+
output['content'] = ''
728+
return (output['outer_tag'], output['outer_atts'], output['inner_tag'],
729+
output['inner_atts'], output['content'], output['eat'])
722730

723731
def formatFootnote(self, marker, atts='', anchor=True):
724732
if anchor:
@@ -1539,7 +1547,7 @@ def fParseNoteRefs(self, match):
15391547
# Build the link (if any)...
15401548
result = '<span id="noteref{0}">{1}</span>'.format(refid, num)
15411549
if not nolink:
1542-
result = """<a href="#note{0}">{1}</a>""".format(labelid, result)
1550+
result = '<a href="#note{0}">{1}</a>'.format(labelid, result)
15431551

15441552
# Build the reference...
15451553
result = '<sup{0}>{1}</sup>'.format(atts, result)

textile/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ def generate_tag(tag, content, attributes=None):
5454
enc = 'unicode'
5555
if six.PY2:
5656
enc = 'UTF-8'
57+
if not tag:
58+
return content
5759
# FIXME: Kind of an ugly hack. There *must* be a cleaner way. I tried
5860
# adding text by assigning it to a.text. That results in non-ascii text
5961
# being html-entity encoded. Not bad, but not entirely matching

0 commit comments

Comments
 (0)