summaryrefslogtreecommitdiff
path: root/asciidoc/attrs.py
diff options
context:
space:
mode:
Diffstat (limited to 'asciidoc/attrs.py')
-rw-r--r--asciidoc/attrs.py77
1 files changed, 73 insertions, 4 deletions
diff --git a/asciidoc/attrs.py b/asciidoc/attrs.py
index f61b62b..42a6aae 100644
--- a/asciidoc/attrs.py
+++ b/asciidoc/attrs.py
@@ -1,6 +1,7 @@
import re
import typing
+from . import get_compat_mode
from .utils import get_args, get_kwargs
@@ -15,16 +16,85 @@ def parse_attributes(attrs: str, output_dict: typing.Dict) -> None:
output_dict: {}
attrs: 'hello,world'
- output_dict: {'2': 'world', '0': 'hello,world', '1': 'hello'}
+ output_dict: {'0': 'hello,world', '1': 'hello', '2': 'world',}
attrs: '"hello", planet="earth"'
- output_dict: {'planet': 'earth', '0': '"hello", planet="earth"', '1': 'hello'}
+ output_dict: {'0': '"hello", planet="earth"', '1': 'hello' 'planet': 'earth', }
"""
if not attrs:
return
output_dict['0'] = attrs
# Replace line separators with spaces so line spanning works.
s = re.sub(r'\s', ' ', attrs)
+ d = legacy_parse(s) if get_compat_mode() == 1 else future_parse(s)
+ output_dict.update(d)
+ assert len(d) > 0
+
+
+def future_parse(s: str) -> dict:
+ d = {}
+ key = ''
+ value = ''
+ count = 1
+ quote = None
+ in_quotes = False
+ had_quotes = False
+
+ def add_value():
+ nonlocal count, d, key, value
+ key = key.strip()
+ value = value.strip()
+ if had_quotes:
+ value = value[1:-1]
+
+ if not value and not had_quotes:
+ value = None
+
+ if key:
+ d[key] = value if value else ''
+ key = ''
+ else:
+ d["{}".format(count)] = value
+ count += 1
+ value = ''
+
+ for i in range(len(s)):
+ char = s[i]
+
+ if char == ',' and not in_quotes:
+ add_value()
+ had_quotes = False
+ elif value and char == '=' and not in_quotes:
+ key = value
+ value = ''
+ elif not in_quotes and (char == '"' or char == "'") \
+ and (i == 0 or s[i - 1] != '\\'):
+ in_quotes = True
+ quote = char
+ value += char
+ elif in_quotes and char == quote and (i == 0 or s[i - 1] != '\\'):
+ in_quotes = False
+ had_quotes = True
+ quote = None
+ value += char
+ elif char == '\\' and i < len(s) - 1 and (s[i + 1] == '"' or s[i + 1] == "'"):
+ pass
+ else:
+ value += char
+
+ if key and key[0] == '=' and not value:
+ value = key + "="
+ key = ""
+
+ if not value and s.rstrip()[-1] == ',':
+ value = ' '
+
+ if had_quotes or value or key:
+ add_value()
+ return d
+
+
+def legacy_parse(s: str) -> dict:
d = {}
try:
d.update(get_args(s))
@@ -47,5 +117,4 @@ def parse_attributes(attrs: str, output_dict: typing.Dict) -> None:
for k in list(d.keys()): # Drop any empty positional arguments.
if d[k] == '':
del d[k]
- output_dict.update(d)
- assert len(d) > 0
+ return d