fix: read a spaced line list in prose citations

This commit is contained in:
Abdessamad Derraz committed 2026-10-23 16:21:04 +02:00
1 parent 1faf434460
commit 506d18c935
2 files changed
+48

No files matched your search

+17
View File
@@ -231,6 +231,14 @@ PROSE_CONT_RE = re.compile(r",(?P<range>\d+(?:-\d+)?)(?![\w-])(?!\.\d)")
# A spaced continuation is accepted only for a range: `x.c:55-71, 80-147`
# follows the source_ref convention, while `x.c:100, 200 files` is prose.
PROSE_CONT_SPACED_RE = re.compile(r", +(?P<range>\d+-\d+)(?![\w-])(?!\.\d)")
# A spaced single line joins the run only inside a list that closes the
# citation: `bgmusic.c:29, 321)` and `.gitlab-ci.yml:110, 116, 139, 400`
# end on a bracket, a semicolon, a sentence end or the line end, while in
# `x.c:100, 200 files` a word follows and the number is prose.
PROSE_CONT_LIST_RE = re.compile(
r"(?:, +\d+(?:-\d+)?(?![\w-])(?!\.\d))+(?=[)\];]|\.(?!\w)|\s*$)"
)
_PROSE_LIST_RANGE_RE = re.compile(r"\d+(?:-\d+)?")
# Words that read as prose before a filename. Anything else in project
# position marks the citation external, the way `munt ROMInfo.cpp` does in
# a source_ref: the profile does not declare that repository.
@@ -391,6 +399,15 @@ def _prose_runs(
end = match.end()
while True:
cont = PROSE_CONT_RE.match(line, end)
if cont is None and (listed := PROSE_CONT_LIST_RE.match(line, end)):
spans.extend(
(item.start(), item.end())
for item in _PROSE_LIST_RANGE_RE.finditer(
line, end, listed.end()
)
)
end = listed.end()
break
if cont is None:
cont = PROSE_CONT_SPACED_RE.match(line, end)
if cont is None:
+31
View File
@@ -3599,6 +3599,37 @@ class TestCollectCitations(unittest.TestCase):
citation = collect_citations(document)[0]
self.assertEqual(citation.ref, "x.c:100")
def test_spaced_lone_number_closing_the_citation_joins_the_run(self):
# vkquake wrote `(Quake/bgmusic.c:29, 321).` and cemu a list of ten
# lines of .gitlab-ci.yml: only the first number was ever compared.
cases = {
"music (Quake/bgmusic.c:29, 321).\n": [(29, 29), (321, 321)],
"(ref: a/b.cpp:1586-1633, 2646).\n": [(1586, 1633), (2646, 2646)],
"jobs in .gitlab-ci.yml:110, 116, 139-140\n": [
(110, 110), (116, 116), (139, 140)
],
"read at x.c:5, 6; then y\n": [(5, 5), (6, 6)],
}
for text, spans in cases.items():
citation = collect_citations({"notes": text})[0]
self.assertEqual(
[(p.start, p.end) for p in citation.parts], spans, text
)
line = text.splitlines()[0]
self.assertEqual(
[line[lo:hi] for lo, hi in citation.spans],
[p.raw for p in citation.parts],
)
def test_spaced_number_list_followed_by_a_word_stays_prose(self):
for text in (
"It reads x.c:5, 6, 7 players at once.\n",
"It reads x.c:5, 6 and 7 at once.\n",
"Lines 3, 4 and 5, version 2, 3 players.\n",
):
refs = [c.ref for c in collect_citations({"notes": text})]
self.assertEqual(refs, ["x.c:5"] if "x.c" in text else [], text)
def test_declared_repository_name_is_not_external(self):
document = {
"upstream": "https://github.com/o/mednafen",