mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-12 21:13:49 -06:00
fix: collect abbreviated prose citations
A location written without its file, (:507), reads in the file named last in the scalar, either cited or named as 'path:' before a list. A dotless file cited with its directory (tools/errorgen:20) is a citation too. devilutionx, corsixth, starship, plastic, eden-nightly, theforceengine, lightspark and higan_sfc gain 33 citations that bump and realign now follow. Two read that way pointed at another file and now name theirs: devilutionx assets.cpp:511-518, corsixth app.lua:1591.
This commit is contained in:
1 parent
8dc3ac82c7
commit
a0ecca0024
4 files changed
+123
-40
No files matched your search
+88
-38
@@ -220,10 +220,21 @@ PROSE_EXTENSIONLESS = (
|
||||
"COPYING",
|
||||
"CHANGELOG",
|
||||
)
|
||||
PROSE_CITE_RE = re.compile(
|
||||
# Any other dotless file is cited with its directory, which a constant or a
|
||||
# hex address never carries: lightspark's tools/errorgen:20.
|
||||
_PROSE_PATH = (
|
||||
r"(?P<path>[A-Za-z0-9_][\w./+-]*\.[A-Za-z]\w*"
|
||||
r"|(?:[\w./+-]*/)?(?:" + "|".join(PROSE_EXTENSIONLESS) + r"))"
|
||||
r":(?P<range>\d+(?:-\d+)?)"
|
||||
r"|(?:[\w./+-]*/)?(?:" + "|".join(PROSE_EXTENSIONLESS) + r")"
|
||||
r"|(?:[\w.+-]+/)+[A-Za-z_][\w+-]*)"
|
||||
)
|
||||
PROSE_CITE_RE = re.compile(_PROSE_PATH + r":(?P<range>\d+(?:-\d+)?)")
|
||||
# A file named before its locations, `Source/engine/assets.cpp:` then a
|
||||
# list, and a location that leaves the file out, `(:507)`, which reads in
|
||||
# the file named last: devilutionx, corsixth and starship cite their load
|
||||
# order this way. Neither was collected, so no bump or guard followed them.
|
||||
_PROSE_FILE_NAMED_RE = re.compile(_PROSE_PATH + r":(?=\s|$)")
|
||||
_PROSE_ABBREVIATED_RE = re.compile(
|
||||
r"(?:(?<=[(\s])|^):(?P<range>\d+(?:-\d+)?)(?![\w:-])(?!\.\d)"
|
||||
)
|
||||
PROSE_LIST_ITEM_RE = re.compile(r"\d+[.)](?:\s|$)")
|
||||
PROSE_WRAPPED_RANGE_RE = re.compile(r":\d+(?:-\d+)?(?:[,)\s]|$)")
|
||||
@@ -344,6 +355,12 @@ def _prose_runs(
|
||||
joined line, so a writer can put each span back on its own line.
|
||||
"""
|
||||
lines = text.splitlines()
|
||||
# The file an abbreviated location reads in, and the role it was named
|
||||
# under, carried from line to line within the scalar.
|
||||
named: tuple[str, str] | None = None
|
||||
# Where the run wrapped from the line before ends in this one: its
|
||||
# ranges are that run's, not abbreviated locations of their own.
|
||||
carried = 0
|
||||
for number, own in enumerate(lines):
|
||||
# A literal block keeps its line breaks, so a citation wrapped after
|
||||
# `file:` or after a range's comma lost the ranges on the next line
|
||||
@@ -369,46 +386,35 @@ def _prose_runs(
|
||||
elif following and line.endswith(","):
|
||||
joined_at = len(line) + 1
|
||||
line += " " + following
|
||||
consumed = 0
|
||||
for match in PROSE_CITE_RE.finditer(line):
|
||||
consumed, carried = carried, 0
|
||||
events = sorted(
|
||||
[(m.start(), 0, m) for m in PROSE_CITE_RE.finditer(line)]
|
||||
+ [(m.start(), 1, m) for m in _PROSE_FILE_NAMED_RE.finditer(line)]
|
||||
+ [(m.start(), 2, m) for m in _PROSE_ABBREVIATED_RE.finditer(line)],
|
||||
key=lambda event: (event[0], event[1]),
|
||||
)
|
||||
for _start, kind, match in events:
|
||||
if match.start() >= boundary:
|
||||
break
|
||||
if match.start() < consumed:
|
||||
continue
|
||||
token_start = max(line.rfind(" ", 0, match.start()),
|
||||
line.rfind("\t", 0, match.start())) + 1
|
||||
token = line[token_start:].split()[0] if line[token_start:] else ""
|
||||
if "://" in token:
|
||||
if kind == 1:
|
||||
if "://" not in line[max(0, match.start() - 3):match.end()]:
|
||||
named = (match.group("path"), "")
|
||||
continue
|
||||
path = match.group("path")
|
||||
path_start = match.start("path")
|
||||
# A dotfile citation opens its token with the dot: `.gitlab-ci.yml`
|
||||
# after a delimiter is the filename, while the dot of `boot.cfg`
|
||||
# inside a word belongs to the word before it.
|
||||
if (
|
||||
path_start > 0
|
||||
and line[path_start - 1] == "."
|
||||
and (path_start == 1 or line[path_start - 2] in " \t(")
|
||||
):
|
||||
path_start -= 1
|
||||
path = "." + path
|
||||
# A path opening its line reads its role or project word at the
|
||||
# end of the line before: genesis_plus_gx_expanded wrapped
|
||||
# `(Batocera` and `package/batocera/...mk:7` one line apart.
|
||||
lead = line[:path_start]
|
||||
if number and not lead.strip():
|
||||
lead = lines[number - 1].rstrip() + " "
|
||||
role = _prose_role(lead, len(lead))
|
||||
if not role and _prose_external(lead, len(lead), known):
|
||||
# Kept with its project word, the source_ref convention: the
|
||||
# report looks for the project inside the declared trees
|
||||
# (mupen64plus-ae vendors `rice Config.cpp`) and calls the
|
||||
# citation EXTERNAL only when none carries it.
|
||||
before = lead.rstrip()
|
||||
word = before[max(before.rfind(" "), before.rfind("\t"),
|
||||
before.rfind("(")) + 1:]
|
||||
path = f"{word} {path}"
|
||||
path_span = (path_start, match.end("path"))
|
||||
if kind == 2:
|
||||
if named is None:
|
||||
continue
|
||||
path, role = named
|
||||
path_start = match.start()
|
||||
path_span = (path_start, path_start)
|
||||
else:
|
||||
path, role, path_start, path_span = _prose_path(
|
||||
line, lines, number, match, known
|
||||
)
|
||||
if path is None:
|
||||
continue
|
||||
named = (path, role)
|
||||
spans = [(match.start("range"), match.end("range"))]
|
||||
end = match.end()
|
||||
while True:
|
||||
@@ -429,6 +435,9 @@ def _prose_runs(
|
||||
spans.append((cont.start("range"), cont.end("range")))
|
||||
end = cont.end()
|
||||
consumed = end
|
||||
if end > boundary:
|
||||
indent = len(lines[number + 1]) - len(lines[number + 1].lstrip())
|
||||
carried = indent + end - joined_at
|
||||
parts = []
|
||||
for lo, hi in spans:
|
||||
rng = line[lo:hi]
|
||||
@@ -438,3 +447,44 @@ def _prose_runs(
|
||||
number, path_span, tuple(spans), tuple(parts),
|
||||
line[path_start:end], joined_at if end > boundary else 0,
|
||||
)
|
||||
|
||||
|
||||
def _prose_path(
|
||||
line: str, lines: list[str], number: int, match: re.Match,
|
||||
known: frozenset[str] | set[str],
|
||||
) -> tuple[str | None, str, int, tuple[int, int]]:
|
||||
"""(path, role, start, span) of one written citation, None for a URL."""
|
||||
token_start = max(line.rfind(" ", 0, match.start()),
|
||||
line.rfind("\t", 0, match.start())) + 1
|
||||
token = line[token_start:].split()[0] if line[token_start:] else ""
|
||||
if "://" in token:
|
||||
return None, "", 0, (0, 0)
|
||||
path = match.group("path")
|
||||
path_start = match.start("path")
|
||||
# A dotfile citation opens its token with the dot: `.gitlab-ci.yml`
|
||||
# after a delimiter is the filename, while the dot of `boot.cfg`
|
||||
# inside a word belongs to the word before it.
|
||||
if (
|
||||
path_start > 0
|
||||
and line[path_start - 1] == "."
|
||||
and (path_start == 1 or line[path_start - 2] in " \t(")
|
||||
):
|
||||
path_start -= 1
|
||||
path = "." + path
|
||||
# A path opening its line reads its role or project word at the
|
||||
# end of the line before: genesis_plus_gx_expanded wrapped
|
||||
# `(Batocera` and `package/batocera/...mk:7` one line apart.
|
||||
lead = line[:path_start]
|
||||
if number and not lead.strip():
|
||||
lead = lines[number - 1].rstrip() + " "
|
||||
role = _prose_role(lead, len(lead))
|
||||
if not role and _prose_external(lead, len(lead), known):
|
||||
# Kept with its project word, the source_ref convention: the
|
||||
# report looks for the project inside the declared trees
|
||||
# (mupen64plus-ae vendors `rice Config.cpp`) and calls the
|
||||
# citation EXTERNAL only when none carries it.
|
||||
before = lead.rstrip()
|
||||
word = before[max(before.rfind(" "), before.rfind("\t"),
|
||||
before.rfind("(")) + 1:]
|
||||
path = f"{word} {path}"
|
||||
return path, role, path_start, (path_start, match.end("path"))
|
||||
Reference in new issue
Block a user