a1abe159fa
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>
129 lines
3.9 KiB
Python
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
|