From 124e96cd09849c5c5d5e80f2cff8c909eac61365 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Thu, 5 Nov 2026 19:35:32 +0100 Subject: [PATCH] fix: keep glossary tooltips out of proper names The glossary's capitalised terms matched mostly inside product names and paths: Free Unix Spectrum Emulator, Windows Terminal, Documents/Dolphin Emulator, on 35 pages. A capitalised term after a capitalised word or a slash is now left alone. Acronyms keep their tooltip. --- scripts/sitestarlight.py | 13 ++++++++++++- tests/test_site_render.py | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/scripts/sitestarlight.py b/scripts/sitestarlight.py index bf532b9f5..f4ffbf027 100644 --- a/scripts/sitestarlight.py +++ b/scripts/sitestarlight.py @@ -244,10 +244,21 @@ def _tooltip_line(line: str, pattern: re.Pattern, pending: dict[str, str]) -> st return "".join(out) +_NAME_BEFORE = re.compile(r"(?:/|\b[A-Z][\w'-]*[ \t]+)$") + + +def _in_proper_name(term: str, before: str) -> bool: + """A capitalised term after a capitalised word or a slash is part of a + name: Free Unix Spectrum Emulator, Windows Terminal, Documents/Dolphin + Emulator. An acronym (BIOS, ZIP) is the term wherever it stands.""" + first = term.split()[0] + return first[:1].isupper() and not first.isupper() and bool(_NAME_BEFORE.search(before)) + + def _tooltip_text(text: str, pattern: re.Pattern, pending: dict[str, str]) -> str: def swap(match: re.Match) -> str: term = match.group(1) - if term not in pending: + if term not in pending or _in_proper_name(term, text[:match.start()]): return term definition = pending.pop(term) return f'{term}' diff --git a/tests/test_site_render.py b/tests/test_site_render.py index e943dffde..eebcaf79d 100644 --- a/tests/test_site_render.py +++ b/tests/test_site_render.py @@ -484,3 +484,24 @@ class AMemberIsReadInItsArchive(unittest.TestCase): lambda _f: True, owner="fbneo")) self.assertIn("Collection copy: member `sm1.sm1` of", rows) self.assertIn(shipped, rows) + + +class NoTooltipInsideAName(unittest.TestCase): + """The glossary's capitalised terms matched almost only product names: + Free Unix Spectrum Emulator, Windows Terminal, Documents/Dolphin Emulator.""" + + def test_names_are_left_and_terms_are_marked(self): + import sitestarlight + + terms = {"Emulator": "An app that acts like a console.", + "Terminal": "A window where you type commands.", + "BIOS": "The console's built-in software."} + for line in ("Fuse (Free Unix Spectrum Emulator) reads it.", + "Open Windows Terminal (WSL).", + "Copy it to Documents/Dolphin Emulator/Sys."): + with self.subTest(line=line): + self.assertNotIn("rb-term", sitestarlight.add_tooltips(line, terms)) + marked = sitestarlight.add_tooltips( + "Emulator settings come first. The PlayStation BIOS goes there.", terms) + self.assertIn('title="An app that acts like a console.">Emulator', marked) + self.assertIn('>BIOS', marked)