From 6a3471378ec4b5471838791054e686de29ac7e6b Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sat, 24 Oct 2026 04:02:57 +0200 Subject: [PATCH] fix: one spelling of shared files per system The focused system's size is spelled out below the list when its name leaves no room for it. The browser's system folder test is renamed _os_folder: _system_folder already names the --from refusal. --- install.py | 20 +++++++++++++++----- tests/test_install_tui.py | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/install.py b/install.py index 5822a0ee4..fad91a913 100644 --- a/install.py +++ b/install.py @@ -10785,12 +10785,13 @@ def _system_rows(state: TuiState) -> list[TuiRow]: right = f"{_plural(need, 'file')}, {format_size(row['bytes_needed'])}" narrow = (format_size(row["bytes_needed"]),) elif not own: + # Two spellings of shared, never cut: "+ 28 sh." and ", shared" + # sat beside "+ 1689 shared" on one 40-column screen. right = f"{_plural(need, 'file')}, {format_size(size)}, all shared" - narrow = (f"{format_size(size)}, shared", format_size(size)) + narrow = (f"{format_size(size)}, all shared", format_size(size)) else: right = f"{_plural(own, 'file')}, {format_size(own_size)} + {count} shared" - narrow = (f"{format_size(own_size)} + {count} shared", - f"{format_size(own_size)} + {count} sh.", format_size(own_size)) + narrow = (f"{format_size(own_size)} + {count} shared", format_size(own_size)) rows.append(TuiRow("system", f"{box} {label}", right, row["system"], "" if need else "dim", narrow)) return rows @@ -11090,7 +11091,7 @@ _POSIX_ROOT_SYSTEM = frozenset(( _WINDOWS_HIDDEN = 0x2 | 0x4 -def _system_folder(path: Path, folder: Path) -> bool: +def _os_folder(path: Path, folder: Path) -> bool: """A folder of the system, not one a person keeps files in: the recycle bin and restore points of a Windows drive ($RECYCLE.BIN, System Volume Information, hidden by Explorer), and /bin, /etc, /usr and the @@ -11121,7 +11122,7 @@ def _browse_to(state: TuiState, folder: Path | None, came_from: Path | None = No focus = next((index for index, row in enumerate(state.browse_rows) if row.action == "dir" and isinstance(row.value, Path) and row.label == f"{row.value.name}/" - and not _system_folder(row.value, folder)), 0) + and not _os_folder(row.value, folder)), 0) if not focus and not state.status: state.status = ("This is your home folder: no setup reads its BIOS files " "here. Go back to type a path." if folder == state.home @@ -12256,6 +12257,7 @@ def _ticked_files(state: TuiState) -> list[dict]: def _view_systems(state: TuiState, width: int, height: int) -> tuple: rows = tui_rows(state) + whole_rows = rows if width < 60: # The name first: the size alone stays beside it, the count is in # the total below. @@ -12273,6 +12275,14 @@ def _view_systems(state: TuiState, width: int, height: int) -> tuple: f"{format_size(sum(e['size'] for e in chosen))}" + (" before your options" if _counts_predate_options(state) else "")] focused = rows[min(state.focus.get("systems", 0), len(rows) - 1)] + drawn = str(_row_line(focused, True, width)) + if focused.action == "system" and not ( + f"> {focused.label}" in drawn + and any(form and drawn.endswith(form) for form in (focused.right, *focused.narrow))): + # A long name kept whole leaves no room for its size, and a name + # longer than the screen is cut: both are spelled out below. + whole = whole_rows[min(state.focus.get("systems", 0), len(whole_rows) - 1)] + footer.insert(0, f"{whole.label[4:]}: {whole.right}") if focused.value == OTHER_SYSTEMS: footer.insert(0, OTHER_HELP) elif "shared" in focused.right: diff --git a/tests/test_install_tui.py b/tests/test_install_tui.py index 170e7008d..7b8021979 100644 --- a/tests/test_install_tui.py +++ b/tests/test_install_tui.py @@ -447,7 +447,7 @@ class Flow(unittest.TestCase): self.assertEqual(press(state, "enter"), []) self.assertIn("No system is ticked", state.status) focus = next(i for i, row in enumerate(install.tui_rows(state)) - if row.value == "nintendo-gba") + if row.value == "epoch-scv") state.focus["systems"] = focus press(state, "right") self.assertEqual(press(state, "enter"), [("run", "confirm")]) @@ -1513,7 +1513,7 @@ class AuditRoundTwo(unittest.TestCase): state = self.systems() press(state, "n") state.focus["systems"] = next(i for i, row in enumerate(install.tui_rows(state)) - if row.value == "nintendo-gba") + if row.value == "epoch-scv") press(state, "right") self.assertEqual(state.ticked, {"nintendo-gba"}) press(state, "/", "p", "l", "a", "y") @@ -2841,6 +2841,35 @@ class NarrowSystemNames(unittest.TestCase): self.assertIn("3 files, 30.0 MB + 27 shared", "\n".join(install.tui_view(state, 120, 40))) + def test_one_spelling_of_shared_and_the_focused_size_below(self): + """At 40 columns the shared part read "+ 1689 shared", "+ 28 sh.", + ", shared" and ", all shared" on one screen, and a long name kept + whole lost its size.""" + state = checked_state() + names = {"epoch-scv": "Epoch Super Cassette Vision", "sega-dc": "Sega Dreamcast", + "snk-ng": "SNK Neo Geo"} + state.manifest = {**state.manifest, "system_titles": names} + state.systems = [ + {"event": "system", "platform": "retroarch", "system": system, "name": system, + "files": count, "present": 0, "missing": count, "wrong_hash": 0, + "bytes_needed": count * 1024} + for system, count in (("epoch-scv", 30), ("sega-dc", 1690), ("snk-ng", 3))] + state.files = [{"event": "file", "platform": "retroarch", "dest": f"s{n}.bin", + "systems": ["sega-dc", "snk-ng"], "size": 1024, "state": "missing"} + for n in range(3)] + state.ticked = set(names) + state.stack.append("systems") + spellings = set() + for cols in (40, 46, 52, 80): + text = "\n".join(install.tui_view(state, cols, 15)) + spellings |= set(re.findall(r"\+ \d+ sh\w*\.?|, (?:all )?shared", text)) + self.assertLessEqual(spellings, {"+ 3 shared", ", all shared"}, spellings) + state.focus["systems"] = next( + index for index, row in enumerate(install.tui_rows(state)) + if row.value == "epoch-scv") + text = " ".join(" ".join(install.tui_view(state, 40, 15)).split()) + self.assertIn("Epoch Super Cassette Vision: 30 files, 30.0 KB", text) + class Crash(unittest.TestCase): """An unexpected error ends on one sentence and a log, never a traceback."""