diff --git a/scripts/profile_sync.py b/scripts/profile_sync.py index 7de18484..ee663dad 100644 --- a/scripts/profile_sync.py +++ b/scripts/profile_sync.py @@ -515,6 +515,12 @@ def _walk_document( yield from _walk_document(item, spot) +# What separates one citation from the next in prose. lynx-emu writes +# "...:112; mednafen src/lynx/system.cpp:86-93": without the semicolon the +# project word read as prose and the citation was charged to the fork. +_PROSE_LIST_DELIMITERS = ",;:(" + + def _prose_external( line: str, path_start: int, known: frozenset[str] | set[str] = frozenset() ) -> bool: @@ -529,7 +535,7 @@ def _prose_external( `mednafen src/lynx/rom.cpp:55` it is the declared upstream itself. """ before = line[:path_start].rstrip() - if not before or before[-1] in ",:(": + if not before or before[-1] in _PROSE_LIST_DELIMITERS: return False word_start = max(before.rfind(" "), before.rfind("\t"), before.rfind("(")) + 1 word = before[word_start:] @@ -538,7 +544,7 @@ def _prose_external( if word.lower() in PROSE_LINKING_WORDS or word.lower() in known: return False lead = before[:word_start].rstrip() - return not lead or lead[-1] in ",:(" + return not lead or lead[-1] in _PROSE_LIST_DELIMITERS def resolve_project_word(path: str, trees: Iterable[list[str] | None]) -> str | None: diff --git a/tests/test_profile_sync.py b/tests/test_profile_sync.py index 345bae3e..8ea6016b 100644 --- a/tests/test_profile_sync.py +++ b/tests/test_profile_sync.py @@ -3028,6 +3028,19 @@ class TestCollectCitations(unittest.TestCase): [("main.c", 112, 112), ("main.c", 1624, 1633)], ) + def test_a_semicolon_separates_citations_like_a_comma(self): + # lynx-emu: "...:112; mednafen src/lynx/system.cpp:86-93" cites the + # mednafen upstream, not the fork the profile was read from. + for line in ( + "see Lynx.emu/src/lynx/system.cpp:112; mednafen src/lynx/system.cpp:86-93", + "see Lynx.emu/src/lynx/system.cpp:112, mednafen src/lynx/system.cpp:86-93", + ): + with self.subTest(line=line): + start = line.index("src/lynx/system.cpp:86") + self.assertTrue(profile_sync._prose_external(line, start)) + line = "boot; then src/lynx/system.cpp:86" + self.assertFalse(profile_sync._prose_external(line, line.index("src/"))) + def test_spans_locate_the_tokens_on_the_line(self): document = {"notes": "See main.c:112,1624-1633 for the boot path.\n"} citation = collect_citations(document)[0]