summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Peveler <matt.peveler@gmail.com>2021-10-28 11:59:03 -1000
committerGitHub <noreply@github.com>2021-10-28 11:59:03 -1000
commit29197204241ae2b9fdf209b5af6898275c20264f (patch)
tree4529a898f12cc151ebb65cdae26b44e44844a825
parent8e721eb8e7da622f6201b6c5937a5f33baac2cc6 (diff)
downloadasciidoc-py3-29197204241ae2b9fdf209b5af6898275c20264f.tar.gz
Fix handling escaped attributes inside macros (#206)
-rw-r--r--asciidoc/asciidoc.py24
-rw-r--r--tests/test_asciidoc.py65
2 files changed, 79 insertions, 10 deletions
diff --git a/asciidoc/asciidoc.py b/asciidoc/asciidoc.py
index 4c323f1..c5fc2b8 100644
--- a/asciidoc/asciidoc.py
+++ b/asciidoc/asciidoc.py
@@ -799,12 +799,12 @@ def subs_attrs(lines, dictionary=None):
n = 0
result = start
for c in text[start:]:
- # Skip braces that are followed by a backslash.
- if result == len(text) - 1 or text[result + 1] != '\\':
- if c == '{':
- n = n + 1
- elif c == '}':
- n = n - 1
+ if result == len(text):
+ break
+ if c == '{':
+ n = n + 1
+ elif c == '}':
+ n = n - 1
result = result + 1
if n == 0:
break
@@ -872,6 +872,7 @@ def subs_attrs(lines, dictionary=None):
for reo in [reo1, reo2]:
pos = 0
while True:
+ line = line.replace('\\{', '{\\')
mo = reo.search(line, pos)
if not mo:
break
@@ -971,6 +972,7 @@ def subs_attrs(lines, dictionary=None):
assert False, 'illegal attribute: %s' % attr
s = str(s)
line = line[:mo.start()] + s + line[end:]
+ line = line.replace('{\\', '\\{')
pos = mo.start() + len(s)
# Drop line if it contains unsubstituted {name} references.
skipped = re.search(r'(?s)\{[^\\\W][-\w]*?\}(?!\\)', line)
@@ -991,7 +993,7 @@ def subs_attrs(lines, dictionary=None):
break
expr = mo.group('expr')
action = mo.group('action')
- expr = expr.replace('{\\', '{')
+ expr = expr.replace('{\\', '\\{')
expr = expr.replace('}\\', '}')
s = system(action, expr, attrs=dictionary)
if dictionary is not None and action in ('counter', 'counter2', 'set', 'set2'):
@@ -1006,8 +1008,9 @@ def subs_attrs(lines, dictionary=None):
if skipped:
break
if not skipped:
- # Remove backslash from escaped entries.
- line = line.replace('{\\', '{')
+ # Put back slash for leftmost curly brace for subsequent parses of
+ # escaped attributes. We don't need the escaped right curly braces though.
+ line = line.replace('{\\', '\\{')
line = line.replace('}\\', '}')
result.append(line)
if string_result:
@@ -4441,7 +4444,8 @@ class Writer:
def write_line(self, line=None):
if not (self.skip_blank_lines and (not line or not line.strip())):
- self.f.write((line or '') + self.newline)
+ # Replace out any escaped attributes with non-escaped versions
+ self.f.write((re.sub(r'\\({[a-zA-Z0-9_][a-zA-Z0-9_\-]*)', '\\1', line) or '') + self.newline)
self.lines_out = self.lines_out + 1
def write(self, *args, **kwargs):
diff --git a/tests/test_asciidoc.py b/tests/test_asciidoc.py
new file mode 100644
index 0000000..71d36fe
--- /dev/null
+++ b/tests/test_asciidoc.py
@@ -0,0 +1,65 @@
+from asciidoc import asciidoc
+import io
+import pytest
+
+
+@pytest.mark.parametrize(
+ "input,expected",
+ (
+ (
+ '{attach}file.txt',
+ '<div class="paragraph"><p></p></div>\r\n'
+ ),
+ (
+ '\\{attach}file{0}.txt',
+ '<div class="paragraph"><p></p></div>\r\n'
+ ),
+ (
+ '\\{attach}file.txt',
+ '<div class="paragraph"><p>{attach}file.txt</p></div>\r\n'
+ ),
+ (
+ '\\{0}file.txt',
+ '<div class="paragraph"><p>{0}file.txt</p></div>\r\n'
+ ),
+ (
+ 'link:{attach}file.txt[file]',
+ '<div class="paragraph"><p></p></div>\r\n'
+ ),
+ (
+ 'link:\\{attach}file.txt[file]',
+ '<div class="paragraph"><p>' +
+ '<a href="{attach}file.txt">file</a></p></div>\r\n'
+ ),
+ (
+ 'link:\\{attach}file\\{0}.txt[file\\{bar}too\\{1}]',
+ '<div class="paragraph"><p><a href="{attach}file{0}.txt">' +
+ 'file{bar}too{1}</a></p></div>\r\n'
+ ),
+ (
+ 'image:\\{attach}file.jpg[]',
+ '<div class="paragraph"><p><span class="image">\r\n' +
+ '<img src="{attach}file.jpg" alt="{attach}file.jpg" />\r\n' +
+ '</span></p></div>\r\n'
+ ),
+ (
+ 'image:\\{attach}file.jpg[foo]',
+ '<div class="paragraph"><p><span class="image">\r\n' +
+ '<img src="{attach}file.jpg" alt="foo" />\r\n</span></p></div>\r\n'
+ ),
+ (
+ 'image:\\{attach}file.jpg[\\{bar}?]',
+ '<div class="paragraph"><p><span class="image">\r\n' +
+ '<img src="{attach}file.jpg" alt="{bar}?" />\r\n</span></p></div>\r\n'
+ ),
+ )
+)
+def test_ignore_attribute(input, expected):
+ infile = io.StringIO(input)
+ outfile = io.StringIO()
+ options = [
+ ('--out-file', outfile),
+ ('--no-header-footer', '')
+ ]
+ asciidoc.execute('asciidoc', options, [infile])
+ assert outfile.getvalue() == expected