make handles bold.
This commit is contained in:
1 parent
f577242432
commit
69b87777e5
728 files changed
+3291
-3087
No files matched your search
@@ -796,7 +796,7 @@ def emit_all(
|
||||
|
||||
|
||||
_NUMBER_LINE: re.Pattern[str] = re.compile(
|
||||
r"^(\*\*(\d+)/\*\*)(?: +@([A-Za-z0-9_]+))?[ \t]*$",
|
||||
r"^(\*\*(\d+)/\*\*)(?: +(?:\*\*)?@([A-Za-z0-9_]+)(?:\*\*)?)?(?: +\^([A-Za-z0-9_]+))?[ \t]*$",
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
@@ -858,6 +858,20 @@ def _frontmatter_handle(text: str) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
def _frontmatter_post_id(text: str) -> str:
|
||||
"""Return the note-root ``post_id:`` value, or empty."""
|
||||
in_front = False
|
||||
for line in text.splitlines():
|
||||
if line.strip() == "---":
|
||||
if in_front:
|
||||
return ""
|
||||
in_front = True
|
||||
continue
|
||||
if in_front and line.startswith("post_id:"):
|
||||
return line.split(":", 1)[1].strip().strip("\"'")
|
||||
return ""
|
||||
|
||||
|
||||
def _body_match_keys(body: str) -> set[str]:
|
||||
"""Keys used to pair a note body with ``post.text`` before or after mention split."""
|
||||
mentions, rest = split_leading_mentions(body)
|
||||
@@ -935,12 +949,15 @@ def patch_note_text(text: str, posts: tuple) -> tuple[str, str, str]:
|
||||
body = _extract_post_body(text[match.end():end])
|
||||
post = match_post_for_body(body, posts, used)
|
||||
handle = ""
|
||||
post_id = ""
|
||||
if post is not None:
|
||||
handle = str(post.handle or "")
|
||||
post_id = str(post.post_id or "")
|
||||
if handle:
|
||||
used.add(post.post_id)
|
||||
if not handle and index == 0 and root_handle:
|
||||
handle = root_handle
|
||||
post_id = _frontmatter_post_id(text)
|
||||
region = text[match.end():end]
|
||||
if not handle:
|
||||
unmatched.append(f"**{number}/**")
|
||||
@@ -948,7 +965,9 @@ def patch_note_text(text: str, posts: tuple) -> tuple[str, str, str]:
|
||||
pieces.append(region)
|
||||
last = end
|
||||
continue
|
||||
new_line = f"**{number}/** @{handle}"
|
||||
new_line = f"**{number}/** **@{handle}**"
|
||||
if post_id:
|
||||
new_line += f" ^{post_id}"
|
||||
if new_line != match.group(0).rstrip():
|
||||
changed = True
|
||||
formatted = format_post_text(body)
|
||||
|
||||
@@ -102,7 +102,7 @@ def _source_block(post: PostData) -> str:
|
||||
|
||||
|
||||
_LEADING_MENTIONS: re.Pattern[str] = re.compile(
|
||||
r"^((?:@[A-Za-z0-9_]+(?:[ \t]+@[A-Za-z0-9_]+)*)[ \t]*)(.*)$",
|
||||
r"^((?:(?:\*\*)?@[A-Za-z0-9_]+(?:\*\*)?(?:[ \t]+(?:\*\*)?@[A-Za-z0-9_]+(?:\*\*)?)*)[ \t]*)(.*)$",
|
||||
re.DOTALL,
|
||||
)
|
||||
|
||||
@@ -113,21 +113,34 @@ def split_leading_mentions(text: str) -> tuple[str, str]:
|
||||
match = _LEADING_MENTIONS.match(raw)
|
||||
if match is None:
|
||||
return "", raw
|
||||
mentions = " ".join(match.group(1).split())
|
||||
mentions = " ".join(
|
||||
part.strip("*") for part in match.group(1).split() if part.strip("*")
|
||||
)
|
||||
rest = match.group(2).lstrip(" \t")
|
||||
if rest.startswith("\n"):
|
||||
rest = rest.lstrip("\n")
|
||||
return mentions, rest
|
||||
|
||||
|
||||
def format_mention_line(mentions: str) -> str:
|
||||
"""Bold each leading reply handle."""
|
||||
handles = [
|
||||
part.strip("*")
|
||||
for part in mentions.split()
|
||||
if part.strip("*").startswith("@")
|
||||
]
|
||||
return " ".join(f"**{handle}**" for handle in handles)
|
||||
|
||||
|
||||
def format_post_text(text: str) -> str:
|
||||
"""Put leading reply mentions on their own line, then the tweet body."""
|
||||
"""Put leading reply mentions on their own bold line, then the tweet body."""
|
||||
mentions, rest = split_leading_mentions(text)
|
||||
if not mentions:
|
||||
return text
|
||||
line = format_mention_line(mentions)
|
||||
if not rest:
|
||||
return mentions
|
||||
return f"{mentions}\n\n{rest}"
|
||||
return line
|
||||
return f"{line}\n\n{rest}"
|
||||
|
||||
|
||||
def _post_block(
|
||||
@@ -136,10 +149,11 @@ def _post_block(
|
||||
media_by_post: dict[str, tuple[str, ...]] | None,
|
||||
branch_links: list[str] | None = None,
|
||||
) -> str:
|
||||
"""Render one post body (``**N/** @handle`` + text + media + branch links)."""
|
||||
"""Render one post: number, bold speaker, block id, mentions, text, media."""
|
||||
if not post.handle:
|
||||
raise ValueError(f"empty handle on post {post.post_id}")
|
||||
parts = [f"**{n}/** @{post.handle}", "", format_post_text(post.text)]
|
||||
head = f"**{n}/** **@{post.handle}** ^{post.post_id}"
|
||||
parts = [head, "", format_post_text(post.text)]
|
||||
media = (media_by_post or {}).get(post.post_id) or ()
|
||||
if media:
|
||||
parts.append("")
|
||||
|
||||
@@ -43,7 +43,9 @@ class PostBlockAttributionTests(unittest.TestCase):
|
||||
post("1898440015182729598", "SebAaltonen", "WG_RR_EN", "1"),
|
||||
None,
|
||||
)
|
||||
self.assertTrue(block.startswith("**19/** @SebAaltonen\n"))
|
||||
self.assertTrue(
|
||||
block.startswith("**19/** **@SebAaltonen** ^1898440015182729598\n")
|
||||
)
|
||||
self.assertIn("WG_RR_EN", block)
|
||||
|
||||
def test_empty_handle_raises(self) -> None:
|
||||
@@ -61,12 +63,19 @@ class PostBlockAttributionTests(unittest.TestCase):
|
||||
),
|
||||
None,
|
||||
)
|
||||
self.assertIn("**19/** @SebAaltonen\n\n@NOTimothyLottes\n\nI said WG_RR_EN", block)
|
||||
self.assertIn(
|
||||
"**19/** **@SebAaltonen** ^1898440015182729598\n\n"
|
||||
"**@NOTimothyLottes**\n\nI said WG_RR_EN",
|
||||
block,
|
||||
)
|
||||
|
||||
def test_format_post_text_is_idempotent(self) -> None:
|
||||
original = "@AgileJebrim @SebAaltonen The higher the occupancy"
|
||||
once = format_post_text(original)
|
||||
self.assertEqual(once, "@AgileJebrim @SebAaltonen\n\nThe higher the occupancy")
|
||||
self.assertEqual(
|
||||
once,
|
||||
"**@AgileJebrim** **@SebAaltonen**\n\nThe higher the occupancy",
|
||||
)
|
||||
self.assertEqual(format_post_text(once), once)
|
||||
self.assertEqual(split_leading_mentions("holy truthnuke")[0], "")
|
||||
|
||||
@@ -83,9 +92,9 @@ class RenderAttributionTests(unittest.TestCase):
|
||||
source_url="https://x.com/rianflo/status/1",
|
||||
)
|
||||
text = render_spine(thread, ["1", "2", "3"], [], {}, "2026-08-25")
|
||||
self.assertIn("**1/** @rianflo", text)
|
||||
self.assertIn("**2/** @NOTimothyLottes", text)
|
||||
self.assertIn("**3/** @rianflo", text)
|
||||
self.assertIn("**1/** **@rianflo** ^1", text)
|
||||
self.assertIn("**2/** **@NOTimothyLottes** ^2", text)
|
||||
self.assertIn("**3/** **@rianflo** ^3", text)
|
||||
|
||||
def test_mixed_branch_labels_seb_and_jebrim(self) -> None:
|
||||
thread = ThreadData(
|
||||
@@ -120,12 +129,15 @@ class RenderAttributionTests(unittest.TestCase):
|
||||
"SebAaltonen",
|
||||
"2026-08-25",
|
||||
)
|
||||
self.assertIn("**1/** @NOTimothyLottes", text)
|
||||
self.assertIn("**2/** @SebAaltonen", text)
|
||||
self.assertIn("**3/** @AgileJebrim", text)
|
||||
self.assertIn("**1/** **@NOTimothyLottes** ^1898352640825651644", text)
|
||||
self.assertIn("**2/** **@SebAaltonen** ^1898440015182729598", text)
|
||||
self.assertIn("**3/** **@AgileJebrim** ^1898385745892495810", text)
|
||||
for line in text.splitlines():
|
||||
if line.startswith("**") and "/**" in line:
|
||||
self.assertRegex(line, r"^\*\*\d+/\*\* @[A-Za-z0-9_]+$")
|
||||
if "/**" in line and line.startswith("**"):
|
||||
self.assertRegex(
|
||||
line,
|
||||
r"^\*\*\d+/\*\* \*\*@[A-Za-z0-9_]+\*\* \^[A-Za-z0-9_]+$",
|
||||
)
|
||||
|
||||
|
||||
class RelabelPatchTests(unittest.TestCase):
|
||||
@@ -229,11 +241,11 @@ class RelabelPatchTests(unittest.TestCase):
|
||||
b'{"schema_version": 2, "root_post_id": "root", "items": []}\n'
|
||||
))
|
||||
branch = (notes / "branch.md").read_text(encoding="utf-8")
|
||||
self.assertIn("**19/** @SebAaltonen", branch)
|
||||
self.assertIn("**33/** @AgileJebrim", branch)
|
||||
self.assertIn("**19/** **@SebAaltonen** ^1898440015182729598", branch)
|
||||
self.assertIn("**33/** **@AgileJebrim** ^1898385745892495810", branch)
|
||||
self.assertIn("1. **Onat Turkcuoglu** (@onatt0) - Apr 30", branch)
|
||||
index = (notes / "index.md").read_text(encoding="utf-8")
|
||||
self.assertIn("**1/** @SebAaltonen", index)
|
||||
self.assertIn("**1/** **@SebAaltonen** ^root", index)
|
||||
self.assertIn(" - vulkan", index)
|
||||
self.assertIn("draft: false", index)
|
||||
|
||||
@@ -241,17 +253,18 @@ class RelabelPatchTests(unittest.TestCase):
|
||||
with TemporaryDirectory() as raw:
|
||||
vault, _asset, notes = self._vault(raw)
|
||||
(notes / "index.md").write_text(
|
||||
"---\ndraft: false\n---\n\n**1/** @SebAaltonen\n\n"
|
||||
"---\ndraft: false\n---\n\n"
|
||||
"**1/** **@SebAaltonen** ^root\n\n"
|
||||
"Stupid hardware question\n",
|
||||
encoding="utf-8",
|
||||
newline="\n",
|
||||
)
|
||||
(notes / "branch.md").write_text(
|
||||
"---\ndraft: false\n---\n\n"
|
||||
"**19/** @SebAaltonen\n\n"
|
||||
"@NOTimothyLottes\n\n"
|
||||
"**19/** **@SebAaltonen** ^1898440015182729598\n\n"
|
||||
"**@NOTimothyLottes**\n\n"
|
||||
"I said WG_RR_EN\n\n"
|
||||
"**33/** @AgileJebrim\n\n"
|
||||
"**33/** **@AgileJebrim** ^1898385745892495810\n\n"
|
||||
"On the flip side, it appears that using 128\n",
|
||||
encoding="utf-8",
|
||||
newline="\n",
|
||||
@@ -280,7 +293,8 @@ class RelabelPatchTests(unittest.TestCase):
|
||||
new, state, reason = patch_note_text(text, posts)
|
||||
self.assertEqual(state, "rewrite")
|
||||
self.assertEqual(reason, "")
|
||||
self.assertIn("@NOTimothyLottes\n\nI said WG_RR_EN", new)
|
||||
self.assertIn("**@NOTimothyLottes**\n\nI said WG_RR_EN", new)
|
||||
self.assertIn("**19/** **@SebAaltonen** ^1898440015182729598", new)
|
||||
again, state2, _reason = patch_note_text(new, posts)
|
||||
self.assertEqual(state2, "noop")
|
||||
self.assertEqual(again, new)
|
||||
@@ -296,8 +310,8 @@ class RelabelPatchTests(unittest.TestCase):
|
||||
new, state, reason = patch_note_text(text, posts)
|
||||
self.assertEqual(state, "rewrite")
|
||||
self.assertEqual(reason, "")
|
||||
self.assertIn("**30/** @simplex_fx", new)
|
||||
self.assertIn("**31/** @simplex_fx", new)
|
||||
self.assertIn("**30/** **@simplex_fx** ^1", new)
|
||||
self.assertIn("**31/** **@simplex_fx** ^2", new)
|
||||
|
||||
def test_empty_handle_is_conflict(self) -> None:
|
||||
with TemporaryDirectory() as raw:
|
||||
|
||||
Reference in new issue
Block a user