mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 20:29:06 -05:00
fix: show every field of structured profile blocks
The analysis and firmware blocks printed their source_ref as plain code, dropped any list or map inside a list item (cemu's firmware title contents), cut values at 200 characters and let a folded note's second line leave its admonition. Citations are now pinned links and every value is shown on its own line.
This commit is contained in:
1 parent
76b41741ec
commit
90e54dcb43
3 files changed
+89
-15
No files matched your search
@@ -3055,6 +3055,22 @@ def _plain_value(value: object) -> str:
|
||||
return _escape_tags(str(value))
|
||||
|
||||
|
||||
def _structured_field_text(profile: dict) -> Callable[[object, object], str]:
|
||||
"""Scalars of a structured block, citations linked at the profile's pin.
|
||||
|
||||
The file entries and platform details linked their source_ref, and the
|
||||
analysis and firmware blocks printed 186 of them as plain code.
|
||||
"""
|
||||
def text(key: object, value: object) -> str:
|
||||
if key == "source_ref" and isinstance(value, str):
|
||||
return _source_ref_markdown(profile, value)
|
||||
if isinstance(value, str):
|
||||
return link_prose_citations(profile, _field_text(key, value))
|
||||
return _field_text(key, value)
|
||||
|
||||
return text
|
||||
|
||||
|
||||
def _render_structured_blocks(profile: dict) -> list[str]:
|
||||
"""Every remaining structured field, as a collapsible section."""
|
||||
lines: list[str] = []
|
||||
@@ -3090,7 +3106,8 @@ def _render_structured_blocks(profile: dict) -> list[str]:
|
||||
lines.append(f'???+ abstract "{label}"')
|
||||
lines.append("")
|
||||
start = len(lines)
|
||||
_render_yaml_value(lines, val, indent=4)
|
||||
_render_yaml_value(lines, val, indent=4,
|
||||
field_text=_structured_field_text(profile))
|
||||
lines[start:] = [_escape_tags(line) for line in lines[start:]]
|
||||
lines.append("")
|
||||
|
||||
@@ -5168,6 +5185,7 @@ from sitesources import ( # noqa: E402,F401
|
||||
from siterender import ( # noqa: E402,F401
|
||||
_by_mode,
|
||||
_count,
|
||||
_field_text,
|
||||
_render_yaml_value,
|
||||
_slugify_anchor,
|
||||
_system_page_map,
|
||||
|
||||
+28
-14
@@ -8,6 +8,7 @@ import sys
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
from collections.abc import Callable
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from pathlib import Path
|
||||
|
||||
@@ -212,9 +213,10 @@ def _field_text(key: object, value: object) -> str:
|
||||
elif value is None:
|
||||
text = "none"
|
||||
else:
|
||||
text = str(value)
|
||||
if len(text) > 200:
|
||||
text = text[:200] + "..."
|
||||
# One line: a folded note's second line started at column 0 and
|
||||
# left the admonition it was written in. Never cut: 34 notes lost
|
||||
# their end, and a cut citation links to another line.
|
||||
text = " ".join(str(value).split())
|
||||
return f"`{text}`" if key == "source_ref" else text
|
||||
|
||||
|
||||
@@ -223,12 +225,19 @@ def _field_label(key: object) -> str:
|
||||
return str(key).replace("_", " ")
|
||||
|
||||
|
||||
def _render_yaml_value(lines: list[str], val: object, indent: int = 4) -> None:
|
||||
FieldText = Callable[[object, object], str]
|
||||
|
||||
|
||||
def _render_yaml_value(
|
||||
lines: list[str], val: object, indent: int = 4,
|
||||
field_text: FieldText = _field_text,
|
||||
) -> None:
|
||||
"""Render any YAML value as a nested markdown list.
|
||||
|
||||
Every level is a list item and its children a sublist four spaces in.
|
||||
A key written as a paragraph with its children indented below it read as
|
||||
an indented code block: the clownmdemu page showed the raw asterisks.
|
||||
``field_text`` renders each scalar, so a page can link a source_ref.
|
||||
"""
|
||||
pad = " " * indent
|
||||
if isinstance(val, dict):
|
||||
@@ -236,27 +245,32 @@ def _render_yaml_value(lines: list[str], val: object, indent: int = 4) -> None:
|
||||
if isinstance(v, (dict, list)) and v:
|
||||
lines.append(f"{pad}- **{_field_label(k)}:**")
|
||||
lines.append("")
|
||||
_render_yaml_value(lines, v, indent + 4)
|
||||
_render_yaml_value(lines, v, indent + 4, field_text)
|
||||
else:
|
||||
lines.append(f"{pad}- **{_field_label(k)}:** {_field_text(k, v)}")
|
||||
lines.append(f"{pad}- **{_field_label(k)}:** {field_text(k, v)}")
|
||||
lines.append("")
|
||||
elif isinstance(val, list):
|
||||
for item in val:
|
||||
if isinstance(item, dict):
|
||||
parts = [
|
||||
f"{_field_label(ik)}: {_field_text(ik, iv)}"
|
||||
for ik, iv in item.items()
|
||||
if not isinstance(iv, (dict, list))
|
||||
]
|
||||
lines.append(f"{pad}- {', '.join(parts)}")
|
||||
# Scalars on the item's line, lists and maps as its children:
|
||||
# cemu's firmware titles lost the files each title carries.
|
||||
scalars = {ik: iv for ik, iv in item.items()
|
||||
if not (isinstance(iv, (dict, list)) and iv)}
|
||||
nested = {ik: iv for ik, iv in item.items() if ik not in scalars}
|
||||
parts = [f"{_field_label(ik)}: {field_text(ik, iv)}"
|
||||
for ik, iv in scalars.items()]
|
||||
lines.append(f"{pad}- {', '.join(parts)}".rstrip())
|
||||
if nested:
|
||||
lines.append("")
|
||||
_render_yaml_value(lines, nested, indent + 4, field_text)
|
||||
else:
|
||||
lines.append(f"{pad}- {_field_text(None, item)}")
|
||||
lines.append(f"{pad}- {field_text(None, item)}")
|
||||
lines.append("")
|
||||
elif isinstance(val, str) and "\n" in val:
|
||||
for line in val.split("\n"):
|
||||
lines.append(f"{pad}{line}")
|
||||
else:
|
||||
lines.append(f"{pad}{_field_text(None, val)}")
|
||||
lines.append(f"{pad}{field_text(None, val)}")
|
||||
|
||||
|
||||
def _platform_link(name: str, display: str, prefix: str = "") -> str:
|
||||
|
||||
@@ -139,5 +139,47 @@ class BundledFilesAreNotToSource(unittest.TestCase):
|
||||
'<span class="rb-badge rb-badge-danger">1</span> |', page)
|
||||
|
||||
|
||||
class StructuredBlocks(unittest.TestCase):
|
||||
PIN = "1e0de94dc7e669c0925a22c0fccf6cdc837af0a0"
|
||||
|
||||
def profile(self, block: str, value: object) -> dict:
|
||||
return {"source": "https://github.com/libretro/blastem",
|
||||
"source_commit": self.PIN, block: value}
|
||||
|
||||
def render(self, profile: dict) -> str:
|
||||
import generate_site
|
||||
|
||||
return "\n".join(generate_site._render_structured_blocks(profile))
|
||||
|
||||
def test_a_source_ref_in_a_block_is_a_pinned_link(self):
|
||||
"""186 citations in analysis and firmware blocks were plain code."""
|
||||
page = self.render(self.profile("analysis", {"tmss": {
|
||||
"source_ref": "libblastem.c:355-359"}}))
|
||||
self.assertIn(
|
||||
f"[`libblastem.c:355-359`](https://github.com/libretro/blastem/blob/"
|
||||
f"{self.PIN}/libblastem.c#L355-L359)", page)
|
||||
|
||||
def test_a_list_inside_a_list_item_is_shown(self):
|
||||
"""cemu's firmware titles lost the files each title carries."""
|
||||
page = self.render(self.profile("firmware_titles", [
|
||||
{"id": "0005001b-10042400", "name": "Shared fonts",
|
||||
"content": ["CafeCn.ttf", "CafeKr.ttf"]}]))
|
||||
self.assertIn(" - id: 0005001b-10042400, name: Shared fonts\n", page)
|
||||
self.assertIn(" - **content:**", page)
|
||||
self.assertIn(" - CafeKr.ttf", page)
|
||||
|
||||
def test_a_folded_note_stays_inside_its_block(self):
|
||||
page = self.render(self.profile("analysis", {"tmss": {
|
||||
"note": "The core points\nsystem/tmss_path at the system directory."}}))
|
||||
self.assertIn("- **note:** The core points system/tmss_path at the", page)
|
||||
body = page.split("\n")[1:]
|
||||
self.assertEqual([line for line in body if line and not line.startswith(" ")], [])
|
||||
|
||||
def test_a_long_note_is_not_cut(self):
|
||||
note = "word " * 80 + "end."
|
||||
page = self.render(self.profile("analysis", {"x": {"note": note}}))
|
||||
self.assertIn("end.", page)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user