__filename__ = "markdown.py" __author__ = "Bob Mottram" __license__ = "AGPL3+" __version__ = "1.3.0" __maintainer__ = "Bob Mottram" __email__ = "bob@libreserver.org" __status__ = "Production" __module_group__ = "Web Interface" def _markdown_emphasis_html(markdown: str) -> str: """Add italics and bold html markup to the given markdown """ replacements = { ' **': ' ', '** ': ' ', '**.': '.', '**:': ':', '**;': ';', '?**': '?', '\n**': '\n', '**,': ',', '**\n': '\n', '>**': '>', '**<': '<', '>*': '>', '*<': '<', ' *': ' ', '* ': ' ', '?*': '?', '\n*': '\n', '*.': '.', '*:': ':', '*;': ';', '*,': ',', '*\n': '\n', ' _': '
' in line:
code_section = True
else:
if '
' in line:
code_section = False
if code_section:
result += line + '\n'
continue
if '> ' not in line:
result += line + '\n'
prev_quote_line = None
continue
line_str = line.strip()
if not line_str.startswith('> '):
result += line + '\n'
prev_quote_line = None
continue
line_str = line_str.replace('> ', '', 1).strip()
if prev_quote_line:
new_prev_line = prev_quote_line.replace('\n', '')
result = result.replace(prev_quote_line, new_prev_line) + ' '
line_str += '\n'
else:
line_str = '' + line_str + '\n' result += line_str prev_quote_line = line_str if '\n' in result: result = result.replace('\n', '') if result.endswith('\n') and \ not markdown.endswith('\n'): result = result[:len(result) - 1] return result def _markdown_replace_links(markdown: str, images: bool = False) -> str: """Replaces markdown links with html Optionally replace image links """ replace_links = {} text = markdown start_chars = '[' if images: start_chars = '![' while start_chars in text: if ')' not in text: break text = text.split(start_chars, 1)[1] markdown_link = start_chars + text.split(')')[0] + ')' if ']' not in markdown_link or \ '(' not in markdown_link: text = text.split(')', 1)[1] continue link_text = markdown_link.split(start_chars)[1].split(']')[0] link_text = link_text.replace('`', '') if not images: replace_links[markdown_link] = \ '' + \ link_text + '' else: link_text = markdown_link.split(start_chars)[1].split(']')[0] replace_links[markdown_link] = \ '' text = text.split(')', 1)[1] for md_link, html_link in replace_links.items(): lines = markdown.split('\n') markdown = '' code_section = False ctr = 0 for line in lines: if ctr > 0: markdown += '\n' # avoid code sections if not code_section: if '
' in line:
code_section = True
else:
if '
' in line:
code_section = False
if code_section:
markdown += line
ctr += 1
continue
markdown += line.replace(md_link, html_link)
ctr += 1
return markdown
def _markdown_replace_bullet_points(markdown: str) -> str:
"""Replaces bullet points
"""
lines = markdown.split('\n')
bullet_style = ('* ', ' * ', '- ', ' - ')
bullet_matched = ''
start_line = -1
line_ctr = 0
changed = False
code_section = False
for line in lines:
if not line.strip():
# skip blank lines
line_ctr += 1
continue
# skip over code sections
if not code_section:
if '' in line:
code_section = True
else:
if '
' in line:
code_section = False
if code_section:
line_ctr += 1
continue
if not bullet_matched:
for test_str in bullet_style:
if line.startswith(test_str):
bullet_matched = test_str
start_line = line_ctr
break
else:
if not line.startswith(bullet_matched):
for index in range(start_line, line_ctr):
line_text = lines[index].replace(bullet_matched, '', 1)
if index == start_line:
lines[index] = ''
lines[line_ctr] = '
'
section_active = False
changed = True
line_ctr += 1
if not changed:
return markdown
markdown = ''
for line in lines:
markdown += line + '\n'
return markdown
def markdown_to_html(markdown: str) -> str:
"""Converts markdown formatted text to html
"""
markdown = _markdown_replace_code(markdown)
markdown = _markdown_replace_bullet_points(markdown)
markdown = _markdown_replace_quotes(markdown)
markdown = _markdown_emphasis_html(markdown)
markdown = _markdown_replace_links(markdown, True)
markdown = _markdown_replace_links(markdown)
# replace headers
lines_list = markdown.split('\n')
html_str = ''
ctr = 0
code_section = False
titles = {
"h5": '#####',
"h4": '####',
"h3": '###',
"h2": '##',
"h1": '#'
}
for line in lines_list:
if ctr > 0:
html_str += '' in line:
code_section = True
else:
if '
' in line:
code_section = False
if code_section:
html_str += line
ctr += 1
continue
for hsh, hashes in titles.items():
if line.startswith(hashes):
line = line.replace(hashes, '').strip()
line = '<' + hsh + '>' + line + '' + hsh + '>\n'
ctr = -1
break
html_str += line
ctr += 1
html_str = html_str.replace('
', '')
html_str = html_str.replace('
', '
')
return html_str