fix(claude): render markdown tables in notes
This commit is contained in:
@@ -249,6 +249,41 @@ def inline_plain(text: str, site: Site, at: str) -> str:
|
|||||||
return re.sub(r"\x00(\d+)\x00", lambda m: links[int(m[1])], text)
|
return re.sub(r"\x00(\d+)\x00", lambda m: links[int(m[1])], text)
|
||||||
|
|
||||||
|
|
||||||
|
# gfm pipe tables: a header row, a row of dashes, then body rows up to a line without a pipe
|
||||||
|
PIPE = re.compile(r"(?<!\\)\|")
|
||||||
|
SEPARATOR_CELL = re.compile(r"^:?-+:?$")
|
||||||
|
ALIGN = {(True, True): "center", (False, True): "right", (True, False): "left"}
|
||||||
|
|
||||||
|
|
||||||
|
def table_cells(line: str) -> list[str]:
|
||||||
|
s = line.strip()
|
||||||
|
s = s.removeprefix("|")
|
||||||
|
s = s[:-1] if s.endswith("|") and not s.endswith("\\|") else s
|
||||||
|
return [c.strip().replace("\\|", "|") for c in PIPE.split(s)]
|
||||||
|
|
||||||
|
|
||||||
|
def table_start(lines: list[str], i: int) -> list[str] | None:
|
||||||
|
"""the column alignments if a table starts at lines[i], else None"""
|
||||||
|
if i + 1 >= len(lines) or not (PIPE.search(lines[i]) and PIPE.search(lines[i + 1])):
|
||||||
|
return None
|
||||||
|
seps = table_cells(lines[i + 1])
|
||||||
|
if len(table_cells(lines[i])) != len(seps):
|
||||||
|
return None
|
||||||
|
if not all(SEPARATOR_CELL.match(c) for c in seps):
|
||||||
|
return None
|
||||||
|
return [ALIGN.get((c[0] == ":", c[-1] == ":"), "") for c in seps]
|
||||||
|
|
||||||
|
|
||||||
|
def table_row(line: str, aligns: list[str], tag: str, site: Site, at: str) -> str:
|
||||||
|
# short rows are padded, extra cells dropped, as gfm does
|
||||||
|
cells = (table_cells(line) + [""] * len(aligns))[: len(aligns)]
|
||||||
|
row = []
|
||||||
|
for cell, align in zip(cells, aligns):
|
||||||
|
style = f' style="text-align: {align}"' if align else ""
|
||||||
|
row.append(f"<{tag}{style}>{inline(cell, site, at)}</{tag}>")
|
||||||
|
return f"<tr>{''.join(row)}</tr>"
|
||||||
|
|
||||||
|
|
||||||
def markdown(text: str, site: Site, at: str) -> str:
|
def markdown(text: str, site: Site, at: str) -> str:
|
||||||
lines = text.splitlines()
|
lines = text.splitlines()
|
||||||
out: list[str] = []
|
out: list[str] = []
|
||||||
@@ -294,6 +329,20 @@ def markdown(text: str, site: Site, at: str) -> str:
|
|||||||
out.append(f"<h{level}>{inline(m[2], site, at)}</h{level}>")
|
out.append(f"<h{level}>{inline(m[2], site, at)}</h{level}>")
|
||||||
i += 1
|
i += 1
|
||||||
continue
|
continue
|
||||||
|
if aligns := table_start(lines, i):
|
||||||
|
flush_para()
|
||||||
|
close_lists()
|
||||||
|
head = table_row(line, aligns, "th", site, at)
|
||||||
|
i += 2
|
||||||
|
body = []
|
||||||
|
while i < len(lines) and PIPE.search(lines[i]):
|
||||||
|
body.append(table_row(lines[i], aligns, "td", site, at))
|
||||||
|
i += 1
|
||||||
|
tbody = f"<tbody>{''.join(body)}</tbody>" if body else ""
|
||||||
|
out.append(
|
||||||
|
f'<div class="table"><table><thead>{head}</thead>{tbody}</table></div>'
|
||||||
|
)
|
||||||
|
continue
|
||||||
if m := re.match(r"^(\s*)([-*]|\d+\.)\s+(.*)$", line):
|
if m := re.match(r"^(\s*)([-*]|\d+\.)\s+(.*)$", line):
|
||||||
flush_para()
|
flush_para()
|
||||||
indent, tag = len(m[1]), "ol" if m[2][0].isdigit() else "ul"
|
indent, tag = len(m[1]), "ol" if m[2][0].isdigit() else "ul"
|
||||||
@@ -314,6 +363,7 @@ def markdown(text: str, site: Site, at: str) -> str:
|
|||||||
i < len(lines)
|
i < len(lines)
|
||||||
and lines[i].strip()
|
and lines[i].strip()
|
||||||
and not re.match(r"^\s*([-*]|\d+\.)\s+|^\s*```|^#{1,4}\s", lines[i])
|
and not re.match(r"^\s*([-*]|\d+\.)\s+|^\s*```|^#{1,4}\s", lines[i])
|
||||||
|
and not table_start(lines, i)
|
||||||
):
|
):
|
||||||
item.append(lines[i].strip())
|
item.append(lines[i].strip())
|
||||||
i += 1
|
i += 1
|
||||||
|
|||||||
Reference in New Issue
Block a user