make handles bold.

This commit is contained in:
ed committed 2026-08-25 16:26:52 -04:00
1 parent f577242432
commit 69b87777e5
728 files changed
+3291 -3087

No files matched your search

+21 -2
View File
@@ -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)
+21 -7
View File
@@ -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("")
+35 -21
View File
@@ -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: