diff --git a/claude/skills/notes/notes.py b/claude/skills/notes/notes.py index 72f4272..d9c9fed 100755 --- a/claude/skills/notes/notes.py +++ b/claude/skills/notes/notes.py @@ -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) +# gfm pipe tables: a header row, a row of dashes, then body rows up to a line without a pipe +PIPE = re.compile(r"(? 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"