Merge pull request #593 from C-Li/feishu_fix

Optimize the display of Markdown titles in Lark card information.
This commit is contained in:
Xubin Ren 2026-02-13 17:02:27 +08:00 committed by GitHub
commit 3f59a8e234
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 45 additions and 5 deletions

1
.gitignore vendored
View File

@ -14,6 +14,7 @@ docs/
*.pywz *.pywz
*.pyzz *.pyzz
.venv/ .venv/
venv/
__pycache__/ __pycache__/
poetry.lock poetry.lock
.pytest_cache/ .pytest_cache/

View File

@ -166,6 +166,10 @@ class FeishuChannel(BaseChannel):
re.MULTILINE, re.MULTILINE,
) )
_HEADING_RE = re.compile(r"^(#{1,6})\s+(.+)$", re.MULTILINE)
_CODE_BLOCK_RE = re.compile(r"(```[\s\S]*?```)", re.MULTILINE)
@staticmethod @staticmethod
def _parse_md_table(table_text: str) -> dict | None: def _parse_md_table(table_text: str) -> dict | None:
"""Parse a markdown table into a Feishu table element.""" """Parse a markdown table into a Feishu table element."""
@ -185,17 +189,52 @@ class FeishuChannel(BaseChannel):
} }
def _build_card_elements(self, content: str) -> list[dict]: def _build_card_elements(self, content: str) -> list[dict]:
"""Split content into markdown + table elements for Feishu card.""" """Split content into div/markdown + table elements for Feishu card."""
elements, last_end = [], 0 elements, last_end = [], 0
for m in self._TABLE_RE.finditer(content): for m in self._TABLE_RE.finditer(content):
before = content[last_end:m.start()].strip() before = content[last_end:m.start()]
if before: if before.strip():
elements.append({"tag": "markdown", "content": before}) elements.extend(self._split_headings(before))
elements.append(self._parse_md_table(m.group(1)) or {"tag": "markdown", "content": m.group(1)}) elements.append(self._parse_md_table(m.group(1)) or {"tag": "markdown", "content": m.group(1)})
last_end = m.end() last_end = m.end()
remaining = content[last_end:].strip() remaining = content[last_end:]
if remaining.strip():
elements.extend(self._split_headings(remaining))
return elements or [{"tag": "markdown", "content": content}]
def _split_headings(self, content: str) -> list[dict]:
"""Split content by headings, converting headings to div elements."""
protected = content
code_blocks = []
for m in self._CODE_BLOCK_RE.finditer(content):
code_blocks.append(m.group(1))
protected = protected.replace(m.group(1), f"\x00CODE{len(code_blocks)-1}\x00", 1)
elements = []
last_end = 0
for m in self._HEADING_RE.finditer(protected):
before = protected[last_end:m.start()].strip()
if before:
elements.append({"tag": "markdown", "content": before})
level = len(m.group(1))
text = m.group(2).strip()
elements.append({
"tag": "div",
"text": {
"tag": "lark_md",
"content": f"**{text}**",
},
})
last_end = m.end()
remaining = protected[last_end:].strip()
if remaining: if remaining:
elements.append({"tag": "markdown", "content": remaining}) elements.append({"tag": "markdown", "content": remaining})
for i, cb in enumerate(code_blocks):
for el in elements:
if el.get("tag") == "markdown":
el["content"] = el["content"].replace(f"\x00CODE{i}\x00", cb)
return elements or [{"tag": "markdown", "content": content}] return elements or [{"tag": "markdown", "content": content}]
async def send(self, msg: OutboundMessage) -> None: async def send(self, msg: OutboundMessage) -> None: