" for x in list_body.split("\1") if x])
def tag_color(children, attr, surrounding):
hex_re = r"^#?([0-9a-f]{6}|[0-9a-f]{3})$"
potential_color = attr.lower().strip()
if potential_color in NAMED_COLORS:
return f"{children}"
m = re.match(hex_re, potential_color)
if m:
return f"{children}"
# return just the way it was if we can't parse it
return f"[color={attr}]{children}[/color]"
def tag_spoiler(children, attr, surrounding):
spoiler_name = attr if attr else "Spoiler"
content = f"
{children}
"
container = f"""
{spoiler_name}
{content}
"""
return container
def tag_image(children, attr, surrounding):
img = f""
if not is_tag(surrounding[0], 'img'):
img = f"
{img}"
if not is_tag(surrounding[1], 'img'):
img = f"{img}
",
"spoiler": tag_spoiler,
}
# [img] is considered block for the purposes of collapsing whitespace,
# despite being potentially inline (since the resulting tag is inline, but creates a block container around itself and sibling images).
# [code] has a special case in is_inline().
INLINE_TAGS = {
'b', 'i', 's', 'u', 'color', 'big', 'small', 'url'
}
def make_emoji(name, code):
return f' '
EMOJI = {
'angry': make_emoji('angry', 'angry'),
'(': make_emoji('frown', '('),
'D': make_emoji('grin', 'D'),
'imp': make_emoji('imp', 'imp'),
'angryimp': make_emoji('impangry', 'angryimp'),
'impangry': make_emoji('impangry', 'impangry'),
'lobster': make_emoji('lobster', 'lobster'),
'|': make_emoji('neutral', '|'),
'pensive': make_emoji('pensive', 'pensive'),
'scissors': make_emoji('scissors', 'scissors'),
')': make_emoji('smile', ')'),
'smiletear': make_emoji('smiletear', 'smiletear'),
'crytear': make_emoji('smiletear', 'crytear'),
',': make_emoji('sob', ','),
'T': make_emoji('sob', 'T'),
'cry': make_emoji('sob', 'cry'),
'sob': make_emoji('sob', 'sob'),
'o': make_emoji('surprised', 'o'),
'O': make_emoji('surprised', 'O'),
'hmm': make_emoji('think', 'hmm'),
'think': make_emoji('think', 'think'),
'thinking': make_emoji('think', 'thinking'),
'P': make_emoji('tongue', 'P'),
'p': make_emoji('tongue', 'p'),
'weary': make_emoji('weary', 'weary'),
';': make_emoji('wink', ';'),
'wink': make_emoji('wink', 'wink'),
}
TEXT_ONLY = ["code"]
def break_lines(text):
text = re.sub(r" +\n", " ", text)
text = re.sub(r"\n\n+", "
", text)
return text
def is_inline(e):
if e is None:
return False # i think
if is_text(e):
return True
if is_tag(e):
if is_tag(e, 'code'): # special case, since [code] can be inline OR block
return '\n' not in e['children']
return e['name'] in INLINE_TAGS
return e['type'] != 'rule'
def should_collapse(text, surrounding):
if not isinstance(text, str):
return False
if not text:
return True
if not text.strip() and '\n' not in text:
return not is_inline(surrounding[0]) and not is_inline(surrounding[1])
return False
def babycode_to_html(s):
subj = escape(s.strip().replace('\r\n', '\n').replace('\r', '\n'))
parser = Parser(subj)
parser.valid_bbcode_tags = TAGS.keys()
parser.bbcode_tags_only_text_children = TEXT_ONLY
parser.valid_emotes = EMOJI.keys()
uncollapsed = parser.parse()
elements = []
for i in range(len(uncollapsed)):
e = uncollapsed[i]
surrounding = (
uncollapsed[i - 1] if i-1 >= 0 else None,
uncollapsed[i + 1] if i+1 < len(uncollapsed) else None
)
if not should_collapse(e, surrounding):
elements.append(e)
out = ""
def fold(element, nobr, surrounding):
if isinstance(element, str):
if nobr:
return element
return break_lines(element)
match element['type']:
case "bbcode":
c = ""
for i in range(len(element['children'])):
child = element['children'][i]
_surrounding = (
element['children'][i - 1] if i-1 >= 0 else None,
element['children'][i + 1] if i+1 < len(element['children']) else None
)
_nobr = element['name'] == "code" or element['name'] == "ul" or element['name'] == "ol"
c = c + fold(child, _nobr, _surrounding)
res = TAGS[element['name']](c, element['attr'], surrounding)
return res
case "link":
return f"{element['url']}"
case 'emote':
return EMOJI[element['name']]
case "rule":
return ""
for i in range(len(elements)):
e = elements[i]
surrounding = (
elements[i - 1] if i-1 >= 0 else None,
elements[i + 1] if i+1 < len(elements) else None
)
out = out + fold(e, False, surrounding)
return out