mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-29 23:27:19 -05:00
feat: write the options glance from the parser
The glance on the installer page is written from install.py's argument parser when the page is built, grouped by GLANCE_GROUPS. An option no group names lands under Other, so a new option cannot be left off the page.
This commit is contained in:
1 parent
db0065e4f5
commit
8a8931e4c6
5 files changed
+83
-11
No files matched your search
+52
-1
@@ -861,6 +861,57 @@ def options_table(markdown: str) -> list[str]:
|
||||
return rows
|
||||
|
||||
|
||||
# The installer page's glance groups its options by task. The list is
|
||||
# written from the parser when the page is built: an option the parser
|
||||
# gains and no group names lands under "Other", never off the page.
|
||||
GLANCE_HEADING = "## Options at a glance"
|
||||
GLANCE_GROUPS: tuple[tuple[str, tuple[str, ...]], ...] = (
|
||||
("Where and for what", ("--platform", "--dest", "--target", "--every-board", "--save-dir",
|
||||
"--romm-firmware", "--standalone-copies")),
|
||||
("Fewer files", ("--system", "--core", "--emulator", "--region", "--no-game-data",
|
||||
"--declared-only", "--installed-cores", "--cores-dir")),
|
||||
("Look first", ("--check", "--dry-run", "--list-platforms", "--list-targets",
|
||||
"--list-systems", "--list-cores", "--list-emulators")),
|
||||
("From files you have", ("--from", "--from-pack", "--manifest", "--offline", "--restore")),
|
||||
("How the run talks", ("--tui", "--plain", "--no-input", "--yes", "--quiet", "--verbose",
|
||||
"--events", "--jobs", "--version", "--help")),
|
||||
)
|
||||
GLANCE_OTHER = "Other"
|
||||
|
||||
|
||||
def installer_flags() -> list[str]:
|
||||
"""Each option's first flag, in the order --help lists them."""
|
||||
return [usage.split()[0].rstrip(",") for usage, _help in installer_options()]
|
||||
|
||||
|
||||
def options_glance() -> list[str]:
|
||||
"""One line per group of the glance, each option a link to its row."""
|
||||
flags = installer_flags()
|
||||
groups = [(label, [flag for flag in members if flag in flags]) for label, members in GLANCE_GROUPS]
|
||||
named = {flag for _label, members in GLANCE_GROUPS for flag in members}
|
||||
groups.append((GLANCE_OTHER, [flag for flag in flags if flag not in named]))
|
||||
return [
|
||||
f"- **{label}**: " + ", ".join(f"[`{flag}`](#option-{flag.lstrip('-')})" for flag in members)
|
||||
for label, members in groups if members
|
||||
]
|
||||
|
||||
|
||||
def expand_glance(markdown: str) -> str:
|
||||
"""The glance's list, after the sentence that opens the section."""
|
||||
start = markdown.find(f"\n{GLANCE_HEADING}\n")
|
||||
if start == -1:
|
||||
return markdown
|
||||
body_start = start + len(GLANCE_HEADING) + 2
|
||||
end = markdown.find("\n## ", body_start)
|
||||
end = len(markdown) if end == -1 else end
|
||||
body = markdown[body_start:end].strip("\n")
|
||||
if any(line.startswith("- ") for line in body.splitlines()):
|
||||
raise ValueError(f"{GLANCE_HEADING}: the list is written from install.py's parser, "
|
||||
"not by hand")
|
||||
return (markdown[:body_start] + "\n" + body + "\n\n" + "\n".join(options_glance())
|
||||
+ "\n" + markdown[end:])
|
||||
|
||||
|
||||
def expand_options(markdown: str) -> str:
|
||||
if "installer-options" not in markdown:
|
||||
return markdown
|
||||
@@ -898,7 +949,7 @@ def hide_hashes(markdown: str) -> str:
|
||||
|
||||
def prepare_page(markdown: str, page: Path) -> str:
|
||||
"""Everything this module does to a page before it is decorated."""
|
||||
markdown = expand_options(expand_commands(resolve_images(localize_images(markdown, page))))
|
||||
markdown = expand_glance(expand_options(expand_commands(resolve_images(localize_images(markdown, page)))))
|
||||
if page.parts[:1] == ("wiki",):
|
||||
markdown = hide_hashes(markdown)
|
||||
return markdown
|
||||
|
||||
@@ -202,9 +202,7 @@ class BuiltSite(unittest.TestCase):
|
||||
def test_search_fields_hold_no_text(self) -> None:
|
||||
texts = []
|
||||
for path in (DIST / "systems").rglob("index.html"):
|
||||
# The title meta reads the visible h1 (PageTitle.astro). The
|
||||
# search fields are attributes on empty spans.
|
||||
for match in re.finditer(r"<(\w+)[^>]*data-pagefind-meta=\"(?!title\")[^>]*>([^<]*)</\1>",
|
||||
for match in re.finditer(r"<(\w+)[^>]*data-pagefind-meta=[^>]*>([^<]*)</\1>",
|
||||
path.read_text(encoding="utf-8")):
|
||||
if match[2].strip():
|
||||
texts.append(str(path.relative_to(DIST)))
|
||||
|
||||
@@ -15,6 +15,7 @@ import re
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
import yaml
|
||||
|
||||
@@ -23,6 +24,7 @@ sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
||||
|
||||
import check_freshness # noqa: E402
|
||||
import generate_site as gs # noqa: E402
|
||||
import sitediagrams # noqa: E402
|
||||
import siterender # noqa: E402
|
||||
|
||||
DIST = REPO_ROOT / "website" / "dist"
|
||||
@@ -122,6 +124,32 @@ class SourcePathsFreshness(unittest.TestCase):
|
||||
self.assertIn("sitesources.py --fetch", finding.detail)
|
||||
|
||||
|
||||
class OptionsGlanceFromTheParser(unittest.TestCase):
|
||||
"""--declared-only and --offline reached install.py and its Options
|
||||
table, and not the hand-written glance above it."""
|
||||
|
||||
def test_every_parser_option_has_a_group(self):
|
||||
named = {flag for _label, flags in sitediagrams.GLANCE_GROUPS for flag in flags}
|
||||
self.assertEqual(set(sitediagrams.installer_flags()) - named, set())
|
||||
self.assertEqual(named - set(sitediagrams.installer_flags()), set())
|
||||
|
||||
def test_an_option_no_group_names_still_lands(self):
|
||||
with mock.patch.object(sitediagrams, "installer_flags",
|
||||
return_value=["--platform", "--brand-new"]):
|
||||
lines = sitediagrams.options_glance()
|
||||
self.assertEqual(lines, [
|
||||
"- **Where and for what**: [`--platform`](#option-platform)",
|
||||
"- **Other**: [`--brand-new`](#option-brand-new)",
|
||||
])
|
||||
|
||||
def test_the_source_holds_no_list(self):
|
||||
text = (REPO_ROOT / "wiki" / "installer.md").read_text(encoding="utf-8")
|
||||
section = text[text.index(sitediagrams.GLANCE_HEADING):text.index("\n## One line")]
|
||||
self.assertNotIn("\n- ", section)
|
||||
with self.assertRaises(ValueError):
|
||||
sitediagrams.expand_glance(f"# x\n\n{sitediagrams.GLANCE_HEADING}\n\n- a\n\n## y\n")
|
||||
|
||||
|
||||
@unittest.skipUnless((DIST / "systems" / "arcade-acclaim-zn-1" / "index.html").is_file(),
|
||||
"site not built")
|
||||
class BuiltCrumbs(unittest.TestCase):
|
||||
|
||||
@@ -323,7 +323,8 @@ class OneOptionsTable(unittest.TestCase):
|
||||
self.text = _wiki("installer.md")
|
||||
|
||||
def test_each_option_links_to_its_row(self):
|
||||
glance = _section(self.text, "Options at a glance")
|
||||
# The glance is written from the parser when the page is built.
|
||||
glance = _section(sitediagrams.expand_glance(self.text), "Options at a glance")
|
||||
table = _section(self.text, "Options")
|
||||
self.assertNotIn("installer-options", glance)
|
||||
self.assertNotIn("|", glance)
|
||||
|
||||
@@ -25,12 +25,6 @@ How the command protects your machine is under
|
||||
|
||||
Each links to its row in the [Options](#options) table.
|
||||
|
||||
- **Where and for what**: [`--platform`](#option-platform), [`--dest`](#option-dest), [`--target`](#option-target), [`--every-board`](#option-every-board), [`--save-dir`](#option-save-dir), [`--romm-firmware`](#option-romm-firmware), [`--standalone-copies`](#option-standalone-copies)
|
||||
- **Fewer files**: [`--system`](#option-system), [`--core`](#option-core), [`--emulator`](#option-emulator), [`--region`](#option-region), [`--no-game-data`](#option-no-game-data), [`--declared-only`](#option-declared-only), [`--installed-cores`](#option-installed-cores), [`--cores-dir`](#option-cores-dir)
|
||||
- **Look first**: [`--check`](#option-check), [`--dry-run`](#option-dry-run), [`--list-platforms`](#option-list-platforms), [`--list-targets`](#option-list-targets), [`--list-systems`](#option-list-systems), [`--list-cores`](#option-list-cores), [`--list-emulators`](#option-list-emulators)
|
||||
- **From files you have**: [`--from`](#option-from), [`--from-pack`](#option-from-pack), [`--manifest`](#option-manifest), [`--offline`](#option-offline), [`--restore`](#option-restore)
|
||||
- **How the run talks**: [`--tui`](#option-tui), [`--plain`](#option-plain), [`--no-input`](#option-no-input), [`--yes`](#option-yes), [`--quiet`](#option-quiet), [`--verbose`](#option-verbose), [`--events`](#option-events), [`--jobs`](#option-jobs), [`--version`](#option-version), [`--help`](#option-help)
|
||||
|
||||
## One line
|
||||
|
||||
```bash
|
||||
|
||||
Reference in new issue
Block a user