fix(weixin): wrap long copy-unfriendly lines

This commit is contained in:
LeonSGP43 2026-05-03 21:23:43 +08:00 committed by Teknium
parent a494a614d0
commit 7244a1f0d3
2 changed files with 66 additions and 1 deletions

View file

@ -23,6 +23,7 @@ import re
import secrets import secrets
import struct import struct
import tempfile import tempfile
import textwrap
import time import time
import uuid import uuid
from datetime import datetime from datetime import datetime
@ -32,6 +33,8 @@ from urllib.parse import quote, urlparse
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
WEIXIN_COPY_LINE_WIDTH = 120
try: try:
import aiohttp import aiohttp
@ -731,6 +734,46 @@ def _normalize_markdown_blocks(content: str) -> str:
return "\n".join(result).strip() return "\n".join(result).strip()
def _wrap_copy_friendly_lines_for_weixin(content: str) -> str:
"""Wrap long display lines that are hard to copy in WeChat clients."""
if not content:
return content
wrapped: List[str] = []
in_code_block = False
for raw_line in content.splitlines():
line = raw_line.rstrip()
stripped = line.strip()
if _FENCE_RE.match(stripped):
in_code_block = not in_code_block
wrapped.append(line)
continue
if (
in_code_block
or len(line) <= WEIXIN_COPY_LINE_WIDTH
or not stripped
or stripped.startswith("|")
or _TABLE_RULE_RE.match(stripped)
):
wrapped.append(line)
continue
wrapped_lines = textwrap.wrap(
line,
width=WEIXIN_COPY_LINE_WIDTH,
break_long_words=False,
break_on_hyphens=False,
replace_whitespace=False,
drop_whitespace=True,
)
wrapped.extend(wrapped_lines or [line])
return "\n".join(wrapped).strip()
def _split_markdown_blocks(content: str) -> List[str]: def _split_markdown_blocks(content: str) -> List[str]:
if not content: if not content:
return [] return []
@ -2022,7 +2065,7 @@ class WeixinAdapter(BasePlatformAdapter):
def format_message(self, content: Optional[str]) -> str: def format_message(self, content: Optional[str]) -> str:
if content is None: if content is None:
return "" return ""
return _normalize_markdown_blocks(content) return _wrap_copy_friendly_lines_for_weixin(_normalize_markdown_blocks(content))
async def send_weixin_direct( async def send_weixin_direct(

View file

@ -54,6 +54,28 @@ class TestWeixinFormatting:
assert adapter.format_message(content) == content assert adapter.format_message(content) == content
def test_format_message_wraps_long_plain_lines_for_copying(self):
adapter = _make_adapter()
content = (
"Here is a long issue template line with many copyable fields "
+ " ".join(f"field_{idx}=value_{idx}" for idx in range(24))
)
formatted = adapter.format_message(content)
assert "\n" in formatted
assert all(len(line) <= weixin.WEIXIN_COPY_LINE_WIDTH for line in formatted.splitlines())
assert " ".join(formatted.split()) == " ".join(content.split())
def test_format_message_does_not_wrap_long_code_block_lines(self):
adapter = _make_adapter()
command = "hermes " + " ".join(f"--option-{idx}=value" for idx in range(30))
content = f"```bash\n{command}\n```"
assert adapter.format_message(content) == content
def test_format_message_returns_empty_string_for_none(self): def test_format_message_returns_empty_string_for_none(self):
adapter = _make_adapter() adapter = _make_adapter()