Files
crypto_okx/lib/common/markdown_html_lib.py
T
dekun a1abe159fa Initial standalone crypto_okx with one-click deploy.
Add deploy/manage.sh bootstrap for git.bz121.com/dekun/crypto_okx and point docs at this repo.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-13 20:00:59 +08:00

129 lines
3.9 KiB
Python

"""Markdown → HTML for system guide / options docs."""
from __future__ import annotations
import re
def render_markdown_html(md_text: str) -> str:
try:
import markdown # type: ignore
return markdown.markdown(
md_text,
extensions=["tables", "fenced_code", "nl2br", "sane_lists"],
)
except Exception:
return _simple_md_html(md_text)
def _simple_md_html(md_text: str) -> str:
from html import escape
lines = md_text.replace("\r\n", "\n").replace("\r", "\n").splitlines()
out: list[str] = []
i = 0
in_code = False
code_buf: list[str] = []
list_buf: list[str] = []
list_ordered = False
def flush_list() -> None:
nonlocal list_buf, list_ordered
if not list_buf:
return
tag = "ol" if list_ordered else "ul"
out.append(f"<{tag}>")
for item in list_buf:
out.append(f"<li>{_inline_md(item)}</li>")
out.append(f"</{tag}>")
list_buf = []
def flush_code() -> None:
nonlocal code_buf, in_code
if not code_buf:
return
out.append(f"<pre><code>{escape(chr(10).join(code_buf))}</code></pre>")
code_buf = []
in_code = False
while i < len(lines):
line = lines[i]
if line.strip().startswith("```"):
flush_list()
if in_code:
flush_code()
else:
in_code = True
i += 1
continue
if in_code:
code_buf.append(line)
i += 1
continue
if re.match(r"^\s*\|", line) and i + 1 < len(lines) and re.match(r"^\s*\|?\s*[-:| ]+\|", lines[i + 1]):
flush_list()
header = [c.strip() for c in line.strip().strip("|").split("|")]
i += 2
rows: list[list[str]] = []
while i < len(lines) and re.match(r"^\s*\|", lines[i]):
rows.append([c.strip() for c in lines[i].strip().strip("|").split("|")])
i += 1
out.append("<table><thead><tr>" + "".join(f"<th>{_inline_md(h)}</th>" for h in header) + "</tr></thead><tbody>")
for row in rows:
out.append("<tr>" + "".join(f"<td>{_inline_md(c)}</td>" for c in row) + "</tr>")
out.append("</tbody></table>")
continue
if re.match(r"^#{1,3}\s+", line):
flush_list()
m = re.match(r"^(#{1,3})\s+(.*)$", line)
if m:
level = len(m.group(1))
out.append(f"<h{level}>{_inline_md(m.group(2))}</h{level}>")
i += 1
continue
if line.strip() == "---":
flush_list()
out.append("<hr>")
i += 1
continue
if line.startswith(">"):
flush_list()
out.append(f"<blockquote>{_inline_md(line.lstrip('>').strip())}</blockquote>")
i += 1
continue
m = re.match(r"^(\d+)\.\s+(.*)$", line.strip())
if m:
if list_buf and not list_ordered:
flush_list()
list_ordered = True
list_buf.append(m.group(2))
i += 1
continue
if re.match(r"^[-*]\s+", line.strip()):
if list_buf and list_ordered:
flush_list()
list_ordered = False
list_buf.append(re.sub(r"^[-*]\s+", "", line.strip()))
i += 1
continue
if not line.strip():
flush_list()
i += 1
continue
flush_list()
out.append(f"<p>{_inline_md(line.strip())}</p>")
i += 1
flush_list()
flush_code()
return "\n".join(out)
def _inline_md(text: str) -> str:
from html import escape
s = escape(text)
s = re.sub(r"`([^`]+)`", r"<code>\1</code>", s)
s = re.sub(r"\*\*([^*]+)\*\*", r"<strong>\1</strong>", s)
return s